Signed-off-by: chy <chy@163.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package top.lidee.taie.oss.config;
|
||||
|
||||
import top.lidee.taie.oss.ossbuilder.FileClientFactory;
|
||||
import top.lidee.taie.oss.ossbuilder.LideeOSSTemplate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
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;
|
||||
|
||||
/**
|
||||
* springboot自动装配类
|
||||
*
|
||||
* @author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(OSSProperties.class)
|
||||
@ConditionalOnProperty(name= "spring.lidee.subscribes.oss.enabled", havingValue="true")
|
||||
public class AutoConfiguration {
|
||||
private static Logger logger = LoggerFactory.getLogger(AutoConfiguration.class);
|
||||
|
||||
@Autowired
|
||||
private OSSProperties ossProperties;
|
||||
|
||||
public AutoConfiguration() {
|
||||
logger.info("spring lidee subscribes oss is actived");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public LideeOSSTemplate lideeOSSTemplate() throws Exception{
|
||||
FileClientFactory fileClientFactory = new FileClientFactory(ossProperties);
|
||||
return fileClientFactory.getObject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package top.lidee.taie.oss.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* AmazonS3配置项
|
||||
*
|
||||
* @author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
public class OSSAmazonS3Properties implements Serializable {
|
||||
|
||||
private String url;
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
private String bucketName;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getBucketName() {
|
||||
return bucketName;
|
||||
}
|
||||
|
||||
public void setBucketName(String bucketName) {
|
||||
this.bucketName = bucketName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package top.lidee.taie.oss.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 云储存 公共配置项
|
||||
* @author WongBin
|
||||
* @date 2023/8/24
|
||||
*/
|
||||
|
||||
public class OSSBaseProperties implements Serializable {
|
||||
private String type;
|
||||
private String url;
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
private String bucketName;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getBucketName() {
|
||||
return bucketName;
|
||||
}
|
||||
|
||||
public void setBucketName(String bucketName) {
|
||||
this.bucketName = bucketName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package top.lidee.taie.oss.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* minio配置项
|
||||
*
|
||||
* @author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
|
||||
public class OSSMinioProperties implements Serializable {
|
||||
|
||||
private String url;
|
||||
private int port=9000;
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
private String bucketName;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getBucketName() {
|
||||
return bucketName;
|
||||
}
|
||||
|
||||
public void setBucketName(String bucketName) {
|
||||
this.bucketName = bucketName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package top.lidee.taie.oss.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class OSSNFSProperties implements Serializable {
|
||||
|
||||
private String path = "/app/disk/upload";
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package top.lidee.taie.oss.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* oss组件配置项
|
||||
*
|
||||
* @author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.lidee.subscribes.oss")
|
||||
public class OSSProperties implements Serializable {
|
||||
|
||||
/** 默认激活oss组件 */
|
||||
private boolean enabled = true;
|
||||
|
||||
/** 允许上传的文件后缀,为空不限制,例如:.png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi */
|
||||
private String fileTypeWhiteList="";
|
||||
|
||||
/** 防盗链,允许访问的域名,为空不限制,例如:sili.anji-plus.com,www.anji-plus.com */
|
||||
private String refererWhiteList="";
|
||||
|
||||
/** minio组件配置项 */
|
||||
private OSSMinioProperties minio;
|
||||
|
||||
/** AmazonS3组件配置项 */
|
||||
private OSSAmazonS3Properties amazonS3;
|
||||
|
||||
/** 默认使用服务器本地文件夹,多节点时配合nfs */
|
||||
private OSSNFSProperties nfs;
|
||||
|
||||
private OSSBaseProperties huaweiObs;
|
||||
|
||||
public OSSBaseProperties getHuaweiObs() {
|
||||
return huaweiObs;
|
||||
}
|
||||
|
||||
public void setHuaweiObs(OSSBaseProperties huaweiObs) {
|
||||
this.huaweiObs = huaweiObs;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getFileTypeWhiteList() {
|
||||
return fileTypeWhiteList;
|
||||
}
|
||||
|
||||
public void setFileTypeWhiteList(String fileTypeWhiteList) {
|
||||
this.fileTypeWhiteList = fileTypeWhiteList;
|
||||
}
|
||||
|
||||
public String getRefererWhiteList() {
|
||||
return refererWhiteList;
|
||||
}
|
||||
|
||||
public void setRefererWhiteList(String refererWhiteList) {
|
||||
this.refererWhiteList = refererWhiteList;
|
||||
}
|
||||
|
||||
public OSSMinioProperties getMinio() {
|
||||
return minio;
|
||||
}
|
||||
|
||||
public void setMinio(OSSMinioProperties minio) {
|
||||
this.minio = minio;
|
||||
}
|
||||
|
||||
public OSSAmazonS3Properties getAmazonS3() {
|
||||
return amazonS3;
|
||||
}
|
||||
|
||||
public void setAmazonS3(OSSAmazonS3Properties amazonS3) {
|
||||
this.amazonS3 = amazonS3;
|
||||
}
|
||||
|
||||
public OSSNFSProperties getNfs() {
|
||||
return nfs;
|
||||
}
|
||||
|
||||
public void setNfs(OSSNFSProperties nfs) {
|
||||
this.nfs = nfs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package top.lidee.taie.oss.exceptions;
|
||||
|
||||
/**
|
||||
* OSS异常
|
||||
*/
|
||||
public class LideeOSSException extends RuntimeException{
|
||||
|
||||
public LideeOSSException(String message){
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LideeOSSException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
|
||||
public LideeOSSException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package top.lidee.taie.oss.exceptions;
|
||||
|
||||
public class LideeOSSExceptionBuilder {
|
||||
public LideeOSSExceptionBuilder() {
|
||||
}
|
||||
|
||||
public static LideeOSSException build(String code) {
|
||||
return new LideeOSSException(code);
|
||||
}
|
||||
|
||||
public static LideeOSSException build(Throwable throwable) {
|
||||
return new LideeOSSException(throwable);
|
||||
}
|
||||
|
||||
public static LideeOSSException build(String code, Throwable throwable) {
|
||||
return new LideeOSSException(code, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package top.lidee.taie.oss.exceptions;
|
||||
|
||||
public class LideeOSSTypeLimitedException extends LideeOSSException {
|
||||
|
||||
public LideeOSSTypeLimitedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LideeOSSTypeLimitedException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
|
||||
public LideeOSSTypeLimitedException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package top.lidee.taie.oss.exceptions;
|
||||
|
||||
public class LideeOSSTypeLimitedExceptionBuilder {
|
||||
public LideeOSSTypeLimitedExceptionBuilder() {
|
||||
}
|
||||
|
||||
public static LideeOSSTypeLimitedException build(String code) {
|
||||
return new LideeOSSTypeLimitedException(code);
|
||||
}
|
||||
|
||||
public static LideeOSSTypeLimitedException build(Throwable throwable) {
|
||||
return new LideeOSSTypeLimitedException(throwable);
|
||||
}
|
||||
|
||||
public static LideeOSSTypeLimitedException build(String code, Throwable throwable) {
|
||||
return new LideeOSSTypeLimitedException(code, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package top.lidee.taie.oss.ossbuilder;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import top.lidee.taie.oss.config.OSSAmazonS3Properties;
|
||||
import top.lidee.taie.oss.config.OSSMinioProperties;
|
||||
import top.lidee.taie.oss.config.OSSProperties;
|
||||
import top.lidee.taie.oss.ossbuilder.builders.AmazonS3Client;
|
||||
import top.lidee.taie.oss.ossbuilder.builders.HuaweiOBSClient;
|
||||
import top.lidee.taie.oss.ossbuilder.builders.NFSClient;
|
||||
import top.lidee.taie.oss.ossbuilder.builders.MinioClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 文件存储客户端工厂
|
||||
*
|
||||
* @Author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
public class FileClientFactory implements FactoryBean<LideeOSSTemplate> {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(FileClientFactory.class);
|
||||
|
||||
private LideeOSSTemplate lideeOSSTemplate;
|
||||
|
||||
private OSSProperties ossProperties;
|
||||
|
||||
public FileClientFactory(OSSProperties ossProperties){
|
||||
this.ossProperties = ossProperties;
|
||||
this.initFileClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LideeOSSTemplate getObject() throws Exception {
|
||||
return lideeOSSTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return LideeOSSTemplate.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return FactoryBean.super.isSingleton();
|
||||
}
|
||||
|
||||
/** 初始化文件存储,顺序如下:
|
||||
* 1.优先判断minio相关配置是否设置,如果有使用minio
|
||||
* 2.优先判断minio相关配置是否设置,如果有使用minio
|
||||
* 3.默认,以上没有启用时,使用本地存储代替
|
||||
*/
|
||||
protected void initFileClient(){
|
||||
// 如果minio配置项存在时,使用minio文件存储
|
||||
OSSMinioProperties minio = this.ossProperties.getMinio();
|
||||
if(minio != null && !StringUtils.isEmpty(minio.getUrl())){
|
||||
this.lideeOSSTemplate = new MinioClient(this.ossProperties);
|
||||
return;
|
||||
}
|
||||
// 如果AmazonS3配置项存在时,使用AmazonS3服务器
|
||||
OSSAmazonS3Properties amazonS3 = this.ossProperties.getAmazonS3();
|
||||
if(amazonS3 != null && !StringUtils.isEmpty(amazonS3.getUrl())){
|
||||
this.lideeOSSTemplate = new AmazonS3Client(this.ossProperties);
|
||||
return;
|
||||
}
|
||||
if(Objects.nonNull(ossProperties.getHuaweiObs()) && !StringUtils.isEmpty(
|
||||
ossProperties.getHuaweiObs().getUrl())){
|
||||
this.lideeOSSTemplate = new HuaweiOBSClient(ossProperties);
|
||||
return;
|
||||
}
|
||||
// 如果minio和AmazonS3配置项不存在时,使用本地存储,
|
||||
this.lideeOSSTemplate = new NFSClient(this.ossProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package top.lidee.taie.oss.ossbuilder;
|
||||
|
||||
import top.lidee.taie.oss.config.OSSProperties;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSException;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSTypeLimitedExceptionBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* OSS标准调用接口
|
||||
* @Author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
public interface LideeOSSTemplate {
|
||||
|
||||
final static Logger logger = LoggerFactory.getLogger(LideeOSSTemplate.class);
|
||||
|
||||
default void init(OSSProperties config){
|
||||
|
||||
}
|
||||
default void close(){
|
||||
|
||||
}
|
||||
|
||||
/**文件后缀白名单
|
||||
* @return
|
||||
*/
|
||||
String getFileTypeWhiteList();
|
||||
|
||||
/**
|
||||
* 将字符串切割成list,支持|或者,分割线
|
||||
* @param listStr
|
||||
* @return
|
||||
*/
|
||||
default List<String> splitToList(String listStr){
|
||||
List<String> list = new ArrayList<>();
|
||||
if(StringUtils.isEmpty(listStr)){
|
||||
return list;
|
||||
}
|
||||
if(listStr.contains("|")){
|
||||
list = Arrays.asList(listStr.split("\\|"));
|
||||
}
|
||||
if(listStr.contains(",")){
|
||||
list = Arrays.asList(listStr.split(","));
|
||||
}
|
||||
List<String> upperList = new ArrayList<>();
|
||||
upperList.addAll(list.stream().map(String::toUpperCase).collect(Collectors.toList()));
|
||||
return upperList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传文件的文件后缀
|
||||
* @param file
|
||||
* @return .png
|
||||
*/
|
||||
default String getSuffixName(MultipartFile file){
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
if(StringUtils.isEmpty(originalFilename) || !originalFilename.contains(".")){
|
||||
throw new LideeOSSException("original file name or type is empty");
|
||||
}
|
||||
//文件后缀名
|
||||
String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||||
return suffixName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件的后缀名是否在白名单中,存在返回true
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
default boolean isAllowedFileSuffixName(MultipartFile file){
|
||||
String sufixwhiteListStr = getFileTypeWhiteList();
|
||||
if(sufixwhiteListStr == null){
|
||||
return true;
|
||||
}
|
||||
sufixwhiteListStr = sufixwhiteListStr.trim();
|
||||
if(StringUtils.isEmpty(sufixwhiteListStr)){
|
||||
return true;
|
||||
}
|
||||
String suffixName = getSuffixName(file).toUpperCase();
|
||||
// 文件后缀白名单校验(不区分大小写)
|
||||
List<String> sufixwhiteList = splitToList(sufixwhiteListStr);
|
||||
return sufixwhiteList.contains(suffixName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件后缀名是否在白名单中,如果不在报异常,中止文件保存
|
||||
* @param file
|
||||
*/
|
||||
default void checkFileSuffixName(MultipartFile file){
|
||||
// 是否是允许的文件后缀
|
||||
boolean allowedFileSuffix = isAllowedFileSuffixName(file);
|
||||
if(allowedFileSuffix == false){
|
||||
logger.warn("file {} type is not in allow list {}", file.getOriginalFilename(), getFileTypeWhiteList());
|
||||
throw LideeOSSTypeLimitedExceptionBuilder.build("file type is not in allow list");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入参数为前端文件上传对象MultipartFile
|
||||
* 返回的是新文件名,下载删除需要
|
||||
* @param file
|
||||
* @return 文件名,1c6bf10daa0e43ac8da32c96fc30dae7.png
|
||||
*/
|
||||
default String uploadFileByInputStream(MultipartFile file) throws LideeOSSException {
|
||||
checkFileSuffixName(file);//判断文件后缀名是否在白名单中,如果不在报异常,中止文件保存
|
||||
|
||||
String suffixName = getSuffixName(file);
|
||||
String fileId = UUID.randomUUID().toString();
|
||||
fileId = fileId.replaceAll("-","");
|
||||
String fileObjectName = fileId + suffixName;
|
||||
return uploadFileByInputStream(file, fileObjectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入参数为前端文件上传对象MultipartFile
|
||||
* 返回的是objectName 作为下载文件的依据,客服端需要存储
|
||||
*
|
||||
* @param file
|
||||
* @param fileObjectName 上传原始文件名 OrderExcel20220322.xls
|
||||
* @return 上传原始文件名 OrderExcel20220322.xls
|
||||
*/
|
||||
String uploadFileByInputStream(MultipartFile file, String fileObjectName) throws LideeOSSException;
|
||||
|
||||
/**
|
||||
* 根据fileObjectName下载文件流
|
||||
*
|
||||
* @param fileObjectName 402b6193-e70e-40a9-bf5b-73a78ea1e8ab.png
|
||||
* @return
|
||||
*/
|
||||
byte[] downloadFile(String fileObjectName) throws LideeOSSException;
|
||||
|
||||
/**
|
||||
* 根据fileObjectName删除
|
||||
*
|
||||
* @param fileObjectName 402b6193-e70e-40a9-bf5b-73a78ea1e8ab.png
|
||||
* @return
|
||||
*/
|
||||
void deleteFile(String fileObjectName);
|
||||
void deleteFiles(List<String> fileObjectNames);
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package top.lidee.taie.oss.ossbuilder.builders;
|
||||
|
||||
import com.amazonaws.ClientConfiguration;
|
||||
import com.amazonaws.Protocol;
|
||||
import com.amazonaws.auth.AWSCredentials;
|
||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||
import com.amazonaws.auth.BasicAWSCredentials;
|
||||
import com.amazonaws.client.builder.AwsClientBuilder;
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
||||
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
|
||||
import com.amazonaws.services.s3.model.GetObjectRequest;
|
||||
import com.amazonaws.services.s3.model.ObjectMetadata;
|
||||
import com.amazonaws.services.s3.model.S3Object;
|
||||
import top.lidee.taie.oss.config.OSSProperties;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSException;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSExceptionBuilder;
|
||||
import top.lidee.taie.oss.ossbuilder.LideeOSSTemplate;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 文件存储 使用AmazonS3服务器
|
||||
*
|
||||
* 接口文档 https://docs.aws.amazon.com/zh_cn/sdk-for-java/v1/developer-guide/examples-s3.html
|
||||
* 代码参考 https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/java/example_code/s3/src/main/java/aws/example/s3
|
||||
*
|
||||
* @Author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
public class AmazonS3Client implements LideeOSSTemplate {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(AmazonS3Client.class);
|
||||
|
||||
private AmazonS3 amazonS3;
|
||||
|
||||
// 存储桶名称
|
||||
private String bucketName;
|
||||
// 允许的文件后缀 白名单
|
||||
private String fileTypeWhiteList;
|
||||
|
||||
@Override
|
||||
public String getFileTypeWhiteList() {
|
||||
return fileTypeWhiteList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(amazonS3!=null){
|
||||
amazonS3.shutdown();
|
||||
logger.info("shutdown-oss-client");
|
||||
}
|
||||
}
|
||||
|
||||
public AmazonS3Client(OSSProperties ossProperties){
|
||||
this.fileTypeWhiteList = ossProperties.getFileTypeWhiteList();
|
||||
String url = ossProperties.getAmazonS3().getUrl();
|
||||
String accessKey = ossProperties.getAmazonS3().getAccessKey();
|
||||
String secretKey = ossProperties.getAmazonS3().getSecretKey();
|
||||
this.bucketName = ossProperties.getAmazonS3().getBucketName();
|
||||
try{
|
||||
AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
|
||||
ClientConfiguration clientConfig = new ClientConfiguration();
|
||||
clientConfig.setProtocol(Protocol.HTTP);
|
||||
clientConfig.setSignerOverride("S3SignerType");
|
||||
|
||||
AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard()
|
||||
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
|
||||
.withClientConfiguration(clientConfig)
|
||||
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(url, "cn-north-1"));
|
||||
this.amazonS3 = builder.build();
|
||||
|
||||
// 如存储桶不存在,创建之。
|
||||
boolean found = this.amazonS3.doesBucketExistV2(this.bucketName);
|
||||
if (!found) {
|
||||
this.amazonS3.createBucket(this.bucketName);
|
||||
}
|
||||
logger.info("初始化文件存储,激活AmazonS3存储桶:{}", this.bucketName);
|
||||
}catch (Exception e){
|
||||
logger.error("初始化文件存储,激活AmazonS3存储桶:{}失败:{}" ,this.bucketName, e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String uploadFileByInputStream(MultipartFile file, String fileObjectName) throws LideeOSSException {
|
||||
//判断文件后缀名是否在白名单中,如果不在报异常,中止文件保存
|
||||
checkFileSuffixName(file);
|
||||
|
||||
InputStream fileInputStream = null;
|
||||
try {
|
||||
fileInputStream = file.getInputStream();
|
||||
|
||||
ObjectMetadata metadata = new ObjectMetadata();
|
||||
metadata.setContentType("plain/text");
|
||||
metadata.addUserMetadata("title", "someTitle");
|
||||
this.amazonS3.putObject(this.bucketName, fileObjectName, fileInputStream, metadata);
|
||||
} catch (Exception e) {
|
||||
logger.error("save file to AmazonS3 store error:", e);
|
||||
throw LideeOSSExceptionBuilder.build("save file to AmazonS3 store error", e);
|
||||
} finally {
|
||||
try {
|
||||
if (fileInputStream != null) {
|
||||
fileInputStream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("close InputStream error:", e);
|
||||
}
|
||||
}
|
||||
return fileObjectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] downloadFile(String fileObjectName) throws LideeOSSException {
|
||||
byte[] fileBytes = null;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
S3Object object = this.amazonS3.getObject(new GetObjectRequest(this.bucketName, fileObjectName));
|
||||
inputStream = object.getObjectContent();
|
||||
if (inputStream == null) {
|
||||
logger.error("file {} not exist in AmazonS3 store ", fileObjectName);
|
||||
throw LideeOSSExceptionBuilder.build("file not exist in AmazonS3 store, objectName="+ fileObjectName);
|
||||
}
|
||||
fileBytes = IOUtils.toByteArray(inputStream);
|
||||
} catch (Exception e) {
|
||||
logger.error("read file from minio store error:", e);
|
||||
throw LideeOSSExceptionBuilder.build("read file from AmazonS3 store error, objectName="+ fileObjectName);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return fileBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFile(String fileObjectName) {
|
||||
try{
|
||||
this.amazonS3.deleteObject(this.bucketName, fileObjectName);
|
||||
}catch (Exception e){
|
||||
logger.warn("delete file in AmazonS3 store fail, bucket={}, file={}", this.bucketName, fileObjectName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFiles(List<String> fileObjectNames) {
|
||||
try{
|
||||
if(CollectionUtils.isEmpty(fileObjectNames)){
|
||||
return;
|
||||
}
|
||||
List<DeleteObjectsRequest.KeyVersion> keys = fileObjectNames.stream().map(fileObject -> new DeleteObjectsRequest.KeyVersion(fileObject)).collect(Collectors.toList());
|
||||
DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(this.bucketName).withKeys(keys);
|
||||
this.amazonS3.deleteObjects(deleteObjectsRequest);
|
||||
}catch (Exception e){
|
||||
logger.warn("delete file in AmazonS3 store fail, bucket={}, file={}", this.bucketName, fileObjectNames.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package top.lidee.taie.oss.ossbuilder.builders;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import top.lidee.taie.oss.config.OSSProperties;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSException;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSExceptionBuilder;
|
||||
import top.lidee.taie.oss.ossbuilder.LideeOSSTemplate;
|
||||
import com.obs.services.ObsClient;
|
||||
import com.obs.services.model.ObsObject;
|
||||
|
||||
/**
|
||||
* https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0603.html
|
||||
*
|
||||
* @author WongBin
|
||||
* @date 2023/8/24
|
||||
*/
|
||||
public class HuaweiOBSClient implements LideeOSSTemplate {
|
||||
// 存储桶名称
|
||||
private String bucketName;
|
||||
// 允许的文件后缀 白名单
|
||||
private String fileTypeWhiteList;
|
||||
private ObsClient ossClient;
|
||||
|
||||
public HuaweiOBSClient(OSSProperties properties) {
|
||||
this.init(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(OSSProperties config) {
|
||||
// Endpoint以北京四为例,其他地区请按实际情况填写。
|
||||
/*String endPoint = "https://obs.cn-north-4.myhuaweicloud.com";
|
||||
String ak = "*** Provide your Access Key ***";
|
||||
String sk = "*** Provide your Secret Key ***";*/
|
||||
// 创建ObsClient实例
|
||||
ossClient = new ObsClient(config.getHuaweiObs().getAccessKey(),
|
||||
config.getHuaweiObs().getSecretKey(), config.getHuaweiObs().getUrl());
|
||||
this.bucketName = config.getHuaweiObs().getBucketName();
|
||||
this.fileTypeWhiteList = config.getFileTypeWhiteList();
|
||||
|
||||
// localfile2 为待上传的本地文件路径,需要指定到具体的文件名
|
||||
/*PutObjectRequest request = new PutObjectRequest();
|
||||
request.setBucketName("bucketname");
|
||||
request.setObjectKey("objectkey2");
|
||||
request.setFile(new File("localfile2"));
|
||||
obsClient.putObject(request);*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(ossClient!=null){
|
||||
try {
|
||||
ossClient.close();
|
||||
}catch (Exception ex){
|
||||
logger.error("close-client-err:{}",ex);
|
||||
}
|
||||
logger.info("shutdown-oss-client");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileTypeWhiteList() {
|
||||
return fileTypeWhiteList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传,输入参数为InputStream
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String uploadFileByInputStream(MultipartFile file, String fileObjectName)
|
||||
throws LideeOSSException {
|
||||
//判断文件后缀名是否在白名单中,如果不在报异常,中止文件保存
|
||||
checkFileSuffixName(file);
|
||||
InputStream fileInputStream = null;
|
||||
try {
|
||||
ossClient.putObject(this.bucketName, fileObjectName, file.getInputStream());
|
||||
} catch (Exception e) {
|
||||
logger.error("save file error:", e);
|
||||
throw LideeOSSExceptionBuilder.build("save file error", e);
|
||||
} finally {
|
||||
try {
|
||||
if (fileInputStream != null) {
|
||||
fileInputStream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("close InputStream error:", e);
|
||||
}
|
||||
}
|
||||
return fileObjectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据fileUUid下载文件
|
||||
*
|
||||
* @param fileObjectName
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public byte[] downloadFile(String fileObjectName) throws LideeOSSException {
|
||||
byte[] fileBytes = null;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
ObsObject obsObject = ossClient.getObject(this.bucketName, fileObjectName);
|
||||
if (obsObject == null) {
|
||||
logger.error("file {} not exist in minio store ", fileObjectName);
|
||||
throw LideeOSSExceptionBuilder.build("file not exist,objectName="+ fileObjectName);
|
||||
}
|
||||
inputStream = obsObject.getObjectContent();
|
||||
fileBytes = IOUtils.toByteArray(inputStream);
|
||||
} catch (Exception e) {
|
||||
logger.error("read file error:", e);
|
||||
throw LideeOSSExceptionBuilder.build("read file error, objectName="+ fileObjectName);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return fileBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFile(String fileObjectName) {
|
||||
try{
|
||||
ossClient.deleteObject(this.bucketName, fileObjectName);
|
||||
}catch (Exception e){
|
||||
logger.warn("delete file fail, bucket={}, file={}", this.bucketName, fileObjectName);
|
||||
}
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0804.html
|
||||
@Override
|
||||
public void deleteFiles(List<String> fileObjectNames) {
|
||||
if(CollectionUtils.isEmpty(fileObjectNames)){
|
||||
return;
|
||||
}
|
||||
fileObjectNames.stream().forEach(this::deleteFile);
|
||||
/*try{
|
||||
|
||||
//ossClient.deleteObjects(this.bucketName, fileObjectNames);
|
||||
ListVersionsRequest request = new ListVersionsRequest(bucketName);
|
||||
// 每次批量删除100个对象
|
||||
request.setMaxKeys(100);
|
||||
//request.set
|
||||
ListVersionsResult result;
|
||||
do {
|
||||
result = ossClient.listVersions(request);
|
||||
|
||||
DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(bucketName);
|
||||
deleteRequest.setQuiet(true); // 注意此demo默认是详细模式,如果要使用简单模式,请添加本行代码
|
||||
for(VersionOrDeleteMarker v : result.getVersions()) {
|
||||
deleteRequest.addKeyAndVersion(v.getKey(), v.getVersionId());
|
||||
}
|
||||
|
||||
DeleteObjectsResult deleteResult = ossClient.deleteObjects(deleteRequest);
|
||||
// 获取删除成功的对象
|
||||
logger.info("deleted-obj:{}",deleteResult.getDeletedObjectResults());
|
||||
// 获取删除失败的对象
|
||||
logger.info("delete-err-obj:{}",deleteResult.getErrorResults());
|
||||
|
||||
request.setKeyMarker(result.getNextKeyMarker());
|
||||
// 如果没有开启多版本对象,就不需要设置VersionIdMarker
|
||||
request.setVersionIdMarker(result.getNextVersionIdMarker());
|
||||
}while(result.isTruncated());
|
||||
}catch (Exception e){
|
||||
logger.warn("delete file fail, bucket={}, file={}", this.bucketName, fileObjectNames.toString());
|
||||
}*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package top.lidee.taie.oss.ossbuilder.builders;
|
||||
|
||||
import top.lidee.taie.oss.config.OSSProperties;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSException;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSExceptionBuilder;
|
||||
import top.lidee.taie.oss.ossbuilder.LideeOSSTemplate;
|
||||
import io.minio.PutObjectOptions;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件存储 使用minio服务器
|
||||
*
|
||||
* @Author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
public class MinioClient implements LideeOSSTemplate {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(MinioClient.class);
|
||||
|
||||
private io.minio.MinioClient minioClient;
|
||||
|
||||
// 存储桶名称
|
||||
private String bucketName;
|
||||
// 允许的文件后缀 白名单
|
||||
private String fileTypeWhiteList;
|
||||
|
||||
@Override
|
||||
public String getFileTypeWhiteList() {
|
||||
return fileTypeWhiteList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(minioClient!=null){
|
||||
logger.info("shutdown-oss-client");
|
||||
}
|
||||
}
|
||||
|
||||
public MinioClient(OSSProperties ossProperties){
|
||||
this.fileTypeWhiteList = ossProperties.getFileTypeWhiteList();
|
||||
String url = ossProperties.getMinio().getUrl();
|
||||
int port = ossProperties.getMinio().getPort();
|
||||
String accessKey = ossProperties.getMinio().getAccessKey();
|
||||
String secretKey = ossProperties.getMinio().getSecretKey();
|
||||
this.bucketName = ossProperties.getMinio().getBucketName();
|
||||
try{
|
||||
this.minioClient = new io.minio.MinioClient(url, port, accessKey, secretKey);
|
||||
// 如存储桶不存在,创建之。
|
||||
boolean found = minioClient.bucketExists(this.bucketName);
|
||||
if (!found) {
|
||||
minioClient.makeBucket(this.bucketName);
|
||||
}
|
||||
logger.info("初始化文件存储,激活Minio分布式存储桶:{}", this.bucketName);
|
||||
}catch (Exception e){
|
||||
logger.error("初始化文件存储,激活Minio存储桶:{}失败:{}" ,this.bucketName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传,输入参数为InputStream
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String uploadFileByInputStream(MultipartFile file, String fileObjectName) throws LideeOSSException {
|
||||
//判断文件后缀名是否在白名单中,如果不在报异常,中止文件保存
|
||||
checkFileSuffixName(file);
|
||||
|
||||
InputStream fileInputStream = null;
|
||||
try {
|
||||
fileInputStream = file.getInputStream();
|
||||
PutObjectOptions options = new PutObjectOptions(fileInputStream.available(), -1);
|
||||
options.setContentType("application/octet-stream");
|
||||
minioClient.putObject(this.bucketName, fileObjectName, fileInputStream, options);
|
||||
} catch (Exception e) {
|
||||
logger.error("save file to minio store error:", e);
|
||||
throw LideeOSSExceptionBuilder.build("save file to minio store error", e);
|
||||
} finally {
|
||||
try {
|
||||
if (fileInputStream != null) {
|
||||
fileInputStream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("close InputStream error:", e);
|
||||
}
|
||||
}
|
||||
return fileObjectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据fileUUid下载文件
|
||||
*
|
||||
* @param fileObjectName
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public byte[] downloadFile(String fileObjectName) throws LideeOSSException {
|
||||
byte[] fileBytes = null;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = minioClient.getObject(this.bucketName, fileObjectName);
|
||||
if (inputStream == null) {
|
||||
logger.error("file {} not exist in minio store ", fileObjectName);
|
||||
throw LideeOSSExceptionBuilder.build("file not exist in minio store, objectName="+ fileObjectName);
|
||||
}
|
||||
fileBytes = IOUtils.toByteArray(inputStream);
|
||||
} catch (Exception e) {
|
||||
logger.error("read file from minio store error:", e);
|
||||
throw LideeOSSExceptionBuilder.build("read file from minio store error, objectName="+ fileObjectName);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return fileBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFile(String fileObjectName) {
|
||||
try{
|
||||
minioClient.removeObject(this.bucketName, fileObjectName);
|
||||
}catch (Exception e){
|
||||
logger.warn("delete file in minio store fail, bucket={}, file={}", this.bucketName, fileObjectName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFiles(List<String> fileObjectNames) {
|
||||
try{
|
||||
if(CollectionUtils.isEmpty(fileObjectNames)){
|
||||
return;
|
||||
}
|
||||
minioClient.removeObjects(this.bucketName, fileObjectNames);
|
||||
}catch (Exception e){
|
||||
logger.warn("delete file in minio store fail, bucket={}, file={}", this.bucketName, fileObjectNames.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package top.lidee.taie.oss.ossbuilder.builders;
|
||||
|
||||
import top.lidee.taie.oss.config.OSSProperties;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSException;
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSExceptionBuilder;
|
||||
import top.lidee.taie.oss.ossbuilder.LideeOSSTemplate;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件存储 使用服务器本地文件夹
|
||||
* @Author: Devli
|
||||
* @since 2022/3/22 14:16
|
||||
*/
|
||||
public class NFSClient implements LideeOSSTemplate {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(NFSClient.class);
|
||||
|
||||
private String nfsLocalStore = "/app/disk/upload";
|
||||
|
||||
// 允许的文件后缀 白名单
|
||||
private String fileTypeWhiteList;
|
||||
|
||||
@Override
|
||||
public String getFileTypeWhiteList() {
|
||||
return fileTypeWhiteList;
|
||||
}
|
||||
|
||||
public NFSClient(OSSProperties ossProperties){
|
||||
this.fileTypeWhiteList = ossProperties.getFileTypeWhiteList();
|
||||
if (ossProperties.getNfs() != null && !StringUtils.isEmpty(ossProperties.getNfs().getPath())) {
|
||||
this.nfsLocalStore = ossProperties.getNfs().getPath();
|
||||
}
|
||||
if (!StringUtils.endsWithIgnoreCase(this.nfsLocalStore, java.io.File.separator)) {
|
||||
this.nfsLocalStore = this.nfsLocalStore + java.io.File.separator;
|
||||
}
|
||||
java.io.File localDir = new java.io.File(this.nfsLocalStore);
|
||||
if (!localDir.exists()) {
|
||||
localDir.mkdirs();
|
||||
}
|
||||
logger.info("初始化文件存储,激活服务器本地文件存储,路径{}", this.nfsLocalStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFileByInputStream(MultipartFile file, String fileObjectName) throws LideeOSSException {
|
||||
//判断文件后缀名是否在白名单中,如果不在报异常,中止文件保存
|
||||
checkFileSuffixName(file);
|
||||
|
||||
java.io.File objectFile = null;
|
||||
try {
|
||||
// 本地文件保存路径
|
||||
String filePath = nfsLocalStore + fileObjectName;
|
||||
objectFile = new java.io.File(filePath);
|
||||
file.transferTo(objectFile);
|
||||
} catch (Exception e) {
|
||||
logger.error("save file to local store error:", e);
|
||||
throw LideeOSSExceptionBuilder.build("save file to local store error", e);
|
||||
} finally {
|
||||
objectFile = null;
|
||||
}
|
||||
return fileObjectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] downloadFile(String fileObjectName) throws LideeOSSException {
|
||||
byte[] fileBytes = null;
|
||||
java.io.File objectFile = null;
|
||||
try {
|
||||
// 本地文件保存路径
|
||||
String filePath = nfsLocalStore + fileObjectName;
|
||||
objectFile = new java.io.File(filePath);
|
||||
fileBytes = FileUtils.readFileToByteArray(objectFile);
|
||||
} catch (Exception e) {
|
||||
logger.error("read file from local store error:", e);
|
||||
throw LideeOSSExceptionBuilder.build("read file from local store error, objectName="+ fileObjectName);
|
||||
} finally {
|
||||
objectFile = null;
|
||||
}
|
||||
return fileBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFile(String fileObjectName) {
|
||||
try{
|
||||
// 本地文件保存路径
|
||||
String filePath = nfsLocalStore + fileObjectName;
|
||||
java.io.File file = new java.io.File(filePath);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFiles(List<String> fileObjectNames) {
|
||||
if(CollectionUtils.isEmpty(fileObjectNames)){
|
||||
return;
|
||||
}
|
||||
fileObjectNames.stream().forEach(fileObjectName -> {
|
||||
this.deleteFile(fileObjectName);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package top.lidee.taie.oss.utils;
|
||||
|
||||
import top.lidee.taie.oss.exceptions.LideeOSSException;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
|
||||
public class ResponseUtil {
|
||||
|
||||
/**
|
||||
* 根据文件后缀来判断,是显示图片\视频\音频,还是下载文件
|
||||
* @param fileObjectName 文件原始名称,如:订单导入.xls banner.png
|
||||
* @param fileBytes 文件字节流
|
||||
* @param isIEBrowser 是否是IE浏览器
|
||||
* @return
|
||||
*/
|
||||
public static ResponseEntity<byte[]> writeBody(String fileObjectName, byte[] fileBytes, boolean isIEBrowser){
|
||||
try{
|
||||
if(StringUtils.isEmpty(fileObjectName) || !fileObjectName.contains(".")){
|
||||
throw new LideeOSSException("original file name or type is empty");
|
||||
}
|
||||
// 文件后缀名
|
||||
String fileSuffixName = fileObjectName.substring(fileObjectName.lastIndexOf("."));
|
||||
|
||||
// 初始化响应体
|
||||
ResponseEntity.BodyBuilder builder = ResponseEntity.ok();
|
||||
builder.contentLength(fileBytes.length);
|
||||
|
||||
// 判断文件是图片视频还是文件
|
||||
String pattern1 = "(.png|.jpg|.jpeg|.bmp|.gif|.icon)";
|
||||
String pattern2 = "(.flv|.swf|.mkv|.avi|.rm|.rmvb|.mpeg|.mpg|.ogg|.ogv|.mov|.wmv|.mp4|.webm|.wav|.mid|.mp3|.aac)";
|
||||
if (StringPatternUtil.StringMatchIgnoreCase(fileSuffixName, pattern1)) {
|
||||
builder.cacheControl(CacheControl.noCache()).contentType(MediaType.IMAGE_PNG);
|
||||
} else if (StringPatternUtil.StringMatchIgnoreCase(fileSuffixName, pattern2)) {
|
||||
builder.header("Content-Type", "video/mp4; charset=UTF-8");
|
||||
} else {
|
||||
//application/octet-stream 二进制数据流(最常见的文件下载)
|
||||
builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
fileObjectName = URLEncoder.encode(fileObjectName, "UTF-8");
|
||||
if (isIEBrowser) {
|
||||
builder.header("Content-Disposition", "attachment; filename=" + fileObjectName);
|
||||
} else {
|
||||
builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + fileObjectName);
|
||||
}
|
||||
}
|
||||
return builder.body(fileBytes);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package top.lidee.taie.oss.utils;
|
||||
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class StringPatternUtil {
|
||||
private static final String STRING_STYLE_RED = "<span class='infoDanger'>%s</span>";
|
||||
private static final String UNDERLINE = "_";
|
||||
|
||||
public StringPatternUtil() {
|
||||
}
|
||||
|
||||
public static boolean StringMatch(String sourceStr, String pattern) {
|
||||
boolean result = false;
|
||||
|
||||
try {
|
||||
if (StringUtils.isEmpty(sourceStr) || StringUtils.isEmpty(pattern)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Pattern p = Pattern.compile(pattern);
|
||||
Matcher m = p.matcher(sourceStr);
|
||||
if (m.find()) {
|
||||
result = true;
|
||||
}
|
||||
} catch (Exception var5) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean StringMatchIgnoreCase(String sourceStr, String pattern) {
|
||||
boolean result = false;
|
||||
|
||||
try {
|
||||
if (StringUtils.isEmpty(sourceStr) || StringUtils.isEmpty(pattern)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
sourceStr = sourceStr.toLowerCase();
|
||||
pattern = pattern.toLowerCase();
|
||||
result = StringMatch(sourceStr, pattern);
|
||||
} catch (Exception var4) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String StringFind(String sourceStr, String pattern) {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (StringUtils.isEmpty(sourceStr) || StringUtils.isEmpty(pattern)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Pattern p = Pattern.compile(pattern);
|
||||
Matcher m = p.matcher(sourceStr);
|
||||
if (m.find()) {
|
||||
result = m.group(0);
|
||||
}
|
||||
} catch (Exception var5) {
|
||||
result = "";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String replace(String sourceStr, String pattern, String replaceStr) {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (StringUtils.isEmpty(sourceStr) || StringUtils.isEmpty(pattern)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Pattern p = Pattern.compile(pattern);
|
||||
Matcher m = p.matcher(sourceStr);
|
||||
result = m.replaceAll(replaceStr);
|
||||
} catch (Exception var6) {
|
||||
result = "";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=top.lidee.taie.oss.config.AutoConfiguration
|
||||
Reference in New Issue
Block a user