一、普通上传方式
流程:前端提交上传请求-> gateway -> 转发到上传服务 -> 上传服务将图片流数据传入给对象存储OSS -> OSS 返回一个地址给上传服务 -> 上传服务返回OSS图片存储地址
缺点:经过服务器,效率减低
优点:相对安全
二、服务端签名后直传OSS(推荐)
流程: 首先把OSS的账号密码存在自己服务器中 -->
前端向服务器要到一个Policy -->
服务器利用阿里云的账号密码生成一个 防伪签名(包含访问阿里云的授权令牌,以及要上传阿里云的哪个地址等信息) -->
前端带着 防伪签名 + 带着被上传的文件,上传给阿里云OSS- -->
阿里云验证防伪签名是否正确,正确,上传,失败,不能上传。
三、上传图片代码
(1) 原生API
第一步:导入sdk依赖
<dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.10.2</version> </dependency>
第二步:创建上传类
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import java.io.FileInputStream;
import java.io.InputStream;
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "exampledir/exampleobject.txt";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "D:\\localpath\\examplefile.txt";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
InputStream inputStream = new FileInputStream(filePath);
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, inputStream);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
(2)利用SpringCloud Alibaba-OSS对象存储
SpringCloud Alibaba-OSS地址 https://github.com/alibaba/spring-cloud-alibaba
第一步:引入对象存储的starter
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alicloud-oss</artifactId> <version>2.2.0.RELEASE</version> </dependency>
第二步: 配置yml文件
spring:
cloud:
alicloud:
access-key: LTAIdfd5tJdfrG88cuzdsfsdfmgnSeGcLoW
secret-key: DISbdflFkdHW3VsadfnO5gEqgu5Xl0ETrWp7
oss:
endpoint: oss-cn-beijing.aliyuncs.com
第三步:测试使用
@Autowired
private OSSClient ossClient;
@Test
public void testUpload2(){
try {
InputStream inputStream = new FileInputStream("C:\\Users\\詹姆斯李\\Pictures\\1.jpg");
// 创建PutObject请求。
ossClient.putObject("gulimail-2022-7-2", "1.png", inputStream);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
System.out.println("图片上传成功");
}
四、服务端签名后直传OSS的实战
1、拿到后端OSS的签名
// 填写Bucket名称,例如examplebucket。
String bucket = "gulimail-2022-7-2";
// 填写Host地址,格式为https://bucketname.endpoint。
String host = "https:" + bucket + "." + endpoint;
String format = new SimpleDateFormat("yyyy-MM-dd").format(new java.util.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("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));
} catch (Exception e) {
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
}
return respMap;
}
2、前端带着返回的签名,把图片存储到阿里云OSS