今天码帮帮系统已经整合到上传项目案例的功能了,这里有一些图片资源需要上传,之前做项目对接过七牛云,也有使用过阿里云的视频点播服务,不过这次对接阿里云的OSS确实有点小尴尬,感觉文档不是很好对接,因为之前对接过七牛云,所以会有对接七牛云的流程在脑海里!按在七牛云的对接流程是服务端通过accessKeyId、accessKeySecret、endpoint得到签名,然后客户端根据签名上传,当然也有纯客户端的做法,但是作为一个服务端开发者,认为accessKeyId、accessKeySecret这些信息放在客户端,容易暴露出去,不是很安全,所以对接阿里云也是按照这种思路去做的,但是看了阿里云的OSS文档并没有找到这样的流程文档,可能是OSS体系太过庞大了,导致文档太多,没找到吧!那么本文将演示如何通过JAVA服务端生成签名,到VUE客户端上传图片的完整流程!
创建Bucket
注意地域,这玩意一定要记好,不然后面会有坑!那么到这里基本的就差不多了,后面还有跨域、在线预览问题,后面会单独讲!
导入依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.2.3</version>
</dependency>
编写阿里云OSS基本工具
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.aliyun.oss.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import java.io.File;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @description: 阿里云OSS工具
* 官方链接地址:https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1737.5f3e3bd36kleqs
* 公共云下OSS Region和Endpoint对照表:https://help.aliyun.com/document_detail/31837.htm?spm=a2c4g.11186623.0.0.7b6b2c20Qv3xQw#concept-zt4-cvy-5db
* 在线预览问题:https://help.aliyun.com/noticelist/articleid/1060057906.html
* @author TAO
* @date 2021/11/30 22:26
*/
@Slf4j
public class AliUtil {
private static String accessKeyId = "xxx";
private static String accessKeySecret = "xxx";
//公共云下OSS Region和Endpoint对照表:https://help.aliyun.com/document_detail/31837.htm?spm=a2c4g.11186623.0.0.7b6b2c20Qv3xQw#concept-zt4-cvy-5db
private static String endpoint = "oss-cn-beijing.aliyuncs.com";
/**
* 获取临时访问OSS签名 前端-用签名的方式上传文件
* @param bucketName
* @param dir bucket中的目录
* @return
*/
public static Map<String, String> getSignature(String bucketName, String dir) {
Map<String, String> respMap = new LinkedHashMap<>();
String endpointForSig = endpoint;
String host = "https://" + bucketName + "." + endpointForSig;
OSSClient client = new OSSClient(endpointForSig, accessKeyId, accessKeySecret);
try {
//设置过期时间为半小时1800L
long expireTime = 60 * 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
java.sql.Date expiration = new java.sql.Date(expireEndTime);
// PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
PolicyConditions policyConditions = new PolicyConditions();
policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
String postPolicy = client.generatePostPolicy(expiration, policyConditions);
byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = client.calculatePostSignature(postPolicy);
respMap.put("accessid", accessKeyId);
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) {
log.info("获取阿里云OSS签名失败===>{}", e.getMessage());
}
return respMap;
}
public static Map<String, String> getSignature(String bucketName) {
return getSignature(bucketName, "");
}
/**
* 上传文件
* @param bucketName
* @param fileName 文件名
* @param file 文件
*/
public static void uploadFile(String bucketName, String fileName, File file) {
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 上传文件
PutObjectResult putObjectResult = ossClient.putObject(bucketName, fileName, file);
String eTag = putObjectResult.getETag();
log.info("eTag===>", eTag);
// 关闭client
ossClient.shutdown();
}
/**
* 从OSS下载文件,将文件存储在项目tmp目录下,文件名是时间戳
* @param objectName objectName oss文件名
* @param bucketName 文件本地存储路径
* @return
*/
public static String downloadFileFromOSS(String objectName, String bucketName) {
String resource;
String OS = System.getProperty("os.name").toLowerCase();
if (OS.equals("linux")) {
resource = new ClassPathResource("/background/template_bg_image.jpg").getPath();
} else {
resource = AliUtil.class.getClassLoader().getResource("background/template_bg_image.jpg").getPath();
}
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 填写不包含Bucket名称在内的Object完整路径,例如testfolder/exampleobject.txt。
ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(resource));
ossClient.shutdown();
return resource;
}
/***
* 获取下载地址
*/
public static String getDownUrl(String key, String bucket) {
OSSClient client = new OSSClient(endpoint, accessKeyId, accessKeySecret);
//判断文件是否存在
// 设置URL过期时间为10年
Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 10 * 365);
// 生成URL
URL url = client.generatePresignedUrl(bucket, key, expiration);
client.shutdown();
String s = url.toString().substring(0, url.toString().indexOf("?"));
//生产环境中,OSS地址为内网地址,在此处转成外网地址
if (s.contains("-internal")) {
s = s.replace("-internal", "");
}
return s;
}
public static void main(String[] args) {
String bucketName = "你的bucketName";
File file = new File("C:\\Users\\Administrator\\Desktop\\test.png");
String fileName = "tttyyy.jpg";
Map<String, String> signature = AliUtil.getSignature(bucketName);
log.info("signature===>",signature.toString());
AliUtil.uploadFile(bucketName, fileName, file);
}
}
编写controller
@GetMapping("/getOssSignature")
@ApiOperation(value = "获取阿里云oss签名", authorizations = @Authorization(value = "token"))
public R getSkillByType(){
Map<String, String> signature = AliUtil.getSignature("你的bucketName");
return R.ok(signature);
}
请求测试
完成,这里也可自行测试java的main方法启动上传图片,亲测有效!
VUE这里直接使用element的el-upload作为上传组件!
el-upload
<el-upload class="upload-demo" drag list-type="picture-card" :on-preview="handlePictureCardPreview"
:on-remove="handleRemove" :http-request="fileUpload" action="https://jsonplaceholder.typicode.com/posts/"
multiple>el-upload>
其他代码
let axios = require('axios')
data(){
return{
dialogImageUrl: '',
dialogVisible: false
}
},
methods:{
handleRemove (file, fileList) {
console.log(file, fileList)
},
handlePictureCardPreview (file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
}
}
核心代码
fileUpload(param){
let file = param.file // 得到文件的内容
console.log("===>",file);
getOssSignature().then(res =>{
console.log("res===>",res);
let sendData = new FormData();
sendData.append('OSSAccessKeyId', res.accessid);
sendData.append('policy', res.policy);
sendData.append('Signature', res.signature);
sendData.append('keys', res.dir);
sendData.append('key',file.name)
sendData.append('success_action_status', 200) // 指定返回的状态码
sendData.append('file', file)
axios.post(res.host, sendData).then(() => {
console.log('得到上传到阿里云的图片地址: ' + res.host+file.name)
})
}).catch(err =>{
console.error("获取签名失败!!!")
});
}
那么到这里VUE客户端代码就完成了!但是还有两个问题,一个是跨域如下!
另一个是在线预览,如下