1.概要
OSS(Object Storage Service),即对象存储服务,官方解释是使用HTTP API存储和检索非结构化数据(非结构化的静态资源,如图片、音频、视频、日志文件等)和元数据对象的工具,这里提到的对象是费静态。通俗说就是一个资源托管的地方,将系统所要用的文件上传到云硬盘上,该云硬盘提供了文件下载、上传等一列服务,这样的服务以及技术可以统称为OSS。总的来说,OSS就是集存储与访问于一身的资源对象托管服务,用于存储静态资源,同时还提供备份、容灾等常见功能。常见的提供OSS服务的厂商有阿里云、华为云等
2.OSS相关术语
1.桶(bucket)
用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。
2.对象
对象是 OSS 存储数据的基本单元,也被称为OSS的文件。对象由元信息(Object Meta)、用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的Key来标识。
3.地域
地域表示 OSS 的数据中心所在物理位置。您可以根据费用、请求来源等综合选择数据存储的地域。详情请查看OSS已经开通的Region。
4.访问域名(Endpoint)
Endpoint 表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。具体的内容请参见各个Region对应的Endpoint。
5.访问密钥(AccessKey)
简称AK,指的是访问身份验证中用到的AccessKeyId和AccessKeySecret。OSS通过使用AccessKeyId和AccessKeySecret对称加密的方法来验证某个请求发送者的身份。AccessKeyId用来标识用户,AccessKeySecret用于加密签名字符串和OSS用来验证签名字符串的密钥,AccessKeySecret必须保密。
3.相关代码实现
1.加入依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
2.在application.yml(或properties)中进行OSS相关属性配置
aliyun:
# 阿里云OSS配置
oss:
endpoint: ${your_endpoint}
accessKeyId: ${your_accessKeyId}
accessKeySecret: ${your_accessKeySecret}
bucketName: ${your_bucketName}
#以上根据自身具体的OSS信息来进行填充
3.如何拿到OSS属性配置
在阿里云开通OSS服务时,会让你选择一个访问地域,哪个就是你的endpoint
成功开通后,去创建一个Bucket,自定义一个bucketName再点击右上角头像,在权限与安全中选择AccessKey
点击创建后得到专属你的唯一标识AccessKey,注意AccessKeySecret它只会显示一次,要及时保存,不然下次就要重新创建了
4.编写读取OSS配置类
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
@Data
public class AliOssProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
package com.zhan.Service;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectResult;
import com.zhan.Config.AliOssProperties;
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;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
/**
* @Author:zhan
* @Date:2024/8/23 16:03
*/
@Service
@Slf4j
public class FileService {
@Autowired
private AliOssProperties aliOssProperties;
public String upload(MultipartFile file){
String bucketName = aliOssProperties.getBucketName();
String endPoint = aliOssProperties.getEndpoint();
String accessKeyId = aliOssProperties.getAccessKeyId();
String accessKeySecret = aliOssProperties.getAccessKeySecret();
// 创建OSS对象
OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
//获取原生文件名
String originalFilename = file.getOriginalFilename();
//JDK8的日期格式
LocalDateTime time = LocalDateTime.now();
DateTimeFormatter dft = DateTimeFormatter.ofPattern("yyyy/MM/dd");
//拼装OSS上存储的路径
String folder = dft.format(time);
String fileName = generateUUID();
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
//在OSS上bucket下的文件名
String uploadFileName = "user/" + folder + "/" + fileName + extension;
try {
PutObjectResult result = ossClient.putObject(bucketName, uploadFileName, file.getInputStream());
//拼装返回路径
if (result != null) {
return "https://"+bucketName+"."+endPoint+"/"+uploadFileName;
}
} catch (IOException e) {
log.error("文件上传失败:{}",e.getMessage());
} finally {
//OSS关闭服务,不然会造成OOM
ossClient.shutdown();
}
return null;
}
/**
* 获取随机字符串
* @return
*/
private String generateUUID() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
/**
* 下载文件
* @param fileName 文件在OSS上的路径
* @param localFile 本地文件
*/
public void download(String fileName, File localFile) {
String bucketName = aliOssProperties.getBucketName();
String endPoint = aliOssProperties.getEndpoint();
String accessKeyId = aliOssProperties.getAccessKeyId();
String accessKeySecret = aliOssProperties.getAccessKeySecret();
// 创建OSS对象
OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
try {
ossClient.getObject(new GetObjectRequest(bucketName, fileName), localFile);
} catch (Exception e) {
log.error("文件下载失败:{}", e.getMessage());
} finally {
ossClient.shutdown();
}
}
/**
* 查看文件
* @param fileName 文件在OSS上的路径
* @return 文件输入流
*/
public InputStream view(String fileName) {
String bucketName = aliOssProperties.getBucketName();
String endPoint = aliOssProperties.getEndpoint();
String accessKeyId = aliOssProperties.getAccessKeyId();
String accessKeySecret = aliOssProperties.getAccessKeySecret();
// 创建OSS对象
OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
try {
OSSObject ossObject = ossClient.getObject(bucketName, fileName);
return ossObject.getObjectContent();
} catch (Exception e) {
log.error("文件查看失败:{}", e.getMessage());
} finally {
ossClient.shutdown();
}
return null;
}
/**
* 删除文件
* @param fileName 文件在OSS上的路径
*/
public void delete(String fileName) {
String bucketName = aliOssProperties.getBucketName();
String endPoint = aliOssProperties.getEndpoint();
String accessKeyId = aliOssProperties.getAccessKeyId();
String accessKeySecret = aliOssProperties.getAccessKeySecret();
// 创建OSS对象
OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
try {
ossClient.deleteObject(bucketName, fileName);
} catch (Exception e) {
log.error("文件删除失败:{}", e.getMessage());
} finally {
ossClient.shutdown();
}
}
}
5.编写控制类进行测试
@Api(tags = "文件上传")
@Slf4j
@RestController
@RequestMapping("/oss")
public class OSSController {
@Autowired
private FileService fileService;
/**
* 文件上传接口
* @param file
* @return
*/
@PostMapping("/upload")
@ApiOperation(value = "文件上传")
public Map<String, Object> upload(@RequestPart("file") MultipartFile file){
String imgFileStr = fileService.upload(file);
return buildResult(imgFileStr);
}
/**
* 测试返回拼装,根据公司自己封装的统一返回去写
* @param str
* @return
*/
private Map<String,Object> buildResult(String str){
Map<String, Object> result = new HashMap<>();
//判断字符串用lang3下的StringUtils去判断,这块我就不引入新的依赖了
if(str== null || "".equals(str)){
result.put("code",10000);
result.put("msg","图片上传失败");
result.put("data",null);
}else{
result.put("code",200);
result.put("msg","图片上传成功");
result.put("data",str);
}
return result;
}
}