diff --git a/db/0pigxx_boot.sql b/db/0pigxx_boot.sql index c8a98207c..67648e3d9 100644 --- a/db/0pigxx_boot.sql +++ b/db/0pigxx_boot.sql @@ -312,6 +312,7 @@ CREATE TABLE `sys_file` ( `dir` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '文件夹名称', `original` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '原始文件名', `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '文件类型', + `hash` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '文件hash', `file_size` bigint(20) DEFAULT NULL COMMENT '文件大小', `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ' ' COMMENT '创建人', `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ' ' COMMENT '修改人', diff --git a/db/2pigxx.sql b/db/2pigxx.sql index 5bed1fb1c..259d797fc 100644 --- a/db/2pigxx.sql +++ b/db/2pigxx.sql @@ -309,6 +309,7 @@ CREATE TABLE `sys_file` ( `dir` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '文件夹名称', `original` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '原始文件名', `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '文件类型', + `hash` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '文件hash', `file_size` bigint(20) DEFAULT NULL COMMENT '文件大小', `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ' ' COMMENT '创建人', `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ' ' COMMENT '修改人', diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysFile.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysFile.java index 94faffb94..d8e08feb1 100644 --- a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysFile.java +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysFile.java @@ -38,91 +38,97 @@ import java.time.LocalDateTime; @EqualsAndHashCode(callSuper = true) public class SysFile extends Model { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - /** - * 编号 - */ - @TableId(type = IdType.ASSIGN_ID) - @Schema(description = "文件编号") - private Long id; + /** + * 编号 + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "文件编号") + private Long id; - /** - * 文件名 - */ - @Schema(description = "文件名") - private String fileName; + /** + * 文件名 + */ + @Schema(description = "文件名") + private String fileName; - /** - * 原文件名 - */ - @Schema(description = "原始文件名") - private String original; + /** + * 原文件名 + */ + @Schema(description = "原始文件名") + private String original; - /** - * 容器名称 - */ - @Schema(description = "存储桶名称") - private String bucketName; + /** + * 容器名称 + */ + @Schema(description = "存储桶名称") + private String bucketName; - /*** - * 文件夹 - */ - @Schema(description = "文件夹") - private String dir; + /*** + * 文件夹 + */ + @Schema(description = "文件夹") + private String dir; - /** - * 文件类型 - */ - @Schema(description = "文件类型") - private String type; + /** + * 文件类型 + */ + @Schema(description = "文件类型") + private String type; - /** - * 文件组 - */ - @Schema(description = "文件组") - private Long groupId; + /** + * 文件组 + */ + @Schema(description = "文件组") + private Long groupId; - /** - * 文件大小 - */ - @Schema(description = "文件大小") - private Long fileSize; + /** + * 文件大小 + */ + @Schema(description = "文件大小") + private Long fileSize; - /** - * 上传人 - */ - @TableField(fill = FieldFill.INSERT) - @Schema(description = "创建者") - private String createBy; + /** + * 文件hash + */ + @Schema(description = "文件hash") + private String hash; - /** - * 上传时间 - */ - @TableField(fill = FieldFill.INSERT) - @Schema(description = "创建时间") - private LocalDateTime createTime; + /** + * 上传人 + */ + @TableField(fill = FieldFill.INSERT) + @Schema(description = "创建者") + private String createBy; - /** - * 更新人 - */ - @TableField(fill = FieldFill.INSERT) - @Schema(description = "更新者") - private String updateBy; + /** + * 上传时间 + */ + @TableField(fill = FieldFill.INSERT) + @Schema(description = "创建时间") + private LocalDateTime createTime; - /** - * 更新时间 - */ - @TableField(fill = FieldFill.UPDATE) - @Schema(description = "更新时间") - private LocalDateTime updateTime; + /** + * 更新人 + */ + @TableField(fill = FieldFill.INSERT) + @Schema(description = "更新者") + private String updateBy; - /** - * 删除标识:1-删除,0-正常 - */ - @TableLogic - @TableField(fill = FieldFill.INSERT) - @Schema(description = "删除标记,1:已删除,0:正常") - private String delFlag; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.UPDATE) + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + /** + * 删除标识:1-删除,0-正常 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + @Schema(description = "删除标记,1:已删除,0:正常") + private String delFlag; } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysFileServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysFileServiceImpl.java index 062760810..d0eadd9a0 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysFileServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysFileServiceImpl.java @@ -24,6 +24,7 @@ import cn.hutool.core.lang.tree.TreeNode; import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; import com.amazonaws.services.s3.model.S3Object; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -61,173 +62,182 @@ import java.util.*; @AllArgsConstructor public class SysFileServiceImpl extends ServiceImpl implements SysFileService { - private final FileTemplate fileTemplate; + private final FileTemplate fileTemplate; - private final SysFileGroupMapper fileGroupMapper; + private final SysFileGroupMapper fileGroupMapper; - private final FileProperties properties; + private final FileProperties properties; - /** - * 上传文件 - * @param file 文件流 - * @param dir 文件夹 - * @param groupId 分组ID - * @param type 类型 - * @return - */ - @Override - public R uploadFile(MultipartFile file, String dir, Long groupId, String type) { - String fileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename()); - Map resultMap = new HashMap<>(4); - resultMap.put("bucketName", properties.getBucketName()); - resultMap.put("fileName", fileName); + /** + * 上传文件 + * + * @param file 文件流 + * @param dir 文件夹 + * @param groupId 分组ID + * @param type 类型 + * @return + */ + @Override + public R uploadFile(MultipartFile file, String dir, Long groupId, String type) { + String fileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename()); + Map resultMap = new HashMap<>(4); + resultMap.put("bucketName", properties.getBucketName()); + resultMap.put("fileName", fileName); - resultMap.put("url", String.format("/admin/sys-file/oss/file?fileName=%s", fileName)); + resultMap.put("url", String.format("/admin/sys-file/oss/file?fileName=%s", fileName)); - try (InputStream inputStream = file.getInputStream()) { - fileTemplate.putObject(properties.getBucketName(), dir, fileName, inputStream, file.getContentType()); - // 文件管理数据记录,收集管理追踪文件 - fileLog(file, dir, fileName, groupId, type); - } - catch (Exception e) { - log.error("上传失败", e); - return R.failed(e.getLocalizedMessage()); - } - return R.ok(resultMap); - } + try (InputStream inputStream = file.getInputStream()) { + fileTemplate.putObject(properties.getBucketName(), dir, fileName, inputStream, file.getContentType()); + // 文件管理数据记录,收集管理追踪文件 + fileLog(file, dir, fileName, groupId, type); + } catch (Exception e) { + log.error("上传失败", e); + return R.failed(e.getLocalizedMessage()); + } + return R.ok(resultMap); + } - /** - * 读取文件 - * @param bucket - * @param fileName - * @param response - */ - @Override - public void getFile(String fileName, HttpServletResponse response) { - TenantContextHolder.setTenantSkip(); - SysFile sysFile = baseMapper.selectOne(Wrappers.lambdaQuery().eq(SysFile::getFileName, fileName)); - try (S3Object s3Object = fileTemplate.getObject(sysFile.getBucketName(), sysFile.getDir(), fileName)) { - response.setContentType("application/octet-stream; charset=UTF-8"); - IoUtil.copy(s3Object.getObjectContent(), response.getOutputStream()); - } - catch (Exception e) { - log.error("文件读取异常: {}", e.getLocalizedMessage()); - } - } + /** + * 读取文件 + * + * @param bucket + * @param fileName + * @param response + */ + @Override + public void getFile(String fileName, HttpServletResponse response) { + TenantContextHolder.setTenantSkip(); + SysFile sysFile = baseMapper.selectOne(Wrappers.lambdaQuery().eq(SysFile::getFileName, fileName)); + try (S3Object s3Object = fileTemplate.getObject(sysFile.getBucketName(), sysFile.getDir(), fileName)) { + response.setContentType("application/octet-stream; charset=UTF-8"); + // 文件唯一hash + response.addHeader("Hash", sysFile.getHash()); + IoUtil.copy(s3Object.getObjectContent(), response.getOutputStream()); + } catch (Exception e) { + log.error("文件读取异常: {}", e.getLocalizedMessage()); + } + } - /** - * 删除文件 - * @param id - * @return - */ - @Override - @SneakyThrows - @Transactional(rollbackFor = Exception.class) - public Boolean deleteFile(Long id) { - SysFile file = this.getById(id); - if (Objects.isNull(file)) { - return Boolean.FALSE; - } - fileTemplate.removeObject(properties.getBucketName(), file.getFileName()); - return this.removeById(id); - } + /** + * 删除文件 + * + * @param id + * @return + */ + @Override + @SneakyThrows + @Transactional(rollbackFor = Exception.class) + public Boolean deleteFile(Long id) { + SysFile file = this.getById(id); + if (Objects.isNull(file)) { + return Boolean.FALSE; + } + fileTemplate.removeObject(properties.getBucketName(), file.getFileName()); + return this.removeById(id); + } - /** - * 查询文件组列表 - * @param fileGroup SysFileGroup对象,用于筛选条件 - * @return 包含文件组树形结构列表的List对象 - */ - @Override - public List> listFileGroup(SysFileGroup fileGroup) { - // 从数据库查询文件组列表 - List> treeNodeList = fileGroupMapper.selectList(Wrappers.query(fileGroup)) - .stream() - .map(group -> { - TreeNode treeNode = new TreeNode<>(); - treeNode.setName(group.getName()); - treeNode.setId(group.getId()); - treeNode.setParentId(group.getPid()); - return treeNode; - }) - .toList(); + /** + * 查询文件组列表 + * + * @param fileGroup SysFileGroup对象,用于筛选条件 + * @return 包含文件组树形结构列表的List对象 + */ + @Override + public List> listFileGroup(SysFileGroup fileGroup) { + // 从数据库查询文件组列表 + List> treeNodeList = fileGroupMapper.selectList(Wrappers.query(fileGroup)) + .stream() + .map(group -> { + TreeNode treeNode = new TreeNode<>(); + treeNode.setName(group.getName()); + treeNode.setId(group.getId()); + treeNode.setParentId(group.getPid()); + return treeNode; + }) + .toList(); - // 构建树形结构 - List> treeList = TreeUtil.build(treeNodeList, CommonConstants.MENU_TREE_ROOT_ID); - return CollUtil.isEmpty(treeList) ? new ArrayList<>() : treeList; - } + // 构建树形结构 + List> treeList = TreeUtil.build(treeNodeList, CommonConstants.MENU_TREE_ROOT_ID); + return CollUtil.isEmpty(treeList) ? new ArrayList<>() : treeList; + } - /** - * 添加或更新文件组 - * @param fileGroup SysFileGroup对象,要添加或更新的文件组信息 - * @return 添加或更新成功返回true,否则返回false - */ - @Override - public Boolean saveOrUpdateGroup(SysFileGroup fileGroup) { - if (Objects.isNull(fileGroup.getId())) { - // 插入文件组 - fileGroupMapper.insert(fileGroup); - } - else { - // 更新文件组 - fileGroupMapper.updateById(fileGroup); - } - return Boolean.TRUE; - } + /** + * 添加或更新文件组 + * + * @param fileGroup SysFileGroup对象,要添加或更新的文件组信息 + * @return 添加或更新成功返回true,否则返回false + */ + @Override + public Boolean saveOrUpdateGroup(SysFileGroup fileGroup) { + if (Objects.isNull(fileGroup.getId())) { + // 插入文件组 + fileGroupMapper.insert(fileGroup); + } else { + // 更新文件组 + fileGroupMapper.updateById(fileGroup); + } + return Boolean.TRUE; + } - /** - * 删除文件组 - * @param id 待删除文件组的ID - * @return 删除成功返回true,否则返回false - */ - @Override - public Boolean deleteGroup(Long id) { - // 根据ID删除文件组 - fileGroupMapper.deleteById(id); - return Boolean.TRUE; - } + /** + * 删除文件组 + * + * @param id 待删除文件组的ID + * @return 删除成功返回true,否则返回false + */ + @Override + public Boolean deleteGroup(Long id) { + // 根据ID删除文件组 + fileGroupMapper.deleteById(id); + return Boolean.TRUE; + } - /** - * 移动文件组 - * @param fileGroupDTO SysFileGroupDTO对象,要移动的文件组信息 - * @return 移动成功返回true,否则返回false - */ - @Override - public Boolean moveFileGroup(SysFileGroupDTO fileGroupDTO) { - // 创建SysFile对象并设置groupId属性 - SysFile file = new SysFile(); - file.setGroupId(fileGroupDTO.getGroupId()); + /** + * 移动文件组 + * + * @param fileGroupDTO SysFileGroupDTO对象,要移动的文件组信息 + * @return 移动成功返回true,否则返回false + */ + @Override + public Boolean moveFileGroup(SysFileGroupDTO fileGroupDTO) { + // 创建SysFile对象并设置groupId属性 + SysFile file = new SysFile(); + file.setGroupId(fileGroupDTO.getGroupId()); - // 根据IDS更新对应的SysFile记录 - baseMapper.update(file, Wrappers.lambdaQuery().in(SysFile::getId, fileGroupDTO.getIds())); - return Boolean.TRUE; - } + // 根据IDS更新对应的SysFile记录 + baseMapper.update(file, Wrappers.lambdaQuery().in(SysFile::getId, fileGroupDTO.getIds())); + return Boolean.TRUE; + } - /** - * 文件管理数据记录,收集管理追踪文件 - * @param file 上传的文件格式 - * @param dir 文件夹 - * @param fileName 文件名 - * @param groupId 文件组ID - * @param type 文件类型 - */ - private void fileLog(MultipartFile file, String dir, String fileName, Long groupId, String type) { - // 创建SysFile对象并设置相关属性 - SysFile sysFile = new SysFile(); - sysFile.setFileName(fileName); + /** + * 文件管理数据记录,收集管理追踪文件 + * + * @param file 上传的文件格式 + * @param dir 文件夹 + * @param fileName 文件名 + * @param groupId 文件组ID + * @param type 文件类型 + */ + @SneakyThrows + private void fileLog(MultipartFile file, String dir, String fileName, Long groupId, String type) { + // 创建SysFile对象并设置相关属性 + SysFile sysFile = new SysFile(); + sysFile.setFileName(fileName); - // 对原始文件名进行编码转换 - String originalFilename = new String( - Objects.requireNonNull(file.getOriginalFilename()).getBytes(StandardCharsets.ISO_8859_1), - StandardCharsets.UTF_8); - sysFile.setDir(dir); - sysFile.setOriginal(originalFilename); - sysFile.setFileSize(file.getSize()); - sysFile.setBucketName(properties.getBucketName()); - sysFile.setType(type); - sysFile.setGroupId(groupId); + // 对原始文件名进行编码转换 + String originalFilename = new String( + Objects.requireNonNull(file.getOriginalFilename()).getBytes(StandardCharsets.ISO_8859_1), + StandardCharsets.UTF_8); + sysFile.setDir(dir); + sysFile.setOriginal(originalFilename); + sysFile.setFileSize(file.getSize()); + sysFile.setBucketName(properties.getBucketName()); + sysFile.setType(type); + sysFile.setGroupId(groupId); - // 调用save方法保存SysFile对象 - this.save(sysFile); - } + sysFile.setHash(SecureUtil.md5(file.getInputStream())); + // 调用save方法保存SysFile对象 + this.save(sysFile); + } }