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)
.classpath
/docs/.vitepress/cache/
# IDEA
.idea/
# logs
**/logs
**/*.log

View File

@ -34,6 +34,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<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.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* SpringMVC配置
*
* @author contact@liuxp.me
* @since 2024/06/11
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private LoginUserInterceptor loginUserInterceptor;
private final LoginUserInterceptor loginUserInterceptor;
public WebMvcConfig(LoginUserInterceptor loginUserInterceptor) {
this.loginUserInterceptor = loginUserInterceptor;
}
/**
* 前置拦截器

View File

@ -29,6 +29,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<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.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* 定时任务演示工程定期清理文件
*
* @author contact@liuxp.me
* @since 2024/06/17
*/
@ -19,20 +19,23 @@ import java.util.List;
@Slf4j
public class CleanTask {
@Resource
private StorageService storageService;
private final StorageService storageService;
public CleanTask(StorageService storageService) {
this.storageService = storageService;
}
@Scheduled(cron = "0 0 */1 * * ?")
public void clean(){
public void clean() {
List<FileMetadataInfoVo> fileList = storageService.list(new FileMetadataInfoDTO());
for (FileMetadataInfoVo infoVo : fileList) {
log.info("文件清理文件key="+infoVo.getFileKey());
try{
log.info("文件清理文件key=" + infoVo.getFileKey());
try {
storageService.remove(infoVo.getFileKey());
}catch (Exception e){
log.error(infoVo.getFileKey()+"文件清理失败",e);
} catch (Exception e) {
log.error(infoVo.getFileKey() + "文件清理失败", e);
}
}
}

View File

@ -16,23 +16,12 @@
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springboot3.version>3.3.2</springboot3.version>
</properties>
<dependencies>
<dependency>
<groupId>me.liuxp</groupId>
<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>
<groupId>me.liuxp</groupId>
@ -46,35 +35,45 @@
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<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>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<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>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
</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>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot3.version}</version>
<version>${spring-boot3.version}</version>
<executions>
<execution>
<goals>

View File

@ -8,8 +8,8 @@ import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
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.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* SpringMVC配置
*
* @author contact@liuxp.me
* @since 2024/06/11
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private LoginUserInterceptor loginUserInterceptor;
private final LoginUserInterceptor loginUserInterceptor;
public WebMvcConfig(LoginUserInterceptor loginUserInterceptor) {
this.loginUserInterceptor = loginUserInterceptor;
}
/**
* 前置拦截器

View File

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

View File

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

View File

@ -5,6 +5,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* MinioPlus配置类
@ -14,6 +15,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
*/
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "minioplus")
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>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.liuxp</groupId>
<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.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
@ -44,14 +43,17 @@ import java.util.Optional;
@Slf4j
public class StorageEngineServiceImpl implements StorageEngineService {
@Resource
MetadataRepository metadataRepository;
private final MetadataRepository metadataRepository;
@Resource
MinioPlusProperties properties;
private final MinioPlusProperties properties;
@Resource
MinioS3Client minioS3Client;
private final MinioS3Client minioS3Client;
public StorageEngineServiceImpl(MetadataRepository metadataRepository, MinioPlusProperties properties, MinioS3Client minioS3Client) {
this.metadataRepository = metadataRepository;
this.properties = properties;
this.minioS3Client = minioS3Client;
}
/**
* 上传任务初始化
@ -365,7 +367,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
// 文件权限校验元数据为空或者当前登录用户不是文件所有者时抛出异常
this.authentication(metadata, fileKey, userId);
if(!StorageBucketEnums.IMAGE.getCode().equals(metadata.getStorageBucket())){
if (!StorageBucketEnums.IMAGE.getCode().equals(metadata.getStorageBucket())) {
// 不是图片时返回文件类型
return metadata.getFileSuffix();
}
@ -413,7 +415,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
@Override
public Boolean createFile(FileMetadataInfoSaveDTO saveDTO, byte[] fileBytes) {
// 写入文件
return createFile(saveDTO,new ByteArrayInputStream(fileBytes));
return createFile(saveDTO, new ByteArrayInputStream(fileBytes));
}
@Override
@ -538,6 +540,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
* @param fileSize 文件大小
* @return {@link Integer}
*/
@Override
public Integer computeChunkNum(Long fileSize) {
// 计算分块数量
double tempNum = (double) fileSize / properties.getPart().getSize();

View File

@ -26,15 +26,15 @@ import org.liuxp.minioplus.core.engine.StorageEngineService;
import org.liuxp.minioplus.core.repository.MetadataRepository;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* 存储组件Service层公共方法实现类
*
* @author contact@liuxp.me
* @since 2023/06/26
* @since 2023/06/26
*/
@Service
public class StorageServiceImpl implements StorageService {
@ -42,20 +42,23 @@ public class StorageServiceImpl implements StorageService {
/**
* 存储引擎Service接口定义
*/
@Resource
StorageEngineService storageEngineService;
private final StorageEngineService storageEngineService;
/**
* 文件元数据服务接口定义
*/
@Resource
MetadataRepository fileMetadataRepository;
private final MetadataRepository fileMetadataRepository;
/**
* MinioPlus配置信息注入类
*/
@Resource
MinioPlusProperties properties;
private final MinioPlusProperties properties;
public StorageServiceImpl(StorageEngineService storageEngineService, MetadataRepository fileMetadataRepository, MinioPlusProperties properties) {
this.storageEngineService = storageEngineService;
this.fileMetadataRepository = fileMetadataRepository;
this.properties = properties;
}
@Override
public FilePreShardingVo sharding(long fileSize) {
@ -94,11 +97,11 @@ public class StorageServiceImpl implements StorageService {
public FileCheckResultVo init(String fileMd5, String fullFileName, long fileSize, Boolean isPrivate, String userId) {
// isPrivate 为空时设置为 false
isPrivate = isPrivate!=null && isPrivate ;
isPrivate = isPrivate != null && isPrivate;
FileCheckResultVo resultVo = storageEngineService.init(fileMd5,fullFileName,fileSize,isPrivate,userId);
FileCheckResultVo resultVo = storageEngineService.init(fileMd5, fullFileName, fileSize, isPrivate, userId);
if(resultVo!=null){
if (resultVo != null) {
for (FileCheckResultVo.Part part : resultVo.getPartList()) {
part.setUrl(remakeUrl(part.getUrl()));
}
@ -109,9 +112,9 @@ public class StorageServiceImpl implements StorageService {
@Override
public CompleteResultVo complete(String fileKey, List<String> partMd5List, String userId) {
CompleteResultVo completeResultVo = storageEngineService.complete(fileKey,partMd5List,userId);
CompleteResultVo completeResultVo = storageEngineService.complete(fileKey, partMd5List, userId);
if(completeResultVo!=null){
if (completeResultVo != null) {
for (FileCheckResultVo.Part part : completeResultVo.getPartList()) {
part.setUrl(remakeUrl(part.getUrl()));
}
@ -122,17 +125,17 @@ public class StorageServiceImpl implements StorageService {
@Override
public String download(String fileKey, String userId) {
return storageEngineService.download(fileKey,userId);
return storageEngineService.download(fileKey, userId);
}
@Override
public String image(String fileKey, String userId) {
return storageEngineService.image(fileKey,userId);
return storageEngineService.image(fileKey, userId);
}
@Override
public String preview(String fileKey, String userId) {
return storageEngineService.preview(fileKey,userId);
return storageEngineService.preview(fileKey, userId);
}
@Override
@ -154,7 +157,7 @@ public class StorageServiceImpl implements StorageService {
public FileMetadataInfoVo createFile(String fullFileName, Boolean isPrivate, String userId, byte[] fileBytes) {
// 组装文件保存入参
FileMetadataInfoSaveDTO saveDTO = buildSaveDto(fullFileName, isPrivate, userId,fileBytes);
FileMetadataInfoSaveDTO saveDTO = buildSaveDto(fullFileName, isPrivate, userId, fileBytes);
// 查询MinIO中是否存在相同MD5值的文件
FileMetadataInfoDTO fileMetadataInfo = new FileMetadataInfoDTO();
@ -163,9 +166,9 @@ public class StorageServiceImpl implements StorageService {
boolean sameMd5 = false;
if(CollUtil.isNotEmpty(alreadyFileList)){
if (CollUtil.isNotEmpty(alreadyFileList)) {
for (FileMetadataInfoVo fileMetadataInfoVo : alreadyFileList) {
if(Boolean.TRUE.equals(fileMetadataInfoVo.getIsFinished())){
if (Boolean.TRUE.equals(fileMetadataInfoVo.getIsFinished())) {
saveDTO.setStorageBucket(fileMetadataInfoVo.getStorageBucket());
saveDTO.setStoragePath(fileMetadataInfoVo.getStoragePath());
sameMd5 = true;
@ -174,7 +177,7 @@ public class StorageServiceImpl implements StorageService {
}
}
if(!sameMd5){
if (!sameMd5) {
// 新文件时执行写入逻辑
storageEngineService.createFile(saveDTO, fileBytes);
}
@ -185,7 +188,7 @@ public class StorageServiceImpl implements StorageService {
@Override
public FileMetadataInfoVo createFile(String fullFileName, Boolean isPrivate, String userId, InputStream inputStream) {
return createFile(fullFileName, isPrivate, userId,IoUtil.readBytes(inputStream));
return createFile(fullFileName, isPrivate, userId, IoUtil.readBytes(inputStream));
}
@Override
@ -195,13 +198,13 @@ public class StorageServiceImpl implements StorageService {
// 获得输入流
InputStream inputStream = httpResponse.bodyStream();
// 调用处理函数
return createFile(fullFileName, isPrivate, userId,inputStream);
return createFile(fullFileName, isPrivate, userId, inputStream);
}
@Override
public FileMetadataInfoVo createBigFile(String fullFileName, String md5, long fileSize,Boolean isPrivate, String userId,InputStream inputStream) {
public FileMetadataInfoVo createBigFile(String fullFileName, String md5, long fileSize, Boolean isPrivate, String userId, InputStream inputStream) {
// 组装文件保存入参
FileMetadataInfoSaveDTO saveDTO = buildSaveDto(fullFileName,md5,fileSize, isPrivate, userId);
FileMetadataInfoSaveDTO saveDTO = buildSaveDto(fullFileName, md5, fileSize, isPrivate, userId);
// 查询MinIO中是否存在相同MD5值的文件
FileMetadataInfoDTO fileMetadataInfo = new FileMetadataInfoDTO();
@ -210,9 +213,9 @@ public class StorageServiceImpl implements StorageService {
boolean sameMd5 = false;
if(CollUtil.isNotEmpty(alreadyFileList)){
if (CollUtil.isNotEmpty(alreadyFileList)) {
for (FileMetadataInfoVo fileMetadataInfoVo : alreadyFileList) {
if(Boolean.TRUE.equals(fileMetadataInfoVo.getIsFinished())){
if (Boolean.TRUE.equals(fileMetadataInfoVo.getIsFinished())) {
saveDTO.setStorageBucket(fileMetadataInfoVo.getStorageBucket());
saveDTO.setStoragePath(fileMetadataInfoVo.getStoragePath());
sameMd5 = true;
@ -221,7 +224,7 @@ public class StorageServiceImpl implements StorageService {
}
}
if(!sameMd5){
if (!sameMd5) {
// 新文件时执行写入逻辑
storageEngineService.createFile(saveDTO, inputStream);
}
@ -230,7 +233,7 @@ public class StorageServiceImpl implements StorageService {
}
@Override
public Pair<FileMetadataInfoVo,byte[]> read(String fileKey) {
public Pair<FileMetadataInfoVo, byte[]> read(String fileKey) {
return storageEngineService.read(fileKey);
}
@ -239,18 +242,18 @@ public class StorageServiceImpl implements StorageService {
return storageEngineService.remove(fileKey);
}
FileMetadataInfoSaveDTO buildSaveDto(String fullFileName, Boolean isPrivate, String userId, byte[] fileBytes){
FileMetadataInfoSaveDTO buildSaveDto(String fullFileName, Boolean isPrivate, String userId, byte[] fileBytes) {
if(null==fileBytes){
if (null == fileBytes) {
throw new MinioPlusException(MinioPlusErrorCode.FILE_BYTES_FAILED);
}
// 计算文件MD5值
String md5 = SecureUtil.md5().digestHex(fileBytes);
return buildSaveDto(fullFileName,md5,fileBytes.length,isPrivate,userId);
return buildSaveDto(fullFileName, md5, fileBytes.length, isPrivate, userId);
}
FileMetadataInfoSaveDTO buildSaveDto(String fullFileName, String md5,long fileSize,Boolean isPrivate, String userId){
FileMetadataInfoSaveDTO buildSaveDto(String fullFileName, String md5, long fileSize, Boolean isPrivate, String userId) {
// 生成UUID作为文件KEY
String key = IdUtil.fastSimpleUUID();
@ -290,12 +293,13 @@ public class StorageServiceImpl implements StorageService {
/**
* 重写文件地址
*
* @param url 文件地址
* @return 重写后的文件地址
*/
private String remakeUrl(String url){
private String remakeUrl(String url) {
if(CharSequenceUtil.isNotBlank(properties.getBrowserUrl())){
if (CharSequenceUtil.isNotBlank(properties.getBrowserUrl())) {
return url.replace(properties.getBackend(), properties.getBrowserUrl());
}
return url;

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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!--<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>-->
</dependencies>
</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>
<artifactId>minio-plus-common</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -9,14 +9,12 @@ import io.minio.errors.XmlParserException;
import io.minio.http.Method;
import io.minio.messages.Part;
import lombok.extern.slf4j.Slf4j;
import org.liuxp.minioplus.common.config.MinioPlusProperties;
import org.liuxp.minioplus.common.enums.MinioPlusErrorCode;
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.MinioS3Client;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
@ -29,7 +27,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@Slf4j
@Repository
public class MinioS3ClientImpl implements MinioS3Client {
/**
@ -41,14 +38,17 @@ public class MinioS3ClientImpl implements MinioS3Client {
*/
private static final String PART_NUMBER = "partNumber";
@Resource
private MinioPlusProperties properties;
private final MinioPlusProperties properties;
private CustomMinioClient minioClient = null;
public CustomMinioClient getClient(){
public MinioS3ClientImpl(MinioPlusProperties properties) {
this.properties = properties;
}
if(null==this.minioClient){
public CustomMinioClient getClient() {
if (null == this.minioClient) {
MinioAsyncClient client = MinioAsyncClient.builder()
.endpoint(properties.getBackend())
.credentials(properties.getKey(), properties.getSecret())
@ -63,8 +63,9 @@ public class MinioS3ClientImpl implements MinioS3Client {
public Boolean bucketExists(String bucketName) {
try {
return this.getClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()).get();
} catch (InsufficientDataException | InternalException | InvalidKeyException | IOException | NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) {
log.error(MinioPlusErrorCode.BUCKET_EXISTS_FAILED.getMessage()+":{}", e.getMessage(), e);
} catch (InsufficientDataException | InternalException | InvalidKeyException | IOException |
NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) {
log.error("{}:{}", MinioPlusErrorCode.BUCKET_EXISTS_FAILED.getMessage(), e.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.BUCKET_EXISTS_FAILED);
}
}
@ -78,7 +79,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
this.getClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
} 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);
}
}
@ -89,7 +90,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
CreateMultipartUploadResponse createMultipartUploadResponse = this.getClient().createMultipartUpload(bucketName, null, objectName, null, null);
return createMultipartUploadResponse.result().uploadId();
} 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);
}
}
@ -100,7 +101,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
Part[] partArray = new Part[parts.size()];
for (int i = 0; i < parts.size(); i++) {
partArray[i] = new Part(parts.get(i).getPartNumber(),parts.get(i).getEtag());
partArray[i] = new Part(parts.get(i).getPartNumber(), parts.get(i).getEtag());
}
try {
@ -108,7 +109,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
, objectName, uploadId, partArray, null, null);
return objectWriteResponse != null;
} 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);
}
}
@ -134,14 +135,14 @@ public class MinioS3ClientImpl implements MinioS3Client {
} catch (Exception e) {
// 查询分片失败打印日志返回空的分片信息
log.error(MinioPlusErrorCode.LIST_PARTS_FAILED.getMessage()+":{}", e.getMessage());
log.error("{}:{}", MinioPlusErrorCode.LIST_PARTS_FAILED.getMessage(), e.getMessage());
}
return listParts;
}
@Override
public String getUploadObjectUrl(String bucketName, String objectName, String uploadId,String partNumber) {
public String getUploadObjectUrl(String bucketName, String objectName, String uploadId, String partNumber) {
Map<String, String> queryParams = Maps.newHashMapWithExpectedSize(2);
queryParams.put(UPLOAD_ID, uploadId);
@ -157,7 +158,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
.extraQueryParams(queryParams)
.build());
} 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);
}
}
@ -165,7 +166,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
@Override
public String getDownloadUrl(String fileName, String contentType, String bucketName, String objectName) {
Map<String, String> reqParams = new HashMap<>();
reqParams.put("response-content-disposition", "attachment;filename=\""+fileName+"\"");
reqParams.put("response-content-disposition", "attachment;filename=\"" + fileName + "\"");
reqParams.put("response-content-type", contentType);
try {
@ -178,7 +179,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
.extraQueryParams(reqParams)
.build());
} 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);
}
}
@ -199,14 +200,14 @@ public class MinioS3ClientImpl implements MinioS3Client {
.extraQueryParams(reqParams)
.build());
} 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);
}
}
@Override
public Boolean putObject(String bucketName, String objectName, InputStream stream, long size, String contentType) {
try{
try {
// 检查存储桶是否已经存在
boolean isExist = this.getClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()).get();
@ -220,12 +221,13 @@ public class MinioS3ClientImpl implements MinioS3Client {
this.getClient().putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(stream,size,0L)
.stream(stream, size, 0L)
.contentType(contentType)
.build());
} catch (InsufficientDataException | InternalException | InvalidKeyException | IOException | NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) {
log.error(MinioPlusErrorCode.WRITE_FAILED.getMessage(),e);
} catch (InsufficientDataException | InternalException | InvalidKeyException | IOException |
NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) {
log.error(MinioPlusErrorCode.WRITE_FAILED.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.WRITE_FAILED);
}
@ -239,7 +241,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
// 文件流转换为字节码
return IoUtil.readBytes(inputStream);
} catch (Exception e) {
log.error(MinioPlusErrorCode.READ_FAILED.getMessage(),e);
log.error(MinioPlusErrorCode.READ_FAILED.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.READ_FAILED);
}
}
@ -249,7 +251,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
try {
this.getClient().removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
} catch (Exception e) {
log.error(MinioPlusErrorCode.DELETE_FAILED.getMessage(),e);
log.error(MinioPlusErrorCode.DELETE_FAILED.getMessage(), e);
throw new MinioPlusException(MinioPlusErrorCode.DELETE_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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot2.version}</version>
</dependency>
<dependency>
<groupId>me.liuxp</groupId>

View File

@ -1,8 +1,6 @@
package org.liuxp.minioplus.extension.controller;
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 org.liuxp.minioplus.api.StorageService;
import org.liuxp.minioplus.api.model.vo.CompleteResultVo;
@ -20,50 +18,48 @@ 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.*;
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;
/**
* 对象存储标准接口定义
* 本类的方法是给前端使用的方法
*
* @author contact@liuxp.me
* @since 2024/6/18
*/
@Controller
@RequestMapping("/storage")
@Tag(name = "MinIO Plus 接口")
@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 ICON_PATH = "/storage/icon/";
/**
* 存储引擎Service接口定义
*/
@Resource
private StorageService storageService;
private final StorageService storageService;
public StorageController(StorageService storageService) {
this.storageService = storageService;
}
/**
* 文件预分片方法
* 在大文件上传时为了防止前端重复计算文件MD5值提供该方法
*
* @param preShardingDTO 文件预分片入参DTO
* @return 预分片结果
*/
@Operation(summary = "文件预分片")
@PostMapping("/upload/sharding")
@ResponseBody
public Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO){
@Override
public Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO) {
FilePreShardingVo resultVo = storageService.sharding(preShardingDTO.getFileSize());
@ -73,51 +69,49 @@ public class StorageController {
/**
* 上传任务初始化
* 上传前的预检查秒传分块上传和断点续传等特性均基于该方法实现
*
* @param fileCheckDTO 文件预检查入参
* @return 检查结果
*/
@Operation(summary = "上传任务初始化")
@PostMapping("/upload/init")
@ResponseBody
public Response<FileCheckResultVo> init(@RequestBody @Validated FileCheckDTO fileCheckDTO) {
@Override
public Response<FileCheckResultVo> init(FileCheckDTO fileCheckDTO) {
// 取得当前登录用户信息
String userId = UserHolder.get();
FileCheckResultVo resultVo = storageService.init(fileCheckDTO.getFileMd5(),fileCheckDTO.getFullFileName(),fileCheckDTO.getFileSize(),fileCheckDTO.getIsPrivate(),userId);
FileCheckResultVo resultVo = storageService.init(fileCheckDTO.getFileMd5(), fileCheckDTO.getFullFileName(), fileCheckDTO.getFileSize(), fileCheckDTO.getIsPrivate(), userId);
return Response.success(resultVo);
}
/**
* 文件上传完成
* @param fileKey 文件KEY
*
* @param fileKey 文件KEY
* @param fileCompleteDTO 文件完成入参DTO
* @return 是否成功
*/
@Operation(summary = "上传完成")
@PostMapping("/upload/complete/{fileKey}")
@ResponseBody
public Response<Object> complete(@PathVariable("fileKey") String fileKey, @RequestBody FileCompleteDTO fileCompleteDTO) {
@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);
log.debug("合并文件开始fileKey=" + fileKey + ",partMd5List=" + fileCompleteDTO.getPartMd5List());
CompleteResultVo completeResultVo = storageService.complete(fileKey, fileCompleteDTO.getPartMd5List(), userId);
return Response.success(completeResultVo);
}
/**
* 文件下载
*
* @param fileKey 文件KEY
* @return 文件下载地址
*/
@Operation(summary = "文件下载")
@GetMapping("/download/{fileKey}")
public String download(@PathVariable String fileKey) {
@Override
public String download(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
@ -128,12 +122,12 @@ public class StorageController {
/**
* 获取图像
*
* @param fileKey 文件KEY
* @return 原图地址
*/
@Operation(summary = "图片预览 - 原图")
@GetMapping("/image/{fileKey}")
public String previewOriginal(@PathVariable String fileKey) {
@Override
public String previewOriginal(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
@ -146,18 +140,18 @@ public class StorageController {
* 文件预览
* 当文件为图片时返回图片的缩略图
* 当文件不是图片时返回文件类型图标
*
* @param fileKey 文件KEY
* @return 缩略图地址
*/
@Operation(summary = "图片预览 - 缩略图")
@GetMapping("/preview/{fileKey}")
public String previewMedium(@PathVariable String fileKey) {
@Override
public String previewMedium(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
String url = storageService.preview(fileKey, userId);
if(url.length()<10){
if (url.length() < 10) {
// 当返回值为文件类型时取得图标
url = ICON_PATH + url;
}
@ -168,30 +162,27 @@ public class StorageController {
/**
* 根据文件类型取得图标
* @param response HttpServletResponse
*
* @param fileType 文件扩展名
*/
@Operation(summary = "获取图标")
@GetMapping("/icon/{fileType}")
public void icon(HttpServletResponse response,@PathVariable String fileType) {
@Override
public void icon(String fileType) {
try {
// 根据文件后缀取得桶
String storageBucket = StorageBucketEnums.getBucketByFileSuffix(fileType);
ClassPathResource cpr = new ClassPathResource(storageBucket+".png");
ClassPathResource cpr = new ClassPathResource(storageBucket + ".png");
byte[] bytes = FileCopyUtils.copyToByteArray(cpr.getInputStream());
response.setHeader("content-disposition", "inline");
response.setHeader("Content-Length", String.valueOf(bytes.length));
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
IoUtil.copy(inputStream, response.getOutputStream());
inputStream.close();
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);
log.error(MinioPlusErrorCode.FILE_ICON_FAILED.getMessage(), e);
// 图标获取失败
throw new MinioPlusException(MinioPlusErrorCode.FILE_ICON_FAILED);
}

View File

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

View File

@ -15,11 +15,21 @@
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<!--<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<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>
<groupId>me.liuxp</groupId>
<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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<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-source-plugin.version>3.0.1</maven-source-plugin.version>
<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>
<mysql-connector-j.version>8.0.33</mysql-connector-j.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>
<knife4j.version>4.4.0</knife4j.version>
<swagger.version>2.2.8</swagger.version>
@ -63,24 +67,44 @@
<dependencyManagement>
<dependencies>
<!-- spring-boot-dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version>
</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>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</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>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
@ -103,13 +127,6 @@
<artifactId>swagger-annotations</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatisplus.version}</version>
<scope>compile</scope>
</dependency>
<!-- minio -->
<dependency>
<groupId>io.minio</groupId>