阿里OSS 上传图片 springboot整合阿里云OSS做服务端签名让微信小程序文件直传OSS

  • Post author:
  • Post category:小程序


前段web参考地址:

https://www.cnblogs.com/pnz-bug/p/10381839.html


后台java 才考地址:

https://blog.csdn.net/huangxiangdi/article/details/104725048/

1、需求:

想让小程序直接上传图片、文件到OSS存储,不需要经过我的服务器接收文件再转发到OSS存储。



好处

  • 可以减轻自己服务器的压力,和不必要的麻烦。

  • 有利于维护和扩展(比如扩容、迁移等等)。

  • 可以更加快的存储到OSS中,不需要多次来回传输。

  • 不占用自己服务器的带宽,阿里的OSS节点处理更快。

  • 等等。。。





2、基本原理介绍(官方描述,我觉得很简单了)

在这里插入图片描述

服务端签名后前端(小程序)直传的原理如下:

  1. 用户发送请求到自己服务器获取上传的Policy和签名。
  2. 自己的服务器返回前端直传oss需要Policy和签名给用户。
  3. 用户直接上传数据到OSS。

3、springboot 搞起来

1.新建一个springboot 项目,添加依赖

<!--阿里oss-->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>2.8.3</version>
</dependency>

2.编写一个OSS的配置类(可以根据自己的需求来,注入等方式都可以)

public class AliOssConfig {
    /**
     * 填写您的AccessKeyId
     */
    public final static String accessId = "xxxx";
    /**
     * 填写您的AccessKeySecret
     */
    public final static String accessKey = "xxxxx";
    /**
     * 填写您的 endpoint(地域节点),就是你OSS的区域节点的域名
     */
    public final static String endpoint = "xxxx.aliyuncs.com";
    /**
     * 填写您的 bucketName ,就是你再OSS创建Bucket的名称
     */
    public final static String bucket = "xxx";
    /**
     * 直传地址,格式为 bucketName.endpoint (Bucket域名)
     */
    public final static String host = "https://" + bucket +"."+ endpoint;

    /*
     * ============= 配置上传过期时间、大小等等 =========
     */
    /**
     * 上传截止时间(秒)
     */
    public final static long expireTime = 30;

    /**
     * 上传文件最小(字节)
     */
    public final static long min = 0;
    /**
     * 上传文件最大(字节)
     */
    public final static long max = 1048576000;

    /**
     * 上传文件的前缀、可忽略
     */
    public final static String dir = "user/";
}

3.创建controller

@RestController
@RequestMapping("/ali/oss")
public class AliOssController {
    /**
     * 创建OSS客户端
     */
    private OSSClient client = new OSSClient(AliOssConfig.endpoint, AliOssConfig.accessId, AliOssConfig.accessKey);

    /**
     * 前端获取直传的policy信息
     * 前端可以使用响应的参数进行直传到oss存储
     *
     * @return
     */
    @GetMapping("/policy")
    public AliOssPolicy getPolicy() {
        // 直传有效截止时间
        long expireEndTime = System.currentTimeMillis() + (AliOssConfig.expireTime * 1000);
        Date expiration = new Date(expireEndTime);
        PolicyConditions policyConditions = new PolicyConditions();
        // 设置可上传文件的大小
        policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, AliOssConfig.min, AliOssConfig.max);
        // 设置上传文件的前缀、可忽略
        policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, AliOssConfig.dir);
        // 生成policy
        String postPolicy = client.generatePostPolicy(expiration, policyConditions);
        byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
        String encodedPolicy = BinaryUtil.toBase64String(binaryData);
        String postSignature = client.calculatePostSignature(postPolicy);
        // 封装policy等信息
        AliOssPolicy aliOssPolicy = new AliOssPolicy();
        aliOssPolicy.setOssAccessKeyId(AliOssConfig.accessId);
        aliOssPolicy.setPolicy(encodedPolicy);
        aliOssPolicy.setSignature(postSignature);
        aliOssPolicy.setDir(AliOssConfig.dir);
        aliOssPolicy.setHost(AliOssConfig.host);
        aliOssPolicy.setExpire(String.valueOf(expireEndTime / 1000));
        return aliOssPolicy;
    }
}

4.创建一个封装类来响应给前端

public class AliOssPolicy implements Serializable {
    /**
     * 上传认证id
     */
    private String ossAccessKeyId;
    /**
     * policy
     */
    private String policy;
    /**
     * 签名
     */
    private String signature;
    /**
     * 直传文件的开头(路径)
     */
    private String dir;
    /**
     * 直传地址
     */
    private String host;
    /**
     * 上传截止时间
     */
    private String expire;
	
    // get和set省略
}

5、小程序 搞起来

// 调用小程序api选择图片上传
    wx.chooseImage({
      success: function(res) {
        var tempFilePaths = res.tempFilePaths
        // 上传图片到oss
        wx.uploadFile({
          // 直传的oss地址
          url: 'https://xxxx.xxxx.aliyuncs.com',
          // 上传的文件
          filePath: tempFilePaths[0],
          // 必须为file
          name: 'file',
          // 表单数据
          formData: {
            // key:文件路径,如 user/666.png
            //直接 key: "${filename}" 是存放在根目录,文件名为上传的文件名
            // 如果后端签名时指定了dir则开头必须同后端的一致,如后端指定了 “user/” 开头则必须是 user/xxx.xx
            key: "user/666.png",
            // 自定义成功响应值 ,默认响应204
            success_action_status: '200',
            OssAccessKeyId: 'xxxx',
            // 后端签名后发回的policy
            policy: 'xxxxxx',
            // 后端返回的签名
            signature: 'xxxxx'
          },
          success: function(res) {
            if (res.statusCode == 200) {
              console.log("上传成功!")
              console.log(res)
            } else {
              console.log("上传失败!")
              console.log(res)
            }
          },
          fail(error) {
            console.log("上传错误")
            console.log(error)
          }
        })
      }
    })

1.设置跨域问题请参考阿里OSS 文件

前段javascript例子: web OSS 阿里上传 参考地址:


https://www.cnblogs.com/pnz-bug/p/10381839.html


<!-- 项目源码地址  https://github.com/Pangnz/OssUpload -->


<


br


><!


DOCTYPE


html>


<


html


>




<


head


>




<


meta


charset="utf-8" />




<


title


>web直传oss</


title


>




<


style


type="text/css">




.file-box {




position: relative;




display: inline-block;




width: 160px;




height: 160px;




background: url(img/aaa.png) no-repeat;




background-size: cover;




background-position: center;




}




#input_file {




width: 100%;




height: 100%;




opacity: 0;




filter: alpha(opacity=0);




}




</


style


>




</


head


>




<


body


>




<


p


>oss web服务端签名后直传</


p


>




<


div


class="file-box">




<


input


type="file" value="" name="file" id="input_file" accept="image/gif,image/jpeg,image/jpg,image/png,image/svg"




onchange="imgPreview(this,0)">




</


div


>




<


script


src="js/jquery-3.3.1.min.js" type="text/javascript" charset="utf-8"></


script


>




<


script


type="text/javascript">




let uploadObj; // 上传凭证对象




let verifyImg; //上传之后的图片oss地址




function imgPreview(fileDom, i) {




// 获取上传凭证




$.ajax({




url: '', // 这里是请求的后台通过oss上传凭证的接口




data: JSON.stringify({




data: ''




}),




dataType: 'json',




type: 'post',




headers: {




'Content-Type': 'application/json',




},




success: function(response) {




if (response && response.header.ret == 'S') {




uploadObj = response.data;




// 获取到上传凭证成功之后 封装请求的数据




let request = new FormData();




request.append("OSSAccessKeyId", uploadObj.accessid); //Bucket 拥有者的Access Key Id。




request.append("policy", uploadObj.policy); //policy规定了请求的表单域的合法性




request.append("Signature", uploadObj.signature); //根据Access Key Secret和policy计算的签名信息,OSS验证该签名信息从而验证该Post请求的合法性




//---以上都是阿里的认证策略




let file = document.getElementById("input_file").files[0];




if (!file) {




return;




}




request.append("key", `${uploadObj.dir}/${file.name}`); //文件名字,可设置路径




request.append("success_action_status", '200'); // 让服务端返回200,不然,默认会返回204




request.append('file', file); //需要上传的文件 file




$.ajax({




url: uploadObj.host, //上传阿里地址




data: request,




processData: false, //默认true,设置为 false,不需要进行序列化处理




cache: false, //设置为false将不会从浏览器缓存中加载请求信息




async: false, //发送同步请求




contentType: false, //避免服务器不能正常解析文件---------具体的可以查下这些参数的含义




dataType: 'json', //不涉及跨域  写json即可




type: 'post',




success: function(response) { //callbackHost:success,request中就是 回调的一些信息,包括状态码什么的




// console.log(response);




},




error: function(error) {




alert("上传图片成功");




verifyImg = `${uploadObj.host}/${uploadObj.dir}/${file.name}`;




}




});




} else {




alert(`${response && response.header.msg[0]}`);




}




},




error: function(error) {




console.log(error);




},




});




console.log(`上传的文件oss地址${verifyImg}`);




//判断是否支持FileReader




if (window.FileReader) {




var reader = new FileReader();




} else {




alert("您的设备不支持图片预览功能,如需该功能请升级您的设备!");




}




//获取文件




var file = fileDom.files[0];




if (!file) {




return;




}




var imageType = /^image\//;




//是否是图片




if (!imageType.test(file.type)) {




alert("请选择图片!");




return;




}




//读取完成




reader.onload = function(e) {




//图片路径设置为读取的图片




// img.src = e.target.result;




document.getElementsByClassName('file-box')[i].style.background = "url(" + e.target.result + ")no-repeat"; //回显图片




document.getElementsByClassName('file-box')[i].style.backgroundSize = '';




};




reader.readAsDataURL(file);




}




</


script


>




</


body


>


</


html


>