提交
This commit is contained in:
86
jeepay-components/jeepay-components-oss/pom.xml
Normal file
86
jeepay-components/jeepay-components-oss/pom.xml
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion> <!-- POM模型版本 -->
|
||||
|
||||
<groupId>com.jeequan</groupId> <!-- 组织名, 类似于包名 -->
|
||||
<artifactId>jeepay-components-oss</artifactId> <!-- 项目名称 -->
|
||||
<packaging>jar</packaging> <!-- 项目的最终打包类型/发布形式, 可选[jar, war, pom, maven-plugin]等 -->
|
||||
<version>${isys.version}</version> <!-- 项目当前版本号 -->
|
||||
<description>Jeepay计全支付系统 [jeepay-components-oss]</description> <!-- 项目描述 -->
|
||||
<url>https://www.jeequan.com</url>
|
||||
|
||||
<parent>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<artifactId>jeepay-components</artifactId>
|
||||
<version>Final</version>
|
||||
</parent>
|
||||
|
||||
<!-- 项目属性 -->
|
||||
<properties>
|
||||
<projectRootDir>${basedir}/../../</projectRootDir>
|
||||
</properties>
|
||||
|
||||
<!-- 项目依赖声明 -->
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<artifactId>jeepay-components-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 添加 spring-webmvc 基础依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<scope>provided</scope> <!-- 仅编译依赖该jar, 运行时存在 -->
|
||||
</dependency>
|
||||
|
||||
<!-- slf4j -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring-boot 相关注解 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
<scope>provided</scope> <!-- 仅编译依赖该jar, 运行时存在 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<scope>provided</scope> <!-- 仅编译依赖该jar, 运行时存在 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<scope>provided</scope> <!-- 仅编译依赖该jar, 运行时存在 -->
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里云oss组件 -->
|
||||
<dependency>
|
||||
<groupId>com.aliyun.oss</groupId>
|
||||
<artifactId>aliyun-sdk-oss</artifactId>
|
||||
<scope>compile</scope> <!-- 当对象存储使用aliyunOSS时,需要改为:compile, 否则使用provided仅用于编译代码 -->
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes><include>**/*.xml</include></includes><!-- maven可以将mapper.xml进行打包处理,否则仅对java文件处理 -->
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.jeequan.jeepay.components.oss.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 系统Yml配置参数定义Bean
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021-04-27 15:50
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix="isys")
|
||||
public class OssYmlConfig {
|
||||
|
||||
@NestedConfigurationProperty //指定该属性为嵌套值, 否则默认为简单值导致对象为空(外部类不存在该问题, 内部static需明确指定)
|
||||
private Oss oss;
|
||||
|
||||
/** 系统oss配置信息 **/
|
||||
@Data
|
||||
public static class Oss{
|
||||
|
||||
/** 存储根路径 **/
|
||||
private String fileRootPath;
|
||||
|
||||
/** 公共读取块 **/
|
||||
private String filePublicPath;
|
||||
|
||||
/** 私有读取块 **/
|
||||
private String filePrivatePath;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.jeequan.jeepay.components.oss.constant;
|
||||
|
||||
/**
|
||||
* oss 存储位置
|
||||
* @author terrfly
|
||||
* @date 2021/7/12 10:48
|
||||
*/
|
||||
public enum OssSavePlaceEnum {
|
||||
|
||||
PUBLIC, //公共读取
|
||||
|
||||
PRIVATE; //私有存储
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.jeequan.jeepay.components.oss.constant;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* oss 服务枚举值
|
||||
* @author terrfly
|
||||
* @date 2021/7/12 10:48
|
||||
*/
|
||||
@Getter
|
||||
public enum OssServiceTypeEnum {
|
||||
|
||||
LOCAL("localFile"), //本地存储
|
||||
|
||||
ALIYUN_OSS("aliyunOss"); //阿里云oss
|
||||
|
||||
/** 名称 **/
|
||||
private String serviceName;
|
||||
|
||||
OssServiceTypeEnum(String serviceName){
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.jeequan.jeepay.components.oss.ctrl;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import com.jeequan.jeepay.components.oss.model.OssFileConfig;
|
||||
import com.jeequan.jeepay.components.oss.service.IOssService;
|
||||
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
|
||||
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.core.model.DBOSSConfig;
|
||||
import com.jeequan.jeepay.core.service.ISysConfigService;
|
||||
import com.jeequan.jeepay.core.utils.FileKit;
|
||||
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 统一文件上传接口(ossFile)
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/6/8 17:07
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/ossFiles")
|
||||
public class OssFileController extends AbstractCtrl {
|
||||
|
||||
@Autowired private ISysConfigService sysConfigService;
|
||||
|
||||
/** 文件上传、 将二进制文件上传到服务器, 在保存到对应是oss上。 (单文件) */
|
||||
@PostMapping("/singleFile")
|
||||
public ApiRes singleFileUpload(@RequestParam("file") MultipartFile file) {
|
||||
|
||||
if( file == null ) {
|
||||
return ApiRes.fail(ApiCodeEnum.SYSTEM_ERROR, "选择文件不存在");
|
||||
}
|
||||
try {
|
||||
|
||||
// 获取业务类型
|
||||
String bizType = getValStringRequired("bizType");
|
||||
|
||||
// 文件存储路径
|
||||
String saveDirAndFileName = commonCheckAndGetFilePath(bizType, file.getOriginalFilename(), file.getSize());
|
||||
|
||||
// 预览地址
|
||||
String url = getOssService().upload2PreviewUrl(OssFileConfig.getOssFileConfigByBizType(bizType).getOssSavePlaceEnum(), file, saveDirAndFileName);
|
||||
return ApiRes.ok(url);
|
||||
|
||||
} catch (BizException biz) {
|
||||
throw biz;
|
||||
} catch (Exception e) {
|
||||
logger.error("upload error, fileName = {}", file.getOriginalFilename(), e);
|
||||
throw new BizException(ApiCodeEnum.SYSTEM_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** 获取文件的上传form表单参数, 文件不上传到服务器, 返回form直接上传到对应的oss地址。 */
|
||||
@PostMapping("/form")
|
||||
public ApiRes formParams() {
|
||||
|
||||
String bizType = getValStringRequired("bizType"); // 获取文件上传类型
|
||||
String sourceFileName = getValStringRequired("sourceFileName"); //用户上传的原始文件名称
|
||||
Long sourceFileSize = getValLongRequired("sourceFileSize"); //用户上传的原始文件大小 单位: 字节Byte
|
||||
|
||||
// 文件存储路径
|
||||
String saveDirAndFileName = commonCheckAndGetFilePath(bizType, sourceFileName, sourceFileSize);
|
||||
|
||||
OssFileConfig ossFileConfig = OssFileConfig.getOssFileConfigByBizType(bizType);
|
||||
|
||||
IOssService.UploadFormParams result = getOssService().genFormParams(bizType, ossFileConfig, saveDirAndFileName);
|
||||
return ApiRes.ok(result);
|
||||
}
|
||||
|
||||
/** 统一校验, 获取文件的存储地址 */
|
||||
private String commonCheckAndGetFilePath(String bizType, String fileOriginalFilename, Long fileSize){
|
||||
|
||||
OssFileConfig ossFileConfig = OssFileConfig.getOssFileConfigByBizType(bizType);
|
||||
|
||||
//1. 判断bizType 是否可用
|
||||
if(ossFileConfig == null){
|
||||
throw new BizException("类型有误");
|
||||
}
|
||||
|
||||
// 2. 判断文件是否支持
|
||||
String fileSuffix = FileKit.getFileSuffix(fileOriginalFilename, false);
|
||||
if( !ossFileConfig.isAllowFileSuffix(fileSuffix) ){
|
||||
throw new BizException("上传文件格式不支持!");
|
||||
}
|
||||
|
||||
// 3. 判断文件大小是否超限
|
||||
if( !ossFileConfig.isMaxSizeLimit(fileSize) ){
|
||||
throw new BizException("上传大小请限制在["+ossFileConfig.getMaxSize() / 1024 / 1024 +"M]以内!");
|
||||
}
|
||||
|
||||
// 新文件地址 (xxx/xxx.jpg 格式)
|
||||
return bizType + "/" + UUID.fastUUID() + "." + fileSuffix;
|
||||
}
|
||||
|
||||
|
||||
/** 后端java直接调用上传 */
|
||||
public String singleFileUpload(MultipartFile file, String bizType) {
|
||||
|
||||
// 文件存储路径
|
||||
String saveDirAndFileName = commonCheckAndGetFilePath(bizType, file.getOriginalFilename(), file.getSize());
|
||||
|
||||
// 预览地址
|
||||
return getOssService().upload2PreviewUrl(OssFileConfig.getOssFileConfigByBizType(bizType).getOssSavePlaceEnum(), file, saveDirAndFileName);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private IOssService getOssService(){
|
||||
|
||||
DBOSSConfig dbossConfig = sysConfigService.getOssConfig();
|
||||
return SpringBeansUtil.getBean(dbossConfig.getOssUseType() + "OssService", IOssService.class);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.jeequan.jeepay.components.oss.model;
|
||||
|
||||
import cn.hutool.core.io.file.FileWriter;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/***
|
||||
* 构建一个MultipartFile 用作自定义上传
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2022/1/18 12:33
|
||||
*/
|
||||
public class MockMultipartFile implements MultipartFile {
|
||||
|
||||
private String originalFilename;
|
||||
|
||||
private Long size;
|
||||
|
||||
private InputStream inputStream;
|
||||
|
||||
public MockMultipartFile(String originalFilename, Long size, InputStream inputStream){
|
||||
this.originalFilename = originalFilename;
|
||||
this.size = size;
|
||||
this.inputStream = inputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.originalFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalFilename() {
|
||||
return this.originalFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
throw new BizException("方法未实现");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() throws IOException {
|
||||
throw new IOException("方法未实现");
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return this.inputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferTo(File dest) throws IOException, IllegalStateException {
|
||||
FileWriter.create(dest).writeFromStream(inputStream);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.jeequan.jeepay.components.oss.model;
|
||||
|
||||
import com.jeequan.jeepay.components.oss.constant.OssSavePlaceEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 定义文件上传的配置信息
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/6/8 16:38
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class OssFileConfig {
|
||||
|
||||
/** 用户头像 **/
|
||||
public interface BIZ_TYPE {
|
||||
String AVATAR = "avatar"; /** 用户头像 **/
|
||||
String IF_BG = "ifBG"; /** 接口类型卡片背景图片 **/
|
||||
String CERT = "cert"; /** 接口参数 **/
|
||||
String WX_FILE = "wxFile"; /** 微信相关文件 **/
|
||||
String APPLYMENT = "applyment"; /** 进件资料 **/
|
||||
String QRC = "qrc"; /** 码牌相关图片 **/
|
||||
String OEM = "oem"; /** OEM站点信息 **/
|
||||
String NOTICE = "notice"; /** 公告内的图片 **/
|
||||
String CHANNEL_BILL = "channelBill"; /** 渠道对账文件 **/
|
||||
String APP_FILE = "appFile"; /** 升级文件 **/
|
||||
String AGENT_FILE = "agentFile"; /** 代理授权文件 **/
|
||||
String AUDIO = "audio"; /** 音频文件 **/
|
||||
String MATERIAL = "material"; /** 素材文件 **/
|
||||
}
|
||||
|
||||
/** 图片类型后缀格式 **/
|
||||
public static final Set<String> IMG_SUFFIX = new HashSet<>(Arrays.asList("jpg", "png", "jpeg", "gif", "ico", "svg", "bmp"));
|
||||
|
||||
/** 证书相关文件格式 **/
|
||||
public static final Set<String> CERT_SUFFIX = new HashSet<>(Arrays.asList("crt", "p12", "pem", "pfx", "cer", "sm2", "key"));
|
||||
|
||||
/** 站点文件格式 **/
|
||||
public static final Set<String> AGENT_FILE_SUFFIX = new HashSet<>(Arrays.asList("pdf", "docx" ,"xlsx"));
|
||||
|
||||
public static final Set<String> AUDIO_SUFFIX = new HashSet<>(Arrays.asList("mp3", "wav"));
|
||||
|
||||
public static final Set<String> MATERIAL_SUFFIX = new HashSet<>(Arrays.asList("jgp", "JFIF"));
|
||||
|
||||
/** 全部后缀格式的文件标识符 **/
|
||||
public static final String ALL_SUFFIX_FLAG = "*";
|
||||
|
||||
/** 不校验文件大小标识符 **/
|
||||
public static final Long ALL_MAX_SIZE = -1L;
|
||||
|
||||
/** 允许上传的最大文件大小的默认值 **/
|
||||
public static final Long DEFAULT_MAX_SIZE = 5 * 1024 * 1024L;
|
||||
|
||||
private static final Map<String, OssFileConfig> ALL_BIZ_TYPE_MAP = new HashMap<>();
|
||||
static{
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.AVATAR, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.IF_BG, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.APPLYMENT, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.CERT, new OssFileConfig(OssSavePlaceEnum.PRIVATE, CERT_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.WX_FILE, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.QRC, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.OEM, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.NOTICE, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.CHANNEL_BILL, new OssFileConfig(OssSavePlaceEnum.PUBLIC, new HashSet<>(Collections.singletonList(ALL_SUFFIX_FLAG)), DEFAULT_MAX_SIZE) );
|
||||
|
||||
// appFile , 默认大小50M
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.APP_FILE, new OssFileConfig(OssSavePlaceEnum.PUBLIC, new HashSet<>(Collections.singletonList("apk")), 50 * 1024 * 1024L) );
|
||||
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.AGENT_FILE, new OssFileConfig(OssSavePlaceEnum.PUBLIC, AGENT_FILE_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.AUDIO, new OssFileConfig(OssSavePlaceEnum.PUBLIC, AUDIO_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
//素材文件
|
||||
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.MATERIAL, new OssFileConfig(OssSavePlaceEnum.PUBLIC, MATERIAL_SUFFIX, DEFAULT_MAX_SIZE) );
|
||||
}
|
||||
|
||||
/** 存储位置 **/
|
||||
private OssSavePlaceEnum ossSavePlaceEnum;
|
||||
|
||||
/** 允许的文件后缀, 默认全部类型 **/
|
||||
private Set<String> allowFileSuffix = new HashSet<>(Arrays.asList(ALL_SUFFIX_FLAG));
|
||||
|
||||
/** 允许的文件大小, 单位: Byte **/
|
||||
private Long maxSize = DEFAULT_MAX_SIZE;
|
||||
|
||||
|
||||
/** 是否在允许的文件类型后缀内 **/
|
||||
public boolean isAllowFileSuffix(String fixSuffix){
|
||||
|
||||
if(this.allowFileSuffix.contains(ALL_SUFFIX_FLAG)){ //允许全部
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.allowFileSuffix.contains(StringUtils.defaultIfEmpty(fixSuffix, "").toLowerCase());
|
||||
}
|
||||
|
||||
/** 是否在允许的大小范围内 **/
|
||||
public boolean isMaxSizeLimit(Long fileSize){
|
||||
|
||||
if(ALL_MAX_SIZE.equals(this.maxSize)){ //允许全部大小
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.maxSize >= ( fileSize == null ? 0L : fileSize);
|
||||
}
|
||||
|
||||
|
||||
public static OssFileConfig getOssFileConfigByBizType(String bizType){
|
||||
return ALL_BIZ_TYPE_MAP.get(bizType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.jeequan.jeepay.components.oss.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
import com.aliyun.oss.common.utils.BinaryUtil;
|
||||
import com.aliyun.oss.model.GetObjectRequest;
|
||||
import com.aliyun.oss.model.PolicyConditions;
|
||||
import com.jeequan.jeepay.components.oss.constant.OssSavePlaceEnum;
|
||||
import com.jeequan.jeepay.components.oss.model.OssFileConfig;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import com.jeequan.jeepay.core.model.DBOSSConfig;
|
||||
import com.jeequan.jeepay.core.service.ISysConfigService;
|
||||
import com.jeequan.jeepay.core.utils.DateKit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 阿里云OSS 实现类
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/7/12 18:20
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AliyunOssOssService implements IOssService{
|
||||
|
||||
@Autowired private ISysConfigService sysConfigService;
|
||||
|
||||
public OSS getOssClient(){
|
||||
|
||||
DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();
|
||||
|
||||
return new OSSClientBuilder().build(aliyunOssConfigModel.getEndpoint(), aliyunOssConfigModel.getAccessKeyId(), aliyunOssConfigModel.getAccessKeySecret());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String upload2PreviewUrl(OssSavePlaceEnum ossSavePlaceEnum, MultipartFile multipartFile, String saveDirAndFileName) {
|
||||
|
||||
try {
|
||||
|
||||
DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();
|
||||
|
||||
getOssClient().putObject(ossSavePlaceEnum == OssSavePlaceEnum.PUBLIC ? aliyunOssConfigModel.getPublicBucketName() : aliyunOssConfigModel.getPrivateBucketName()
|
||||
, saveDirAndFileName, multipartFile.getInputStream());
|
||||
|
||||
return genUrlHost(ossSavePlaceEnum, true, saveDirAndFileName);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOssService.UploadFormParams genFormParams(String bizType, OssFileConfig ossFileConfig, String saveDirAndFileName) {
|
||||
|
||||
try {
|
||||
|
||||
|
||||
DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();
|
||||
|
||||
//生成Policy Post policy 文档: https://help.aliyun.com/document_detail/31988.html?spm=a2c4g.11186623.6.1635.4dbb2e3cCqA5WM
|
||||
PolicyConditions policyConds = new PolicyConditions();
|
||||
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, ossFileConfig.getMaxSize()); //上传文件限制
|
||||
String postPolicy = getOssClient().generatePostPolicy(new Date(DateKit.currentTimeMillis() + aliyunOssConfigModel.getExpireTime()), policyConds);
|
||||
|
||||
|
||||
IOssService.UploadFormParams result = new UploadFormParams();
|
||||
result.setFormActionUrl(this.genUrlHost(ossFileConfig.getOssSavePlaceEnum(), true, null)); //前端请求的url地址
|
||||
result.setOssFileUrl(this.genUrlHost(ossFileConfig.getOssSavePlaceEnum(), true, saveDirAndFileName)); //当上传成功 oss响应200时, 使用该路径作为文件路径
|
||||
|
||||
//返回前端form表单的参数。 文档: https://help.aliyun.com/document_detail/31988.html?spm=a2c4g.11186623.2.7.b37c436781S3Gx#reference-smp-nsw-wdb
|
||||
JSONObject formParams = new JSONObject();
|
||||
formParams.put("OSSAccessKeyId", aliyunOssConfigModel.getAccessKeyId()); //AccessKeyId
|
||||
formParams.put("policy", BinaryUtil.toBase64String(postPolicy.getBytes("utf-8"))); //policy为一段经过UTF-8和base64编码的JSON文本
|
||||
formParams.put("Signature", getOssClient().calculatePostSignature(postPolicy)); //签名
|
||||
formParams.put("key", saveDirAndFileName); //上传的文件名
|
||||
formParams.put("success_action_status", "200"); //上传成功响应200, 默认204
|
||||
result.setFormParams(formParams);
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("生成上传form表单数据失败", e);
|
||||
throw new BizException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean downloadFile(OssSavePlaceEnum ossSavePlaceEnum, String source, String target) {
|
||||
|
||||
try {
|
||||
|
||||
DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();
|
||||
|
||||
String bucket = ossSavePlaceEnum == OssSavePlaceEnum.PRIVATE ? aliyunOssConfigModel.getPrivateBucketName() : aliyunOssConfigModel.getPublicBucketName();
|
||||
this.getOssClient().getObject(new GetObjectRequest(bucket, source), new File(target));
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("error", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** 返回请求地址 / 文件地址 **/
|
||||
public String genUrlHost(OssSavePlaceEnum ossSavePlaceEnum, boolean isHttps, String saveDirAndFileName){
|
||||
|
||||
// 私有文件 && 存在下载地址 : 返回存储地址
|
||||
if(ossSavePlaceEnum == OssSavePlaceEnum.PRIVATE && StringUtils.isNotEmpty(saveDirAndFileName)){
|
||||
return saveDirAndFileName;
|
||||
}
|
||||
|
||||
DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();
|
||||
|
||||
// 公共读 or 上传action
|
||||
|
||||
// 文档:https://www.alibabacloud.com/help/zh/doc-detail/39607.htm example: https://BucketName.Endpoint/ObjectName
|
||||
return
|
||||
( isHttps ? "https://" : "http://" )
|
||||
+ ( ossSavePlaceEnum == OssSavePlaceEnum.PUBLIC ? aliyunOssConfigModel.getPublicBucketName() : aliyunOssConfigModel.getPrivateBucketName() )
|
||||
+ "." + aliyunOssConfigModel.getEndpoint() + "/" + StringUtils.defaultIfEmpty(saveDirAndFileName, "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.jeequan.jeepay.components.oss.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jeequan.jeepay.components.oss.constant.OssSavePlaceEnum;
|
||||
import com.jeequan.jeepay.components.oss.model.OssFileConfig;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* OSSService 接口
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/7/12 18:18
|
||||
*/
|
||||
public interface IOssService {
|
||||
|
||||
@Data
|
||||
class UploadFormParams{
|
||||
|
||||
private String formActionUrl;
|
||||
private String ossFileUrl;
|
||||
private JSONObject formParams;
|
||||
}
|
||||
|
||||
/** 上传文件 & 生成下载/预览URL **/
|
||||
String upload2PreviewUrl(OssSavePlaceEnum ossSavePlaceEnum, MultipartFile multipartFile, String saveDirAndFileName);
|
||||
|
||||
/** 生成上传form表单的参数 **/
|
||||
UploadFormParams genFormParams(String bizType, OssFileConfig ossFileConfig, String saveDirAndFileName);
|
||||
|
||||
/** 将文件下载到本地
|
||||
* 返回是否 写入成功
|
||||
* false: 写入失败, 或者文件不存在
|
||||
* **/
|
||||
boolean downloadFile(OssSavePlaceEnum ossSavePlaceEnum, String source, String target);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.jeequan.jeepay.components.oss.service;
|
||||
|
||||
import com.jeequan.jeepay.components.oss.config.OssYmlConfig;
|
||||
import com.jeequan.jeepay.components.oss.constant.OssSavePlaceEnum;
|
||||
import com.jeequan.jeepay.components.oss.model.OssFileConfig;
|
||||
import com.jeequan.jeepay.core.service.ISysConfigService;
|
||||
import com.jeequan.jeepay.core.utils.JsonKit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 本地存储 实现类
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/7/12 18:19
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class LocalFileOssService implements IOssService{
|
||||
|
||||
@Autowired private ISysConfigService sysConfigService;
|
||||
@Autowired private OssYmlConfig ossYmlConfig;
|
||||
|
||||
@Override
|
||||
public String upload2PreviewUrl(OssSavePlaceEnum ossSavePlaceEnum, MultipartFile multipartFile, String saveDirAndFileName) {
|
||||
|
||||
try {
|
||||
|
||||
String savePath = ossSavePlaceEnum ==
|
||||
OssSavePlaceEnum.PUBLIC ? ossYmlConfig.getOss().getFilePublicPath() : ossYmlConfig.getOss().getFilePrivatePath();
|
||||
|
||||
File saveFile = new File(savePath + File.separator + saveDirAndFileName);
|
||||
|
||||
//如果文件夹不存在则创建文件夹
|
||||
File dir = saveFile.getParentFile();
|
||||
if(!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
multipartFile.transferTo(saveFile);
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
log.error("", e);
|
||||
}
|
||||
|
||||
// 私有文件 不返回预览文件地址
|
||||
if(ossSavePlaceEnum == OssSavePlaceEnum.PRIVATE){
|
||||
return saveDirAndFileName;
|
||||
}
|
||||
return sysConfigService.getOssConfig().getOssPublicSiteUrl() + "/" + saveDirAndFileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadFormParams genFormParams(String bizType, OssFileConfig ossFileConfig, String saveDirAndFileName) {
|
||||
|
||||
IOssService.UploadFormParams result = new UploadFormParams();
|
||||
result.setFormActionUrl("LOCAL_SINGLE_FILE_URL"); //前端请求的url地址为本地标识符
|
||||
result.setOssFileUrl(null); // 不设置最终文件, 通过上传成功后进行获取。
|
||||
result.setFormParams(JsonKit.newJson("bizType", bizType));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean downloadFile(OssSavePlaceEnum ossSavePlaceEnum, String source, String target) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user