本文主要讲解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


更多相关文章

  1. [简讯] 微软Linux子系统已经支持中文
  2. Springboot实现文件上传下载
  3. 【不用框架】文件上传和下载
  4. 使用Rails 3.2和AJAX(非flash上传解决方案)将多个文件直接上载到
  5. 使用ajax请求上传文件[副本]
  6. 在上传前预览xls、xlsx、doc等文件的缩略图
  7. Struts2 使用Jquery+ajax 文件上传
  8. 如何在Rails 4(使用jquery)中上传多个文件?
  9. jQuery 异步上传插件 Uploadify302 使用 (JavaEE Spring MVC)

随机推荐

  1. Android imageView图片按比例缩放
  2. freescale Android(安卓)Camera 调试总结
  3. Android(安卓)Paint和Color类
  4. android系统中“关于设备”中android版本
  5. this android sdk requires android deve
  6. 【Android】Android取消EditText自动获取
  7. Android NDK学习记录(一)
  8. android应用程序键盘事件机制
  9. 报错You need to use a Theme.AppCompat
  10. 【android初级】之android布局属性详解