文件上传

This commit is contained in:
wangqiy 2025-04-16 14:22:36 +08:00
parent 51ab157613
commit 6f271e53b9
11 changed files with 601 additions and 10 deletions

View File

@ -1,7 +1,13 @@
package com.agri.web.controller.common;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.agri.common.config.OSSConfig;
import com.agri.common.utils.AliyunOSSUtils;
import com.agri.common.utils.ApiUtils;
import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -31,6 +37,12 @@ public class CommonController
@Autowired
private ServerConfig serverConfig;
@Autowired
private AliyunOSSUtils aliyunOSSUtils;
@Autowired
private OSSConfig ossConfig;
/**
* 通用下载请求
*
@ -67,22 +79,25 @@ public class CommonController
* 通用上传请求
*/
@PostMapping("/common/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
public AjaxResult uploadFile(MultipartFile file) throws Exception {
try {
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
String url = "";
String fileName = "";
if ("oss".equals(ossConfig.getUploadType())){
url = aliyunOSSUtils.upLoadFile(file);
fileName = FileUtils.getName(url);
}else {
// 上传并返回新文件名称
fileName = FileUploadUtils.upload(filePath, file);
url = serverConfig.getUrl() + fileName;
}
AjaxResult ajax = AjaxResult.success();
ajax.put("fileName", fileName);
ajax.put("url", url);
return ajax;
}
catch (Exception e)
{
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
@ -115,4 +130,14 @@ public class CommonController
log.error("下载文件失败", e);
}
}
/**
* 获取上传文件签名
* @return
*/
@Operation(summary = "获取上传文件签名",method = "GET")
@GetMapping("/getSign")
public String getOssSign() {
return ApiUtils.successData(aliyunOSSUtils.getSign());
}
}

View File

@ -226,3 +226,4 @@ sms:
signature: 青蛙农业
#模板ID 非必须配置如果使用sendMessage的快速发送需此配置
template-id: SMS_473805253

View File

@ -13,3 +13,15 @@ knife4j:
username: admin
# 密码
password: admin123
# 阿里云相关配置
aliyun:
oss:
endpoint: oss-cn-chengdu.aliyuncs.com
accessKeyId: LTAI5tEFj4BeiBfWgEDiRJn7
accessKeySecret: 4kOMnSCvTN9KAufb1ul0dHzQuYo8Mz
bucketName: gov-cloud
prefixKey: backend/
# domainName: https://ossnew.ljnhs.cn/
maxSize: 100 #文件大小限制(单位: m) 默认10m
uploadType: oss

View File

@ -137,6 +137,19 @@
</exclusion>
</exclusions>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--阿里云oss-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,60 @@
package com.agri.common.config;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component("ossConfig")
@ConfigurationProperties(prefix = "aliyun.oss")
@Data
public class OSSConfig {
/**
* OSS 访问域名
*/
private String endpoint;
/**
* 标识用户
*/
private String accessKeyId;
/**
* 加密签名字符串
*/
private String accessKeySecret;
/**
* 存储空间名称
*/
private String bucketName;
/**
* 文件/对象名称的前缀,类似目录
*/
private String prefixKey;
/**
* 自定义域名,预览图片用到
*/
// private String domainName;
/**
* 文件大小限制(单位: m)
*/
private Long maxSize;
/**
* 上传方式
*/
private String uploadType;
@Bean
public OSS ossClient() {
return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
}
public Long getMaxSize() {
if (maxSize == null || maxSize == 0) {
maxSize = 10L;
}
return maxSize * 1024 * 1204;
}
}

View File

@ -0,0 +1,47 @@
package com.agri.common.exception;
public class BusinessException extends RuntimeException {
private String code;
private final String message;
private Object data;
public BusinessException(String code, String message) {
this.message = message;
this.code = code;
}
public BusinessException(String code, String message, Object data) {
this.message = message;
this.code = code;
this.data = data;
}
public BusinessException(String message) {
this.message = message;
this.code = "0";
}
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
public Object getData() {
return data;
}
/**
* 去除异常中的堆栈跟踪信息减小异常控制代码流性能损耗
*/
// @Override
// public Throwable fillInStackTrace() {
// return this;
// }
}

View File

@ -0,0 +1,205 @@
package com.agri.common.utils;
import com.agri.common.config.OSSConfig;
import com.agri.common.exception.BusinessException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
@Slf4j
@Component
public class AliyunOSSUtils {
/**
* 图片格式
*/
private static final String[] FILE_TYPE = new String[]{".bmp", ".jpg",
".jpeg", ".gif", ".png", ".mp4", ".jfif", ".ico", ".pdf"};
@Resource
private OSS ossClient;
@Resource
private OSSConfig ossConfig;
/**
* 图像上传
*
* @param uploadFile 图像流处理
* @return 文件访问路径
*/
public String upLoadFile(MultipartFile uploadFile) {
return ossPutObject(uploadFile, null);
}
/**
* 图像上传
*
* @param uploadFile 图像流处理
* @param prefixKey 文件/对象名称的前缀,类似目录,例如:backend/
* @return 文件访问路径
*/
public String upLoadFile(MultipartFile uploadFile, String prefixKey) {
return ossPutObject(uploadFile, prefixKey);
}
@Deprecated
public String uploadAvatar(MultipartFile uploadFile) {
return ossPutObject(uploadFile,null);
}
/**
* 图片上传
*
* @param inputStream 图像流处理
* @return 文件访问路径
*/
@Deprecated
public String upLoadFile(InputStream inputStream) {
String suffix = ".png";
//文件名
String key = ossConfig.getPrefixKey() + UUID.randomUUID().toString()
.replace("-", "") + suffix;
try {
ossClient.putObject(ossConfig.getBucketName(), key, inputStream);
inputStream.close();
log.info("--------图片上传成功--------");
} catch (Exception e) {
log.info("oos上传失败:" + e.getMessage());
throw new BusinessException("图片上传失败");
}
//返回文件访问路径
return key;
}
/**
* 图片上传
*
* @param inputStream 图像流处理
* @return 文件访问路径
*/
public String upLoadOtherFile(InputStream inputStream, String filename) {
String suffix = filename.substring(filename.lastIndexOf("."));
//文件名
String key = ossConfig.getPrefixKey() + UUID.randomUUID().toString()
.replace("-", "") + suffix;
try {
ossClient.putObject(ossConfig.getBucketName(), key, inputStream);
inputStream.close();
} catch (Exception e) {
log.error("oos上传失败:{}", e.getMessage());
throw new BusinessException("文件上传失败");
}
//返回文件访问路径
return key;
}
/**
* 校验文件后缀
*
* @param suffix 文件后缀
* @return
*/
private void verifySuffix(String suffix) {
// 校验文件格式
for (String type : FILE_TYPE) {
if (type.equalsIgnoreCase(suffix)) {
return;
}
}
throw new BusinessException("暂不支持此格式的文件");
}
/**
* 获取签名
*
* @return
*/
public Map<String, String> getSign() {
String accessId = ossConfig.getAccessKeyId(); // 请填写您的AccessKeyId
String endpoint = ossConfig.getEndpoint(); // 请填写您的 endpoint
String bucket = ossConfig.getBucketName(); // 请填写您的 bucketname
String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
String dir = ossConfig.getPrefixKey(); // 用户上传文件时指定的前缀
try {
long expireTime = 180;//60秒
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
Map<String, String> respMap = new LinkedHashMap<>();
respMap.put("accessid", accessId);
respMap.put("policy", encodedPolicy);
respMap.put("signature", postSignature);
respMap.put("dir", dir);
respMap.put("host", host);
respMap.put("expire", String.valueOf(expireEndTime / 1000));
return respMap;
} catch (Exception e) {
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
throw new BusinessException("获取签名失败");
}
}
/**
* oss 文件上传并获得访问路径
*
* @param uploadFile 需要上传的文件
* @param prefixKey 文件/对象名称的前缀,类似目录 例如:backend/
* @return
*/
private String ossPutObject(MultipartFile uploadFile, String prefixKey) {
//获取文件名称
String originalFilename = uploadFile.getOriginalFilename();
//文件后缀
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
verifySuffix(suffix);
long size = uploadFile.getSize();
if (size > ossConfig.getMaxSize()) {
throw new BusinessException("文件超出大小限制");
}
//前缀,类似目录
if (StringUtils.isBlank(prefixKey)) {
prefixKey = ossConfig.getPrefixKey();
}
//文件路径=prefixKey+文件名称
String key = prefixKey + UUID.randomUUID().toString()
.replace("-", "") + suffix;
try {
InputStream inputStream = uploadFile.getInputStream();
ossClient.putObject(ossConfig.getBucketName(), key, inputStream);
inputStream.close();
log.info("--------文件上传成功--------");
} catch (Exception e) {
log.error("oos上传失败:", e);
throw new BusinessException("图片上传失败");
}
//返回文件访问路径
return key;
}
}

View File

@ -0,0 +1,123 @@
package com.agri.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
@Data
public class ApiUtils {
/** 成功code */
public static final int SUCCESS_CODE = 200;
/** 成功消息 */
public static final String SUCCESS_MESSAGE = "操作成功";
/** 错误code */
public static final int ERROR_CODE = 500;
/** 错误消息 */
public static final String ERROR_MESSAGE = "操作失败";
/** api登录失效 */
public static final String LOGIN_FAILURE = "10001";
/** 驴团长api登录失效 */
public static final String GROUPBUY_LOGIN_FAILURE = "110001";
/** 缺少服务商企业id参数 **/
public static final String ENTERPRISEID_MISS = "10002";
/** 订单提示弹窗 **/
public static final String ORDER_TIPS = "10003";
/** 商品详情error显示占位图 */
public static final String GOODS_DETAILS_ERROR = "10005";
/** 服务商品库存不足 */
public static final String UNDER_STOCK = "10006";
/** 商品已存在 */
public static final String GOODS_EXISTS = "10007";
/** 数据不存在 */
public static final String DATA_NOT_EXISTS = "10008";
/** 硬弹框code */
public static final String HARDFRAME = "33333";
/** 未注册弹窗 */
public static final String UNRFGISTERED_TIPS = "12100";
/** 用户被禁用 */
public static final String USER_DISABLED = "12101";
/** 城市合伙人权限未开通 */
public static final String USER_AUTH_FAILURE = "12102";
/** 再来一单所有商品失效 */
public static final String all_goods_effective = "44444";
private Integer code;
private String msg;
private Object data = new HashMap<>();
public ApiUtils() {}
public ApiUtils(Object data) {
this.code = SUCCESS_CODE;
if(data!=null){
this.data = data;
}
this.msg = SUCCESS_MESSAGE;
}
public ApiUtils(Integer code, String message) {
this.code = code;
this.msg = message;
}
public ApiUtils(Integer code, String message, Object data) {
this.code = code;
this.msg = message;
this.data = data;
}
public static SerializeConfig config = new SerializeConfig();
//对象为null返回{}
//枚举类型处理
public static SerializerFeature[] reatures = new SerializerFeature[] {
SerializerFeature.WriteMapNullValue,//为null也返回
SerializerFeature.WriteNullStringAsEmpty,//字符串为null返回""
SerializerFeature.WriteNullListAsEmpty,//数组/列表为null返回[]
SerializerFeature.WriteNullNumberAsZero,//数值类型Integer,Long为null返回0
SerializerFeature.DisableCircularReferenceDetect,// 消除循环引用
};
static {
config.put(Date.class, new SimpleDateFormatSerializer());//日期类型处理为null返回""
config.put(BigDecimal.class, new BigDecimalSerializer());//BigDecimal类型处理为null返回"0"
config.setAsmEnable(false);
}
public static String error() {
return JSON.toJSONString(new ApiUtils(ERROR_CODE, ERROR_MESSAGE.toString()), config, reatures);
}
public static String error(String message) {
return JSON.toJSONString(new ApiUtils(ERROR_CODE,message), config, reatures);
}
public static String error(Integer code, String message) {
return JSON.toJSONString(new ApiUtils(code,message), config, reatures);
}
public static String success() {
return JSON.toJSONString(new ApiUtils(SUCCESS_CODE, SUCCESS_MESSAGE.toString()), config, reatures);
}
public static String success(Integer code, String message){
return JSON.toJSONString(new ApiUtils(code, message), config, reatures);
}
public static String success(String message) {
return JSON.toJSONString(new ApiUtils(SUCCESS_CODE, message), config, reatures);
}
public static String successData(Object data) {
return JSON.toJSONString(new ApiUtils(data), config, reatures);
}
public static String resultData(Integer code, String message, Object data) {
return JSON.toJSONString(new ApiUtils(code, message, data), config, reatures);
}
}

View File

@ -0,0 +1,19 @@
package com.agri.common.utils;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import java.io.IOException;
import java.lang.reflect.Type;
public class BigDecimalSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object o1, Type type, int i) throws IOException {
if(object == null) {
serializer.write("0.00");
return ;
}
serializer.write(String.format("%.2f", object));
}
}

View File

@ -0,0 +1,29 @@
package com.agri.common.utils;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatSerializer implements ObjectSerializer {
private final String timePattern="yyyy-MM-dd HH:mm:ss";
private final String datePattern="yyyy-MM-dd";
@Override
public void write(JSONSerializer serializer, Object object, Object o1, Type type, int i) throws IOException {
if (object == null) {
serializer.getWriter().write("\"\"");
return;
}
Date date = (Date) object;
SimpleDateFormat format = new SimpleDateFormat(timePattern);
String text = format.format(date);
serializer.write(text);
}
}

View File

@ -25,6 +25,12 @@ import com.agri.common.utils.uuid.IdUtils;
*/
public class FileUtils
{
/** 字符常量:斜杠 {@code '/'} */
public static final char SLASH = '/';
/** 字符常量:反斜杠 {@code '\\'} */
public static final char BACKSLASH = '\\';
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
/**
@ -256,4 +262,55 @@ public class FileUtils
}
return strFileExtendName;
}
/**
* 返回文件名
*
* @param filePath 文件
* @return 文件名
*/
public static String getName(String filePath)
{
if (null == filePath)
{
return null;
}
int len = filePath.length();
if (0 == len)
{
return filePath;
}
if (isFileSeparator(filePath.charAt(len - 1)))
{
// 以分隔符结尾的去掉结尾分隔符
len--;
}
int begin = 0;
char c;
for (int i = len - 1; i > -1; i--)
{
c = filePath.charAt(i);
if (isFileSeparator(c))
{
// 查找最后一个路径分隔符/或者\
begin = i + 1;
break;
}
}
return filePath.substring(begin, len);
}
/**
* 是否为Windows或者LinuxUnix文件分隔符<br>
* Windows平台下分隔符为\LinuxUnix/
*
* @param c 字符
* @return 是否为Windows或者LinuxUnix文件分隔符
*/
public static boolean isFileSeparator(char c)
{
return SLASH == c || BACKSLASH == c;
}
}