
文件存储大致分为以上三种方式:普通文件上传,普通文件的分布式情况,文件存储服务。
普通文件上传: 单体应用或小项目可以部署在一个服务器上,浏览器发送上传文件的请求将文件存储在项目中的某个位置,如下次要用到此文件浏览器可以发送请求给服务器,服务器返回此文件进行展示。
普通文件的分布式情况: 分布式情况下,商品服务分布在不同的服务器上。若只将文件存储在A服务器中,下次浏览器的请求被负载均衡到B服务器,则浏览器访问不到文件。
文件存储服务: 无论浏览器发到那个服务进行文件上传,最终将上传的文件统一存储在文件存储系统中例如自建的服务器,云存储服务(阿里云,七牛云等)。本文记录阿里云对象存储服务OSS相关知识。
存储类型(Storage Class)
OSS提供标准、低频访问、归档、冷归档四种存储类型,全面覆盖从热到冷的各种数据存储场景。其中标准存储类型提供高持久、高可用、高性能的对象存储服务,能够支持频繁的数据访问;低频访问存储类型适合长期保存不经常访问的数据(平均每月访问频率1到2次),存储单价低于标准类型;归档存储类型适合需要长期保存(建议半年以上)的归档数据;冷归档存储适合需要超长时间存放的极冷数据。更多信息,请参见存储类型介绍。
存储空间(Bucket)
存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。您可以根据实际需求,创建不同类型的存储空间来存储不同的数据。
对象(Object)
对象是OSS存储数据的基本单元,也被称为OSS的文件。对象由元信息(Object Meta)、用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的Key来标识。对象元信息是一组键值对,表示了对象的一些属性,例如最后修改时间、大小等信息,同时您也可以在元信息中存储一些自定义的信息。
地域(Region)
地域表示OSS的数据中心所在物理位置。您可以根据费用、请求来源等选择合适的地域创建Bucket。更多信息,请参见OSS已开通的地域。
访问域名(Endpoint)
Endpoint表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。更多信息,请参见各个Region对应的Endpoint。
访问密钥(AccessKey)
AccessKey简称AK,指的是访问身份验证中用到的AccessKey ID和AccessKey Secret。OSS通过使用AccessKey ID和AccessKey Secret对称加密的方法来验证某个请求的发送者身份。AccessKey ID用于标识用户;AccessKey Secret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,必须保密。关于获取AccessKey的方法,请参见获取AccessKey。
使用过程:

<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.5.0</version>
</dependency>
@Test
public void testUpload() throws FileNotFoundException {
//endPoint以杭州为例 其他Region请按实际情况填写
String endPoint = "oss-cn-hangzhou.aliyuncs.com";
//云账号AccessKey所有API访问权限 建议遵循阿里云安全最佳实践创建并适用 RAM子账号进行API访问或日常运维
String accessKeyId = "LTAI5t7r1Aw5ndBsVy55R46m";
String accessKeySecret = "ZjZEnr5QVeCrrZ2vstdEKm4y5Xdd21";
//创建OSSClient实例
OSS ossClient = new OSSClientBuilder().build(endPoint,accessKeyId,accessKeySecret);
//文件流上传
InputStream inputStream = new FileInputStream("C:\\Users\\Administrator.DESKTOP-UJHR16T\\Pictures\\I\\IMG_4909(20210220-081040).JPG");
ossClient.putObject("gulimall-hello-11","Ha.JPG",inputStream);
System.out.println("上传完成!");
//oss客户端关闭
ossClient.shutdown();
}


<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
spring:
cloud:
alicloud:
access-key: LTAI5t7r1Aw5ndBsVy55R4hhh
secret-key: ZjZEnr5QVeCrrZ2vstdEKm4y5Xdsa
oss:
endPoint: oss-cn-hangzhou.aliyuncs.com
@Autowired
private OSSClient ossClient;
@Test
public void testUpload() throws FileNotFoundException {
//文件流上传
InputStream inputStream = new FileInputStream("C:\\Users\\Administrator.DESKTOP-UJHR16T\\Pictures\\Camera Roll\\IMG_6254.JPG");
ossClient.putObject("gulimall-hello-1128","shuai.JPG",inputStream);
System.out.println("上传完成!");
//oss客户端关闭
ossClient.shutdown();
}


gulimall-third-party 第三方服务作为整个项目文件上传服务,若为每个微服务创建文件存储功能,都使用OSS对象存储服务则过于繁琐,只需创建gulimall-third-party 第三方服务即可。
4.1.1 导入依赖
<!--springcloud-alibababa的oss依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--openfeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
4.1.2 编写配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
alicloud:
access-key: LTAI5t7r1Aw5ndBsVy55R4dsa
secret-key: ZjZEnr5QVeCrrZ2vstdEKm4y5Xdas1
oss:
endPoint: oss-cn-hangzhou.aliyuncs.com
bucket: gulimall-hello-1128
application:
name: gulimall-third-party
server:
port: 30000
spring.application.name=gulimall-third-party
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=1d48db76-7f24-4cd2-b671-8a0ee2esda1
spring.cloud.nacos.config.ext-config[0].data-id=oss.yml
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[0].refresh=true
4.1.3 编写代码
@RestController
public class OssController {
@Autowired
OSS ossClient;
@Value("${spring.cloud.alicloud.oss.endpoint}")
private String endpoint;
@Value("${spring.cloud.alicloud.oss.bucket}")
private String bucket;
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
@RequestMapping("/oss/policy")
public R policy() {
//https://gulimall-hello-1128.oss-cn-hangzhou.aliyuncs.com/hahaha.jpg
String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
// callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
//String callbackUrl = "http://88.88.88.88:8888";
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format + "/"; // 用户上传文件时指定的前缀。
Map<String, String> respMap = null;
try {
long expireTime = 30;
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(StandardCharsets.UTF_8);
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
respMap = new LinkedHashMap<String, String>();
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));
// respMap.put("expire", formatISO8601Date(expiration));
} catch (Exception e) {
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
}
return R.ok().put("data",respMap);
}
}