SpringBoot integrates OSS file upload

1. Register an Alibaba Cloud account and activate the OSS service

1. Log in to the Alibaba Cloud account
image
2. Create a bucket
image
3. Create a sub-user
image
Assign permissions to self-users and open all permissions to operate OSS (can also be changed according to business needs)
image
4. Configure and upload cross-domain rules

  • Any source: *
  • Allowed method: POST
  • Any request header Headers: *

image

2. File upload method

1. Server direct transmission method

Every OSS user will use the upload service. The common upload method on the web side is that the user uploads the file to the application server through the browser or the App side, and the application server then uploads the file to the OSS. image
Compared with directly uploading the data to the OSS, the above method has three disadvantages:

  • Slow upload: user data needs to be uploaded to the application server first, and then uploaded to OSS. The network transmission time is twice as long as that of direct transmission to OSS. If the data is not transferred through the application server, but directly transmitted to the OSS, the speed will be greatly improved. Moreover, OSS adopts BGP bandwidth, which can guarantee the transmission speed between various operators in various places
  • Poor scalability: If there are more subsequent users, the application server will become a bottleneck
  • High cost: Multiple application servers need to be prepared. Since OSS upload traffic is free, if the data is directly transmitted to OSS without passing through the application server, several application servers will be saved

2. After the server-side signature, the front-end direct transmission

The web front-end server requests a signature, and then the front-end (Vue) uploads directly, which will not put pressure on the server, and is safe and reliable.
Related information: Overview of server-side signature direct upload and setting upload callback

Java Connection Example: Java Practice OSS
image

Upload callback process
image

  1. The web front end requests the application server to obtain the parameters required for uploading (such as OSS accessKeyId, policy, callback and other parameters)
  2. The application server returns related parameters
  3. The web front end directly initiates a file upload request to the OSS service
  4. After the upload is complete, the OSS service will call back the callback interface of the application server
  5. The application server returns a response to the OSS service
  6. The OSS service returns the content of the application server callback interface to the web front end

3. SpringBoot integrates OSS to realize file upload

1. Add related dependencies in pom.xml

<dependency>
     <groupId>com.aliyun.oss</groupId>
     <artifactId>aliyun-sdk-oss</artifactId>
     <version>3.10.2</version>
</dependency>

2. Modify the SpringBoot configuration file
image

#操作oss需要的一些参数
aliyun:
  oss:
    accessKeyId: xxx # 阿里云的accessKeyId
    accessKeySecret: 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. Add OSS-related Java configuration
OSSClient used to configure the OSS connection client

/**
 * 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;

    @Bean
    public OSSClient ossClient() {
    
    
        return new OSSClient(ALIYUN_OSS_ENDPOINT, ALIYUN_OSS_ACCESSKEYID, ALIYUN_OSS_ACCESSKEYSECRET);

    }
}

4. Encapsulate the front-end upload strategy to return the object
parameters required for front-end direct upload

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编码过的字符串") 13
    private String policy;
//    @ApiModelProperty("对policy签名后的字符串") 15
    private String signature;
//    @ApiModelProperty("上传文件夹路径前缀") 17
    private String dir;
//    @ApiModelProperty("oss对外服务的访问域名") 19
    private String host;
//    @ApiModelProperty("上传成功后的回调设置")
    private String callback;
// 忽略getter、setter方法
}

5. Encapsulation upload success callback parameter object
When the OSS upload is successful, it will call back the corresponding interface according to the configuration parameters

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. Encapsulate the callback result object after the upload is successful.
The data object returned in the callback interface encapsulates the information of the uploaded file

/**
 * 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;// 文件的mimeType
    private String width;// 图片文件的宽
    private String height;// 图片文件的高
// 忽略getter、setter方法
}

7. Add OSS business interface 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 implementation class

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;

    @Autowired
    private OSSClient ossClient;

    /**
     * 签名生成
     *
     * @return
     */
    @Override
    public 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;
    }

    @Override
    public 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. Define the OssController interface

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 {
    
    

    @Autowired
    private 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;
    }


}

Test the interface, as shown in the figure below, the request returns the corresponding parameters required for uploading the oss file
image

4. Vue file upload test code

In order to test the file upload interface more conveniently and quickly, I choose to use Vue+Element-Ui to build a simple upload case 1. Create a
Vue project
Enter vue ui in the console and start the Vue project graphical management interface
image
to visit http:/ /localhost:8000 , enter the operation interface as shown below, which means the startup is successful
image
Find the project manager and create a new Vue project
image

image

image

image

Here select the Vue2 version
image
and add the dependencies required for this case after the creation is successful:

  • axios: used to initiate Ajax requests to backend services
  • element-ui: This case uses Upload in the ui component library for file upload.
    Enable the corresponding dependencies in main.js in the Vue project
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')

Create the OssUpload component, which can be referenced in the project

<template>
    <el-upload
        class="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>

Front-end and back-end joint debugging

  1. Start the backend service
    image

  2. Start the front-end project
    image

Select the file to upload, as shown in the figure below, it means the upload is successful
image
Check the corresponding OSSBucket, the picture has been successfully stored in the OSS service
image

project address

Guess you like

Origin blog.csdn.net/weixin_45688141/article/details/130969140