新增文件上传功能,支持阿里云、本地文件上传

This commit is contained in:
阿沐 2022-07-27 09:22:11 +08:00
parent 41da694227
commit fd1747c429
15 changed files with 424 additions and 2 deletions

18
fast-boot-api/pom.xml Normal file
View File

@ -0,0 +1,18 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>net.maku</groupId>
<artifactId>fast-boot</artifactId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fast-boot-api</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,67 @@
package net.maku.api.module.storage;
import org.springframework.util.StringUtils;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
/**
* 存储服务
*
* @author 阿沐 babamu@126.com
*/
public interface StorageService {
/**
* 文件路径
* @param prefix 前缀
* @param suffix 后缀
* @return 返回上传路径
*/
default String getPath(String prefix, String suffix) {
//生成uuid
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
//文件路径
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
String path = df.format(new Date()) + "/" + uuid;
if(StringUtils.hasText(prefix)){
path = prefix + "/" + path;
}
return path + "." + suffix;
}
/**
* 文件上传
* @param data 文件字节数组
* @param path 文件路径包含文件名
* @return 返回http地址
*/
String upload(byte[] data, String path);
/**
* 文件上传
* @param data 文件字节数组
* @param suffix 后缀
* @return 返回http地址
*/
String uploadSuffix(byte[] data, String suffix);
/**
* 文件上传
* @param inputStream 字节流
* @param path 文件路径包含文件名
* @return 返回http地址
*/
String upload(InputStream inputStream, String path);
/**
* 文件上传
* @param inputStream 字节流
* @param suffix 后缀
* @return 返回http地址
*/
String uploadSuffix(InputStream inputStream, String suffix);
}

View File

@ -15,6 +15,15 @@
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>net.maku</groupId>
<artifactId>fast-boot-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
</dependency>

View File

@ -0,0 +1,35 @@
package net.maku.storage.config;
import net.maku.storage.enums.StorageTypeEnum;
import net.maku.storage.properties.LocalStorageProperties;
import net.maku.storage.properties.StorageProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* 本地资源映射配置
*
* @author 阿沐 babamu@126.com
*/
@Configuration
@ConditionalOnProperty(prefix = "storage", value = "enabled")
public class LocalResourceConfiguration implements WebMvcConfigurer {
@Resource
private StorageProperties properties;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 如果不是本地存储则返回
if(properties.getConfig().getType() != StorageTypeEnum.LOCAL){
return;
}
LocalStorageProperties local = properties.getLocal();
registry.addResourceHandler("/" + local.getUrl() + "/**")
.addResourceLocations("file:" + local.getPath() + "/");
}
}

View File

@ -0,0 +1,34 @@
package net.maku.storage.config;
import net.maku.api.module.storage.StorageService;
import net.maku.storage.enums.StorageTypeEnum;
import net.maku.storage.properties.StorageProperties;
import net.maku.storage.service.AliyunStorageService;
import net.maku.storage.service.LocalStorageService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 存储配置文件
*
* @author 阿沐 babamu@126.com
*/
@Configuration
@EnableConfigurationProperties(StorageProperties.class)
@ConditionalOnProperty(prefix = "storage", value = "enabled")
public class StorageConfiguration {
@Bean
public StorageService storageService(StorageProperties properties){
if(properties.getConfig().getType() == StorageTypeEnum.LOCAL){
return new LocalStorageService(properties);
}else if(properties.getConfig().getType() == StorageTypeEnum.ALIYUN){
return new AliyunStorageService(properties);
}
return null;
}
}

View File

@ -0,0 +1,17 @@
package net.maku.storage.enums;
/**
* 存储类型枚举
*
* @author 阿沐 babamu@126.com
*/
public enum StorageTypeEnum {
/**
* 本地
*/
LOCAL,
/**
* 阿里云
*/
ALIYUN;
}

View File

@ -0,0 +1,16 @@
package net.maku.storage.properties;
import lombok.Data;
/**
* 阿里云存储配置项
*
* @author 阿沐 babamu@126.com
*/
@Data
public class AliyunStorageProperties {
private String endPoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}

View File

@ -0,0 +1,20 @@
package net.maku.storage.properties;
import lombok.Data;
/**
* 本地存储配置项
*
* @author 阿沐 babamu@126.com
*/
@Data
public class LocalStorageProperties {
/**
* 本地存储路径
*/
private String path;
/**
* 资源起始路径
*/
private String url = "upload";
}

View File

@ -0,0 +1,47 @@
package net.maku.storage.properties;
import lombok.Data;
import net.maku.storage.enums.StorageTypeEnum;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 存储配置项
*
* @author 阿沐 babamu@126.com
*/
@Data
@ConfigurationProperties(prefix = "storage")
public class StorageProperties {
/**
* 是否开启存储
*/
private boolean enabled;
/**
* 通用配置项
*/
private StorageConfig config;
/**
* 本地配置项
*/
private LocalStorageProperties local;
/**
* 阿里云配置项
*/
private AliyunStorageProperties aliyun;
@Data
public static class StorageConfig{
/**
* 访问域名
*/
private String domain;
/**
* 配置路径前缀
*/
private String prefix;
/**
* 存储类型
*/
private StorageTypeEnum type;
}
}

View File

@ -0,0 +1,55 @@
package net.maku.storage.service;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import net.maku.api.module.storage.StorageService;
import net.maku.framework.common.exception.FastException;
import net.maku.storage.properties.StorageProperties;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
/**
* 阿里云存储
*
* @author 阿沐 babamu@126.com
*/
public class AliyunStorageService implements StorageService {
private final StorageProperties properties;
public AliyunStorageService(StorageProperties properties) {
this.properties = properties;
}
@Override
public String upload(byte[] data, String path) {
return upload(new ByteArrayInputStream(data), path);
}
@Override
public String uploadSuffix(byte[] data, String suffix) {
return upload(data, getPath(properties.getConfig().getPrefix(), suffix));
}
@Override
public String upload(InputStream inputStream, String path) {
OSS client = new OSSClientBuilder().build(properties.getAliyun().getEndPoint(),
properties.getAliyun().getAccessKeyId(), properties.getAliyun().getAccessKeySecret());
try {
client.putObject(properties.getAliyun().getBucketName(), path, inputStream);
}catch (Exception e){
throw new FastException("上传文件失败:", e);
} finally {
if (client != null) {
client.shutdown();
}
}
return properties.getConfig().getDomain() + "/" + path;
}
@Override
public String uploadSuffix(InputStream inputStream, String suffix) {
return upload(inputStream, getPath(properties.getConfig().getPrefix(), suffix));
}
}

View File

@ -0,0 +1,60 @@
package net.maku.storage.service;
import net.maku.api.module.storage.StorageService;
import net.maku.framework.common.exception.FastException;
import net.maku.storage.properties.StorageProperties;
import org.springframework.util.FileCopyUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
/**
* 本地存储
*
* @author 阿沐 babamu@126.com
*/
public class LocalStorageService implements StorageService {
private final StorageProperties properties;
public LocalStorageService(StorageProperties properties) {
this.properties = properties;
}
@Override
public String upload(byte[] data, String path) {
return upload(new ByteArrayInputStream(data), path);
}
@Override
public String uploadSuffix(byte[] data, String suffix) {
return upload(data, getPath(properties.getConfig().getPrefix(), suffix));
}
@Override
public String upload(InputStream inputStream, String path) {
try {
File file = new File(properties.getLocal().getPath() + File.separator + path);
// 没有目录则自动创建目录
File parent = file.getParentFile();
if (parent != null && !parent.mkdirs() && !parent.isDirectory()) {
throw new IOException("Directory '" + parent + "' could not be created");
}
FileCopyUtils.copy(inputStream, Files.newOutputStream(file.toPath()));
} catch (Exception e) {
throw new FastException("上传文件失败:", e);
}
return properties.getConfig().getDomain() + "/" + properties.getLocal().getUrl() + "/" + path;
}
@Override
public String uploadSuffix(InputStream inputStream, String suffix) {
return upload(inputStream, getPath(properties.getConfig().getPrefix(), suffix));
}
}

View File

@ -8,4 +8,5 @@ auth:
- /swagger-ui.html
- /swagger-ui/**
- /doc.html
- /sys/oauth/captcha
- /sys/oauth/captcha
- /upload/**

View File

@ -21,6 +21,18 @@ spring:
max-file-size: 1024MB
max-request-size: 1024MB
storage:
enabled: true
config:
# 存储类型local、aliyun
type: local
# 访问域名
domain: http://localhost:8080
# 配置访问前缀
prefix:
local:
# 本地上传路径
path: D://upload
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml

View File

@ -0,0 +1,24 @@
package net.maku;
import cn.hutool.core.io.IoUtil;
import net.maku.api.module.storage.StorageService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.nio.file.Files;
@SpringBootTest
public class FileUploadTest {
@Autowired
private StorageService storageService;
@Test
public void uploadTest() throws Exception{
byte[] data = IoUtil.readBytes(Files.newInputStream(new File("D://upload//1.png").toPath()));
String url = storageService.uploadSuffix(data, "png");
System.out.println(url);
}
}

View File

@ -17,8 +17,9 @@
</parent>
<modules>
<module>fast-boot-system</module>
<module>fast-boot-new</module>
<module>fast-boot-system</module>
<module>fast-boot-api</module>
<module>fast-framework</module>
<module>fast-server</module>
</modules>
@ -34,6 +35,7 @@
<security.oauth2.version>2.3.8.RELEASE</security.oauth2.version>
<captcha.version>1.6.2</captcha.version>
<mapstruct.version>1.4.2.Final</mapstruct.version>
<aliyun.oss.version>3.8.0</aliyun.oss.version>
</properties>
<dependencies>
@ -103,6 +105,11 @@
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
</dependencies>
</dependencyManagement>