mall Integrates OSS for File Upload

Posted by phpBeginner06 on Fri, 06 Sep 2019 04:25:39 +0200

SpringBoot e-commerce project mall (20k+star) address: https://github.com/macrozheng/mall

abstract

This paper mainly explains the process of file upload by mall integrated OSS, which is a direct front-end method after service-side signature.

OSS

Ali Cloud Object Storage Service (OSS) is a mass, safe, low cost, high reliable cloud storage service provided by Ali Cloud.OSS can be used to store large amounts of files such as pictures, audio and video, logs, etc.Various terminal devices, Web site programs, and mobile applications can write or read data directly to the OSS.

Concepts related to OSS

  • Endpoint: Access the domain name through which you can access the OSS service API for file upload, download, and so on.
  • Bucket: A storage space is a container for storing objects, all of which must belong to a storage space.
  • Object: Object, which is the basic unit in which OSS stores data, is also known as an OSS file.
  • AccessKey: The access key refers to the AccessKeyId and AccessessKeySecret used in access authentication.

OSS related settings

Open OSS Service

  • Log on to Ali Yun's official website;
  • Move the mouse to the product label, click the object to store the OSS, and open the OSS product details page.
  • On the OSS product details page, click Open Now.

Create Storage Space

  • Click the console button in the upper right corner of the page to enter the console

  • Select Objects in My Cloud Products to Store OSS

  • Click on the plus sign of the left storage space to create a new one

  • Create a new storage space and set read and write permissions for public read

Setup of Cross-domain Resource Sharing (CORS)

Since browsers are security-minded and do not allow cross-domain resource access, we want to set up cross-domain resource sharing for OSS.

  • Select a storage space to open its underlying settings

  • Click the Settings button that spans settings

  • Click to create a rule

  • Perform cross-domain rule settings

Instructions for Front End Direct Transfer after Service End Signature

Process Sample Diagram

Process description

  1. The Web front end requests the application server to get the parameters needed for uploading (such as OSS accessKeyId, policy, callback, etc.)
  2. Application Server Returns Related Parameters
  3. Web front end initiates file upload request directly to OSS service
  4. The OSS service calls back the callback interface of the application server when the upload is complete
  5. Application Server Returns Response to OSS Service
  6. The OSS service returns the content of the application server callback interface to the Web front end

Integrating OSS for file upload

Adding dependencies to pom.xml

<!-- OSS SDK Related Dependencies -->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>2.5.0</version>
</dependency>

Modify SpringBoot configuration file

Modify the application.yml file to add OSS-related configurations.

Note: endpoint, accessKeyId, accessKeySecret, bucketName, callback, prefix are all related to your own account OSS. Callback needs to be an address accessible to the network.

# OSS-related configuration information
aliyun:
  oss:
    endpoint: oss-cn-shenzhen.aliyuncs.com # Access domain name of oss external service
    accessKeyId: test # User identity used in access authentication
    accessKeySecret: test # User used to encrypt signature strings and key used by oss to verify signature strings
    bucketName: macro-oss # Storage space of oss
    policy:
      expire: 300 # Signature validity period (S)
    maxSize: 10 # Upload file size (M)
    callback: http://localhost:8080/aliyun/oss/callback #Callback address after successful file upload
    dir:
      prefix: mall/images/ # Upload Folder Path Prefix

Adding OSS-related Java configurations

The connection client OSSClient used to configure OSS.

package com.macro.mall.tiny.config;

import com.aliyun.oss.OSSClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by macro on 2018/5/17.
 */
@Configuration
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);
    }
}

Add OSS Upload Policy Encapsulation Object OssPolicyResult

The parameters required for the front-end to upload the file directly are returned from the back-end.

package com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

/**
 * Get OSS Upload File Authorization Return Result
 * Created by macro on 2018/5/17.
 */
public class OssPolicyResult {
    @ApiModelProperty("User identity used in access authentication")
    private String accessKeyId;
    @ApiModelProperty("Policy for user form upload,after base64 Encoded string")
    private String policy;
    @ApiModelProperty("Yes policy Signed string")
    private String signature;
    @ApiModelProperty("Upload Folder Path Prefix")
    private String dir;
    @ApiModelProperty("oss Access domain name for external services")
    private String host;
    @ApiModelProperty("Callback settings after successful upload")
    private String callback;

    //Omit all getters, setter methods
}

Add callback parameter object OssCallbackParam after successful OSS upload

When the OSS uploads successfully, the corresponding interface is called back based on this configuration parameter.

package com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

/**
 * oss Callback parameters after successful upload
 * Created by macro on 2018/5/17.
 */
public class OssCallbackParam {
    @ApiModelProperty("Callback address requested")
    private String callbackUrl;
    @ApiModelProperty("Callback is incoming request Parameters in")
    private String callbackBody;
    @ApiModelProperty("Format of incoming parameters when callback occurs, such as form submission")
    private String callbackBodyType;

    //Omit all getters, setter methods
}

Callback result object OssCallbackResult after successful OSS upload

The data object returned in the callback interface encapsulates the information of the uploaded file.

package com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

/**
 * oss Callback results for uploaded files
 * Created by macro on 2018/5/17.
 */
public class OssCallbackResult {
    @ApiModelProperty("File Name")
    private String filename;
    @ApiModelProperty("file size")
    private String size;
    @ApiModelProperty("File mimeType")
    private String mimeType;
    @ApiModelProperty("Width of picture file")
    private String width;
    @ApiModelProperty("Picture file height")
    private String height;

    //Omit all getters, setter methods
}

Add OSS Business Interface OssService

package com.macro.mall.tiny.service;

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

import javax.servlet.http.HttpServletRequest;

/**
 * oss Upload Management Service
 * Created by macro on 2018/5/17.
 */
public interface OssService {
    /**
     * oss Upload Policy Generation
     */
    OssPolicyResult policy();

    /**
     * oss Upload Successful Callback
     */
    OssCallbackResult callback(HttpServletRequest request);
}

Implement class OssServiceImpl to add OSS business interface OssService

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

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 com.macro.mall.tiny.dto.OssCallbackParam;
import com.macro.mall.tiny.dto.OssCallbackResult;
import com.macro.mall.tiny.dto.OssPolicyResult;
import com.macro.mall.tiny.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;

/**
 * oss Upload Management Service Implementation Class
 * Created by macro on 2018/5/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;

    /**
     * Signature Generation
     */
    @Override
    public OssPolicyResult policy() {
        OssPolicyResult result = new OssPolicyResult();
        // Storage directory
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dir = ALIYUN_OSS_DIR_PREFIX+sdf.format(new Date());
        // Signature validity period
        long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;
        Date expiration = new Date(expireEndTime);
        // file size
        long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024;
        // Callback
        OssCallbackParam callback = new OssCallbackParam();
        callback.setCallbackUrl(ALIYUN_OSS_CALLBACK);
        callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
        callback.setCallbackBodyType("application/x-www-form-urlencoded");
        // Submit Node
        String action = "http://" + 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, dir);
            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"));
            // Return results
            result.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());
            result.setPolicy(policy);
            result.setSignature(signature);
            result.setDir(dir);
            result.setCallback(callbackData);
            result.setHost(action);
        } catch (Exception e) {
            LOGGER.error("Signature generation failed", 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.setWidth(request.getParameter("width"));
        result.setHeight(request.getParameter("height"));
        return result;
    }

}

Add OssController Definition Interface

package com.macro.mall.tiny.controller;


import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.dto.OssCallbackResult;
import com.macro.mall.tiny.dto.OssPolicyResult;
import com.macro.mall.tiny.service.impl.OssServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * Oss Related Operational Interfaces
 * Created by macro on 2018/4/26.
 */
@Controller
@Api(tags = "OssController", description = "Oss Administration")
@RequestMapping("/aliyun/oss")
public class OssController {
    @Autowired
    private OssServiceImpl ossService;

    @ApiOperation(value = "oss Upload Signature Generation")
    @RequestMapping(value = "/policy", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<OssPolicyResult> policy() {
        OssPolicyResult result = ossService.policy();
        return CommonResult.success(result);
    }

    @ApiOperation(value = "oss Upload Successful Callback")
    @RequestMapping(value = "callback", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<OssCallbackResult> callback(HttpServletRequest request) {
        OssCallbackResult ossCallbackResult = ossService.callback(request);
        return CommonResult.success(ossCallbackResult);
    }

}

Perform interface testing

Test the interface to get upload policy

Start the mall-admin-web front end project to test the upload interface

  • Two requests are invoked, and the first time the local interface is accessed to get the upload policy

  • Second call to oss service interface for file upload

  • You can see that the interface call above did not pass in the callback parameter, so the interface returned 204 no content. This time, we tried the callback parameter, and found that the oss service called back the callback interface we defined and returned the corresponding results.

Project Source Address

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

Reference material

Public Number

mall project In the full series of learning tutorials, focus on the first time public number is available.

Topics: Java github SpringBoot SDK