初始化项目
This commit is contained in:
49
xtools-app-sys/xtools-app-sys-file/pom.xml
Normal file
49
xtools-app-sys/xtools-app-sys-file/pom.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-app-sys-file</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools begin -->
|
||||
<!-- xtools-extend begin -->
|
||||
<!-- bcprov 加密库 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-extend</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-extend end -->
|
||||
<!-- xtools-boot-storage-base -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-storage-base</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot-web-base -->
|
||||
<!-- xtools end -->
|
||||
|
||||
<!-- 项目模块 begin -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-app-sys-api</artifactId>
|
||||
</dependency>
|
||||
<!-- 项目模块 end -->
|
||||
|
||||
<!-- jakarta.annotation-api -->
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,46 @@
|
||||
package xtools.app.sys.file.enums;
|
||||
|
||||
import xtools.boot.api.enums.BaseEnum;
|
||||
|
||||
/**
|
||||
* <p>Title : FileBizBaseEnum</p>
|
||||
* <p>Description : FileBizBaseEnum</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/3/24 09:18
|
||||
*/
|
||||
public interface FileBizBaseEnum extends BaseEnum {
|
||||
|
||||
/**
|
||||
* 存储桶
|
||||
*
|
||||
* @return 存储桶
|
||||
*/
|
||||
String bucket();
|
||||
|
||||
/**
|
||||
* 文件权限
|
||||
*
|
||||
* @return 文件权限
|
||||
*/
|
||||
FilePermissionType permission();
|
||||
|
||||
/**
|
||||
* 文件过期时间(小时)
|
||||
*
|
||||
* @return 文件过期时间
|
||||
*/
|
||||
int expireTime();
|
||||
|
||||
/**
|
||||
* 文件扩展名
|
||||
*
|
||||
* @return 文件扩展名
|
||||
*/
|
||||
String[] extArr();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package xtools.app.sys.file.enums;
|
||||
|
||||
/**
|
||||
* <p>Title : FileBizEnum</p>
|
||||
* <p>Description : FileBizEnum</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/3/17 21:09
|
||||
*/
|
||||
public enum FileBizEnum implements FileBizBaseEnum {
|
||||
|
||||
// 系统通知
|
||||
SYS_NOTICE(-10, "系统通知", "sys-notice-editor-img", FilePermissionType.PUBLIC, 12, "png", "jpg", "jpeg", "gif", "bmp", "webp");
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 存储桶
|
||||
*/
|
||||
private final String bucket;
|
||||
|
||||
/**
|
||||
* 文件权限
|
||||
*/
|
||||
private final FilePermissionType permission;
|
||||
|
||||
/**
|
||||
* 文件过期时间(小时)
|
||||
*/
|
||||
private final int expireTime;
|
||||
|
||||
/**
|
||||
* 扩展名
|
||||
*/
|
||||
private final String[] extArr;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param code 编码
|
||||
* @param desc 说明
|
||||
* @param bucket 存储桶
|
||||
* @param permission 文件权限
|
||||
* @param expireTime 文件过期时间(小时)
|
||||
* @param extArr 扩展名
|
||||
*/
|
||||
FileBizEnum(int code, String desc, String bucket, FilePermissionType permission, int expireTime, String... extArr) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
this.bucket = bucket;
|
||||
this.permission = permission;
|
||||
this.expireTime = expireTime;
|
||||
this.extArr = extArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
@Override
|
||||
public FileBizBaseEnum[] all() {
|
||||
return values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储桶
|
||||
*
|
||||
* @return 存储桶
|
||||
*/
|
||||
@Override
|
||||
public String bucket() {
|
||||
return bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件权限
|
||||
*
|
||||
* @return 文件权限
|
||||
*/
|
||||
@Override
|
||||
public FilePermissionType permission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件过期时间
|
||||
*
|
||||
* @return 文件过期时间
|
||||
*/
|
||||
@Override
|
||||
public int expireTime() {
|
||||
return expireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展名
|
||||
*
|
||||
* @return 扩展名
|
||||
*/
|
||||
@Override
|
||||
public String[] extArr() {
|
||||
return extArr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package xtools.app.sys.file.enums;
|
||||
|
||||
import xtools.boot.api.enums.BaseEnum;
|
||||
|
||||
/**
|
||||
* <p>Title : FilePermissionType</p>
|
||||
* <p>Description : FilePermissionType</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/2/15 10:29
|
||||
*/
|
||||
public enum FilePermissionType implements BaseEnum {
|
||||
|
||||
// 公开
|
||||
PUBLIC(0, "公开"),
|
||||
// 私有
|
||||
PRIVATE(1, "私有"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 初始化方法
|
||||
*
|
||||
* @param code Code
|
||||
* @param desc 说明
|
||||
*/
|
||||
FilePermissionType(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断枚举值类型
|
||||
*
|
||||
* @param code 枚举值
|
||||
* @return 枚举值类型
|
||||
*/
|
||||
public static FilePermissionType valueOfCode(int code) {
|
||||
for (FilePermissionType type : values()) {
|
||||
if (type.code == code) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
@Override
|
||||
public BaseEnum[] all() {
|
||||
return values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.app.sys.file.service;
|
||||
|
||||
import xtools.app.sys.model.dto.resp.SysFileResp;
|
||||
|
||||
/**
|
||||
* <p>Title : SysFileDownloadCallback</p>
|
||||
* <p>Description : SysFileDownloadCallback</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : Windows11</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/4/10 21:59
|
||||
*/
|
||||
public interface SysFileDownloadCallback {
|
||||
|
||||
/**
|
||||
* 下载前回调
|
||||
*
|
||||
* @param fileInfo 文件信息
|
||||
* @return 是否继续下载
|
||||
*/
|
||||
default boolean before(SysFileResp fileInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package xtools.app.sys.file.service;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import xtools.app.sys.file.enums.FileBizBaseEnum;
|
||||
import xtools.app.sys.model.dto.resp.SysFileResp;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : SysFileOptService</p>
|
||||
* <p>Description : SysFileOptService</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/3/14 14:06
|
||||
*/
|
||||
public interface SysFileOptService {
|
||||
|
||||
/**
|
||||
* 文件是否存在
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean exists(long id);
|
||||
|
||||
/**
|
||||
* 文件是否存在
|
||||
*
|
||||
* @param bucket 存储桶
|
||||
* @param fileName 文件名
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean exists(String bucket, String fileName);
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @param inputStream 文件输入流
|
||||
* @param contentLength 文件长度
|
||||
* @param userId 用户ID
|
||||
* @param userName 用户名
|
||||
* @param bizType 业务类型
|
||||
* @param bizId 业务ID
|
||||
* @return 文件ID
|
||||
*/
|
||||
Long upload(
|
||||
@NonNull String fileName,
|
||||
@NonNull InputStream inputStream,
|
||||
long contentLength,
|
||||
@NonNull Long userId,
|
||||
@NonNull String userName,
|
||||
@NonNull FileBizBaseEnum bizType,
|
||||
Long bizId
|
||||
);
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param bucket 存储桶
|
||||
* @param fileName 文件名
|
||||
* @param outputStream 输出流
|
||||
* @return 文件信息
|
||||
*/
|
||||
SysFileResp download(String bucket, String fileName, @NonNull OutputStream outputStream);
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param bucket 存储桶
|
||||
* @param fileName 文件名
|
||||
* @param outputStream 输出流
|
||||
* @param callback 回调
|
||||
* @return 文件信息
|
||||
*/
|
||||
SysFileResp download(String bucket, String fileName, @NonNull OutputStream outputStream, SysFileDownloadCallback callback);
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @param outputStream 输出流
|
||||
* @return 文件信息
|
||||
*/
|
||||
SysFileResp download(
|
||||
long id,
|
||||
@NonNull OutputStream outputStream
|
||||
);
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @param outputStream 输出流
|
||||
* @param callback 回调
|
||||
* @return 文件信息
|
||||
*/
|
||||
SysFileResp download(
|
||||
long id,
|
||||
@NonNull OutputStream outputStream,
|
||||
SysFileDownloadCallback callback
|
||||
);
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
boolean delete(long id);
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*
|
||||
* @param idList 文件ID列表
|
||||
* @return 删除结果
|
||||
*/
|
||||
boolean delete(List<Long> idList);
|
||||
|
||||
/**
|
||||
* 文件成功
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @return 成功结果
|
||||
*/
|
||||
boolean success(long id);
|
||||
|
||||
/**
|
||||
* 文件成功
|
||||
*
|
||||
* @param idList 文件ID列表
|
||||
* @return 成功结果
|
||||
*/
|
||||
boolean success(List<Long> idList);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
package xtools.app.sys.file.service.impl;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
import xtools.app.sys.api.SysFileApi;
|
||||
import xtools.app.sys.file.enums.FileBizBaseEnum;
|
||||
import xtools.app.sys.file.service.SysFileDownloadCallback;
|
||||
import xtools.app.sys.file.service.SysFileOptService;
|
||||
import xtools.app.sys.model.dto.req.SysFileAddReq;
|
||||
import xtools.app.sys.model.dto.req.SysFileChangeReq;
|
||||
import xtools.app.sys.model.dto.resp.SysFileResp;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.api.enums.FileDataType;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.boot.api.model.dto.Result;
|
||||
import xtools.boot.storage.base.config.StorageConfig;
|
||||
import xtools.boot.storage.base.service.StorageService;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.core.FileUtils;
|
||||
import xtools.core.HexUtils;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.UuidUtils;
|
||||
import xtools.core.encrypt.Md5Utils;
|
||||
import xtools.core.extend.CheckUtils;
|
||||
import xtools.core.time.CalendarUtils;
|
||||
import xtools.extend.encrypt.Sm3Utils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : SysFileOptServiceImpl</p>
|
||||
* <p>Description : SysFileOptServiceImpl</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/3/14 14:16
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysFileOptServiceImpl implements SysFileOptService, BaseParams {
|
||||
|
||||
/**
|
||||
* 文件最大长度
|
||||
*/
|
||||
private final static long MAX_FILE_SIZE = 5 * 1024 * 1024 * 1024L;
|
||||
|
||||
private final SysFileApi sysFileApi;
|
||||
|
||||
@Resource
|
||||
private StorageConfig storageConfig;
|
||||
|
||||
@Resource
|
||||
private StorageService storageService;
|
||||
|
||||
/**
|
||||
* 文件是否存在
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @return 是否存在
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(long id) {
|
||||
SysFileResp data = getFileData(id);
|
||||
return storageService.exists(data.getBucket(), data.getFilePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件是否存在
|
||||
*
|
||||
* @param bucket 存储桶
|
||||
* @param fileName 文件名
|
||||
* @return 是否存在
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(String bucket, String fileName) {
|
||||
SysFileResp data = getFileData(bucket, fileName);
|
||||
return storageService.exists(data.getBucket(), data.getFilePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @param inputStream 文件输入流
|
||||
* @param contentLength 文件长度
|
||||
* @param userId 用户ID
|
||||
* @param userName 用户名
|
||||
* @param bizType 业务类型
|
||||
* @param bizId 业务ID
|
||||
* @return 文件ID
|
||||
*/
|
||||
@Override
|
||||
public Long upload(
|
||||
@NonNull String fileName,
|
||||
@NonNull InputStream inputStream,
|
||||
long contentLength,
|
||||
@NonNull Long userId,
|
||||
@NonNull String userName,
|
||||
@NonNull FileBizBaseEnum bizType,
|
||||
Long bizId
|
||||
) {
|
||||
// 上传事件
|
||||
Instant uploadTime = Instant.now();
|
||||
// 计算文件码
|
||||
String md5 = null;
|
||||
String sm3 = null;
|
||||
if (contentLength <= MAX_FILE_SIZE) {
|
||||
// 小于5MB的文件才计算文件码
|
||||
try {
|
||||
byte[] bytes = inputStream.readAllBytes();
|
||||
inputStream = new ByteArrayInputStream(bytes);
|
||||
contentLength = bytes.length;
|
||||
if (contentLength <= 0) {
|
||||
throw new BizError("文件长度错误");
|
||||
}
|
||||
byte[] md5Bytes = Md5Utils.encrypt(bytes);
|
||||
if (Objects.nonNull(md5Bytes)) {
|
||||
md5 = HexUtils.formatHex(md5Bytes);
|
||||
}
|
||||
byte[] sm3Bytes = Sm3Utils.encrypt(bytes);
|
||||
if (Objects.nonNull(sm3Bytes)) {
|
||||
sm3 = HexUtils.formatHex(sm3Bytes);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("计算文件码失败", e);
|
||||
throw new BizError("计算文件码失败");
|
||||
}
|
||||
}
|
||||
// 获取文件后缀
|
||||
String suffix = FileUtils.getSuffix(fileName);
|
||||
if (StringUtils.isBlank(suffix)) {
|
||||
throw new BizError("文件格式错误");
|
||||
}
|
||||
// 文件存储器的文件名
|
||||
String filePath = UuidUtils.get() + CP_LINE + fileName;
|
||||
// 获取存储桶
|
||||
String bucket = bizType.bucket();
|
||||
// 计算过期时间
|
||||
int expireTime = bizType.expireTime();
|
||||
if (expireTime <= CP_NUM0) {
|
||||
expireTime = CP_NUM1;
|
||||
}
|
||||
Instant expireDate = CalendarUtils.calc(Calendar.HOUR_OF_DAY, expireTime);
|
||||
// 保存文件
|
||||
storageService.save(bucket, filePath, inputStream, contentLength);
|
||||
SysFileAddReq req = new SysFileAddReq();
|
||||
req.setUserId(userId);
|
||||
req.setUserName(userName);
|
||||
req.setBizId(Objects.nonNull(bizId) ? bizId : bizType.code());
|
||||
req.setBizType(bizType.desc());
|
||||
req.setPermission(bizType.permission().code());
|
||||
req.setBucket(bucket);
|
||||
req.setStorageType(storageConfig.getType());
|
||||
req.setUploadTime(uploadTime);
|
||||
req.setFilePath(filePath);
|
||||
req.setFileName(fileName);
|
||||
req.setFileSize(contentLength);
|
||||
req.setFileType(suffix);
|
||||
req.setMd5(md5);
|
||||
req.setSm3(sm3);
|
||||
req.setDataType(FileDataType.TEMP.code());
|
||||
req.setExpireTime(expireDate);
|
||||
Result<Long> result = sysFileApi.add(req);
|
||||
Long id = result.data();
|
||||
if (CheckUtils.id(id)) {
|
||||
return id;
|
||||
}
|
||||
// 保存记录失败删除文件
|
||||
storageService.del(bucket, fileName);
|
||||
throw new BizError("文件上传失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param bucket 存储桶
|
||||
* @param fileName 文件名
|
||||
* @param outputStream 输出流
|
||||
* @return 文件信息
|
||||
*/
|
||||
@Override
|
||||
public SysFileResp download(String bucket, String fileName, @NonNull OutputStream outputStream) {
|
||||
return download(bucket, fileName, outputStream, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param bucket 存储桶
|
||||
* @param fileName 文件名
|
||||
* @param outputStream 输出流
|
||||
* @param callback 回调
|
||||
* @return 文件信息
|
||||
*/
|
||||
@Override
|
||||
public SysFileResp download(String bucket, String fileName, @NonNull OutputStream outputStream, SysFileDownloadCallback callback) {
|
||||
return download(getFileData(bucket, fileName), outputStream, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @param outputStream 输出流
|
||||
* @return 文件信息
|
||||
*/
|
||||
@Override
|
||||
public SysFileResp download(long id, @NonNull OutputStream outputStream) {
|
||||
return download(id, outputStream, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @param outputStream 输出流
|
||||
* @param callback 回调
|
||||
* @return 文件信息
|
||||
*/
|
||||
@Override
|
||||
public SysFileResp download(long id, @NonNull OutputStream outputStream, SysFileDownloadCallback callback) {
|
||||
return download(getFileData(id), outputStream, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param data 文件信息
|
||||
* @param outputStream 输出流
|
||||
* @param callback 回调
|
||||
* @return 文件信息
|
||||
*/
|
||||
private SysFileResp download(SysFileResp data, @NonNull OutputStream outputStream, SysFileDownloadCallback callback) {
|
||||
if (Objects.isNull(data)) {
|
||||
throw new BizError("文件不存在");
|
||||
}
|
||||
if (Objects.equals(FileDataType.DELETE.code(), data.getDataType())) {
|
||||
throw new BizError("文件已删除");
|
||||
}
|
||||
if (Objects.equals(FileDataType.TEMP.code(), data.getDataType()) && Instant.now().isAfter(data.getExpireTime())) {
|
||||
delete(data.getId());
|
||||
throw new BizError("文件已过期");
|
||||
}
|
||||
String type = storageConfig.getType();
|
||||
if (!Objects.equals(type, data.getStorageType())) {
|
||||
throw new BizError("文件不存在");
|
||||
}
|
||||
if (Objects.nonNull(callback)) {
|
||||
if (!callback.before(data)) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
storageService.get(data.getBucket(), data.getFilePath(), outputStream);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(long id) {
|
||||
return delete(List.of(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*
|
||||
* @param idList 文件ID列表
|
||||
* @return 删除结果
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(List<Long> idList) {
|
||||
if (CollectionUtils.isEmpty(idList)) {
|
||||
return true;
|
||||
}
|
||||
sysFileApi.changeDataTypeByIds(new SysFileChangeReq(idList, FileDataType.DELETE));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件成功
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @return 成功结果
|
||||
*/
|
||||
@Override
|
||||
public boolean success(long id) {
|
||||
return success(List.of(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件成功
|
||||
*
|
||||
* @param idList 文件ID列表
|
||||
* @return 成功结果
|
||||
*/
|
||||
@Override
|
||||
public boolean success(List<Long> idList) {
|
||||
if (CollectionUtils.isEmpty(idList)) {
|
||||
return true;
|
||||
}
|
||||
sysFileApi.changeDataTypeByIds(new SysFileChangeReq(idList, FileDataType.OK));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件数据
|
||||
*
|
||||
* @param id 文件ID
|
||||
* @return 文件数据
|
||||
*/
|
||||
private SysFileResp getFileData(long id) {
|
||||
Result<SysFileResp> result = sysFileApi.getById(id);
|
||||
SysFileResp data = result.data();
|
||||
if (Objects.isNull(data)) {
|
||||
throw new BizError("文件不存在");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件数据
|
||||
*
|
||||
* @param bucket 桶名称
|
||||
* @param fileName 文件名
|
||||
* @return 文件数据
|
||||
*/
|
||||
private SysFileResp getFileData(String bucket, String fileName) {
|
||||
Result<SysFileResp> result = sysFileApi.getByName(bucket, fileName);
|
||||
SysFileResp data = result.data();
|
||||
if (Objects.isNull(data)) {
|
||||
throw new BizError("文件不存在");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package xtools.app.sys.file.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.core.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* <p>Title : FileIdUtils</p>
|
||||
* <p>Description : FileIdUtils</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 1.0.0
|
||||
* @date : 2026/3/17 19:49
|
||||
*/
|
||||
@Slf4j
|
||||
public class FileIdUtils {
|
||||
|
||||
/**
|
||||
* 获取基础文件ID的正则表达式
|
||||
*/
|
||||
private final static Pattern BASE_PATTERN = Pattern.compile("/sys/common/get/(\\d+)/file");
|
||||
|
||||
/**
|
||||
* 获取文件ID
|
||||
*
|
||||
* @param content 文件内容
|
||||
* @return 文件ID
|
||||
*/
|
||||
public static List<Long> get(String content) {
|
||||
return get(BASE_PATTERN, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件ID
|
||||
*
|
||||
* @param content 文件内容
|
||||
* @param regex 正则表达式
|
||||
* @return 文件ID
|
||||
*/
|
||||
public static List<Long> get(String content, String regex) {
|
||||
if (StringUtils.isBlank(regex)) {
|
||||
throw new BizError("regex 不能为空");
|
||||
}
|
||||
return get(Pattern.compile(regex), content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件ID
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
* @param content 文件内容
|
||||
* @return 文件ID
|
||||
*/
|
||||
private static List<Long> get(Pattern pattern, String content) {
|
||||
List<Long> idList = new ArrayList<>();
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return idList;
|
||||
}
|
||||
Matcher matcher = pattern.matcher(content);
|
||||
while (matcher.find()) {
|
||||
String number = matcher.group(1);
|
||||
if (StringUtils.isBlank(number)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
idList.add(Long.parseLong(number.trim()));
|
||||
} catch (NumberFormatException e) {
|
||||
log.info("{}无法转为Long类型", number);
|
||||
}
|
||||
}
|
||||
return idList;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user