mall整合OSS实现文件上传

懵懂的女人 提交于 2021-01-16 13:55:15

本文主要讲解mall整合OSS实现文件上传的过程,采用的是服务端签名后前端直传的方式。

OSS

阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。OSS可用于图片、音视频、日志等海量文件的存储。各种终端设备、Web网站程序、移动应用可以直接向OSS写入或读取数据。

OSS中的相关概念

  • Endpoint:访问域名,通过该域名可以访问OSS服务的API,进行文件上传、下载等操作。

  • Bucket:存储空间,是存储对象的容器,所有存储对象都必须隶属于某个存储空间。

  • Object:对象,对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。

  • AccessKey:访问密钥,指的是访问身份验证中用到的 AccessKeyId 和 AccessKeySecret。

OSS的相关设置

开通OSS服务

  • 登录阿里云官网;

  • 将鼠标移至产品标签页,单击对象存储 OSS,打开OSS 产品详情页面;

  • 在OSS产品详情页,单击立即开通。

创建存储空间

  • 点击网页右上角控制台按钮进入控制台

图片

  • 选择我的云产品中的对象存储OSS

图片

  • 点击左侧存储空间的加号新建存储空间

  • 新建存储空间并设置读写权限为公共读

跨域资源共享(CORS)的设置

由于浏览器处于安全考虑,不允许跨域资源访问,所以我们要设置OSS的跨域资源共享。

  • 选择一个存储空间,打开其基础设置

  • 点击跨越设置的设置按钮

  • 点击创建规则

  • 进行跨域规则设置

服务端签名后前端直传的相关说明

流程示例图

流程介绍

  1. Web前端请求应用服务器,获取上传所需参数(如OSS的accessKeyId、policy、callback等参数)

  2. 应用服务器返回相关参数

  3. Web前端直接向OSS服务发起上传文件请求

  4. 等上传完成后OSS服务会回调应用服务器的回调接口

  5. 应用服务器返回响应给OSS服务

  6. OSS服务将应用服务器回调接口的内容返回给Web前端

整合OSS实现文件上传

在pom.xml中添加相关依赖

<!-- OSS SDK 相关依赖 --><dependency>    <groupId>com.aliyun.oss</groupId>    <artifactId>aliyun-sdk-oss</artifactId>    <version>2.5.0</version></dependency>

修改SpringBoot配置文件

修改application.yml文件,添加OSS相关配置。

注意:endpoint、accessKeyId、accessKeySecret、bucketName、callback、prefix都要改为你自己帐号OSS相关的,callback需要是公网可以访问的地址。

# OSS相关配置信息aliyun:  oss:    endpoint: oss-cn-shenzhen.aliyuncs.com # oss对外服务的访问域名    accessKeyId: test # 访问身份验证中用到用户标识    accessKeySecret: test # 用户用于加密签名字符串和oss用来验证签名字符串的密钥    bucketName: macro-oss # oss的存储空间    policy:      expire: 300 # 签名有效期(S)    maxSize: 10 # 上传文件大小(M)    callback: http://localhost:8080/aliyun/oss/callback # 文件上传成功后的回调地址    dir:      prefix: mall/images/ # 上传文件夹路径前缀

添加OSS的相关Java配置

用于配置OSS的连接客户端OSSClient。

  1. package com.macro.mall.tiny.config;


  2. import com.aliyun.oss.OSSClient;

  3. import org.springframework.beans.factory.annotation.Value;

  4. import org.springframework.context.annotation.Bean;

  5. import org.springframework.context.annotation.Configuration;


  6. /**

  7. * Created by macro on 2018/5/17.

  8. */

  9. @Configuration

  10. public class OssConfig {

  11.    @Value("${aliyun.oss.endpoint}")

  12.    private String ALIYUN_OSS_ENDPOINT;

  13.    @Value("${aliyun.oss.accessKeyId}")

  14.    private String ALIYUN_OSS_ACCESSKEYID;

  15.    @Value("${aliyun.oss.accessKeySecret}")

  16.    private String ALIYUN_OSS_ACCESSKEYSECRET;

  17.    @Bean

  18.    public OSSClient ossClient(){

  19.        return new OSSClient(ALIYUN_OSS_ENDPOINT,ALIYUN_OSS_ACCESSKEYID,ALIYUN_OSS_ACCESSKEYSECRET);

  20.    }

  21. }

添加OSS上传策略封装对象OssPolicyResult

前端直接上传文件时所需参数,从后端返回过来。

  1. package com.macro.mall.tiny.dto;


  2. import io.swagger.annotations.ApiModelProperty;


  3. /**

  4. * 获取OSS上传文件授权返回结果

  5. * Created by macro on 2018/5/17.

  6. */

  7. public class OssPolicyResult {

  8.    @ApiModelProperty("访问身份验证中用到用户标识")

  9.    private String accessKeyId;

  10.    @ApiModelProperty("用户表单上传的策略,经过base64编码过的字符串")

  11.    private String policy;

  12.    @ApiModelProperty("对policy签名后的字符串")

  13.    private String signature;

  14.    @ApiModelProperty("上传文件夹路径前缀")

  15.    private String dir;

  16.    @ApiModelProperty("oss对外服务的访问域名")

  17.    private String host;

  18.    @ApiModelProperty("上传成功后的回调设置")

  19.    private String callback;


  20.    //省略了所有getter,setter方法

  21. }

添加OSS上传成功后的回调参数对象OssCallbackParam

当OSS上传成功后,会根据该配置参数来回调对应接口。

  1. package com.macro.mall.tiny.dto;


  2. import io.swagger.annotations.ApiModelProperty;


  3. /**

  4. * oss上传成功后的回调参数

  5. * Created by macro on 2018/5/17.

  6. */

  7. public class OssCallbackParam {

  8.    @ApiModelProperty("请求的回调地址")

  9.    private String callbackUrl;

  10.    @ApiModelProperty("回调是传入request中的参数")

  11.    private String callbackBody;

  12.    @ApiModelProperty("回调时传入参数的格式,比如表单提交形式")

  13.    private String callbackBodyType;


  14.    //省略了所有getter,setter方法

  15. }

OSS上传成功后的回调结果对象OssCallbackResult

回调接口中返回的数据对象,封装了上传文件的信息。

  1. package com.macro.mall.tiny.dto;


  2. import io.swagger.annotations.ApiModelProperty;


  3. /**

  4. * oss上传文件的回调结果

  5. * Created by macro on 2018/5/17.

  6. */

  7. public class OssCallbackResult {

  8.    @ApiModelProperty("文件名称")

  9.    private String filename;

  10.    @ApiModelProperty("文件大小")

  11.    private String size;

  12.    @ApiModelProperty("文件的mimeType")

  13.    private String mimeType;

  14.    @ApiModelProperty("图片文件的宽")

  15.    private String width;

  16.    @ApiModelProperty("图片文件的高")

  17.    private String height;


  18.    //省略了所有getter,setter方法

  19. }

添加OSS业务接口OssService

  1. package com.macro.mall.tiny.service;


  2. import com.macro.mall.tiny.dto.OssCallbackResult;

  3. import com.macro.mall.tiny.dto.OssPolicyResult;


  4. import javax.servlet.http.HttpServletRequest;


  5. /**

  6. * oss上传管理Service

  7. * Created by macro on 2018/5/17.

  8. */

  9. public interface OssService {

  10.    /**

  11.     * oss上传策略生成

  12.     */

  13.    OssPolicyResult policy();


  14.    /**

  15.     * oss上传成功回调

  16.     */

  17.    OssCallbackResult callback(HttpServletRequest request);

  18. }

添加OSS业务接口OssService的实现类OssServiceImpl

  1. package com.macro.mall.tiny.service.impl;


  2. import cn.hutool.json.JSONUtil;

  3. import com.aliyun.oss.OSSClient;

  4. import com.aliyun.oss.common.utils.BinaryUtil;

  5. import com.aliyun.oss.model.MatchMode;

  6. import com.aliyun.oss.model.PolicyConditions;

  7. import com.macro.mall.tiny.dto.OssCallbackParam;

  8. import com.macro.mall.tiny.dto.OssCallbackResult;

  9. import com.macro.mall.tiny.dto.OssPolicyResult;

  10. import com.macro.mall.tiny.service.OssService;

  11. import org.slf4j.Logger;

  12. import org.slf4j.LoggerFactory;

  13. import org.springframework.beans.factory.annotation.Autowired;

  14. import org.springframework.beans.factory.annotation.Value;

  15. import org.springframework.stereotype.Service;


  16. import javax.servlet.http.HttpServletRequest;

  17. import java.text.SimpleDateFormat;

  18. import java.util.Date;


  19. /**

  20. * oss上传管理Service实现类

  21. * Created by macro on 2018/5/17.

  22. */

  23. @Service

  24. public class OssServiceImpl implements OssService {


  25.    private static final Logger LOGGER = LoggerFactory.getLogger(OssServiceImpl.class);

  26.    @Value("${aliyun.oss.policy.expire}")

  27.    private int ALIYUN_OSS_EXPIRE;

  28.    @Value("${aliyun.oss.maxSize}")

  29.    private int ALIYUN_OSS_MAX_SIZE;

  30.    @Value("${aliyun.oss.callback}")

  31.    private String ALIYUN_OSS_CALLBACK;

  32.    @Value("${aliyun.oss.bucketName}")

  33.    private String ALIYUN_OSS_BUCKET_NAME;

  34.    @Value("${aliyun.oss.endpoint}")

  35.    private String ALIYUN_OSS_ENDPOINT;

  36.    @Value("${aliyun.oss.dir.prefix}")

  37.    private String ALIYUN_OSS_DIR_PREFIX;


  38.    @Autowired

  39.    private OSSClient ossClient;


  40.    /**

  41.     * 签名生成

  42.     */

  43.    @Override

  44.    public OssPolicyResult policy() {

  45.        OssPolicyResult result = new OssPolicyResult();

  46.        // 存储目录

  47.        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

  48.        String dir = ALIYUN_OSS_DIR_PREFIX+sdf.format(new Date());

  49.        // 签名有效期

  50.        long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;

  51.        Date expiration = new Date(expireEndTime);

  52.        // 文件大小

  53.        long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024;

  54.        // 回调

  55.        OssCallbackParam callback = new OssCallbackParam();

  56.        callback.setCallbackUrl(ALIYUN_OSS_CALLBACK);

  57.        callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");

  58.        callback.setCallbackBodyType("application/x-www-form-urlencoded");

  59.        // 提交节点

  60.        String action = "http://" + ALIYUN_OSS_BUCKET_NAME + "." + ALIYUN_OSS_ENDPOINT;

  61.        try {

  62.            PolicyConditions policyConds = new PolicyConditions();

  63.            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize);

  64.            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

  65.            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);

  66.            byte[] binaryData = postPolicy.getBytes("utf-8");

  67.            String policy = BinaryUtil.toBase64String(binaryData);

  68.            String signature = ossClient.calculatePostSignature(postPolicy);

  69.            String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes("utf-8"));

  70.            // 返回结果

  71.            result.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());

  72.            result.setPolicy(policy);

  73.            result.setSignature(signature);

  74.            result.setDir(dir);

  75.            result.setCallback(callbackData);

  76.            result.setHost(action);

  77.        } catch (Exception e) {

  78.            LOGGER.error("签名生成失败", e);

  79.        }

  80.        return result;

  81.    }


  82.    @Override

  83.    public OssCallbackResult callback(HttpServletRequest request) {

  84.        OssCallbackResult result= new OssCallbackResult();

  85.        String filename = request.getParameter("filename");

  86.        filename = "http://".concat(ALIYUN_OSS_BUCKET_NAME).concat(".").concat(ALIYUN_OSS_ENDPOINT).concat("/").concat(filename);

  87.        result.setFilename(filename);

  88.        result.setSize(request.getParameter("size"));

  89.        result.setMimeType(request.getParameter("mimeType"));

  90.        result.setWidth(request.getParameter("width"));

  91.        result.setHeight(request.getParameter("height"));

  92.        return result;

  93.    }


  94. }

添加OssController定义接口

  1. package com.macro.mall.tiny.controller;



  2. import com.macro.mall.tiny.common.api.CommonResult;

  3. import com.macro.mall.tiny.dto.OssCallbackResult;

  4. import com.macro.mall.tiny.dto.OssPolicyResult;

  5. import com.macro.mall.tiny.service.impl.OssServiceImpl;

  6. import io.swagger.annotations.Api;

  7. import io.swagger.annotations.ApiOperation;

  8. import org.springframework.beans.factory.annotation.Autowired;

  9. import org.springframework.stereotype.Controller;

  10. import org.springframework.web.bind.annotation.RequestMapping;

  11. import org.springframework.web.bind.annotation.RequestMethod;

  12. import org.springframework.web.bind.annotation.ResponseBody;


  13. import javax.servlet.http.HttpServletRequest;


  14. /**

  15. * Oss相关操作接口

  16. * Created by macro on 2018/4/26.

  17. */

  18. @Controller

  19. @Api(tags = "OssController", description = "Oss管理")

  20. @RequestMapping("/aliyun/oss")

  21. public class OssController {

  22.    @Autowired

  23.    private OssServiceImpl ossService;


  24.    @ApiOperation(value = "oss上传签名生成")

  25.    @RequestMapping(value = "/policy", method = RequestMethod.GET)

  26.    @ResponseBody

  27.    public CommonResult<OssPolicyResult> policy() {

  28.        OssPolicyResult result = ossService.policy();

  29.        return CommonResult.success(result);

  30.    }


  31.    @ApiOperation(value = "oss上传成功回调")

  32.    @RequestMapping(value = "callback", method = RequestMethod.POST)

  33.    @ResponseBody

  34.    public CommonResult<OssCallbackResult> callback(HttpServletRequest request) {

  35.        OssCallbackResult ossCallbackResult = ossService.callback(request);

  36.        return CommonResult.success(ossCallbackResult);

  37.    }


  38. }

进行接口测试

测试获取上传策略的接口

图片

启动mall-admin-web前端项目来测试上传接口

  • 如何启动前端项目,具体参考该项目的readme文档:https://github.com/macrozheng/mall-admin-web

  • 点击添加商品品牌的上传按钮进行测试

  • 会调用两次请求,第一次访问本地接口获取上传的策略

  • 第二次调用oss服务 的接口进行文件上传

  • 可以看到上面接口调用并没有传入回调参数callback,所以接口返回了204 no content,这次我们传入回调参数callback试试,可以发现oss服务回调了我们自己定义的回调接口,并返回了相应结果。

图片

图片

图片

项目源码地址

https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-09


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!