diff --git a/yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/utils/FileTypeUtils.java b/yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/utils/FileTypeUtils.java index d21b4879a..b623d364a 100644 --- a/yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/utils/FileTypeUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/utils/FileTypeUtils.java @@ -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 = TransmittableThreadLocal.withInitial(Tika::new); /** - * 获得文件的 mineType + * 获得文件的 mineType,对于doc,jar等文件会有误差 * - * @param data 文件内容 - * @return mineType + * @param data 包含文件开头几千个字节的字节数组 + * @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); } } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index 98af005f7..f4aac3014 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.infra.service.file; +import cn.hutool.core.io.FileTypeUtil; +import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.DigestUtil; @@ -13,6 +15,7 @@ import lombok.SneakyThrows; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.io.ByteArrayInputStream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS; @@ -40,10 +43,16 @@ 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); // 文件的后缀 + String sha256Hex = DigestUtil.sha256Hex(content); + /* 如果存在name,则优先使用name的后缀 */ + if (StrUtil.isNotBlank(name)) { + String extName = FileNameUtil.extName(name); + path = StrUtil.isBlank(extName) ? sha256Hex : sha256Hex + "." + extName; + } else { + path = sha256Hex + '.' + FileTypeUtil.getType(new ByteArrayInputStream(content), name); + } } // 如果 name 为空,则使用 path 填充 if (StrUtil.isEmpty(name)) {