本文主要講解mall整合OSS實現文件上傳的過程,採用的是服務端簽名後前端直傳的方式。阿里雲對象存儲服務(Object Storage Service,簡稱OSS),是阿里雲提供的海量、安全、低成本、高可靠的雲存儲服務。OSS可用於圖片、音視頻、日誌等海量文件的存儲。各類終端設備、Web網站程序、移動應用能夠直接向OSS寫入或讀取數據。html
阿里雲對象存儲服務(Object Storage Service,簡稱 OSS),是阿里雲提供的海量、安全、低成本、高可靠的雲存儲服務。OSS可用於圖片、音視頻、日誌等海量文件的存儲。各類終端設備、Web網站程序、移動應用能夠直接向OSS寫入或讀取數據。前端
因爲瀏覽器處於安全考慮,不容許跨域資源訪問,因此咱們要設置OSS的跨域資源共享。java
<!-- OSS SDK 相關依賴 -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.5.0</version>
</dependency>
複製代碼
修改application.yml文件,添加OSS相關配置。git
注意:endpoint、accessKeyId、accessKeySecret、bucketName、callback、prefix都要改成你本身賬號OSS相關的,callback須要是公網能夠訪問的地址。github
# 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的鏈接客戶端OSSClient。web
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);
}
}
複製代碼
前端直接上傳文件時所需參數,從後端返回過來。spring
package com.macro.mall.tiny.dto;
import io.swagger.annotations.ApiModelProperty;
/** * 獲取OSS上傳文件受權返回結果 * Created by macro on 2018/5/17. */
public class OssPolicyResult {
@ApiModelProperty("訪問身份驗證中用到用戶標識")
private String accessKeyId;
@ApiModelProperty("用戶表單上傳的策略,通過base64編碼過的字符串")
private String policy;
@ApiModelProperty("對policy簽名後的字符串")
private String signature;
@ApiModelProperty("上傳文件夾路徑前綴")
private String dir;
@ApiModelProperty("oss對外服務的訪問域名")
private String host;
@ApiModelProperty("上傳成功後的回調設置")
private String callback;
//省略了全部getter,setter方法
}
複製代碼
當OSS上傳成功後,會根據該配置參數來回調對應接口。json
package com.macro.mall.tiny.dto;
import io.swagger.annotations.ApiModelProperty;
/** * oss上傳成功後的回調參數 * Created by macro on 2018/5/17. */
public class OssCallbackParam {
@ApiModelProperty("請求的回調地址")
private String callbackUrl;
@ApiModelProperty("回調是傳入request中的參數")
private String callbackBody;
@ApiModelProperty("回調時傳入參數的格式,好比表單提交形式")
private String callbackBodyType;
//省略了全部getter,setter方法
}
複製代碼
回調接口中返回的數據對象,封裝了上傳文件的信息。後端
package com.macro.mall.tiny.dto;
import io.swagger.annotations.ApiModelProperty;
/** * oss上傳文件的回調結果 * Created by macro on 2018/5/17. */
public class OssCallbackResult {
@ApiModelProperty("文件名稱")
private String filename;
@ApiModelProperty("文件大小")
private String size;
@ApiModelProperty("文件的mimeType")
private String mimeType;
@ApiModelProperty("圖片文件的寬")
private String width;
@ApiModelProperty("圖片文件的高")
private String height;
//省略了全部getter,setter方法
}
複製代碼
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上傳管理Service * Created by macro on 2018/5/17. */
public interface OssService {
/** * oss上傳策略生成 */
OssPolicyResult policy();
/** * oss上傳成功回調 */
OssCallbackResult callback(HttpServletRequest request);
}
複製代碼
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上傳管理Service實現類 * 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;
/** * 簽名生成 */
@Override
public OssPolicyResult policy() {
OssPolicyResult result = new OssPolicyResult();
// 存儲目錄
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String dir = ALIYUN_OSS_DIR_PREFIX+sdf.format(new Date());
// 簽名有效期
long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;
Date expiration = new Date(expireEndTime);
// 文件大小
long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024;
// 回調
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");
// 提交節點
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"));
// 返回結果
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("簽名生成失敗", 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;
}
}
複製代碼
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相關操做接口 * Created by macro on 2018/4/26. */
@Controller
@Api(tags = "OssController", description = "Oss管理")
@RequestMapping("/aliyun/oss")
public class OssController {
@Autowired
private OssServiceImpl ossService;
@ApiOperation(value = "oss上傳簽名生成")
@RequestMapping(value = "/policy", method = RequestMethod.GET)
@ResponseBody
public CommonResult<OssPolicyResult> policy() {
OssPolicyResult result = ossService.policy();
return CommonResult.success(result);
}
@ApiOperation(value = "oss上傳成功回調")
@RequestMapping(value = "callback", method = RequestMethod.POST)
@ResponseBody
public CommonResult<OssCallbackResult> callback(HttpServletRequest request) {
OssCallbackResult ossCallbackResult = ossService.callback(request);
return CommonResult.success(ossCallbackResult);
}
}
複製代碼
如何啓動前端項目,具體參考該項目的readme文檔:github.com/macrozheng/…api
點擊添加商品品牌的上傳按鈕進行測試
開通OSS服務:help.aliyun.com/document_de…
建立存儲空間:help.aliyun.com/document_de…
跨域資源共享(CORS):help.aliyun.com/document_de…
服務端簽名直傳並設置上傳回調:help.aliyun.com/document_de…
mall項目全套學習教程連載中,關注公衆號第一時間獲取。