Spring Boot 应用中常常会遇到存储或处理大量文件的情况,这些文件一般不会存储在服务器本地,因为这样做的话不便于管理和分发。所以一般采用对象存储的方式进行保存。
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。
本文中采用 阿里云对象存储(OSS) 做示例,讲解 Spring 整合 OSS 相关问题。 阿里云OSS文档参考
开始前先要使用 阿里云 的账号购买 OSS 服务。获取 ossAccessKeyId 和 ossAccessKeySecret 。
首先,pom.xml 加入 SDK 依赖:
<!-- 阿里云 对象存储OSS SDK -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
</dependency>
然后编写 OSS 类 OSSClientUtil.java
@Slf4j
@Component
public class OSSClientUtil {
private static final String ossAccessKeyId = "<yourAccessKeyId>";
private static final String ossAccessKeySecret = "<yourAccessKeySecret>";
private static final String ossEndpoint = "http://oss-cn-shenzhen.aliyuncs.com";
private static final String ossBucketName = "<youBucketName>";
private OSSClient ossClient;
private final FileUtil fileUtil;
@Autowired
public OSSClientUtil(FileUtil fileUtil) {
ossClient = new OSSClient(ossEndpoint, ossAccessKeyId, ossAccessKeySecret);
this.fileUtil = fileUtil;
}
/**
* 初始化
*/
public void init() {
ossClient = new OSSClient(ossEndpoint, ossAccessKeyId, ossAccessKeySecret);
}
/**
* 销毁
*/
public void destory() {
ossClient.shutdown();
}
}
然后编写上传文件代码
/**
* 上传到OSS服务器 如果同名文件会覆盖服务器上的
*
* @param instream 文件流
* @param fileName 文件名称 包括后缀名
* @return 出错返回"" ,唯一MD5数字签名
*/
public String uploadFile2OSS(InputStream instream, String fileName) {
String ret = "";
try {
//创建上传Object的Metadata
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(instream.available());
objectMetadata.setCacheControl("no-cache");
objectMetadata.setHeader("Pragma", "no-cache");
objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
objectMetadata.setContentDisposition("inline;filename=" + fileName);
//上传文件
PutObjectResult putResult = ossClient.putObject(ossBucketName, fileName, instream, objectMetadata);
ret = putResult.getETag();
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
try {
if (instream != null) {
instream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return ret;
}
如果单纯上传图片则可以使用如下两个函数:
/**
* 上传图片
*
* @param base64 图片base64(含URI)
* @param fileName 文件名头部
* @return 文件名
*/
public String uploadImg2Oss(String base64, String fileName) {
// base64 转 File
MultipartFile file = fileUtil.base64ToMultipart(base64);
String originalFilename = file.getOriginalFilename();
String name = fileName + originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
try {
InputStream inputStream = file.getInputStream();
this.uploadFile2OSS(inputStream, name);
return name;
} catch (Exception e) {
log.error("图片上传失败");
return null;
}
}
/**
* Description: 判断OSS服务文件上传时文件的contentType
*
* @param FilenameExtension 文件后缀
* @return String
*/
public String getcontentType(String FilenameExtension) {
if (FilenameExtension.equalsIgnoreCase(".bmp")) {
return "image/bmp";
}
if (FilenameExtension.equalsIgnoreCase(".gif")) {
return "image/gif";
}
if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
FilenameExtension.equalsIgnoreCase(".jpg") ||
FilenameExtension.equalsIgnoreCase(".png")) {
return "image/jpeg";
}
if (FilenameExtension.equalsIgnoreCase(".html")) {
return "text/html";
}
if (FilenameExtension.equalsIgnoreCase(".txt")) {
return "text/plain";
}
if (FilenameExtension.equalsIgnoreCase(".vsd")) {
return "application/vnd.visio";
}
if (FilenameExtension.equalsIgnoreCase(".pptx") ||
FilenameExtension.equalsIgnoreCase(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (FilenameExtension.equalsIgnoreCase(".docx") ||
FilenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (FilenameExtension.equalsIgnoreCase(".xml")) {
return "text/xml";
}
return "image/jpeg";
}
最后是获得 URL 方式:
/**
* 获得url链接
*
* @param key
* @return url
*/
public String getUrl(String key) {
// 设置URL过期时间为10年 3600l* 1000*24*365*10
Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
// 生成URL
URL url = ossClient.generatePresignedUrl(ossBucketName, key, expiration);
if (url != null) {
return url.toString();
}
return null;
}
编写测试代码如下:
@PostMapping(value = "/uploadImg")
@ApiOperation(value = "上传图片到OSS")
public String uploadImg(@RequestBody ImageDto dto) {
String[] imgs = dto.getImg().split(",");
if (imgs.length != 2) return "图片需要含URI";
String fileName = "Temp/" + "uploadImgTest-" + UUID.randomUUID().toString().replaceAll("-", "");
String name = ossClientUtil.uploadImg2Oss(dto.getImg(), fileName);
String imgUrl = ossClientUtil.getImgUrl(name);
if (Strings.isNullOrEmpty(imgUrl) || !imgUrl.contains("?")) return "图片保存错误";
String[] imgUrls = imgUrl.split("[?]");
return "上传成功,图片链接: \n" + imgUrls[0];
}
@PostMapping(value = "uploadFile")
@ApiOperation(value = "上传文件到OSS")
public String uploadFile(@ApiParam(value = "上传文件", required = true) MultipartFile file) throws Exception {
String fileName = file.getOriginalFilename().toLowerCase();
String suffix = fileName.substring(fileName.lastIndexOf('.'));
String name = "Temp/" + UUID.randomUUID().toString().replaceAll("-", "") + suffix;
String fileUrl;
ossClientUtil.uploadFile2OSS(file.getInputStream(), name);
if (Strings.isNullOrEmpty(name)) return "上传失败";
fileUrl = ossClientUtil.getUrl(name);
if (!fileUrl.startsWith("http")) return "获取失败";
return "文件上传:\n" + fileUrl.substring(0, fileUrl.indexOf('?'));
}
@GetMapping(value = "/downloadImg")
@ApiOperation(value = "下载图片")
public String downloadImg(String imgUrl) {
String uri = "data:" + ossClientUtil.getcontentType(imgUrl.substring(imgUrl.lastIndexOf("."))) + ";base64,";
String a = uri + imageUtils.image2Base64(imgUrl); // 稳定
return "原图转base64: \n" + a;
}
测试:
上传图片:
上传文件:
下载图片:
PS:本站的 图片/Base64 转换地址 http://www.wuguangnuo.cn/tool/img2base64