Spring Boot專案中實現檔案上傳功能的示例
在實際專案中,檔案上傳是很多專案必不可少的一個功能。那麼在 Spring Boot
專案中又是如何來實現檔案上傳功能的呢?一般來說,上傳的檔案可以儲存到專案根目錄下的某一資料夾中,但這樣做顯然是不太合適的。因此我們選擇將檔案上傳到專門的檔案伺服器中。很多雲計算廠商都提供檔案儲存服務。這裡我選擇的是阿里雲的物件儲存(OSS)。
一、配置OSS
1. 匯入SDK
首先,你需要註冊阿里雲的賬號並開通物件儲存服務。在準備工作完成之後,需要匯入 JAVA 版本的 SDK,這裡使用 maven 進行匯入
<!-- 阿里雲OSS物件儲存 --> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.8.0</version> </dependency>
2. 修改配置檔案
匯入完成後在 application.properties
配置檔案中新增以下內容
# 節點域名 aliyun.oss.endpoint=oss-cn-xxxxxxx.aliyuncs.com # 賬戶id aliyun.oss.accessKeyId=xxxxxxxxxxxxx # 賬戶密碼 aliyun.oss.accessKeySecret=xxxxxxxxxxxxx # bucket名稱 aliyun.oss.bucketName=xxxxxxxxxxx # 簽名過期時間 aliyun.oss.policy.expire=300 # 上傳檔案的最大尺寸 aliyun.oss.maxSize=10 # 上傳地址的字首 aliyun.oss.dir.prefix=xxx # 回撥引數的請求地址 aliyun.oss.callback=http://www.xxxxxx.com/api/aliyun/oss/callback
以上內容在開通服務後均可獲取到,請根據實際情況進行修改
3. 初始化
OSSClient是OSS的Java客戶端,用於管理儲存空間和檔案等OSS資源。使用Java SDK發起OSS請求,您需要初始化一個OSSClient例項,並根據需要修改ClientConfiguration的預設配置項。
根據官方文件的描述,需要初始化一個ossClient
例項並將其注入到Spring容器中,因此可以編寫一個配置類OssConfig
@Configuration @PropertySource(value = {"classpath:application.properties"},encoding = "utf-8") public class OssConfig { @Value("${aliyun.oss.endpoint}") private String endpoint; @Value("${aliyun.oss.accessKeyId}") private String accessKeyId; @Value("${aliyun.oss.accessKeySecret}") private String secretAccessKey; @Bean public OSS ossClient(){ return new OSSClientBuilder().build(endpoint,accessKeyId,secretAccessKey); } }
更多詳細的配置,請參考官方文件:初始化
二、檔案上傳
1. 流程分析
我們以典型的表單上傳為例,在使用物件儲存OSS後,表單上傳分為以下幾個流程:
注:Policy表單域用於驗證請求的合法性。例如可以指定上傳的大小,可以指定上傳的Object名稱等,上傳成功後客戶端跳轉到的URL,上傳成功後客戶端收到的狀態碼。
PolicyConditions policyConds = new PolicyConditions(); policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,maxSize); policyConds.addConditionItem(MatchMode.StartWith,PolicyConditions.COND_KEY,DIR_PREFIX); String postPolicy = ossClient.generatePostPolicy(expiration,policyConds); byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8); // 將Policy字串進行base64編碼 String policy = BinaryUtil.toBase64String(binaryData); // 用OSS的AccessKeySecret對base64編碼後的Policy進行簽名 String signature = ossClient.calculatePostSignature(postPolicy);
前端向OSS伺服器上傳檔案時要上傳Policy表單域,OSS伺服器將對Policy表單域的內容進行驗證。關於 Post Policy 的詳細內容,請參考官方文件:Post Policy
當檔案上傳成功後,OSS伺服器會嚮應用伺服器發起回撥請求,具體流程如下:
使用者只需要在傳送給 OSS 的請求中攜帶相應的 Callback 引數,即能實現回撥。
Callback 引數是由一段經過 base64 編碼的 JSON 字串(欄位)。構建 callback 引數的關鍵是指定請求回撥的伺服器 URL(callbackUrl)以及回撥的內容(callbackBody)。
// 上傳回調引數 Callback callback = new Callback(); // 指定請求回撥的伺服器URL callback.setCallbackUrl(CALLBACK); //(可選)設定回撥請求訊息頭中Host的值,即您的伺服器配置Host的值。 // callback.setCallbackHost("yourCallbackHost"); // 設定發起回撥時請求body的值。 callback.setCallbackBody("{\\\"filename\\\":${object},\\\"mineType\\\":${mimeType}}"); // 設定發起回撥請求的Content-Type。 callback.setCalbackBodyType(Callback.CalbackBodyType.JSON); // 設定發起回撥請求的自定義引數,由Key和Value組成,Key必須以x:開始。 // callback.addCallbackVar("x:dir","value");
更詳細的內容請閱讀官方文件:Callback
2. 功能實現
首先編寫 Post Policy 封裝物件OssPolicyResult
@Data public class OssPolicyResult { @ApiModelProperty("使用者id") private String accessKeyId; @ApiModelProperty("Post Policy經過base64編碼過的字串") private String policy; @ApiModelProperty("對policy簽名後的字串") private String signature; // @ApiModelProperty("物件的鍵值") // private String key; @ApiModelProperty("上傳資料夾路徑字首") private String dir; @ApiModelProperty("oss對外服務的訪問域名") private String host; @ApiModelProperty("上傳成功後的回撥設定") private String callback; }
然後需自定義一個回撥結果物件OssCallBackResult
@Data public class OssCallBackResult { @ApiModelProperty("檔案的連結") private String url; @ApiModelProperty("檔名稱") private String filename; @ApiModelProperty("檔案大小") private String size; @ApiModelProperty("檔案的mimeType") private String mimeType; @ApiModelProperty("圖片檔案的寬") private String width; @ApiModelProperty("圖片檔案的高") private String height; }
注:以上內容可根據實際需要進行修改
之後編寫 Service 介面及實現類
Service 介面:
public interface OssService { // 生成Post Policy OssPolicyResult policy(); // 上傳成功後的回撥 OssCallBackResult callback(Map<String,Object> requestBody); }
Service 實現類:
@Slf4j @Service @PropertySource(value = {"classpath:application.properties"},encoding = "utf-8") public class OssServiceImpl implements OssService { @Value("${aliyun.oss.endpoint}") private String ENDPOINT; @Value("${aliyun.oss.accessKeyId}") private String ACCESS_KEY_ID; @Value("${aliyun.oss.accessKeySecret}") private String SECRET_ACCESS_KEY; @Value("${aliyun.oss.bucketName}") private String BUCKET_NAME; @Value("${aliyun.oss.policy.expire}") private int EXPIRE; @Value("${aliyun.oss.maxSize}") private int MAX_SIZE; @Value("${aliyun.oss.dir.prefix}") private String DIR_PREFIX; @Value("${aliyun.oss.callback}") private String CALLBACK; @Autowired private OSS ossClient; @Override public OssPolicyResult policy() { OssPolicyResult result = new OssPolicyResult(); // 簽名有效期 long expireEndTime = System.currentTimeMillis() + EXPIRE * 1000; Date expiration = new Date(expireEndTime); // 檔名稱 // String filename = UUID.randomUUID().toString(); // 檔案大小 long maxSize = MAX_SIZE * 1024 * 1024; // 提交節點 String action = "http://" + BUCKET_NAME + "." + ENDPOINT; // 上傳回調引數 Callback callback = new Callback(); // 指定請求回撥的伺服器URL callback.setCallbackUrl(CALLBACK); //(可選)設定回撥請求訊息頭中Host的值,即您的伺服器配置Host的值。 // callback.setCallbackHost("yourCallbackHost"); // 設定發起回撥時請求body的值。 callback.setCallbackBody("{\\\"filename\\\":${object}}"); // 設定發起回撥請求的Content-Type。 callback.setCalbackBodyType(Callback.CalbackBodyType.JSON); // 設定發起回撥請求的自定義引數,由Key和Value組成,Key必須以x:開始。 // callback.addCallbackVar("x:dir","value"); try { PolicyConditions policyConds = new PolicyConditions(); policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,maxSize); policyConds.addConditionItem(MatchMode.StartWith,DIR_PREFIX); String postPolicy = ossClient.generatePostPolicy(expiration,policyConds); byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8); // 將Policy字串進行base64編碼 String policy = BinaryUtil.toBase64String(binaryData); // 用OSS的AccessKeySecret對base64編碼後的Policy進行簽名 String signature = ossClient.calculatePostSignature(postPolicy); // 將callback配置進行base64編碼 String callbackData = BinaryUtil.toBase64String(OSSUtils.jsonizeCallback(callback).getBytes()); // 返回結果 result.setAccessKeyId(ACCESS_KEY_ID); result.setPolicy(policy); result.setSignature(signature); // result.setKey(filename); result.setDir(dir); result.setHost(action); result.setCallback(callbackData); } catch (Exception e) { log.error("簽名生成失敗",e); } return result; } @Override public OssCallBackResult callback(Map<String,Object> requestBody) { OssCallBackResult ossCallbackResult = new OssCallBackResult(); // 檔名 String filename = requestBody.get("filename").toString(); // 檔案連結 String url = "https://" + BUCKET_NAME + "." + ENDPOINT + "/" + DIR_PREFIX + "/" + filename; ossCallbackResult.setUrl(url); return ossCallbackResult; } }
新增 Controller 層:
@Api(tags = "阿里雲物件儲存介面") @RequestMapping("/api") @RestController public class OssController { @Autowired private OssService ossService; @ApiOperation(value = "OSS上傳簽名生成") @GetMapping("/aliyun/oss/policy") public Object policy() { return ossService.policy(); } @ApiOperation(value = "OSS上傳成功回撥") @PostMapping("/aliyun/oss/callback") public Object callback(@RequestBody Map<String,Object> requestBody) { return ossService.callback(requestBody); } }
到此這篇關於Spring Boot專案中實現檔案上傳功能的示例的文章就介紹到這了,更多相關Spring Boot實現檔案上傳內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!