!210 文件表type字段修改

Merge pull request !210 from 随心/master
This commit is contained in:
芋道源码 2022-07-09 10:12:22 +00:00 committed by Gitee
commit b0d635e1f0
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
13 changed files with 98 additions and 46 deletions

View File

@ -689,10 +689,10 @@ DROP TABLE IF EXISTS `infra_file`;
CREATE TABLE `infra_file` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '文件编号',
`config_id` bigint NULL DEFAULT NULL COMMENT '配置编号',
`name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件名',
`name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件名',
`path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件路径',
`url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件 URL',
`type` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件类型',
`type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件MIME类型',
`size` int NOT NULL COMMENT '文件大小',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

View File

@ -878,7 +878,7 @@ CREATE TABLE "INFRA_FILE" (
"CONFIG_ID" NUMBER(20,0),
"PATH" NVARCHAR2(512),
"URL" NCLOB,
"TYPE" NVARCHAR2(63),
"TYPE" NVARCHAR2(64),
"SIZE" NUMBER(11,0) NOT NULL,
"CREATOR" NVARCHAR2(64),
"CREATE_TIME" DATE NOT NULL,
@ -908,7 +908,7 @@ COMMENT ON COLUMN "INFRA_FILE"."ID" IS '文件编号';
COMMENT ON COLUMN "INFRA_FILE"."CONFIG_ID" IS '配置编号';
COMMENT ON COLUMN "INFRA_FILE"."PATH" IS '文件路径';
COMMENT ON COLUMN "INFRA_FILE"."URL" IS '文件 URL';
COMMENT ON COLUMN "INFRA_FILE"."TYPE" IS '文件类型';
COMMENT ON COLUMN "INFRA_FILE"."TYPE" IS '文件MIME类型';
COMMENT ON COLUMN "INFRA_FILE"."SIZE" IS '文件大小';
COMMENT ON COLUMN "INFRA_FILE"."CREATOR" IS '创建者';
COMMENT ON COLUMN "INFRA_FILE"."CREATE_TIME" IS '创建时间';

View File

@ -1717,21 +1717,21 @@ CREATE TABLE "infra_file" (
"config_id" int8,
"path" varchar(512) COLLATE "pg_catalog"."default" NOT NULL,
"url" varchar(1024) COLLATE "pg_catalog"."default" NOT NULL,
"type" varchar(63) COLLATE "pg_catalog"."default",
"type" varchar(64) COLLATE "pg_catalog"."default",
"size" int4 NOT NULL,
"creator" varchar(64) COLLATE "pg_catalog"."default",
"create_time" timestamp(6) NOT NULL,
"updater" varchar(64) COLLATE "pg_catalog"."default",
"update_time" timestamp(6) NOT NULL,
"deleted" int2 NOT NULL DEFAULT 0,
"name" varchar(255) COLLATE "pg_catalog"."default"
"name" varchar(512) COLLATE "pg_catalog"."default"
)
;
COMMENT ON COLUMN "infra_file"."id" IS '文件编号';
COMMENT ON COLUMN "infra_file"."config_id" IS '配置编号';
COMMENT ON COLUMN "infra_file"."path" IS '文件路径';
COMMENT ON COLUMN "infra_file"."url" IS '文件 URL';
COMMENT ON COLUMN "infra_file"."type" IS '文件类型';
COMMENT ON COLUMN "infra_file"."type" IS '文件MIME类型';
COMMENT ON COLUMN "infra_file"."size" IS '文件大小';
COMMENT ON COLUMN "infra_file"."creator" IS '创建者';
COMMENT ON COLUMN "infra_file"."create_time" IS '创建时间';

View File

@ -2634,14 +2634,14 @@ CREATE TABLE [dbo].[infra_file] (
[config_id] bigint NULL,
[path] nvarchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[url] nvarchar(1024) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[type] nvarchar(63) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[type] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[size] int NOT NULL,
[creator] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[create_time] datetime2(7) NOT NULL,
[updater] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[update_time] datetime2(7) NOT NULL,
[deleted] bit DEFAULT 0 NOT NULL,
[name] nvarchar(256) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
[name] nvarchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
)
GO
@ -2677,7 +2677,7 @@ EXEC sp_addextendedproperty
GO
EXEC sp_addextendedproperty
'MS_Description', N'文件类型',
'MS_Description', N'文件 MIME 类型',
'SCHEMA', N'dbo',
'TABLE', N'infra_file',
'COLUMN', N'type'

View File

@ -1,9 +1,14 @@
package cn.iocoder.yudao.framework.common.util.io;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import lombok.SneakyThrows;
import java.io.ByteArrayInputStream;
import java.io.File;
/**
@ -58,8 +63,20 @@ public class FileUtils {
return file;
}
public static void main(String[] args) {
/**
* @param content 文件内容
* @param originalName 原始文件名
* @return path唯一不可重复
*/
public static String generatePath(byte[] content, String originalName) {
String sha256Hex = DigestUtil.sha256Hex(content);
// 如果存在name则优先使用name的后缀
if (StrUtil.isNotBlank(originalName)) {
String extName = FileNameUtil.extName(originalName);
return StrUtil.isBlank(extName) ? sha256Hex : sha256Hex + "." + extName;
} else {
return sha256Hex + '.' + FileTypeUtil.getType(new ByteArrayInputStream(content));
}
}
}

View File

@ -4,8 +4,6 @@ import com.alibaba.ttl.TransmittableThreadLocal;
import lombok.SneakyThrows;
import org.apache.tika.Tika;
import java.io.ByteArrayInputStream;
/**
* 文件类型 Utils
*
@ -16,14 +14,35 @@ public class FileTypeUtils {
private static final ThreadLocal<Tika> TIKA = TransmittableThreadLocal.withInitial(Tika::new);
/**
* 获得文件的 mineType
* 获得文件的 mineType对于docjar等文件会有误差
*
* @param data 文件内容
* @return mineType
* @return mineType 无法识别时会返回application/octet-stream
*/
@SneakyThrows
public static String getMineType(byte[] data) {
return TIKA.get().detect(new ByteArrayInputStream(data));
return TIKA.get().detect(data);
}
/**
* 已知文件名获取文件类型在某些情况下比通过字节数组准确例如使用jar文件时通过名字更为准确
*
* @param name 文件名
* @return mineType 无法识别时会返回application/octet-stream
*/
public static String getMineType(String name) {
return TIKA.get().detect(name);
}
/**
* 在拥有文件和数据的情况下最好使用此方法最为准确
*
* @param data 文件内容
* @param name 文件名
* @return mineType 无法识别时会返回application/octet-stream
*/
public static String getMineType(byte[] data, String name) {
return TIKA.get().detect(data, name);
}
}

View File

@ -21,7 +21,7 @@ public class FilePageReqVO extends PageParam {
@ApiModelProperty(value = "文件路径", example = "yudao", notes = "模糊匹配")
private String path;
@ApiModelProperty(value = "文件类型", example = "jpg", notes = "模糊匹配")
@ApiModelProperty(value = "文件类型", example = "application/octet-stream", notes = "模糊匹配")
private String type;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)

View File

@ -13,6 +13,9 @@ public class FileRespVO {
@ApiModelProperty(value = "文件编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "配置编号", required = true, example = "11")
private Long configId;
@ApiModelProperty(value = "文件路径", required = true, example = "yudao.jpg")
private String path;
@ -22,7 +25,7 @@ public class FileRespVO {
@ApiModelProperty(value = "文件 URL", required = true, example = "https://www.iocoder.cn/yudao.jpg")
private String url;
@ApiModelProperty(value = "文件类型", example = "jpg")
@ApiModelProperty(value = "文件MIME类型", example = "application/octet-stream")
private String type;
@ApiModelProperty(value = "文件大小", example = "2048", required = true)

View File

@ -46,9 +46,7 @@ public class FileDO extends BaseDO {
*/
private String url;
/**
* 文件类型
*
* 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取
* 文件的MIME类型例如"application/octet-stream"
*/
private String type;
/**

View File

@ -1,9 +1,10 @@
package cn.iocoder.yudao.module.infra.service.file;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
import cn.iocoder.yudao.framework.file.core.client.FileClient;
import cn.iocoder.yudao.framework.file.core.utils.FileTypeUtils;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
@ -40,10 +41,9 @@ public class FileServiceImpl implements FileService {
@SneakyThrows
public String createFile(String name, String path, byte[] content) {
// 计算默认的 path
String type = FileTypeUtils.getMineType(content);
String type = FileTypeUtils.getMineType(content, name);
if (StrUtil.isEmpty(path)) {
path = DigestUtil.md5Hex(content)
+ '.' + StrUtil.subAfter(type, '/', true); // 文件的后缀
path = FileUtils.generatePath(content, name);
}
// 如果 name 为空则使用 path 填充
if (StrUtil.isEmpty(name)) {

View File

@ -40,7 +40,7 @@ public class FileServiceTest extends BaseDbUnitTest {
// mock 数据
FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到
o.setPath("yunai");
o.setType("jpg");
o.setType("image/jpg");
o.setCreateTime(buildTime(2021, 1, 15));
});
fileMapper.insert(dbFile);
@ -48,7 +48,7 @@ public class FileServiceTest extends BaseDbUnitTest {
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("tudou")));
// 测试 type 不匹配
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> {
o.setType("png");
o.setType("image/png");
}));
// 测试 createTime 不匹配
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> {
@ -90,7 +90,7 @@ public class FileServiceTest extends BaseDbUnitTest {
assertEquals(10L, file.getConfigId());
assertEquals(path, file.getPath());
assertEquals(url, file.getUrl());
assertEquals("jpg", file.getType());
assertEquals("image/jpg", file.getType());
assertEquals(content.length, file.getSize());
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.social;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@ -21,6 +22,11 @@ import lombok.*;
@AllArgsConstructor
public class SocialUserBindDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 关联的用户编号
*

View File

@ -26,27 +26,32 @@
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="文件名" align="center" prop="name" />
<el-table-column label="文件路径" align="center" prop="path" />
<el-table-column label="文件 URL" align="center" prop="url" />
<el-table-column label="文件大小" align="center" prop="size" width="120" :formatter="sizeFormat" />
<el-table-column label="文件类型" align="center" prop="type" width="80" />
<!-- <el-table-column label="文件内容" align="center" prop="content">-->
<!-- <template slot-scope="scope">-->
<!-- <img v-if="scope.row.type === 'jpg' || scope.row.type === 'png' || scope.row.type === 'gif'"-->
<!-- width="200px" :src="getFileUrl + scope.row.id">-->
<!-- <i v-else>非图片无法预览</i>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="上传时间" align="center" prop="createTime" width="180">
<el-table-column label="文件名" :show-overflow-tooltip="true" align="center" min-width="200px" prop="name"/>
<el-table-column label="文件路径" :show-overflow-tooltip="true" align="center" min-width="250px" prop="path"/>
<el-table-column label="文件 URL" :show-overflow-tooltip="true" align="center" min-width="300px" prop="url"/>
<el-table-column label="文件大小" align="center" prop="size" min-width="120px" :formatter="sizeFormat"/>
<el-table-column label="文件类型" :show-overflow-tooltip="true" align="center" prop="type" width="180px"/>
<el-table-column label="文件内容" align="center" prop="content" min-width="150px">
<template slot-scope="scope">
<image-preview v-if="scope.row.type&&scope.row.type.indexOf('image/') === 0" :src="scope.row.url"
:width="'100px'"></image-preview>
<i v-else>无法预览点击
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" target="_blank"
:href="getFileUrl + scope.row.configId + '/get/' + scope.row.path">下载
</el-link>
</i>
</template>
</el-table-column>
<el-table-column label="上传时间" align="center" prop="createTime" min-width="170px">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100">
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" min-width="100px">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['infra:file:delete']">删除</el-button>
v-hasPermi="['infra:file:delete']">删除
</el-button>
</template>
</el-table-column>
</el-table>
@ -77,14 +82,18 @@
</template>
<script>
import { deleteFile, getFilePage } from "@/api/infra/file";
import {deleteFile, getFilePage} from "@/api/infra/file";
import {getAccessToken} from "@/utils/auth";
import ImagePreview from "@/components/ImagePreview";
export default {
name: "File",
components: {
ImagePreview
},
data() {
return {
getFileUrl: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/get/',
getFileUrl: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/',
//
loading: true,
//