SpringBoot整合OSS文件上传
一、注册阿里云账号并开通OSS服务
1、登录阿里云账号

2、创建一个bucket

3、创建子用户

对自用户分配权限,打开操作OSS的全部权限(也可根据业务需求进行更改)

4、配置上传跨域规则
- 任何来源: *
- 允许方法: POST
- 任何请求头Headers: *

二、文件上传方式
1、服务器直传方式
每个OSS的用户都会用到上传服务。Web端常见的上传方法是用户在浏览器或App端上传文件到应用服务器,应用服务器再把文件上传到OSS
和数据直传到OSS相比,以上方法有三个缺点:
- 上传慢:用户数据需先上传到到应用服务器,之后再上传到OSS。网络传输时间比直传到OSS多一倍。如果用于数据不通过应用服务器中转,而是直传到OSS,速度将大大提升。而且OSS采用BGP带宽,能保证各地各运营商之间的传输速度
- 扩展性差:如果后续用户多了,应用服务器会成为瓶颈
- 费用高:需要准备多台应用服务器。由于OSS上传流量是免费的,如果数据直传到OSS,不通过应用服务器,那么将能省下几台应用服务器
2、服务端签名后前端直传
Web前端服务端请求签名,然后前端(Vue)直接上传,不会对服务端产生压力,而且安全可靠。
相关资料:服务端签名直传并设置上传回调概述
Java连接实例:Java实践OSS

上传回调流程

- Web前端请求应用服务器,获取上传所需参数(如OSS的accessKeyId、policy、callback等参数)
- 应用服务器返回相关参数
- Web前端直接向OSS服务发起上传文件请求
- 等上传完成后OSS服务会回调应用服务器的回调接口
- 应用服务器返回响应给OSS服务
- OSS服务将应用服务器回调接口的内容返回给Web前端
3、SpringBoot整合OSS实现文件上传
1、在pom.xml中添加相关依赖
<dependency><groupId>com.aliyun.ossgroupId><artifactId>aliyun-sdk-ossartifactId><version>3.10.2version>
dependency>
2、修改SpringBoot配置文件

#操作oss需要的一些参数
aliyun:oss:accessKeyId: xxx # 阿里云的accessKeyIdaccessKeySecret: xxx # accessKey 密码endPoint: xxx # Endpoint:在阿里云oss控制台查看自己使用的endpoint,eg: oss-cn-shanghai.aliyuncs.com bucketName: xxx # bucket 名称policy:expire: 300 # 签名有效期(S)maxSize: 10 # 上传文件大小(M)callback: http://localhost:8080/aliyun/oss/callback # 文件上传成功后的回调地址dir:prefix: xxx/images/ # 上传文件夹路径前缀
3、添加OSS的相关Java配置
用于配置OSS的连接客户端的OSSClient
/*** TODO 用于配置OSS的连接客户端OSSClient** @author ss_419* @version 1.0* @date 2023/5/28 19:04*/
@Configuration
@Component
public class OssConfig {@Value("${aliyun.oss.endpoint}")private String ALIYUN_OSS_ENDPOINT;@Value("${aliyun.oss.accessKeyId}")private String ALIYUN_OSS_ACCESSKEYID;@Value("${aliyun.oss.accessKeySecret}")private String ALIYUN_OSS_ACCESSKEYSECRET;@Beanpublic OSSClient ossClient() {return new OSSClient(ALIYUN_OSS_ENDPOINT, ALIYUN_OSS_ACCESSKEYID, ALIYUN_OSS_ACCESSKEYSECRET);}
}
4、封装前端上传策略返回对象
前端直传时所需要的参数
package org.pp.oss.model;/*** TODO 获取OSS上传文件授权返回结果** @author ss_419* @version 1.0* @date 2023/5/28 19:07*/
public class OssPolicyResult {private String accessKeyId;
// @ApiModelProperty("用户表单上传的策略,经过base64编码过的字符串") 13private String policy;
// @ApiModelProperty("对policy签名后的字符串") 15private String signature;
// @ApiModelProperty("上传文件夹路径前缀") 17private String dir;
// @ApiModelProperty("oss对外服务的访问域名") 19private String host;
// @ApiModelProperty("上传成功后的回调设置")private String callback;
// 忽略getter、setter方法
}
5、封装上传成功回调参数对象
当OSS上传成功后,会根据该配置参数来回调对应接口
package org.pp.oss.model;/*** TODO oss上传成功后的回调参数** @author ss_419* @version 1.0* @date 2023/5/28 19:10*/
public class OssCallbackParam {//请求的回调地址private String callbackUrl;//回调是传入request中的参数private String callbackBody;//回调时传入参数的格式,比如表单提交形式private String callbackBodyType;public String getCallbackUrl() {return callbackUrl;}public void setCallbackUrl(String callbackUrl) {this.callbackUrl = callbackUrl;}public String getCallbackBody() {return callbackBody;}public void setCallbackBody(String callbackBody) {this.callbackBody = callbackBody;}public String getCallbackBodyType() {return callbackBodyType;}public void setCallbackBodyType(String callbackBodyType) {this.callbackBodyType = callbackBodyType;}
}
6、封装上传成功后回调结果对象
回调接口中返回的数据对象,封装了上传文件的信息
/*** TODO oss上传文件的回调结果** @author ss_419* @version 1.0* @date 2023/5/28 19:14*/
public class OssCallbackResult {private String filename;// 文件名称private String size;// 文件大小private String mimeType;// 文件的mimeTypeprivate String width;// 图片文件的宽private String height;// 图片文件的高
// 忽略getter、setter方法
}
7、添加OSS业务接口OssService
/*** TODO oss上传管理Service** @author ss_419* @version 1.0* @date 2023/5/28 19:16*/
public interface OssService {/*** oss上传策略生成* @return*/OssPolicyResult policy();/*** oss上传成功回调* @param request* @return*/OssCallbackResult callback(HttpServletRequest request);
}
8、OssService实现类
package org.pp.oss.service.impl;/*
package org.pp.oss.service.impl;import org.pp.oss.model.OssCallbackResult;
import org.pp.oss.model.OssPolicyResult;
import org.pp.oss.service.OssService;import javax.servlet.http.HttpServletRequest;*/import cn.hutool.json.JSONUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.pp.oss.model.OssCallbackParam;
import org.pp.oss.model.OssCallbackResult;
import org.pp.oss.model.OssPolicyResult;
import org.pp.oss.service.OssService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;/*** TODO** @author ss_419* @version 1.0* @date 2023/5/28 19:17*/
@Service
public class OssServiceImpl implements OssService {private static final Logger LOGGER = LoggerFactory.getLogger(OssServiceImpl.class);@Value("${aliyun.oss.policy.expire}")private int ALIYUN_OSS_EXPIRE;@Value("${aliyun.oss.maxSize}")private int ALIYUN_OSS_MAX_SIZE;@Value("${aliyun.oss.callback}")private String ALIYUN_OSS_CALLBACK;@Value("${aliyun.oss.bucketName}")private String ALIYUN_OSS_BUCKET_NAME;@Value("${aliyun.oss.endpoint}")private String ALIYUN_OSS_ENDPOINT;@Value("${aliyun.oss.dir.prefix}")private String ALIYUN_OSS_DIR_PREFIX;@Autowiredprivate OSSClient ossClient;/*** 签名生成** @return*/@Overridepublic OssPolicyResult policy() {OssPolicyResult result = new OssPolicyResult();// 存储目录SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");String baseDir = ALIYUN_OSS_DIR_PREFIX + sdf.format(new Date());// 签名有效期long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;Date expiration = new Date(expireEndTime);// 文件大小long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 *1024;// 回调地址OssCallbackParam callback = new OssCallbackParam();callback.setCallbackUrl(ALIYUN_OSS_CALLBACK);callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");callback.setCallbackBody("application/x-www-form-urlencoded");// 提交节点String action = "https://" + ALIYUN_OSS_BUCKET_NAME + "." + ALIYUN_OSS_ENDPOINT;try {PolicyConditions policyConds = new PolicyConditions();policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,0,maxSize);policyConds.addConditionItem(MatchMode.StartWith,PolicyConditions.COND_KEY, baseDir);String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);byte[] binaryData = postPolicy.getBytes("utf-8");String policy = BinaryUtil.toBase64String(binaryData);String signature = ossClient.calculatePostSignature(postPolicy);String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes("UTF-8"));// 返回结果result.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());result.setPolicy(policy);result.setSignature(signature);result.setDir(baseDir);result.setCallback(callbackData);result.setHost(action);} catch (Exception e) {LOGGER.error("签名生成失败{e}", e);}return result;}@Overridepublic OssCallbackResult callback(HttpServletRequest request) {OssCallbackResult result = new OssCallbackResult();String filename = request.getParameter("filename");filename = "http://".concat(ALIYUN_OSS_BUCKET_NAME).concat(".").concat(ALIYUN_OSS_ENDPOINT).concat("/").concat(filename);result.setFilename(filename);result.setSize(request.getParameter("size"));result.setMimeType(request.getParameter("mimeType"));result.setHeight(request.getParameter("height"));result.setWidth(request.getParameter("width"));return result;}}
9、定义OssController接口
package org.pp.oss.controller;import cn.hutool.json.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.pp.oss.model.OssCallbackResult;
import org.pp.oss.model.OssPolicyResult;
import org.pp.oss.service.OssService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;/*** TODO Oss相关操作接口** @author ss_419* @version 1.0* @date 2023/5/28 20:43*/
@RestController
@RequestMapping("/aliyun/oss")
@CrossOrigin
public class AliyunOssController {@Autowiredprivate OssService ossService;@CrossOrigin@RequestMapping("/policys")public Map<String,String> policysMap(){// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。String accessId = "xxx";String accessKey = "xxx";// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。String endpoint = "oss-cn-shanghai.aliyuncs.com";// 填写Bucket名称,例如examplebucket。String bucket = "xxx";// 填写Host地址,格式为https://bucketname.endpoint。String host = "https://" + bucket + "."+ endpoint;// 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。// String callbackUrl = "https://192.168.0.0:8888";// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");String formatData = dateFormat.format(new Date());String dir = "osstest/"+formatData+ "/";// 创建ossClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);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);Map<String, String> 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));return respMap;// respMap.put("expire", formatISO8601Date(expiration));// 回调数据
// JSONObject jasonCallback = new JSONObject();
// jasonCallback.put("callbackUrl", callbackUrl);
// jasonCallback.put("callbackBody",
// "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
// jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
// String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
// respMap.put("callback", base64CallbackBody);
//
// JSONObject ja1 = JSONObject.fromObject(respMap);
// // System.out.println(ja1.toString());
// response.setHeader("Access-Control-Allow-Origin", "*");
// response.setHeader("Access-Control-Allow-Methods", "GET, POST");
// response(request, response, ja1.toString());} catch (Exception e) {// Assert.fail(e.getMessage());System.out.println(e.getMessage());}return null;}/*** oss上传签名生成* @return*/@CrossOrigin@RequestMapping("/policy")public OssPolicyResult policy(){OssPolicyResult result = ossService.policy();System.out.println("result = " + result);return result;}/*** oss上传成功回调* @return*/@RequestMapping("/callback")public OssCallbackResult callback(HttpServletRequest request){OssCallbackResult callback = ossService.callback(request);System.out.println("callback = " + callback);return callback;}}
对接口进行测试,如下图所示,请求返回了oss文件上传时所需的对应参数

4、Vue文件上传测试代码
这里为了更加方便快捷的进行文件上传接口的测试,我选择使用Vue+Element-Ui来搭建一个简单的上传案例
1、创建Vue项目
在控制台中输入vue ui,启动vue项目图形管理界面

访问http://localhost:8000 ,进入如下图操作界面即代表启动成功

找到项目管理器,创建一个新Vue项目




这里选择Vue2版本

创建成功后添加本次案例所需要的依赖:
- axios:用于对后端服务发起Ajax请求
- element-ui:本案例使用到该ui组件库中的Upload,用于文件上传
在Vue项目中的main.js中启用对应依赖
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import axios from "axios";
import VueAxios from "vue-axios";
import router from './router'
import store from './store'Vue.config.productionTip = false
// Vue.use(axios)
Vue.use(VueAxios,axios)
Vue.use(ElementUI);
new Vue({router,store,render: function (h) { return h(App) }
}).$mount('#app')
创建OssUpload组件,该组件可以在项目中引用
<template><el-uploadclass="upload-demo":action="objData.host":before-upload="ossPolicy":data="objData":file-list="fileList"list-type="picture"><el-button size="small" type="primary">点击上传</el-button><div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div></el-upload>
</template><script>
export default {data() {return {fileList: [],objData: {OSSAccessKeyId: '',policy: '',signature: '',key: '',host: '',dir: ''}};},methods: {ossPolicy(file) {let _self = this;// 在上传前 进行服务器签名return new Promise((resolve, reject) => {this.axios.get("http://localhost:8080/aliyun/oss/policy").then(response => {console.log(response)_self.objData.OSSAccessKeyId = response.data.accessKeyId_self.objData.policy = response.data.policy_self.objData.signature = response.data.signature_self.objData.dir = response.data.dir_self.objData.host = response.data.host+''_self.objData.key = response.data.dir + "${filename}"resolve(true) // 继续上传}).catch(error => {console.log(error)reject(false)})})}}
}
</script><style></style>
在HelloWorld.vue中引用文件上传组件
```js
<template><div class="hello"><h1>{{ msg }}</h1><OssUpload></OssUpload></div>
</template><script>
// 引用组件
import OssUpload from "@/components/OssUpload.vue";
export default {name: 'HelloWorld',components: {OssUpload},props: {msg: String}
}
</script>
<style ></style>
前后端联调
-
启动后端服务

-
启动前端项目

选择文件进行上传,如下图所示即表示上传成功

查看对应的OSSBucket,图片已成功存储至OSS服务中

项目地址
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
