!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` ( CREATE TABLE `infra_file` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '文件编号', `id` bigint NOT NULL AUTO_INCREMENT COMMENT '文件编号',
`config_id` bigint NULL DEFAULT NULL 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 '文件路径', `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', `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 '文件大小', `size` int NOT NULL COMMENT '文件大小',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP 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), "CONFIG_ID" NUMBER(20,0),
"PATH" NVARCHAR2(512), "PATH" NVARCHAR2(512),
"URL" NCLOB, "URL" NCLOB,
"TYPE" NVARCHAR2(63), "TYPE" NVARCHAR2(64),
"SIZE" NUMBER(11,0) NOT NULL, "SIZE" NUMBER(11,0) NOT NULL,
"CREATOR" NVARCHAR2(64), "CREATOR" NVARCHAR2(64),
"CREATE_TIME" DATE NOT NULL, "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"."CONFIG_ID" IS '配置编号';
COMMENT ON COLUMN "INFRA_FILE"."PATH" IS '文件路径'; COMMENT ON COLUMN "INFRA_FILE"."PATH" IS '文件路径';
COMMENT ON COLUMN "INFRA_FILE"."URL" IS '文件 URL'; 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"."SIZE" IS '文件大小';
COMMENT ON COLUMN "INFRA_FILE"."CREATOR" IS '创建者'; COMMENT ON COLUMN "INFRA_FILE"."CREATOR" IS '创建者';
COMMENT ON COLUMN "INFRA_FILE"."CREATE_TIME" IS '创建时间'; COMMENT ON COLUMN "INFRA_FILE"."CREATE_TIME" IS '创建时间';

View File

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

View File

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

View File

@ -1,9 +1,14 @@
package cn.iocoder.yudao.framework.common.util.io; 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.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
/** /**
@ -58,8 +63,20 @@ public class FileUtils {
return file; 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 lombok.SneakyThrows;
import org.apache.tika.Tika; import org.apache.tika.Tika;
import java.io.ByteArrayInputStream;
/** /**
* 文件类型 Utils * 文件类型 Utils
* *
@ -16,14 +14,35 @@ public class FileTypeUtils {
private static final ThreadLocal<Tika> TIKA = TransmittableThreadLocal.withInitial(Tika::new); private static final ThreadLocal<Tika> TIKA = TransmittableThreadLocal.withInitial(Tika::new);
/** /**
* 获得文件的 mineType * 获得文件的 mineType对于docjar等文件会有误差
* *
* @param data 文件内容 * @param data 文件内容
* @return mineType * @return mineType 无法识别时会返回application/octet-stream
*/ */
@SneakyThrows @SneakyThrows
public static String getMineType(byte[] data) { 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 = "模糊匹配") @ApiModelProperty(value = "文件路径", example = "yudao", notes = "模糊匹配")
private String path; private String path;
@ApiModelProperty(value = "文件类型", example = "jpg", notes = "模糊匹配") @ApiModelProperty(value = "文件类型", example = "application/octet-stream", notes = "模糊匹配")
private String type; private String type;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)

View File

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

View File

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

View File

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

View File

@ -40,7 +40,7 @@ public class FileServiceTest extends BaseDbUnitTest {
// mock 数据 // mock 数据
FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到 FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到
o.setPath("yunai"); o.setPath("yunai");
o.setType("jpg"); o.setType("image/jpg");
o.setCreateTime(buildTime(2021, 1, 15)); o.setCreateTime(buildTime(2021, 1, 15));
}); });
fileMapper.insert(dbFile); fileMapper.insert(dbFile);
@ -48,7 +48,7 @@ public class FileServiceTest extends BaseDbUnitTest {
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("tudou"))); fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("tudou")));
// 测试 type 不匹配 // 测试 type 不匹配
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> {
o.setType("png"); o.setType("image/png");
})); }));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> {
@ -90,7 +90,7 @@ public class FileServiceTest extends BaseDbUnitTest {
assertEquals(10L, file.getConfigId()); assertEquals(10L, file.getConfigId());
assertEquals(path, file.getPath()); assertEquals(path, file.getPath());
assertEquals(url, file.getUrl()); assertEquals(url, file.getUrl());
assertEquals("jpg", file.getType()); assertEquals("image/jpg", file.getType());
assertEquals(content.length, file.getSize()); 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.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*; import lombok.*;
@ -21,6 +22,11 @@ import lombok.*;
@AllArgsConstructor @AllArgsConstructor
public class SocialUserBindDO extends BaseDO { public class SocialUserBindDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/** /**
* 关联的用户编号 * 关联的用户编号
* *

View File

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