天天看點

servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳

本文主要講解mall整合OSS實作檔案上傳的過程,采用的是服務端簽名後前端直傳的方式。

OSS

阿裡雲對象存儲服務(Object Storage Service,簡稱 OSS),是阿裡雲提供的海量、安全、低成本、高可靠的雲存儲服務。OSS可用于圖檔、音視訊、日志等海量檔案的存儲。各種終端裝置、Web網站程式、移動應用可以直接向OSS寫入或讀取資料。

OSS中的相關概念

  • Endpoint:通路域名,通過該域名可以通路OSS服務的API,進行檔案上傳、下載下傳等操作。
  • Bucket:存儲空間,是存儲對象的容器,所有存儲對象都必須隸屬于某個存儲空間。
  • Object:對象,對象是 OSS 存儲資料的基本單元,也被稱為 OSS 的檔案。
  • AccessKey:通路密鑰,指的是通路身份驗證中用到的 AccessKeyId 和 AccessKeySecret。

OSS的相關設定

開通OSS服務

  • 登入阿裡雲官網;
  • 将滑鼠移至産品标簽頁,單擊對象存儲 OSS,打開OSS 産品詳情頁面;
  • 在OSS産品詳情頁,單擊立即開通。

建立存儲空間

  • 點選網頁右上角控制台按鈕進入控制台
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 選擇我的雲産品中的對象存儲OSS
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 點選左側存儲空間的加号建立存儲空間
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 建立存儲空間并設定讀寫權限為公共讀
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳

跨域資源共享(CORS)的設定

由于浏覽器處于安全考慮,不允許跨域資源通路,是以我們要設定OSS的跨域資源共享。
  • 選擇一個存儲空間,打開其基礎設定
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 點選跨越設定的設定按鈕
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 點選建立規則
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 進行跨域規則設定
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳

服務端簽名後前端直傳的相關說明

流程示例圖

servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳

流程介紹

  1. Web前端請求應用伺服器,擷取上傳所需參數(如OSS的accessKeyId、policy、callback等參數)
  2. 應用伺服器傳回相關參數
  3. Web前端直接向OSS服務發起上傳檔案請求
  4. 等上傳完成後OSS服務會回調應用伺服器的回調接口
  5. 應用伺服器傳回響應給OSS服務
  6. OSS服務将應用伺服器回調接口的内容傳回給Web前端

整合OSS實作檔案上傳

在pom.xml中添加相關依賴

com.aliyun.oss

aliyun-sdk-oss

2.5.0

修改SpringBoot配置檔案

修改application.yml檔案,添加OSS相關配置。

注意:endpoint、accessKeyId、accessKeySecret、bucketName、callback、prefix都要改為你自己帳号OSS相關的,callback需要是公網可以通路的位址。

# 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的相關Java配置

用于配置OSS的連接配接用戶端OSSClient。

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;

@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 com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

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上傳成功後的回調參數對象OssCallbackParam

當OSS上傳成功後,會根據該配置參數來回調對應接口。

package com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

public class OssCallbackParam {

@ApiModelProperty("請求的回調位址")

private String callbackUrl;

@ApiModelProperty("回調是傳入request中的參數")

private String callbackBody;

@ApiModelProperty("回調時傳入參數的格式,比如表單送出形式")

private String callbackBodyType;

//省略了所有getter,setter方法

}

OSS上傳成功後的回調結果對象OssCallbackResult

回調接口中傳回的資料對象,封裝了上傳檔案的資訊。

package com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

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方法

}

添加OSS業務接口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;

public interface OssService {

OssPolicyResult policy();

OssCallbackResult callback(HttpServletRequest request);

}

添加OSS業務接口OssService的實作類OssServiceImpl

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;

@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;

}

}

添加OssController定義接口

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;

@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);

}

}

進行接口測試

測試擷取上傳政策的接口

servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳

啟動mall-admin-web前端項目來測試上傳接口

  • 如何啟動前端項目,具體參考該項目的readme文檔:https://github.com/macrozheng/mall-admin-web
  • 點選添加商品品牌的上傳按鈕進行測試
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 會調用兩次請求,第一次通路本地接口擷取上傳的政策
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 第二次調用oss服務 的接口進行檔案上傳
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
  • 可以看到上面接口調用并沒有傳入回調參數callback,是以接口傳回了204 no content,這次我們傳入回調參數callback試試,可以發現oss服務回調了我們自己定義的回調接口,并傳回了相應結果。
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳

項目源碼位址

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

參考資料

  • 開通OSS服務:https://help.aliyun.com/document_detail/31884.html?spm=a2c4g.11186623.6.566.74b87eaebrfQno
  • 建立存儲空間:https://help.aliyun.com/document_detail/31885.html?spm=a2c4g.11186623.6.567.496228bcVZUZqB
  • 跨域資源共享(CORS):https://help.aliyun.com/document_detail/31928.html?spm=5176.11065259.1996646101.searchclickresult.4d1a5607Pf3e9i
  • 服務端簽名直傳并設定上傳回調:https://help.aliyun.com/document_detail/31927.html?spm=a2c4g.11186623.6.1268.2c256506mNqV1t

推薦閱讀

  • mall架構及功能概覽
  • mall學習所需知識點(推薦資料)
  • mall整合SpringBoot+MyBatis搭建基本骨架
  • mall整合Swagger-UI實作線上API文檔
  • mall整合Redis實作緩存功能
  • mall整合SpringSecurity和JWT實作認證和授權(一)
  • mall整合SpringSecurity和JWT實作認證和授權(二)
  • mall整合SpringTask實作定時任務
  • mall整合Elasticsearch實作商品搜尋
  • mall整合Mongodb實作文檔操作
  • mall整合RabbitMQ實作延遲消息
servlet 上傳圖檔無法立即重新整理顯示_mall整合OSS實作檔案上傳

歡迎關注,點個在看

繼續閱讀