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
- The Web front end requests the application server to get the parameters needed for uploading (such as OSS accessKeyId, policy, callback, etc.)
- Application Server Returns Related Parameters
- Web front end initiates file upload request directly to OSS service
- The OSS service calls back the callback interface of the application server when the upload is complete
- Application Server Returns Response to OSS Service
- 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
- How to start a front-end project, referring specifically to its readme documentation: https://github.com/macrozheng/mall-admin-web
- Click the upload button to add brand to test
- 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
- Open OSS service: https://help.aliyun.com/document_detail/31884.html?spm=a2c4g.11186623.6.566.74b87eaebrfQno
- Create storage: https://help.aliyun.com/document_detail/31885.html?spm=a2c4g.11186623.6.567.496228bcVZUZqB
- Cross-domain Resource Sharing (CORS): https://help.aliyun.com/document_detail/31928.html?spm=5176.11065259.1996646101.searchclickresult.4d1a5607Pf3e9i
- Server Sign Direct Transfer and Set Upload Callback: https://help.aliyun.com/document_detail/31927.html?spm=a2c4g.11186623.6.1268.2c256506mNqV1t
Public Number
mall project In the full series of learning tutorials, focus on the first time public number is available.