feat: 优化Minio注释和函数名称

This commit is contained in:
bunny 2025-05-01 14:32:26 +08:00
parent 0e84f0934e
commit ec1603885f
26 changed files with 220 additions and 171 deletions

View File

@ -197,7 +197,7 @@ AntPath详情https://juejin.cn/spost/7498247273660743732
### 开发环境
根据不docker 启动方式不一样
根据不docker 启动方式不一样
```bash
# 一键启动依赖服务
@ -244,10 +244,10 @@ docker compose up -d
- [ ] 权限树型结构动态添加、更新、删除
- [ ] 用户设置持久化存储到数据库
- [ ] 权限弹窗页面优化
- [ ] 后端文档注释完善
- [x] 后端文档注释完善
- [x] 系统监控后端返回403停止请求
- [ ] 优化用户配置权限逻辑,配置后热更新逻辑等
- [ ] 完善后端注释有需要添加ReadMe文档
- [x] 优化用户配置权限逻辑,配置后热更新逻辑等
- [x] 完善后端注释有需要添加ReadMe文档
- [ ] Redis中获取活跃用户
## 前后端接口规范

View File

@ -2,8 +2,8 @@ package cn.bunny.services.aop;
import cn.bunny.services.domain.common.constant.LocalDateTimeConstant;
import cn.bunny.services.domain.common.enums.JobEnums;
import cn.bunny.services.domain.common.model.dto.quartz.ScheduleExecuteLogJson;
import cn.bunny.services.domain.system.log.entity.ScheduleExecuteLog;
import cn.bunny.services.domain.common.quartz.ScheduleExecuteLogJson;
import cn.bunny.services.mapper.log.ScheduleExecuteLogMapper;
import com.alibaba.fastjson2.JSON;
import jakarta.annotation.Resource;

View File

@ -1,10 +1,10 @@
package cn.bunny.services.controller.system;
import cn.bunny.services.aop.scanner.ControllerApiPermissionScanner;
import cn.bunny.services.domain.common.model.dto.scanner.ScannerControllerInfoVo;
import cn.bunny.services.domain.common.model.vo.result.PageResult;
import cn.bunny.services.domain.common.model.vo.result.Result;
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
import cn.bunny.services.domain.common.scanner.ScannerControllerInfoVo;
import cn.bunny.services.domain.system.system.dto.power.PermissionAddDto;
import cn.bunny.services.domain.system.system.dto.power.PermissionDto;
import cn.bunny.services.domain.system.system.dto.power.PermissionUpdateBatchByParentIdDto;

View File

@ -1,7 +1,7 @@
package cn.bunny.services.controller;
import cn.bunny.services.aop.scanner.ControllerApiPermissionScanner;
import cn.bunny.services.domain.common.scanner.ScannerControllerInfoVo;
import cn.bunny.services.domain.common.model.dto.scanner.ScannerControllerInfoVo;
import cn.bunny.services.domain.system.system.entity.Permission;
import cn.bunny.services.service.system.PermissionService;
import org.junit.jupiter.api.Test;

View File

@ -17,6 +17,25 @@
</properties>
<dependencies>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.30.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

View File

@ -1,4 +1,4 @@
package cn.bunny.services.mail;
package cn.bunny.services.config.mail;
import cn.bunny.services.domain.common.model.dto.email.EmailSend;
import cn.bunny.services.domain.common.model.dto.email.EmailSendInit;

View File

@ -1,23 +0,0 @@
package cn.bunny.services.domain.common.ip;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "IpEntity对象", description = "用户IP相关信息")
public class IpEntity {
@ApiModelProperty("原始地址")
private String ipAddr;
@ApiModelProperty("IP归属地")
private String ipRegion;
}

View File

@ -1,18 +0,0 @@
package cn.bunny.services.domain.common.model.dto.file;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MinioFilePath {
private String filename;
private String uuidFilename;
private String timeUuidFilename;
private String filepath;
private String bucketNameFilepath;
}

View File

@ -0,0 +1,22 @@
package cn.bunny.services.domain.common.model.dto.ip;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "IpEntity对象", title = "用户IP相关信息")
public class IpEntity {
@Schema(name = "ipAddr", title = "原始地址")
private String ipAddr;
@Schema(name = "ipRegion", title = "IP归属地")
private String ipRegion;
}

View File

@ -0,0 +1,31 @@
package cn.bunny.services.domain.common.model.dto.minio;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "MinioFilePath", title = "Minion上传返回西悉尼")
public class MinioUploadFileInfo {
@Schema(name = "filename", title = "文件名")
private String filename;
@Schema(name = "uuidFilename", title = "uuid文件名防止重复")
private String uuidFilename;
@Schema(name = "timeUuidFilename", title = "时间+uuid文件名")
private String timeUuidFilename;
@Schema(name = "filepath", title = "文件路径")
private String filepath;
@Schema(name = "bucketNameFilepath", title = "上传桶名称文件路径")
private String bucketNameFilepath;
}

View File

@ -1,4 +1,4 @@
package cn.bunny.services.domain.common.quartz;
package cn.bunny.services.domain.common.model.dto.quartz;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@ -1,4 +1,4 @@
package cn.bunny.services.domain.common.scanner;
package cn.bunny.services.domain.common.model.dto.scanner;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@ -1,4 +1,4 @@
package cn.bunny.services.domain.common.scanner;
package cn.bunny.services.domain.common.model.dto.scanner;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@ -1,4 +1,4 @@
package cn.bunny.services.domain.common.scanner;
package cn.bunny.services.domain.common.model.dto.scanner;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@ -1,4 +1,4 @@
package cn.bunny.services.domain.common.security;
package cn.bunny.services.domain.common.model.dto.security;
import cn.bunny.services.domain.common.model.vo.LoginVo;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -12,7 +12,8 @@ import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "bunny.minio")
@ConditionalOnProperty(name = "bunny.minio.bucket-name")// 当属性有值时这个配置才生效
// 当属性有值时这个配置才生效
@ConditionalOnProperty(name = "bunny.minio.bucket-name")
@Data
public class MinioProperties {
@ -30,6 +31,7 @@ public class MinioProperties {
MinioClient minioClient = MinioClient.builder().endpoint(endpointUrl).credentials(accessKey, secretKey).build();
try {
// 判断桶是否存在不存在则创建并且可以有公开访问权限
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());

View File

@ -1,7 +1,7 @@
package cn.bunny.services.minio;
import cn.bunny.services.domain.common.constant.MinioConstant;
import cn.bunny.services.domain.common.model.dto.file.MinioFilePath;
import cn.bunny.services.domain.common.model.dto.minio.MinioUploadFileInfo;
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
import cn.bunny.services.exception.AuthCustomerException;
import io.minio.*;
@ -15,8 +15,8 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@ -27,6 +27,7 @@ import java.util.UUID;
@Slf4j
@Service
public class MinioService {
@Resource
private MinioProperties properties;
@ -34,13 +35,45 @@ public class MinioService {
private MinioClient minioClient;
/**
* 获取Minio文件路径
* 上传文件到MinIO并返回文件处理信息
*
* <p><b>文件存储规则</b></p>
* <ul>
* <li>按日期分目录存储格式yyyy/MM-dd</li>
* <li>使用UUID重命名文件防止冲突</li>
* <li>保留原始文件名信息</li>
* <li>支持按类型分类存储通过minioPreType参数</li>
* </ul>
*
* <p><b>返回信息包含</b></p>
* <ol>
* <li>原始文件名</li>
* <li>UUID重命名后的文件名</li>
* <li>带日期路径的文件名</li>
* <li>完整存储路径不含桶名</li>
* <li>完整访问路径含桶名</li>
* </ol>
*
* @param file 上传的文件对象不可为空
* @param minioPreType 文件类型前缀用于分类存储参考MinioConstant定义
* @return 文件处理信息对象包含各种路径信息当file为null时返回null
* @throws IOException 当文件流读取异常时抛出
* @throws AuthCustomerException 当上传失败时抛出错误码UPLOAD_ERROR
* @see MinioConstant 文件类型前缀常量
* @see MinioUploadFileInfo 返回信息数据结构
*/
public static MinioFilePath initUploadFileReturnMinioFilePath(String buckName, String minioPreType, MultipartFile file) {
public MinioUploadFileInfo uploadWithFileInfo(MultipartFile file, String minioPreType) throws IOException {
if (file == null) return null;
// 上传文件时的桶名称
String bucketName = properties.getBucketName();
// 上传对象
try {
String uuid = UUID.randomUUID().toString();
// 定义日期时间格式
LocalDateTime currentDateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM-dd");
String dateFormatter = new SimpleDateFormat("yyyy/MM-dd").format(new Date());
// 文件后缀
String extension = "";
// 原始文件名
@ -52,50 +85,39 @@ public class MinioService {
// UUID防止重名
String uuidFilename = uuid + extension;
// 拼接时间+UUID文件名
String timeUuidFilename = currentDateTime.format(formatter) + "/" + uuidFilename;// 加上时间路径
// 拼接时间+UUID文件名 加上时间路径
String timeUuidFilename = dateFormatter + "/" + uuidFilename;
// 上传根文件夹+拼接时间+UUID文件名
String filepath = MinioConstant.getType(minioPreType) + timeUuidFilename;
// 桶名称+上传根文件夹+拼接时间+UUID文件名
String buckNameFilepath = "/" + buckName + MinioConstant.getType(minioPreType) + timeUuidFilename;
String buckNameFilepath = "/" + bucketName + MinioConstant.getType(minioPreType) + timeUuidFilename;
// 设置及Minio基础信息
MinioFilePath minioFIlePath = new MinioFilePath();
minioFIlePath.setFilename(filename);
minioFIlePath.setUuidFilename(uuidFilename);
minioFIlePath.setTimeUuidFilename(timeUuidFilename);
minioFIlePath.setFilepath(filepath);
minioFIlePath.setBucketNameFilepath(buckNameFilepath);
MinioUploadFileInfo minioUploadFIleInfo = new MinioUploadFileInfo();
minioUploadFIleInfo.setFilename(filename);
minioUploadFIleInfo.setUuidFilename(uuidFilename);
minioUploadFIleInfo.setTimeUuidFilename(timeUuidFilename);
minioUploadFIleInfo.setFilepath(filepath);
minioUploadFIleInfo.setBucketNameFilepath(buckNameFilepath);
return minioFIlePath;
}
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(minioUploadFIleInfo.getFilepath()).stream(file.getInputStream(), file.getSize(), -1).build());
/**
* * 上传文件并返回处理信息
*/
public MinioFilePath uploadObjectReturnFilePath(MultipartFile file, String minioPreType) throws IOException {
if (file == null) return null;
String bucketName = properties.getBucketName();
// 上传对象
try {
MinioFilePath minioFile = initUploadFileReturnMinioFilePath(bucketName, minioPreType, file);
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(minioFile.getFilepath()).stream(file.getInputStream(), file.getSize(), -1).build());
return minioFile;
return minioUploadFIleInfo;
} catch (Exception exception) {
throw new AuthCustomerException(ResultCodeEnum.UPLOAD_ERROR);
}
}
/**
* 获取默认bucket文件并返回字节数组
* 获取默认存储桶中的文件字节数组
*
* @param objectName 对象名称
* @return 文件流对象
* <p><b>注意</b>会一次性读取全部文件内容到内存大文件慎用</p>
*
* @param objectName 对象全路径名称包含目录路径
* @return 文件内容的字节数组
* @throws AuthCustomerException 当获取失败时抛出错误码{@link ResultCodeEnum#GET_BUCKET_EXCEPTION}
*/
public byte[] getBucketObjectByte(String objectName) {
String bucketName = properties.getBucketName();
@ -111,12 +133,13 @@ public class MinioService {
}
/**
* 上传文件
* 上传文件到指定存储桶
*
* @param bucketName 桶名称
* @param filename 文件名
* @param inputStream 输入流
* @param size 大小
* @param bucketName 存储桶名称
* @param filename 对象存储路径包含文件名
* @param inputStream 文件输入流调用方负责关闭
* @param size 文件大小字节
* @throws AuthCustomerException 当上传失败时抛出错误码{@link ResultCodeEnum#UPLOAD_ERROR}
*/
public void putObject(String bucketName, String filename, InputStream inputStream, Long size) {
try {
@ -128,9 +151,10 @@ public class MinioService {
}
/**
* * 删除目标文件
* 批量删除存储桶中的对象文件
*
* @param list 对象文件列表
* @param list 要删除的对象路径列表
* @throws AuthCustomerException 当删除失败时抛出包含错误对象信息
*/
public void removeObjects(List<String> list) {
try {
@ -148,11 +172,12 @@ public class MinioService {
}
/**
* * 更新文件
* 更新存储桶中的文件覆盖写入
*
* @param bucketName 桶名称
* @param filepath 文件路径
* @param file 文件
* @param bucketName 存储桶名称
* @param filepath 对象存储路径
* @param file 新的文件对象
* @throws AuthCustomerException 当更新失败时抛出
*/
public void updateFile(String bucketName, String filepath, MultipartFile file) {
try {
@ -163,10 +188,11 @@ public class MinioService {
}
/**
* 判断桶是否存在
* 检查并创建存储桶如果不存在
*
* @param bucketName 桶名称
* @return 布尔值是否存在
* @param bucketName 存储桶名称
* @return true-已存在false-新创建
* @throws AuthCustomerException 当操作失败时抛出
*/
public boolean createBucketIfNotExists(String bucketName) {
boolean found = false;
@ -185,9 +211,10 @@ public class MinioService {
}
/**
* 创建
* 创建新的存储
*
* @param bucketName 桶的名称
* @param bucketName 存储桶名称需符合命名规范
* @throws AuthCustomerException 当创建失败时抛出
*/
public void makeBucket(String bucketName) {
try {
@ -197,5 +224,4 @@ public class MinioService {
throw new AuthCustomerException("创建失败");
}
}
}

View File

@ -1,6 +1,6 @@
package cn.bunny.services.utils;
import cn.bunny.services.domain.common.ip.IpEntity;
import cn.bunny.services.domain.common.model.dto.ip.IpEntity;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;

View File

@ -0,0 +1,14 @@
import org.junit.jupiter.api.Test;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MinioTest {
@Test
void test() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM-dd");
String date = formatter.format(new Date());
System.out.println(date);
}
}

View File

@ -29,24 +29,6 @@
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.30.0</version>
</dependency>
<!-- asp 切面 -->
<dependency>
@ -57,12 +39,12 @@
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.springframework.boot</groupId> -->
<!-- <artifactId>spring-boot-devtools</artifactId> -->
<!-- <scope>runtime</scope> -->
<!-- <optional>true</optional> -->
<!-- </dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- quartz -->
<dependency>

View File

@ -1,8 +1,8 @@
package cn.bunny.services.aop.scanner;
import cn.bunny.services.domain.common.scanner.ControllerInfo;
import cn.bunny.services.domain.common.scanner.MethodInfo;
import cn.bunny.services.domain.common.scanner.ScannerControllerInfoVo;
import cn.bunny.services.domain.common.model.dto.scanner.ControllerInfo;
import cn.bunny.services.domain.common.model.dto.scanner.MethodInfo;
import cn.bunny.services.domain.common.model.dto.scanner.ScannerControllerInfoVo;
import cn.bunny.services.security.config.WebSecurityConfig;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;

View File

@ -1,7 +1,7 @@
package cn.bunny.services.security.service;
import cn.bunny.services.context.BaseContext;
import cn.bunny.services.domain.common.security.TokenInfo;
import cn.bunny.services.domain.common.model.dto.security.TokenInfo;
import cn.bunny.services.domain.common.model.vo.LoginVo;
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
import cn.bunny.services.security.exception.CustomAuthenticationException;

View File

@ -1,7 +1,7 @@
package cn.bunny.services.security.service;
import cn.bunny.services.domain.common.constant.RedisUserConstant;
import cn.bunny.services.domain.common.security.TokenInfo;
import cn.bunny.services.domain.common.model.dto.security.TokenInfo;
import cn.bunny.services.domain.common.model.vo.LoginVo;
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
import cn.bunny.services.security.exception.CustomAuthenticationException;

View File

@ -1,12 +1,12 @@
package cn.bunny.services.service.configuration.helper.email;
import cn.bunny.services.config.mail.MailSenderConfiguration;
import cn.bunny.services.domain.common.model.dto.email.EmailSend;
import cn.bunny.services.domain.common.model.dto.email.EmailSendInit;
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
import cn.bunny.services.domain.system.email.entity.EmailTemplate;
import cn.bunny.services.domain.system.email.entity.EmailUsers;
import cn.bunny.services.exception.AuthCustomerException;
import cn.bunny.services.mail.MailSenderConfiguration;
import cn.bunny.services.mapper.configuration.EmailUsersMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.mail.MessagingException;

View File

@ -1,7 +1,7 @@
package cn.bunny.services.service.system.impl;
import cn.bunny.services.context.BaseContext;
import cn.bunny.services.domain.common.model.dto.file.MinioFilePath;
import cn.bunny.services.domain.common.model.dto.minio.MinioUploadFileInfo;
import cn.bunny.services.domain.common.model.vo.result.PageResult;
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
import cn.bunny.services.domain.system.files.dto.FileUploadDto;
@ -81,10 +81,8 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
IPage<FilesVo> page = baseMapper.selectListByPage(pageParams, dto);
return PageResult.<FilesVo>builder()
.list(page.getRecords())
.pageNo(page.getCurrent())
.pageSize(page.getSize())
.total(page.getTotal())
.list(page.getRecords()).pageNo(page.getCurrent())
.pageSize(page.getSize()).total(page.getTotal())
.build();
}
@ -97,13 +95,13 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
public void addFiles(FilesAddDto dto) {
List<Files> list = dto.getFiles().stream().map(file -> {
try {
MinioFilePath minioFilePath = minioService.uploadObjectReturnFilePath(file, dto.getFilepath());
MinioUploadFileInfo minioUploadFileInfo = minioService.uploadWithFileInfo(file, dto.getFilepath());
Files files = new Files();
files.setFileType(file.getContentType());
files.setFileSize(file.getSize());
files.setFilepath("/" + properties.getBucketName() + minioFilePath.getFilepath());
files.setFilename(minioFilePath.getFilename());
files.setFilepath("/" + properties.getBucketName() + minioUploadFileInfo.getFilepath());
files.setFilename(minioUploadFileInfo.getFilename());
files.setDownloadCount(dto.getDownloadCount());
return files;
} catch (IOException e) {
@ -111,7 +109,6 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
}
}).toList();
// 保存数据
saveBatch(list);
}
@ -165,8 +162,8 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
String filename = file.getOriginalFilename();
// 上传文件
MinioFilePath minioFIlePath = minioService.uploadObjectReturnFilePath(file, type);
String bucketNameFilepath = minioFIlePath.getBucketNameFilepath();
MinioUploadFileInfo minioUploadFIleInfo = minioService.uploadWithFileInfo(file, type);
String bucketNameFilepath = minioUploadFIleInfo.getBucketNameFilepath();
// 盘读研数据是否过大
String mb = maxFileSize.replace("MB", "");
@ -183,12 +180,9 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
// 返回信息内容化
return FileInfoVo.builder()
.size(FileUtil.getSize(fileSize))
.filepath(bucketNameFilepath)
.fileSize(fileSize)
.fileType(contentType)
.filename(filename)
.url(minioHelper.getObjectNameFullPath(bucketNameFilepath))
.size(FileUtil.getSize(fileSize)).filepath(bucketNameFilepath)
.fileSize(fileSize).fileType(contentType)
.filename(filename).url(minioHelper.getObjectNameFullPath(bucketNameFilepath))
.build();
}