mirror of
https://gitee.com/lxp135/minio-plus.git
synced 2025-12-06 08:58:25 +08:00
initial spring-boot 3 supports
This commit is contained in:
parent
6e84322c79
commit
91f2a84105
7
.gitignore
vendored
7
.gitignore
vendored
@ -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
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前置拦截器
|
* 前置拦截器
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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,20 +19,23 @@ 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() {
|
||||||
|
|
||||||
List<FileMetadataInfoVo> fileList = storageService.list(new FileMetadataInfoDTO());
|
List<FileMetadataInfoVo> fileList = storageService.list(new FileMetadataInfoDTO());
|
||||||
|
|
||||||
for (FileMetadataInfoVo infoVo : fileList) {
|
for (FileMetadataInfoVo infoVo : fileList) {
|
||||||
log.info("文件清理,文件key="+infoVo.getFileKey());
|
log.info("文件清理,文件key=" + infoVo.getFileKey());
|
||||||
try{
|
try {
|
||||||
storageService.remove(infoVo.getFileKey());
|
storageService.remove(infoVo.getFileKey());
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
log.error(infoVo.getFileKey()+"文件清理失败",e);
|
log.error(infoVo.getFileKey() + "文件清理失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录用户拦截器
|
* 登录用户拦截器
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前置拦截器
|
* 前置拦截器
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -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 {
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
org.liuxp.minioplus.common.config.MinioPlusConfig
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
org.liuxp.minioplus.common.config.MinioPlusConfig
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传任务初始化
|
* 上传任务初始化
|
||||||
@ -365,7 +367,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
// 文件权限校验,元数据为空或者当前登录用户不是文件所有者时抛出异常
|
// 文件权限校验,元数据为空或者当前登录用户不是文件所有者时抛出异常
|
||||||
this.authentication(metadata, fileKey, userId);
|
this.authentication(metadata, fileKey, userId);
|
||||||
|
|
||||||
if(!StorageBucketEnums.IMAGE.getCode().equals(metadata.getStorageBucket())){
|
if (!StorageBucketEnums.IMAGE.getCode().equals(metadata.getStorageBucket())) {
|
||||||
// 不是图片时,返回文件类型
|
// 不是图片时,返回文件类型
|
||||||
return metadata.getFileSuffix();
|
return metadata.getFileSuffix();
|
||||||
}
|
}
|
||||||
@ -413,7 +415,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
|
|||||||
@Override
|
@Override
|
||||||
public Boolean createFile(FileMetadataInfoSaveDTO saveDTO, byte[] fileBytes) {
|
public Boolean createFile(FileMetadataInfoSaveDTO saveDTO, byte[] fileBytes) {
|
||||||
// 写入文件
|
// 写入文件
|
||||||
return createFile(saveDTO,new ByteArrayInputStream(fileBytes));
|
return createFile(saveDTO, new ByteArrayInputStream(fileBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -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();
|
||||||
|
|||||||
@ -26,15 +26,15 @@ 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
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class StorageServiceImpl implements StorageService {
|
public class StorageServiceImpl implements StorageService {
|
||||||
@ -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) {
|
||||||
@ -94,11 +97,11 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
public FileCheckResultVo init(String fileMd5, String fullFileName, long fileSize, Boolean isPrivate, String userId) {
|
public FileCheckResultVo init(String fileMd5, String fullFileName, long fileSize, Boolean isPrivate, String userId) {
|
||||||
|
|
||||||
// isPrivate 为空时,设置为 false
|
// 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()) {
|
for (FileCheckResultVo.Part part : resultVo.getPartList()) {
|
||||||
part.setUrl(remakeUrl(part.getUrl()));
|
part.setUrl(remakeUrl(part.getUrl()));
|
||||||
}
|
}
|
||||||
@ -109,9 +112,9 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompleteResultVo complete(String fileKey, List<String> partMd5List, String userId) {
|
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()) {
|
for (FileCheckResultVo.Part part : completeResultVo.getPartList()) {
|
||||||
part.setUrl(remakeUrl(part.getUrl()));
|
part.setUrl(remakeUrl(part.getUrl()));
|
||||||
}
|
}
|
||||||
@ -122,17 +125,17 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String download(String fileKey, String userId) {
|
public String download(String fileKey, String userId) {
|
||||||
return storageEngineService.download(fileKey,userId);
|
return storageEngineService.download(fileKey, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String image(String fileKey, String userId) {
|
public String image(String fileKey, String userId) {
|
||||||
return storageEngineService.image(fileKey,userId);
|
return storageEngineService.image(fileKey, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String preview(String fileKey, String userId) {
|
public String preview(String fileKey, String userId) {
|
||||||
return storageEngineService.preview(fileKey,userId);
|
return storageEngineService.preview(fileKey, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -154,7 +157,7 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
public FileMetadataInfoVo createFile(String fullFileName, Boolean isPrivate, String userId, byte[] fileBytes) {
|
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值的文件
|
// 查询MinIO中是否存在相同MD5值的文件
|
||||||
FileMetadataInfoDTO fileMetadataInfo = new FileMetadataInfoDTO();
|
FileMetadataInfoDTO fileMetadataInfo = new FileMetadataInfoDTO();
|
||||||
@ -163,9 +166,9 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
|
|
||||||
boolean sameMd5 = false;
|
boolean sameMd5 = false;
|
||||||
|
|
||||||
if(CollUtil.isNotEmpty(alreadyFileList)){
|
if (CollUtil.isNotEmpty(alreadyFileList)) {
|
||||||
for (FileMetadataInfoVo fileMetadataInfoVo : alreadyFileList) {
|
for (FileMetadataInfoVo fileMetadataInfoVo : alreadyFileList) {
|
||||||
if(Boolean.TRUE.equals(fileMetadataInfoVo.getIsFinished())){
|
if (Boolean.TRUE.equals(fileMetadataInfoVo.getIsFinished())) {
|
||||||
saveDTO.setStorageBucket(fileMetadataInfoVo.getStorageBucket());
|
saveDTO.setStorageBucket(fileMetadataInfoVo.getStorageBucket());
|
||||||
saveDTO.setStoragePath(fileMetadataInfoVo.getStoragePath());
|
saveDTO.setStoragePath(fileMetadataInfoVo.getStoragePath());
|
||||||
sameMd5 = true;
|
sameMd5 = true;
|
||||||
@ -174,7 +177,7 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!sameMd5){
|
if (!sameMd5) {
|
||||||
// 新文件时,执行写入逻辑
|
// 新文件时,执行写入逻辑
|
||||||
storageEngineService.createFile(saveDTO, fileBytes);
|
storageEngineService.createFile(saveDTO, fileBytes);
|
||||||
}
|
}
|
||||||
@ -185,7 +188,7 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileMetadataInfoVo createFile(String fullFileName, Boolean isPrivate, String userId, InputStream inputStream) {
|
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
|
@Override
|
||||||
@ -195,13 +198,13 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
// 获得输入流
|
// 获得输入流
|
||||||
InputStream inputStream = httpResponse.bodyStream();
|
InputStream inputStream = httpResponse.bodyStream();
|
||||||
// 调用处理函数
|
// 调用处理函数
|
||||||
return createFile(fullFileName, isPrivate, userId,inputStream);
|
return createFile(fullFileName, isPrivate, userId, inputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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值的文件
|
// 查询MinIO中是否存在相同MD5值的文件
|
||||||
FileMetadataInfoDTO fileMetadataInfo = new FileMetadataInfoDTO();
|
FileMetadataInfoDTO fileMetadataInfo = new FileMetadataInfoDTO();
|
||||||
@ -210,9 +213,9 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
|
|
||||||
boolean sameMd5 = false;
|
boolean sameMd5 = false;
|
||||||
|
|
||||||
if(CollUtil.isNotEmpty(alreadyFileList)){
|
if (CollUtil.isNotEmpty(alreadyFileList)) {
|
||||||
for (FileMetadataInfoVo fileMetadataInfoVo : alreadyFileList) {
|
for (FileMetadataInfoVo fileMetadataInfoVo : alreadyFileList) {
|
||||||
if(Boolean.TRUE.equals(fileMetadataInfoVo.getIsFinished())){
|
if (Boolean.TRUE.equals(fileMetadataInfoVo.getIsFinished())) {
|
||||||
saveDTO.setStorageBucket(fileMetadataInfoVo.getStorageBucket());
|
saveDTO.setStorageBucket(fileMetadataInfoVo.getStorageBucket());
|
||||||
saveDTO.setStoragePath(fileMetadataInfoVo.getStoragePath());
|
saveDTO.setStoragePath(fileMetadataInfoVo.getStoragePath());
|
||||||
sameMd5 = true;
|
sameMd5 = true;
|
||||||
@ -221,7 +224,7 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!sameMd5){
|
if (!sameMd5) {
|
||||||
// 新文件时,执行写入逻辑
|
// 新文件时,执行写入逻辑
|
||||||
storageEngineService.createFile(saveDTO, inputStream);
|
storageEngineService.createFile(saveDTO, inputStream);
|
||||||
}
|
}
|
||||||
@ -230,7 +233,7 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<FileMetadataInfoVo,byte[]> read(String fileKey) {
|
public Pair<FileMetadataInfoVo, byte[]> read(String fileKey) {
|
||||||
return storageEngineService.read(fileKey);
|
return storageEngineService.read(fileKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,18 +242,18 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
return storageEngineService.remove(fileKey);
|
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);
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_BYTES_FAILED);
|
||||||
}
|
}
|
||||||
// 计算文件MD5值
|
// 计算文件MD5值
|
||||||
String md5 = SecureUtil.md5().digestHex(fileBytes);
|
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
|
// 生成UUID作为文件KEY
|
||||||
String key = IdUtil.fastSimpleUUID();
|
String key = IdUtil.fastSimpleUUID();
|
||||||
@ -290,12 +293,13 @@ public class StorageServiceImpl implements StorageService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 重写文件地址
|
* 重写文件地址
|
||||||
|
*
|
||||||
* @param url 文件地址
|
* @param url 文件地址
|
||||||
* @return 重写后的文件地址
|
* @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.replace(properties.getBackend(), properties.getBrowserUrl());
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
org.liuxp.minioplus.core.service.impl.StorageServiceImpl,\
|
|
||||||
org.liuxp.minioplus.core.engine.impl.StorageEngineServiceImpl
|
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
#org.liuxp.minioplus.core.service.impl.StorageServiceImpl
|
||||||
|
#org.liuxp.minioplus.core.engine.impl.StorageEngineServiceImpl
|
||||||
@ -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>
|
||||||
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
@ -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>
|
||||||
@ -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,14 +38,17 @@ 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 CustomMinioClient getClient(){
|
public MinioS3ClientImpl(MinioPlusProperties properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
if(null==this.minioClient){
|
public CustomMinioClient getClient() {
|
||||||
|
|
||||||
|
if (null == this.minioClient) {
|
||||||
MinioAsyncClient client = MinioAsyncClient.builder()
|
MinioAsyncClient client = MinioAsyncClient.builder()
|
||||||
.endpoint(properties.getBackend())
|
.endpoint(properties.getBackend())
|
||||||
.credentials(properties.getKey(), properties.getSecret())
|
.credentials(properties.getKey(), properties.getSecret())
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,7 +101,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
|
|||||||
Part[] partArray = new Part[parts.size()];
|
Part[] partArray = new Part[parts.size()];
|
||||||
|
|
||||||
for (int i = 0; i < parts.size(); i++) {
|
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 {
|
try {
|
||||||
@ -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,14 +135,14 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
Map<String, String> queryParams = Maps.newHashMapWithExpectedSize(2);
|
||||||
queryParams.put(UPLOAD_ID, uploadId);
|
queryParams.put(UPLOAD_ID, uploadId);
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,7 +166,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
|
|||||||
@Override
|
@Override
|
||||||
public String getDownloadUrl(String fileName, String contentType, String bucketName, String objectName) {
|
public String getDownloadUrl(String fileName, String contentType, String bucketName, String objectName) {
|
||||||
Map<String, String> reqParams = new HashMap<>();
|
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);
|
reqParams.put("response-content-type", contentType);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -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,14 +200,14 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean putObject(String bucketName, String objectName, InputStream stream, long size, String contentType) {
|
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();
|
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()
|
this.getClient().putObject(PutObjectArgs.builder()
|
||||||
.bucket(bucketName)
|
.bucket(bucketName)
|
||||||
.object(objectName)
|
.object(objectName)
|
||||||
.stream(stream,size,0L)
|
.stream(stream, size, 0L)
|
||||||
.contentType(contentType)
|
.contentType(contentType)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
} catch (InsufficientDataException | InternalException | InvalidKeyException | IOException | NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) {
|
} catch (InsufficientDataException | InternalException | InvalidKeyException | IOException |
|
||||||
log.error(MinioPlusErrorCode.WRITE_FAILED.getMessage(),e);
|
NoSuchAlgorithmException | XmlParserException | ExecutionException | InterruptedException e) {
|
||||||
|
log.error(MinioPlusErrorCode.WRITE_FAILED.getMessage(), e);
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.WRITE_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.WRITE_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +241,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
|
|||||||
// 文件流转换为字节码
|
// 文件流转换为字节码
|
||||||
return IoUtil.readBytes(inputStream);
|
return IoUtil.readBytes(inputStream);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(MinioPlusErrorCode.READ_FAILED.getMessage(),e);
|
log.error(MinioPlusErrorCode.READ_FAILED.getMessage(), e);
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.READ_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.READ_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,7 +251,7 @@ public class MinioS3ClientImpl implements MinioS3Client {
|
|||||||
try {
|
try {
|
||||||
this.getClient().removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
|
this.getClient().removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(MinioPlusErrorCode.DELETE_FAILED.getMessage(),e);
|
log.error(MinioPlusErrorCode.DELETE_FAILED.getMessage(), e);
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.DELETE_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.DELETE_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
org.liuxp.minioplus.s3.official.MinioS3ClientImpl
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
org.liuxp.minioplus.s3.official.MinioS3ClientImpl
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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,50 +18,48 @@ 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")
|
public Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO) {
|
||||||
@ResponseBody
|
|
||||||
public Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO){
|
|
||||||
|
|
||||||
FilePreShardingVo resultVo = storageService.sharding(preShardingDTO.getFileSize());
|
FilePreShardingVo resultVo = storageService.sharding(preShardingDTO.getFileSize());
|
||||||
|
|
||||||
@ -73,51 +69,49 @@ 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();
|
||||||
|
|
||||||
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);
|
return Response.success(resultVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件上传完成
|
* 文件上传完成
|
||||||
* @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();
|
||||||
|
|
||||||
// 打印调试日志
|
// 打印调试日志
|
||||||
log.debug("合并文件开始fileKey="+fileKey+",partMd5List="+fileCompleteDTO.getPartMd5List());
|
log.debug("合并文件开始fileKey=" + fileKey + ",partMd5List=" + fileCompleteDTO.getPartMd5List());
|
||||||
CompleteResultVo completeResultVo = storageService.complete(fileKey,fileCompleteDTO.getPartMd5List(),userId);
|
CompleteResultVo completeResultVo = storageService.complete(fileKey, fileCompleteDTO.getPartMd5List(), userId);
|
||||||
|
|
||||||
return Response.success(completeResultVo);
|
return Response.success(completeResultVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件下载
|
* 文件下载
|
||||||
|
*
|
||||||
* @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,18 +140,18 @@ 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();
|
||||||
|
|
||||||
String url = storageService.preview(fileKey, userId);
|
String url = storageService.preview(fileKey, userId);
|
||||||
if(url.length()<10){
|
if (url.length() < 10) {
|
||||||
// 当返回值为文件类型时,取得图标
|
// 当返回值为文件类型时,取得图标
|
||||||
url = ICON_PATH + url;
|
url = ICON_PATH + url;
|
||||||
}
|
}
|
||||||
@ -168,30 +162,27 @@ 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);
|
||||||
|
|
||||||
ClassPathResource cpr = new ClassPathResource(storageBucket+".png");
|
ClassPathResource cpr = new ClassPathResource(storageBucket + ".png");
|
||||||
|
|
||||||
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);
|
||||||
// 图标获取失败
|
// 图标获取失败
|
||||||
throw new MinioPlusException(MinioPlusErrorCode.FILE_ICON_FAILED);
|
throw new MinioPlusException(MinioPlusErrorCode.FILE_ICON_FAILED);
|
||||||
}
|
}
|
||||||
@ -1,2 +0,0 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
org.liuxp.minioplus.common.config.MinioPlusAutoConfiguration
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
org.liuxp.minioplus.common.config.MinioPlusAutoConfiguration
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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>
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
org.liuxp.minioplus.common.config.MinioPlusAutoConfiguration
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
org.liuxp.minioplus.common.config.MinioPlusAutoConfiguration
|
||||||
49
pom.xml
49
pom.xml
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user