initial spring-boot 3 supports

This commit is contained in:
王宏亮 2024-08-01 11:42:46 +08:00
parent 6e84322c79
commit 91f2a84105
34 changed files with 569 additions and 205 deletions

7
.gitignore vendored
View File

@ -16,3 +16,10 @@ buildNumber.properties
# JDT-specific (Eclipse Java Development Tools) # JDT-specific (Eclipse Java Development Tools)
.classpath .classpath
/docs/.vitepress/cache/ /docs/.vitepress/cache/
# IDEA
.idea/
# logs
**/logs
**/*.log

View File

@ -34,6 +34,7 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>

View File

@ -4,18 +4,20 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/** /**
* SpringMVC配置 * SpringMVC配置
*
* @author contact@liuxp.me * @author contact@liuxp.me
* @since 2024/06/11 * @since 2024/06/11
*/ */
@Configuration @Configuration
public class WebMvcConfig implements WebMvcConfigurer { public class WebMvcConfig implements WebMvcConfigurer {
@Resource private final LoginUserInterceptor loginUserInterceptor;
private LoginUserInterceptor loginUserInterceptor;
public WebMvcConfig(LoginUserInterceptor loginUserInterceptor) {
this.loginUserInterceptor = loginUserInterceptor;
}
/** /**
* 前置拦截器 * 前置拦截器

View File

@ -29,6 +29,7 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>

View File

@ -7,11 +7,11 @@ import org.liuxp.minioplus.api.model.vo.FileMetadataInfoVo;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List; import java.util.List;
/** /**
* 定时任务演示工程定期清理文件 * 定时任务演示工程定期清理文件
*
* @author contact@liuxp.me * @author contact@liuxp.me
* @since 2024/06/17 * @since 2024/06/17
*/ */
@ -19,8 +19,11 @@ import java.util.List;
@Slf4j @Slf4j
public class CleanTask { public class CleanTask {
@Resource private final StorageService storageService;
private StorageService storageService;
public CleanTask(StorageService storageService) {
this.storageService = storageService;
}
@Scheduled(cron = "0 0 */1 * * ?") @Scheduled(cron = "0 0 */1 * * ?")
public void clean() { public void clean() {

View File

@ -16,23 +16,12 @@
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springboot3.version>3.3.2</springboot3.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-plus-all-springboot3-starter</artifactId> <artifactId>minio-plus-all-springboot3-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
@ -46,35 +35,45 @@
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --> <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency> <version>${mybatisplus.version}</version>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${springboot3.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${springboot3.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
<version>${springboot3.version}</version> <version>${spring-boot3.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
<dependencyManagement>
<dependencies>
<!-- spring-boot-dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot3.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot3.version}</version> <version>${spring-boot3.version}</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>

View File

@ -8,8 +8,8 @@ import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
/** /**
* 登录用户拦截器 * 登录用户拦截器

View File

@ -4,18 +4,21 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/** /**
* SpringMVC配置 * SpringMVC配置
*
* @author contact@liuxp.me * @author contact@liuxp.me
* @since 2024/06/11 * @since 2024/06/11
*/ */
@Configuration @Configuration
public class WebMvcConfig implements WebMvcConfigurer { public class WebMvcConfig implements WebMvcConfigurer {
@Resource private final LoginUserInterceptor loginUserInterceptor;
private LoginUserInterceptor loginUserInterceptor;
public WebMvcConfig(LoginUserInterceptor loginUserInterceptor) {
this.loginUserInterceptor = loginUserInterceptor;
}
/** /**
* 前置拦截器 * 前置拦截器

View File

@ -24,11 +24,15 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency> </dependency>
<!-- 自定义的配置类生成元数据信息 --> <!-- 自定义的配置类生成元数据信息 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId> <artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -1,16 +1,10 @@
package org.liuxp.minioplus.common.config; package org.liuxp.minioplus.common.config;
import org.springframework.context.annotation.Bean;
/** /**
* MinioPlusProperties自动配置类 * MinioPlus自动配置类
*
* @author contact@liuxp.me * @author contact@liuxp.me
*/ */
public class MinioPlusConfig { public class MinioPlusConfig {
// do noting cuz use components scan
@Bean
public MinioPlusProperties tosProperties() {
return new MinioPlusProperties();
}
} }

View File

@ -5,6 +5,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/** /**
* MinioPlus配置类 * MinioPlus配置类
@ -14,6 +15,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
*/ */
@Getter @Getter
@Setter @Setter
@Configuration
@ConfigurationProperties(prefix = "minioplus") @ConfigurationProperties(prefix = "minioplus")
public class MinioPlusProperties { public class MinioPlusProperties {

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.liuxp.minioplus.common.config.MinioPlusConfig

View File

@ -0,0 +1 @@
org.liuxp.minioplus.common.config.MinioPlusConfig

View File

@ -19,6 +19,12 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-plus-common</artifactId> <artifactId>minio-plus-common</artifactId>

View File

@ -26,7 +26,6 @@ import org.liuxp.minioplus.s3.def.ListParts;
import org.liuxp.minioplus.s3.def.MinioS3Client; import org.liuxp.minioplus.s3.def.MinioS3Client;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.InputStream; import java.io.InputStream;
@ -44,14 +43,17 @@ import java.util.Optional;
@Slf4j @Slf4j
public class StorageEngineServiceImpl implements StorageEngineService { public class StorageEngineServiceImpl implements StorageEngineService {
@Resource private final MetadataRepository metadataRepository;
MetadataRepository metadataRepository;
@Resource private final MinioPlusProperties properties;
MinioPlusProperties properties;
@Resource private final MinioS3Client minioS3Client;
MinioS3Client minioS3Client;
public StorageEngineServiceImpl(MetadataRepository metadataRepository, MinioPlusProperties properties, MinioS3Client minioS3Client) {
this.metadataRepository = metadataRepository;
this.properties = properties;
this.minioS3Client = minioS3Client;
}
/** /**
* 上传任务初始化 * 上传任务初始化
@ -538,6 +540,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
* @param fileSize 文件大小 * @param fileSize 文件大小
* @return {@link Integer} * @return {@link Integer}
*/ */
@Override
public Integer computeChunkNum(Long fileSize) { public Integer computeChunkNum(Long fileSize) {
// 计算分块数量 // 计算分块数量
double tempNum = (double) fileSize / properties.getPart().getSize(); double tempNum = (double) fileSize / properties.getPart().getSize();

View File

@ -26,13 +26,13 @@ import org.liuxp.minioplus.core.engine.StorageEngineService;
import org.liuxp.minioplus.core.repository.MetadataRepository; import org.liuxp.minioplus.core.repository.MetadataRepository;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* 存储组件Service层公共方法实现类 * 存储组件Service层公共方法实现类
*
* @author contact@liuxp.me * @author contact@liuxp.me
* @since 2023/06/26 * @since 2023/06/26
*/ */
@ -42,20 +42,23 @@ public class StorageServiceImpl implements StorageService {
/** /**
* 存储引擎Service接口定义 * 存储引擎Service接口定义
*/ */
@Resource private final StorageEngineService storageEngineService;
StorageEngineService storageEngineService;
/** /**
* 文件元数据服务接口定义 * 文件元数据服务接口定义
*/ */
@Resource private final MetadataRepository fileMetadataRepository;
MetadataRepository fileMetadataRepository;
/** /**
* MinioPlus配置信息注入类 * MinioPlus配置信息注入类
*/ */
@Resource private final MinioPlusProperties properties;
MinioPlusProperties properties;
public StorageServiceImpl(StorageEngineService storageEngineService, MetadataRepository fileMetadataRepository, MinioPlusProperties properties) {
this.storageEngineService = storageEngineService;
this.fileMetadataRepository = fileMetadataRepository;
this.properties = properties;
}
@Override @Override
public FilePreShardingVo sharding(long fileSize) { public FilePreShardingVo sharding(long fileSize) {
@ -290,6 +293,7 @@ public class StorageServiceImpl implements StorageService {
/** /**
* 重写文件地址 * 重写文件地址
*
* @param url 文件地址 * @param url 文件地址
* @return 重写后的文件地址 * @return 重写后的文件地址
*/ */

View File

@ -1,3 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.liuxp.minioplus.core.service.impl.StorageServiceImpl,\
org.liuxp.minioplus.core.engine.impl.StorageEngineServiceImpl

View File

@ -0,0 +1,2 @@
#org.liuxp.minioplus.core.service.impl.StorageServiceImpl
#org.liuxp.minioplus.core.engine.impl.StorageEngineServiceImpl

View File

@ -20,7 +20,15 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency> </dependency>
<!--<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>-->
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,111 @@
package org.liuxp.minioplus.extension.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.liuxp.minioplus.api.model.vo.FileCheckResultVo;
import org.liuxp.minioplus.api.model.vo.FilePreShardingVo;
import org.liuxp.minioplus.extension.context.Response;
import org.liuxp.minioplus.extension.dto.FileCheckDTO;
import org.liuxp.minioplus.extension.dto.FileCompleteDTO;
import org.liuxp.minioplus.extension.dto.PreShardingDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 对象存储标准接口定义
* 本类的方法是给前端使用的方法
*
* @author contact@liuxp.me
* @since 2024/6/18
*/
@Tag(name = "MinIO Plus 接口")
public interface StorageWebAPI {
/**
* 请求地址前缀
*/
String ROOT_PATH = "/storage";
/**
* 图标请求地址
*/
String ICON_PATH = "/storage/icon/";
/**
* 文件预分片方法
* 在大文件上传时为了防止前端重复计算文件MD5值提供该方法
*
* @param preShardingDTO 文件预分片入参DTO
* @return 预分片结果
*/
@Operation(summary = "文件预分片")
@PostMapping("/upload/sharding")
@ResponseBody
Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO);
/**
* 上传任务初始化
* 上传前的预检查秒传分块上传和断点续传等特性均基于该方法实现
*
* @param fileCheckDTO 文件预检查入参
* @return 检查结果
*/
@Operation(summary = "上传任务初始化")
@PostMapping("/upload/init")
@ResponseBody
Response<FileCheckResultVo> init(@RequestBody @Validated FileCheckDTO fileCheckDTO);
/**
* 文件上传完成
*
* @param fileKey 文件KEY
* @param fileCompleteDTO 文件完成入参DTO
* @return 是否成功
*/
@Operation(summary = "上传完成")
@PostMapping("/upload/complete/{fileKey}")
@ResponseBody
Response<Object> complete(@PathVariable("fileKey") String fileKey, @RequestBody FileCompleteDTO fileCompleteDTO);
/**
* 文件下载
*
* @param fileKey 文件KEY
* @return 文件下载地址
*/
@Operation(summary = "文件下载")
@GetMapping("/download/{fileKey}")
String download(@PathVariable("fileKey") String fileKey);
/**
* 获取图像
*
* @param fileKey 文件KEY
* @return 原图地址
*/
@Operation(summary = "图片预览 - 原图")
@GetMapping("/image/{fileKey}")
String previewOriginal(@PathVariable("fileKey") String fileKey);
/**
* 文件预览
* 当文件为图片时返回图片的缩略图
* 当文件不是图片时返回文件类型图标
*
* @param fileKey 文件KEY
* @return 缩略图地址
*/
@Operation(summary = "图片预览 - 缩略图")
@GetMapping("/preview/{fileKey}")
String previewMedium(@PathVariable("fileKey") String fileKey);
/**
* 根据文件类型取得图标
*
* @param fileType 文件扩展名
*/
@Operation(summary = "获取图标")
@GetMapping("/icon/{fileType}")
void icon(@PathVariable("fileType") String fileType);
}

View File

@ -26,6 +26,13 @@
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-plus-common</artifactId> <artifactId>minio-plus-common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -9,14 +9,12 @@ import io.minio.errors.XmlParserException;
import io.minio.http.Method; import io.minio.http.Method;
import io.minio.messages.Part; import io.minio.messages.Part;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.liuxp.minioplus.common.config.MinioPlusProperties;
import org.liuxp.minioplus.common.enums.MinioPlusErrorCode; import org.liuxp.minioplus.common.enums.MinioPlusErrorCode;
import org.liuxp.minioplus.common.exception.MinioPlusException; import org.liuxp.minioplus.common.exception.MinioPlusException;
import org.liuxp.minioplus.common.config.MinioPlusProperties;
import org.liuxp.minioplus.s3.def.ListParts; import org.liuxp.minioplus.s3.def.ListParts;
import org.liuxp.minioplus.s3.def.MinioS3Client; import org.liuxp.minioplus.s3.def.MinioS3Client;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
@ -29,7 +27,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@Repository
public class MinioS3ClientImpl implements MinioS3Client { public class MinioS3ClientImpl implements MinioS3Client {
/** /**
@ -41,11 +38,14 @@ public class MinioS3ClientImpl implements MinioS3Client {
*/ */
private static final String PART_NUMBER = "partNumber"; private static final String PART_NUMBER = "partNumber";
@Resource private final MinioPlusProperties properties;
private MinioPlusProperties properties;
private CustomMinioClient minioClient = null; private CustomMinioClient minioClient = null;
public MinioS3ClientImpl(MinioPlusProperties properties) {
this.properties = properties;
}
public CustomMinioClient getClient() { public CustomMinioClient getClient() {
if (null == this.minioClient) { if (null == this.minioClient) {
@ -63,8 +63,9 @@ public class MinioS3ClientImpl implements MinioS3Client {
public Boolean bucketExists(String bucketName) { public Boolean bucketExists(String bucketName) {
try { try {
return this.getClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()).get(); return this.getClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()).get();
} catch (InsufficientDataException | InternalException | InvalidKeyException | IOException | NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) { } catch (InsufficientDataException | InternalException | InvalidKeyException | IOException |
log.error(MinioPlusErrorCode.BUCKET_EXISTS_FAILED.getMessage()+":{}", e.getMessage(), e); NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) {
log.error("{}:{}", MinioPlusErrorCode.BUCKET_EXISTS_FAILED.getMessage(), e.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.BUCKET_EXISTS_FAILED); throw new MinioPlusException(MinioPlusErrorCode.BUCKET_EXISTS_FAILED);
} }
} }
@ -78,7 +79,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
this.getClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); this.getClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
} }
} catch (Exception e) { } catch (Exception e) {
log.error(MinioPlusErrorCode.MAKE_BUCKET_FAILED.getMessage()+":{}", e.getMessage(), e); log.error("{}:{}", MinioPlusErrorCode.MAKE_BUCKET_FAILED.getMessage(), e.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.MAKE_BUCKET_FAILED); throw new MinioPlusException(MinioPlusErrorCode.MAKE_BUCKET_FAILED);
} }
} }
@ -89,7 +90,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
CreateMultipartUploadResponse createMultipartUploadResponse = this.getClient().createMultipartUpload(bucketName, null, objectName, null, null); CreateMultipartUploadResponse createMultipartUploadResponse = this.getClient().createMultipartUpload(bucketName, null, objectName, null, null);
return createMultipartUploadResponse.result().uploadId(); return createMultipartUploadResponse.result().uploadId();
} catch (Exception e) { } catch (Exception e) {
log.error(MinioPlusErrorCode.CREATE_MULTIPART_UPLOAD_FAILED.getMessage()+":{}", e.getMessage(), e); log.error("{}:{}", MinioPlusErrorCode.CREATE_MULTIPART_UPLOAD_FAILED.getMessage(), e.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.CREATE_MULTIPART_UPLOAD_FAILED); throw new MinioPlusException(MinioPlusErrorCode.CREATE_MULTIPART_UPLOAD_FAILED);
} }
} }
@ -108,7 +109,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
, objectName, uploadId, partArray, null, null); , objectName, uploadId, partArray, null, null);
return objectWriteResponse != null; return objectWriteResponse != null;
} catch (Exception e) { } catch (Exception e) {
log.error(MinioPlusErrorCode.COMPLETE_MULTIPART_FAILED.getMessage()+",uploadId:{},ObjectName:{},失败原因:{},", uploadId, objectName, e.getMessage(), e); log.error("{},uploadId:{},ObjectName:{},失败原因:{},", MinioPlusErrorCode.COMPLETE_MULTIPART_FAILED.getMessage(), uploadId, objectName, e.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.COMPLETE_MULTIPART_FAILED); throw new MinioPlusException(MinioPlusErrorCode.COMPLETE_MULTIPART_FAILED);
} }
} }
@ -134,7 +135,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
} catch (Exception e) { } catch (Exception e) {
// 查询分片失败打印日志返回空的分片信息 // 查询分片失败打印日志返回空的分片信息
log.error(MinioPlusErrorCode.LIST_PARTS_FAILED.getMessage()+":{}", e.getMessage()); log.error("{}:{}", MinioPlusErrorCode.LIST_PARTS_FAILED.getMessage(), e.getMessage());
} }
return listParts; return listParts;
@ -157,7 +158,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
.extraQueryParams(queryParams) .extraQueryParams(queryParams)
.build()); .build());
} catch (Exception e) { } catch (Exception e) {
log.error(MinioPlusErrorCode.CREATE_UPLOAD_URL_FAILED.getMessage()+":{}", e.getMessage(), e); log.error("{}:{}", MinioPlusErrorCode.CREATE_UPLOAD_URL_FAILED.getMessage(), e.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.CREATE_UPLOAD_URL_FAILED); throw new MinioPlusException(MinioPlusErrorCode.CREATE_UPLOAD_URL_FAILED);
} }
} }
@ -178,7 +179,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
.extraQueryParams(reqParams) .extraQueryParams(reqParams)
.build()); .build());
} catch (Exception e) { } catch (Exception e) {
log.error(MinioPlusErrorCode.CREATE_DOWNLOAD_URL_FAILED.getMessage()+":{}", e.getMessage(), e); log.error("{}:{}", MinioPlusErrorCode.CREATE_DOWNLOAD_URL_FAILED.getMessage(), e.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.CREATE_DOWNLOAD_URL_FAILED); throw new MinioPlusException(MinioPlusErrorCode.CREATE_DOWNLOAD_URL_FAILED);
} }
} }
@ -199,7 +200,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
.extraQueryParams(reqParams) .extraQueryParams(reqParams)
.build()); .build());
} catch (Exception e) { } catch (Exception e) {
log.error(MinioPlusErrorCode.CREATE_PREVIEW_URL_FAILED.getMessage()+":{}", e.getMessage(), e); log.error("{}:{}", MinioPlusErrorCode.CREATE_PREVIEW_URL_FAILED.getMessage(), e.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.CREATE_PREVIEW_URL_FAILED); throw new MinioPlusException(MinioPlusErrorCode.CREATE_PREVIEW_URL_FAILED);
} }
} }
@ -224,7 +225,8 @@ public class MinioS3ClientImpl implements MinioS3Client {
.contentType(contentType) .contentType(contentType)
.build()); .build());
} catch (InsufficientDataException | InternalException | InvalidKeyException | IOException | NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) { } catch (InsufficientDataException | InternalException | InvalidKeyException | IOException |
NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) {
log.error(MinioPlusErrorCode.WRITE_FAILED.getMessage(), e); log.error(MinioPlusErrorCode.WRITE_FAILED.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.WRITE_FAILED); throw new MinioPlusException(MinioPlusErrorCode.WRITE_FAILED);
} }

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.liuxp.minioplus.s3.official.MinioS3ClientImpl

View File

@ -0,0 +1 @@
org.liuxp.minioplus.s3.official.MinioS3ClientImpl

View File

@ -21,7 +21,8 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot2.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>

View File

@ -1,8 +1,6 @@
package org.liuxp.minioplus.extension.controller; package org.liuxp.minioplus.extension.controller;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.liuxp.minioplus.api.StorageService; import org.liuxp.minioplus.api.StorageService;
import org.liuxp.minioplus.api.model.vo.CompleteResultVo; import org.liuxp.minioplus.api.model.vo.CompleteResultVo;
@ -20,49 +18,47 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
/** /**
* 对象存储标准接口定义 * 对象存储标准接口定义
* 本类的方法是给前端使用的方法 * 本类的方法是给前端使用的方法
*
* @author contact@liuxp.me * @author contact@liuxp.me
* @since 2024/6/18 * @since 2024/6/18
*/ */
@Controller
@RequestMapping("/storage")
@Tag(name = "MinIO Plus 接口")
@Slf4j @Slf4j
public class StorageController { @Controller
@RequestMapping(StorageWebAPI.ROOT_PATH)
public class StorageController implements StorageWebAPI {
/** /**
* 重定向 * 重定向
*/ */
private static final String REDIRECT_PREFIX = "redirect:"; private static final String REDIRECT_PREFIX = "redirect:";
/**
* 图标请求地址
*/
private static final String ICON_PATH = "/storage/icon/";
/** /**
* 存储引擎Service接口定义 * 存储引擎Service接口定义
*/ */
@Resource private final StorageService storageService;
private StorageService storageService;
public StorageController(StorageService storageService) {
this.storageService = storageService;
}
/** /**
* 文件预分片方法 * 文件预分片方法
* 在大文件上传时为了防止前端重复计算文件MD5值提供该方法 * 在大文件上传时为了防止前端重复计算文件MD5值提供该方法
*
* @param preShardingDTO 文件预分片入参DTO * @param preShardingDTO 文件预分片入参DTO
* @return 预分片结果 * @return 预分片结果
*/ */
@Operation(summary = "文件预分片") @Override
@PostMapping("/upload/sharding")
@ResponseBody
public Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO) { public Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO) {
FilePreShardingVo resultVo = storageService.sharding(preShardingDTO.getFileSize()); FilePreShardingVo resultVo = storageService.sharding(preShardingDTO.getFileSize());
@ -73,13 +69,12 @@ public class StorageController {
/** /**
* 上传任务初始化 * 上传任务初始化
* 上传前的预检查秒传分块上传和断点续传等特性均基于该方法实现 * 上传前的预检查秒传分块上传和断点续传等特性均基于该方法实现
*
* @param fileCheckDTO 文件预检查入参 * @param fileCheckDTO 文件预检查入参
* @return 检查结果 * @return 检查结果
*/ */
@Operation(summary = "上传任务初始化") @Override
@PostMapping("/upload/init") public Response<FileCheckResultVo> init(FileCheckDTO fileCheckDTO) {
@ResponseBody
public Response<FileCheckResultVo> init(@RequestBody @Validated FileCheckDTO fileCheckDTO) {
// 取得当前登录用户信息 // 取得当前登录用户信息
String userId = UserHolder.get(); String userId = UserHolder.get();
@ -91,14 +86,13 @@ public class StorageController {
/** /**
* 文件上传完成 * 文件上传完成
*
* @param fileKey 文件KEY * @param fileKey 文件KEY
* @param fileCompleteDTO 文件完成入参DTO * @param fileCompleteDTO 文件完成入参DTO
* @return 是否成功 * @return 是否成功
*/ */
@Operation(summary = "上传完成") @Override
@PostMapping("/upload/complete/{fileKey}") public Response<Object> complete(String fileKey, FileCompleteDTO fileCompleteDTO) {
@ResponseBody
public Response<Object> complete(@PathVariable("fileKey") String fileKey, @RequestBody FileCompleteDTO fileCompleteDTO) {
// 取得当前登录用户信息 // 取得当前登录用户信息
String userId = UserHolder.get(); String userId = UserHolder.get();
@ -112,12 +106,12 @@ public class StorageController {
/** /**
* 文件下载 * 文件下载
*
* @param fileKey 文件KEY * @param fileKey 文件KEY
* @return 文件下载地址 * @return 文件下载地址
*/ */
@Operation(summary = "文件下载") @Override
@GetMapping("/download/{fileKey}") public String download(String fileKey) {
public String download(@PathVariable String fileKey) {
// 取得当前登录用户信息 // 取得当前登录用户信息
String userId = UserHolder.get(); String userId = UserHolder.get();
@ -128,12 +122,12 @@ public class StorageController {
/** /**
* 获取图像 * 获取图像
*
* @param fileKey 文件KEY * @param fileKey 文件KEY
* @return 原图地址 * @return 原图地址
*/ */
@Operation(summary = "图片预览 - 原图") @Override
@GetMapping("/image/{fileKey}") public String previewOriginal(String fileKey) {
public String previewOriginal(@PathVariable String fileKey) {
// 取得当前登录用户信息 // 取得当前登录用户信息
String userId = UserHolder.get(); String userId = UserHolder.get();
@ -146,12 +140,12 @@ public class StorageController {
* 文件预览 * 文件预览
* 当文件为图片时返回图片的缩略图 * 当文件为图片时返回图片的缩略图
* 当文件不是图片时返回文件类型图标 * 当文件不是图片时返回文件类型图标
*
* @param fileKey 文件KEY * @param fileKey 文件KEY
* @return 缩略图地址 * @return 缩略图地址
*/ */
@Operation(summary = "图片预览 - 缩略图") @Override
@GetMapping("/preview/{fileKey}") public String previewMedium(String fileKey) {
public String previewMedium(@PathVariable String fileKey) {
// 取得当前登录用户信息 // 取得当前登录用户信息
String userId = UserHolder.get(); String userId = UserHolder.get();
@ -168,14 +162,12 @@ public class StorageController {
/** /**
* 根据文件类型取得图标 * 根据文件类型取得图标
* @param response HttpServletResponse *
* @param fileType 文件扩展名 * @param fileType 文件扩展名
*/ */
@Operation(summary = "获取图标") @Override
@GetMapping("/icon/{fileType}") public void icon(String fileType) {
public void icon(HttpServletResponse response,@PathVariable String fileType) {
try { try {
// 根据文件后缀取得桶 // 根据文件后缀取得桶
String storageBucket = StorageBucketEnums.getBucketByFileSuffix(fileType); String storageBucket = StorageBucketEnums.getBucketByFileSuffix(fileType);
@ -183,13 +175,12 @@ public class StorageController {
byte[] bytes = FileCopyUtils.copyToByteArray(cpr.getInputStream()); byte[] bytes = FileCopyUtils.copyToByteArray(cpr.getInputStream());
response.setHeader("content-disposition", "inline"); ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
response.setHeader("Content-Length", String.valueOf(bytes.length)); attr.getResponse().setHeader("content-disposition", "inline");
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); attr.getResponse().setHeader("Content-Length", String.valueOf(bytes.length));
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
IoUtil.copy(inputStream, response.getOutputStream()); IoUtil.copy(inputStream, attr.getResponse().getOutputStream());
inputStream.close(); }
} catch (Exception e) { } catch (Exception e) {
log.error(MinioPlusErrorCode.FILE_ICON_FAILED.getMessage(), e); log.error(MinioPlusErrorCode.FILE_ICON_FAILED.getMessage(), e);
// 图标获取失败 // 图标获取失败

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.liuxp.minioplus.common.config.MinioPlusAutoConfiguration

View File

@ -15,11 +15,21 @@
<properties> <properties>
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
<!--<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot3.version}</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>
<artifactId>minio-plus-extension</artifactId> <artifactId>minio-plus-extension</artifactId>

View File

@ -0,0 +1,191 @@
package org.liuxp.minioplus.extension.controller;
import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j;
import org.liuxp.minioplus.api.StorageService;
import org.liuxp.minioplus.api.model.vo.CompleteResultVo;
import org.liuxp.minioplus.api.model.vo.FileCheckResultVo;
import org.liuxp.minioplus.api.model.vo.FilePreShardingVo;
import org.liuxp.minioplus.common.enums.MinioPlusErrorCode;
import org.liuxp.minioplus.common.enums.StorageBucketEnums;
import org.liuxp.minioplus.common.exception.MinioPlusException;
import org.liuxp.minioplus.extension.context.Response;
import org.liuxp.minioplus.extension.context.UserHolder;
import org.liuxp.minioplus.extension.dto.FileCheckDTO;
import org.liuxp.minioplus.extension.dto.FileCompleteDTO;
import org.liuxp.minioplus.extension.dto.PreShardingDTO;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.ByteArrayInputStream;
/**
* 对象存储标准接口定义
* 本类的方法是给前端使用的方法
*
* @author contact@liuxp.me
* @since 2024/6/18
*/
@Slf4j
@Controller
@RequestMapping(StorageWebAPI.ROOT_PATH)
public class StorageController implements StorageWebAPI {
/**
* 重定向
*/
private static final String REDIRECT_PREFIX = "redirect:";
/**
* 存储引擎Service接口定义
*/
private final StorageService storageService;
public StorageController(StorageService storageService) {
this.storageService = storageService;
}
/**
* 文件预分片方法
* 在大文件上传时为了防止前端重复计算文件MD5值提供该方法
*
* @param preShardingDTO 文件预分片入参DTO
* @return 预分片结果
*/
@Override
public Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO) {
FilePreShardingVo resultVo = storageService.sharding(preShardingDTO.getFileSize());
return Response.success(resultVo);
}
/**
* 上传任务初始化
* 上传前的预检查秒传分块上传和断点续传等特性均基于该方法实现
*
* @param fileCheckDTO 文件预检查入参
* @return 检查结果
*/
@Override
public Response<FileCheckResultVo> init(FileCheckDTO fileCheckDTO) {
// 取得当前登录用户信息
String userId = UserHolder.get();
FileCheckResultVo resultVo = storageService.init(fileCheckDTO.getFileMd5(), fileCheckDTO.getFullFileName(), fileCheckDTO.getFileSize(), fileCheckDTO.getIsPrivate(), userId);
return Response.success(resultVo);
}
/**
* 文件上传完成
*
* @param fileKey 文件KEY
* @param fileCompleteDTO 文件完成入参DTO
* @return 是否成功
*/
@Override
public Response<Object> complete(String fileKey, FileCompleteDTO fileCompleteDTO) {
// 取得当前登录用户信息
String userId = UserHolder.get();
// 打印调试日志
log.debug("合并文件开始fileKey=" + fileKey + ",partMd5List=" + fileCompleteDTO.getPartMd5List());
CompleteResultVo completeResultVo = storageService.complete(fileKey, fileCompleteDTO.getPartMd5List(), userId);
return Response.success(completeResultVo);
}
/**
* 文件下载
*
* @param fileKey 文件KEY
* @return 文件下载地址
*/
@Override
public String download(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
// 取得文件读取路径
return REDIRECT_PREFIX + storageService.download(fileKey, userId);
}
/**
* 获取图像
*
* @param fileKey 文件KEY
* @return 原图地址
*/
@Override
public String previewOriginal(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
// 取得文件读取路径
return REDIRECT_PREFIX + storageService.image(fileKey, userId);
}
/**
* 文件预览
* 当文件为图片时返回图片的缩略图
* 当文件不是图片时返回文件类型图标
*
* @param fileKey 文件KEY
* @return 缩略图地址
*/
@Override
public String previewMedium(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
String url = storageService.preview(fileKey, userId);
if (url.length() < 10) {
// 当返回值为文件类型时取得图标
url = ICON_PATH + url;
}
// 取得文件读取路径
return REDIRECT_PREFIX + url;
}
/**
* 根据文件类型取得图标
*
* @param fileType 文件扩展名
*/
@Override
public void icon(String fileType) {
try {
// 根据文件后缀取得桶
String storageBucket = StorageBucketEnums.getBucketByFileSuffix(fileType);
ClassPathResource cpr = new ClassPathResource(storageBucket + ".png");
byte[] bytes = FileCopyUtils.copyToByteArray(cpr.getInputStream());
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
attr.getResponse().setHeader("content-disposition", "inline");
attr.getResponse().setHeader("Content-Length", String.valueOf(bytes.length));
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
IoUtil.copy(inputStream, attr.getResponse().getOutputStream());
}
} catch (Exception e) {
log.error(MinioPlusErrorCode.FILE_ICON_FAILED.getMessage(), e);
// 图标获取失败
throw new MinioPlusException(MinioPlusErrorCode.FILE_ICON_FAILED);
}
}
}

View File

@ -22,6 +22,8 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.liuxp</groupId> <groupId>me.liuxp</groupId>

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.liuxp.minioplus.common.config.MinioPlusAutoConfiguration

49
pom.xml
View File

@ -50,9 +50,13 @@
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<maven-source-plugin.version>3.0.1</maven-source-plugin.version> <maven-source-plugin.version>3.0.1</maven-source-plugin.version>
<revision>0.1.5</revision> <revision>0.1.5</revision>
<spring-boot.version>2.7.18</spring-boot.version> <spring-boot2.version>2.7.18</spring-boot2.version>
<spring-boot3.version>3.3.2</spring-boot3.version>
<spring-boot.version>${spring-boot2.version}</spring-boot.version>
<mybatisplus.version>3.5.7</mybatisplus.version> <mybatisplus.version>3.5.7</mybatisplus.version>
<mysql-connector-j.version>8.0.33</mysql-connector-j.version>
<lombok.version>1.18.32</lombok.version> <lombok.version>1.18.32</lombok.version>
<jakarta-servlet-api.version>6.0.0</jakarta-servlet-api.version>
<hutool.version>5.8.28</hutool.version> <hutool.version>5.8.28</hutool.version>
<knife4j.version>4.4.0</knife4j.version> <knife4j.version>4.4.0</knife4j.version>
<swagger.version>2.2.8</swagger.version> <swagger.version>2.2.8</swagger.version>
@ -63,24 +67,44 @@
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- spring-boot-dependencies --> <!-- mybatis-plus -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version> <version>${mybatisplus.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql-connector-j.version}</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>${jakarta-servlet-api.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>${lombok.version}</version> <version>${lombok.version}</version>
</dependency> </dependency>
<!--<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
</dependency>-->
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
@ -103,13 +127,6 @@
<artifactId>swagger-annotations</artifactId> <artifactId>swagger-annotations</artifactId>
<version>${swagger.version}</version> <version>${swagger.version}</version>
</dependency> </dependency>
<!-- mybatis -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatisplus.version}</version>
<scope>compile</scope>
</dependency>
<!-- minio --> <!-- minio -->
<dependency> <dependency>
<groupId>io.minio</groupId> <groupId>io.minio</groupId>