OSS
阿里雲對象存儲服務(Object Storage Service,簡稱 OSS),是阿里雲提供的海量、安全、低成本、高可靠的雲存儲服務。OSS可用於圖片、音視頻、日志等海量文件的存儲。各種終端設備、Web網站程序、移動應用可以直接向OSS寫入或讀取數據。
OSS中得到相關概念
- Endpoint:訪問域名,通過該域名可以訪問OSS服務的API,進行文件上傳、下載等操作。
- Bucket:存儲空間,是存儲對象的容器,所有存儲對象都必須隸屬於某個存儲空間。
- Object:對象,對象是 OSS 存儲數據的基本單元,也被稱為 OSS 的文件。
- AccessKey:訪問密鑰,指的是訪問身份驗證中用到的 AccessKeyId 和 AccessKeySecret。
OSS服務端簽名后前端直傳的相關說明
流程介紹
- Web前端請求應用服務器,獲取上傳所需參數(如OSS的accessKeyId、policy、callback等參數)
- 應用服務器返回相關參數
- Web前端直接向OSS服務發起上傳文件請求
- 等上傳完成后OSS服務會回調應用服務器的回調接口
- 應用服務器返回響應給OSS服務
- OSS服務將應用服務器回調接口的內容返回給Web前端
整合OSS實現文件上傳
一、添加依賴
<!-- OSS SDK 相關依賴 -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.5.0</version>
</dependency>
二、修改配置文件
# OSS相關配置信息
aliyun:
oss:
endpoint: xtslife-oss.oss-cn-chengdu.aliyuncs.com # oss對外服務的訪問域名
accessKeyId: test # 訪問身份驗證中用到用戶標識
accessKeySecret: test # 用戶用於加密簽名字符串和oss用來驗證簽名字符串的密鑰
bucketName: xtslife-oss # oss的存儲空間
policy:
expire: 300 # 簽名有效期(S)
maxSize: 10 # 上傳文件大小(M)
callback: http://localhost:8080/aliyun/oss/callback # 文件上傳成功后的回調地址
dir:
prefix: xtslife/images/ # 上傳文件夾路徑前綴
注意:注意:endpoint、accessKeyId、accessKeySecret、bucketName、callback、prefix都要改為你自己帳號OSS相關的,callback需要是公網可以訪問的地址
三、添加OSS的相關java配置
package top.xtslife.practice.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;
/**
* 用於配置OSS的連接客戶端OSSClient。
* @Author 小濤
* @Create 2019-08-16 18:04
*/
@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);
}
}
四、添加OSS上傳策略封裝對象OssPolicyResult
前端直接上傳文件時所需參數,從后端返回過來。
package top.xtslife.practice.component;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 獲取OSS上傳文件授權返回結果
* @Author 小濤
* @Create 2019-08-16 19:05
*/
@Data
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;
}
五、添加OSS上傳成功后的回調參數對象OssCallbackParam
當OSS上傳成功后,會根據該配置參數來回調對應接口
package top.xtslife.practice.component;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* oss上傳成功后的回調參數
* @Author 小濤
* @Create 2019-08-16 19:34
*/
@Data
public class OssCallbackParam {
@ApiModelProperty("請求的回調地址")
private String callbackUrl;
@ApiModelProperty("回調是傳入request中的參數")
private String callbackBody;
@ApiModelProperty("回調時傳入參數格式,比如表單提交形式")
private String callbackBodyType;
}
六、OSS上傳成功后的回調結果對象OssCallbackResult
回調接口中返回的數據對象,封裝了上傳文件的信息。
package top.xtslife.practice.component;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author 小濤
* @Create 2019-08-16 19:54
*/
@Data
public class OssCallbackResult {
@ApiModelProperty("文件名稱")
private String filename;
@ApiModelProperty("文件大小")
private String size;
@ApiModelProperty("文件的mimeType")
private String mimeType;
@ApiModelProperty("圖片文件的寬")
private String width;
@ApiModelProperty("圖片文件的高")
private String height;
}
七、添加OSS業務接口OssService
package top.xtslife.practice.Service;
import top.xtslife.practice.component.OssCallbackResult;
import top.xtslife.practice.component.OssPolicyResult;
import javax.servlet.http.HttpServletRequest;
/**
* oss上傳管理Service
* @Author 小濤
* @Create 2019-08-16 20:22
*/
public interface OssService {
/**
* oss 上傳生成策略
* @return
*/
OssPolicyResult policy();
/**
* oss上傳成功回調
* @param request
* @return
*/
OssCallbackResult callback(HttpServletRequest request);
}
八、添加OSS業務接口OssService的實現類OssServiceImpl
package top.xtslife.practice.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 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 top.xtslife.practice.Service.OssService;
import top.xtslife.practice.component.OssCallbackParam;
import top.xtslife.practice.component.OssCallbackResult;
import top.xtslife.practice.component.OssPolicyResult;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* oss上傳管理Service實現類
* @Author 小濤
* @Create 2019-08-16 20:28
*/
@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;
/**
* 簽名生成
* @return
*/
@Override
public OssPolicyResult policy() {
OssPolicyResult ossPolicyResult = 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);
// 文件大小
int maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024;
// 回調
OssCallbackParam ossCallbackParam = new OssCallbackParam();
ossCallbackParam.setCallbackUrl(ALIYUN_OSS_CALLBACK);
ossCallbackParam.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
ossCallbackParam.setCallbackBodyType("application/x-www-form-urlencoded");
// 提交節點
String action = "http://"+ ALIYUN_OSS_ENDPOINT;
try {
PolicyConditions policyConditions = new PolicyConditions();
policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,0,maxSize);
policyConditions.addConditionItem(MatchMode.StartWith,PolicyConditions.COND_KEY,dir);
String postPolicy = ossClient.generatePostPolicy(expiration,policyConditions);
byte[] binaryData = new byte[0];
binaryData = postPolicy.getBytes("utf-8");
String policy = BinaryUtil.toBase64String(binaryData);
String signature = ossClient.calculatePostSignature(postPolicy);
String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(ossCallbackParam).toString().getBytes("utf-8"));
// 返回結果
ossPolicyResult.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());
ossPolicyResult.setPolicy(policy);
ossPolicyResult.setSignature(signature);
ossPolicyResult.setDir(dir);
ossPolicyResult.setCallback(callbackData);
ossPolicyResult.setHost(action);
} catch (Exception e) {
LOGGER.error("簽名生成失敗",e);
}
return ossPolicyResult;
}
@Override
public OssCallbackResult callback(HttpServletRequest request) {
OssCallbackResult ossCallbackResult = new OssCallbackResult();
String filename = request.getParameter("filename");
filename ="http://".concat(ALIYUN_OSS_BUCKET_NAME).concat(".").concat(ALIYUN_OSS_ENDPOINT).concat("/").concat(filename);
ossCallbackResult.setFilename(filename);
ossCallbackResult.setSize(request.getParameter("size"));
ossCallbackResult.setMimeType(request.getParameter("mimeType"));
ossCallbackResult.setWidth(request.getParameter("width"));
ossCallbackResult.setHeight(request.getParameter("height"));
return ossCallbackResult;
}
}
九、添加OssController定義接口
package top.xtslife.practice.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.xtslife.practice.Service.OssService;
import top.xtslife.practice.common.CommonResult;
import top.xtslife.practice.component.OssCallbackResult;
import top.xtslife.practice.component.OssPolicyResult;
import javax.servlet.http.HttpServletRequest;
/**
* @Author 小濤
* @Create 2019-08-16 21:46
*/
@RestController
@Api(tags = "OssController",description = "Oss管理")
@RequestMapping("/aliyun/oss")
public class OssController {
@Autowired
private OssService ossServiceImpl;
@ApiOperation("oss上傳簽名生成")
@GetMapping("/policy")
public CommonResult<OssPolicyResult> policy(){
OssPolicyResult ossPolicyResult = ossServiceImpl.policy();
return CommonResult.success(ossPolicyResult);
}
@ApiOperation("oss上傳成功回調")
@PostMapping("callback")
public CommonResult<OssCallbackResult> callback(HttpServletRequest request){
OssCallbackResult ossCallbackResult = ossServiceImpl.callback(request);
return CommonResult.success(ossCallbackResult);
}
}