mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-23 07:41:53 +08:00
commit
b0d635e1f0
@ -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 '创建时间',
|
||||
|
@ -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 '创建时间';
|
||||
|
@ -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 '创建时间';
|
||||
|
@ -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'
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,对于doc,jar等文件会有误差
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
/**
|
||||
|
@ -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)) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
/**
|
||||
* 关联的用户编号
|
||||
*
|
||||
|
@ -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,
|
||||
// 显示搜索条件
|
||||
|
Loading…
Reference in New Issue
Block a user