
1、我们这个系统对接的阿里云OSS需要先对接小鹏OSS系统获取accessKeyId、accessKeySecret,这个可以忽略
aliyun:
oss:
endpoint: https://oss-cn-hangzhou.aliyuncs.com
bucketName: xp-xpd-experience
domain: https://xp-xpd-experience.oss-cn-hangzhou.aliyuncs.com
# 目录权限,不能瞎写,msedprod msedtest
folder: msedtest
# 上传文件大小
maxSizeStr: 3000
# redis过期时间(单位:分钟)
timeoutKey: 1
ossRedisKey: oss:file:key
auth:
idTokenUrl: https://ldap.test.xiaopeng.com/oidc/token
clientId: xp-msed-api-boot
clientSecret: ecDLIIhReieMYgvHQ
grant_type: client_credentials
stsAccessKeyUrl: http://apisix-gw-ali-hd1.test.xiaopeng.com/voyager-authhub/api/sts/get_token
policeName: XpMsedApiBootTESTOss
2、接口
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "单文件上传")
public Result<SysFileRecordVO> uploadFile(@RequestPart MultipartFile file, @RequestParam(value = "folderName", defaultValue = "", required = false) String folderName,
@RequestParam(defaultValue = "OTHER", required = false) FileTypeEnum fileType) {
return R.successWithData(sysFileRecordService.upload(file, folderName, fileType), "文件上传成功!");
}
@GetMapping(value = "/previewFile")
@Operation(summary = "OSS文件预览")
public Result<String> previewFile(@RequestParam(value = "fileName") String fileName) {
String url = sysFileRecordService.getUrl(fileName);
return R.successWithData(url);
}
@PostMapping(value = "/uploads", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "多文件上传")
Result<List<SysFileRecordVO>> uploadFile(@RequestPart MultipartFile[] files, @RequestParam(defaultValue = "OTHER", required = false) FileTypeEnum fileType) {
return R.successWithData(sysFileRecordService.uploads(files, fileType), "文件上传成功!");
}
@GetMapping(value = "/downloadById/{id}")
@Operation(summary = "根据id下载文件")
@Parameters({@Parameter(description = "id", in = ParameterIn.PATH, name = "id"), @Parameter(description = "名称", name = "name")})
ResponseEntity<byte[]> downloadById(@PathVariable Integer id, String name) {
return sysFileRecordService.downloadById(id, name);
}
@Operation(summary = "文件预览")
@GetMapping(value = "/filePreview/{path}")
@Parameter(description = "文件路径", name = "path", in = ParameterIn.PATH)
public ResponseEntity<byte[]> filePreview(@PathVariable("path") String path) {
return sysFileRecordService.filePreview(path);
}
service层
@Slf4j
@Primary
@Service(value = "sysOssFileRecordServiceImpl")
@ConditionalOnProperty(name = "oss.env.oss", havingValue = "true", matchIfMissing = true)
public class SysOssFileRecordServiceImpl extends ServiceImpl<SysFileRecordMapper, SysFileRecord> implements SysFileRecordService {
@Autowired
private OssConfig ossConfig;
@Autowired
private OssAuthConfig ossAuthConfig;
@Autowired
private CacheService cacheService;
@Override
@Transactional(rollbackFor = Exception.class)
public SysFileRecordVO upload(MultipartFile file, String folderName, FileTypeEnum fileTypeEnum) {
String ossRedisKey = ossConfig.getOssRedisKey();
String securityToken = (String) cacheService.hGet(ossRedisKey, "securityToken");
String accessKeyIdKey = (String) cacheService.hGet(ossRedisKey, "accessKeyId");
String accessKeySecretKey = (String) cacheService.hGet(ossRedisKey, "accessKeySecret");
if (StringUtils.isBlank(accessKeyIdKey) && StringUtils.isBlank(accessKeySecretKey)) {
Map<String, String> map = getAccessKeyIdSecret();
accessKeyIdKey = map.get("accessKeyId");
accessKeySecretKey = map.get("accessKeySecret");
securityToken = map.get("securityToken");
}
// Map<String, String> map = getAccessKeyIdSecret();
// String accessKeyIdKey = map.get("accessKeyId");
// String accessKeySecretKey = map.get("accessKeySecret");
// String securityToken = map.get("securityToken");
log.info("accessKeyIdKey:{}", accessKeyIdKey);
log.info("accessKeySecretKey:{}", accessKeySecretKey);
log.info("securityToken:{}", securityToken);
log.info("file:{}", file);
if (file == null) {
throw new ServiceException("文件不能为空");
}
String originalFilename = file.getOriginalFilename();
if (StringUtils.isEmpty(originalFilename)) {
throw new ServiceException("文件不能为空");
}
log.info("originalFilename:{}", originalFilename);
// 默认限制2M
float maxSize = 2;
try {
maxSize = Float.parseFloat(ossConfig.getMaxSizeStr());
} catch (NumberFormatException e) {
log.error("图片允许的大小设置不正确", e);
throw new ServiceException("图片允许的大小设置不正确");
}
if (file.getSize() > (maxSize * 1024 * 1024)) {
throw new ServiceException("上传的文件不能大于" + maxSize + "MB");
}
// 保存文件
try {
String fileName = saveFile(file, folderName);
// 上传阿里云oss
String endpoint = ossConfig.getEndpoint();
String bucketName = ossConfig.getBucketName();
String folder = ossConfig.getFolder();
log.info("bucketName:{}", bucketName);
log.info("endpoint:{}", endpoint);
log.info("folder:{}", folder);
OSS ossClient = AliyunOssUtil.getOSSClient(accessKeyIdKey, accessKeySecretKey, endpoint, securityToken);
File ossFile = new File(fileName);
Map<String, String> upload = AliyunOssUtil.upload(ossClient, ossFile, bucketName, folder, folderName);
log.info("upload:{}", upload);
fileName = upload.get("resultStr");
AssertUtil.isNotBlank(fileName, "小鹏OSS上传失败");
/*if (StringUtils.isBlank(fileName)) {
throw new ServiceException("小鹏OSS上传失败");
}*/
log.info("fileName:{}", fileName);
String fileNameEncode = Base64.encode(fileName);
SysFileRecordVO sysFileRecordVO = new SysFileRecordVO();
sysFileRecordVO.setFilePath(fileNameEncode);
sysFileRecordVO.setFileName(originalFilename);
return sysFileRecordVO;
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException("上传失败");
}
}
@Override
public ResponseEntity<byte[]> downloadFile(String path, String name, boolean isPreview) {
String ossRedisKey = ossConfig.getOssRedisKey();
path = Base64.decodeStr(path);
String securityToken = (String) cacheService.hGet(ossRedisKey, "securityToken");
String accessKeyIdKey = (String) cacheService.hGet(ossRedisKey, "accessKeyId");
String accessKeySecretKey = (String) cacheService.hGet(ossRedisKey, "accessKeySecret");
if (StringUtils.isBlank(accessKeyIdKey) && StringUtils.isBlank(accessKeySecretKey)) {
Map<String, String> map = getAccessKeyIdSecret();
accessKeyIdKey = map.get("accessKeyId");
accessKeySecretKey = map.get("accessKeySecret");
securityToken = map.get("securityToken");
}
String endpoint = ossConfig.getEndpoint();
String bucketName = ossConfig.getBucketName();
OSSClient ossClient = new OSSClient(endpoint, accessKeyIdKey, accessKeySecretKey, securityToken);
OSSObject ossObject = ossClient.getObject(bucketName, path);
try {
boolean found = ossClient.doesObjectExist(bucketName, path); // 检查文件是否存在
if (found) {
InputStream inputStream = ossObject.getObjectContent();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] readBuffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(readBuffer)) != -1) {
byteArrayOutputStream.write(readBuffer, 0, bytesRead);
}
byte[] fileBytes = byteArrayOutputStream.toByteArray();
// 根据isPreview标志来设置响应头
HttpHeaders headers = new HttpHeaders();
if (isPreview) {
// 预览模式,根据文件扩展名设置合适的Content-Type
String contentType = getContentTypeByFileName(path);
headers.setContentType(MediaType.parseMediaType(contentType));
} else {
// 下载模式,设置Content-Disposition为附件
// 对文件名进行URL编码,并指定编码方式
if (StringUtils.isBlank(name)) {
int i = path.lastIndexOf("/");
path = path.substring(i + 1);
} else {
path = name;
}
String encodedFileName = URLEncoder.encode(path, "UTF-8").replaceAll("\\+", "%20");
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + encodedFileName);
// headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
}
// 关闭输入流和输出流
inputStream.close();
byteArrayOutputStream.close();
return new ResponseEntity<>(fileBytes, headers, HttpStatus.OK);
}
return ResponseEntity.notFound().build();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
ossClient.shutdown();
}
}
// 根据文件名获取文件的MIME类型
private String getContentTypeByFileName(String fileName) {
String lowerCaseName = fileName.toLowerCase();
if (lowerCaseName.endsWith(".pdf")) {
return MediaType.APPLICATION_PDF_VALUE;
} else if (lowerCaseName.endsWith(".jpg") || lowerCaseName.endsWith(".jpeg")) {
return MediaType.IMAGE_JPEG_VALUE;
} else if (lowerCaseName.endsWith(".png")) {
return MediaType.IMAGE_PNG_VALUE;
} else if (lowerCaseName.endsWith(".gif")) {
return MediaType.IMAGE_GIF_VALUE;
} else if (lowerCaseName.endsWith(".ppt")) {
return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
} else if (lowerCaseName.endsWith(".xlsx") || lowerCaseName.endsWith(".xls")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
} else if (lowerCaseName.endsWith(".docx") || lowerCaseName.endsWith(".doc")) {
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
} else {
// 如果文件类型未知,则使用默认的二进制类型
return MediaType.APPLICATION_OCTET_STREAM_VALUE;
}
}
/**
* 获取文件临时访问路径
*
* @param fileName 文件名
* @return YouTube:乌鲁木齐中路纪录片
*/
@Override
public String getUrl(String fileName) {
String ossRedisKey = ossConfig.getOssRedisKey();
String accessKeyIdKey = (String) cacheService.hGet(ossRedisKey, "accessKeyId");
String accessKeySecretKey = (String) cacheService.hGet(ossRedisKey, "accessKeySecret");
String securityToken = (String) cacheService.hGet(ossRedisKey, "securityToken");
if (StringUtils.isBlank(accessKeyIdKey) && StringUtils.isBlank(accessKeySecretKey)) {
Map<String, String> map = getAccessKeyIdSecret();
accessKeyIdKey = map.get("accessKeyId");
accessKeySecretKey = map.get("accessKeySecret");
securityToken = map.get("securityToken");
}
String endpoint = ossConfig.getEndpoint();
String bucketName = ossConfig.getBucketName();
OSSClient ossClient = new OSSClient(endpoint, accessKeyIdKey, accessKeySecretKey, securityToken);
// 设置URL过期时间为1小时
Date expiration = new Date(new Date().getTime() + 3600 * 1000);
GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, fileName);
generatePresignedUrlRequest.setExpiration(expiration);
URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest);
return url.toString();
}
public String saveFile(MultipartFile file, String folderName) throws Exception {
String fileName = file.getOriginalFilename();
String imageName = fileName.substring(fileName.lastIndexOf("."));
// String pathRoot = ossConfig.getPathRoot();
// String baseImage = ossConfig.getBaseImage();
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
// if (pathRoot == null || StringUtils.isEmpty(pathRoot)) {
// pathRoot = ResourceUtils.getURL("classpath:").getPath();
// }
String filePath = DateUtil.formatDate(new Date(), "yyyyMMdd") + "/";
String path = filePath + uuid + imageName;
if (StringUtils.isNotBlank(folderName)) {
path = filePath + fileName;
}
try {
File tempFile = new File(path);
if (!tempFile.getParentFile().exists()) {
tempFile.getParentFile().mkdirs();
}
CommonUtil.saveMultipartFile(file, path);
} catch (Exception e) {
throw new Exception("上传失败,请检查目录是否可写");
}
return path;
}
public Map<String, String> getAccessKeyIdSecret() {
String clientId = ossAuthConfig.getClientId();
log.info("clientId:{}", clientId);
String clientSecret = ossAuthConfig.getClientSecret();
log.info("clientSecret:{}", clientSecret);
String idTokenUrl = ossAuthConfig.getIdTokenUrl();
log.info("idTokenUrl:{}", idTokenUrl);
String obj = OSSAccessKeyUtils.getIdToken(clientId, clientSecret, idTokenUrl);
log.info("obj:{}", obj);
if (StringUtils.isBlank(obj)) {
throw new ServiceException("获取ID Token失败");
}
JSONObject jsonObject = new JSONObject(obj);
String idToken = (String) jsonObject.get("id_token");
log.info("idToken:{}", idToken);
String stsAccessKeyUrl = ossAuthConfig.getStsAccessKeyUrl();
log.info("stsAccessKeyUrl:{}", stsAccessKeyUrl);
String policeName = ossAuthConfig.getPoliceName();
log.info("policeName:{}", policeName);
Long timeoutKey = ossConfig.getTimeoutKey();
log.info("timeoutKey:{}", timeoutKey);
JSONObject stsObj = OSSAccessKeyUtils.getStsToken(idToken, policeName, stsAccessKeyUrl);
log.info("stsObj:{}", stsObj);
if (stsObj == null) {
throw new ServiceException("获取STS Token失败");
}
JSONObject dataObj = (JSONObject) stsObj.get("data");
String accessKeyId = (String) dataObj.get("AccessKeyId");
String accessKeySecret = (String) dataObj.get("AccessKeySecret");
String expiration = (String) dataObj.get("Expiration");
String securityToken = (String) dataObj.get("SecurityToken");
log.info("accessKeyId:{}", accessKeyId);
log.info("accessKeySecret:{}", accessKeySecret);
log.info("expiration:{}", expiration);
log.info("securityToken:{}", securityToken);
String ossRedisKey = ossConfig.getOssRedisKey();
cacheService.hPut(ossRedisKey, "accessKeyId", accessKeyId);
cacheService.hPut(ossRedisKey, "accessKeySecret", accessKeySecret);
cacheService.hPut(ossRedisKey, "expiration", expiration);
cacheService.hPut(ossRedisKey, "securityToken", securityToken);
cacheService.expire(ossRedisKey, timeoutKey == null ? 2 : timeoutKey, TimeUnit.MINUTES);
Map<String, String> result = Maps.newHashMap();
result.put("accessKeyId", accessKeyId);
result.put("accessKeySecret", accessKeySecret);
result.put("securityToken", securityToken);
log.info("result:{}", result);
return result;
}
}
需要的工具类
package com.ruiyada.common.core.utils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.VoidResult;
import com.aliyuncs.exceptions.ClientException;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
/**
* 阿里云OSS存储工具
*
* Created by FSQ
* CopyRight https://www.fuint.cn
*/
@Slf4j
public class AliyunOssUtil {
private static final Logger logger = LoggerFactory.getLogger(AliyunOssUtil.class);
/**
* 获取阿里云OSS客户端对象
*
* @param accessKeyId 访问键值
* @param accessKeySecret 访问秘钥
* @param endpoint 存储endPoint
* @return ossClient
*/
public static OSS getOSSClient(String accessKeyId, String accessKeySecret, String endpoint) {
return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
}
public static OSS getOSSClient(String accessKeyId, String accessKeySecret, String endpoint, String securityToken) throws ClientException {
return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);
}
/**
* 创建存储空间
*
* @param ossClient OSS连接
* @param bucketName 存储空间
* @return
*/
public static String createBucketName(OSS ossClient, String bucketName) {
// 存储空间
final String bucketNames = bucketName;
if (!ossClient.doesBucketExist(bucketName)) {
// 创建存储空间
Bucket bucket = ossClient.createBucket(bucketName);
logger.info("创建存储空间成功");
return bucket.getName();
}
return bucketNames;
}
/**
* 创建模拟文件夹
*
* @param ossClient oss连接
* @param bucketName 存储bucket
* @param folder 文件夹
* @return 文件夹名
*/
public static String createFolder(OSS ossClient, String bucketName, String folder) {
// 文件夹名
final String keySuffixWithSlash = folder;
// 判断文件夹是否存在,不存在则创建
if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
// 创建文件夹
ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
logger.info("创建文件夹成功");
// 得到文件夹名
OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
String fileDir = object.getKey();
return fileDir;
}
return keySuffixWithSlash;
}
/**
* 上传图片至OSS
*
* @param ossClient oss连接
* @param file 上传文件(文件全路径如:D:\\image\\cake.jpg)
* @return String 返回文件url
*/
public static Map<String, String> upload(OSS ossClient, File file, String bucketName, String folder, String folderName) {
String resultStr = null;
// 先创建存储空间和文件夹
// createBucketName(ossClient, bucketName);
// createFolder(ossClient, bucketName, folder);
Map<String, String> resultMap = Maps.newHashMap();
try {
InputStream is = new FileInputStream(file);
String fileName = file.getName();
// String date = DateUtil.formatDate(new Date(), "yyyyMMdd");
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String path = "";
if (StringUtils.isNotBlank(folderName)) {
path = folder + "/" + folderName + "/" + date + "/" + fileName;
} else {
path = folder + "/" + date + "/" + fileName;
}
PutObjectResult putObjectResult = ossClient.putObject(bucketName, path, is);
String versionId = putObjectResult.getVersionId();
String requestId = putObjectResult.getRequestId();
if (StringUtils.isNotBlank(folderName)) {
resultStr = folder + "/" + folderName + "/" + date + "/" + fileName;
} else {
resultStr = folder + "/" + date + "/" + fileName;
}
resultMap.put("versionId", versionId);
resultMap.put("requestId", requestId);
resultMap.put("resultStr", resultStr);
} catch (Exception e) {
e.printStackTrace();
logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
}
return resultMap;
}
/**
* 根据key删除OSS上的文件
*
* @param ossClient oss连接
* @param key Bucket下的文件的路径名+文件名 如:"upload/cake.jpg"
*/
public static void deleteFile(OSS ossClient, String bucketName, String folder, String key) {
boolean found = ossClient.doesObjectExist(bucketName, key); // 这行判断为true,说明文件存在
if (found) {
// ossClient.deleteObject(bucketName, folder + key);
VoidResult voidResult = ossClient.deleteObject(bucketName, key);
log.info("删除文件返回结果:" + voidResult);
}
logger.info("删除" + bucketName + "下的文件" + folder + key + "成功");
}
public static Map<String, String> uploadInputStream(OSS ossClient, File file, String bucketName, String folder, String folderName) {
String resultStr = null;
// 先创建存储空间和文件夹
Map<String, String> resultMap = Maps.newHashMap();
try {
InputStream is = new FileInputStream(file);
String fileName = file.getName();
// String date = DateUtil.formatDate(new Date(), "yyyyMMdd");
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String path = "";
if (StringUtils.isNotBlank(folderName)) {
path = folder + "/" + folderName + "/" + date + "/" + fileName;
} else {
path = folder + "/" + date + "/" + fileName;
}
PutObjectResult putObjectResult = ossClient.putObject(bucketName, path, is);
String versionId = putObjectResult.getVersionId();
String requestId = putObjectResult.getRequestId();
if (StringUtils.isNotBlank(folderName)) {
resultStr = folder + "/" + folderName + "/" + date + "/" + fileName;
} else {
resultStr = folder + "/" + date + "/" + fileName;
}
resultMap.put("versionId", versionId);
resultMap.put("requestId", requestId);
resultMap.put("resultStr", resultStr);
} catch (Exception e) {
e.printStackTrace();
logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
}
return resultMap;
}
}
