RequestBodyAdvice接口
它是SpringMVC提供的一個接口,類注釋如下
允許在請求體被讀取並轉換為Object之前對請求進行定制,也允許在結果對象作為@RequestBody或HttpEntity方法參數傳遞給控制器方法之前對其進行處理。 該接口的實現可以直接注冊到RequestMappingHandlerAdapter,或者更有可能使用@ControllerAdvice注釋,在這種情況下它們會被自動檢測。
它提供了四個方法
- supports:首次調用,判斷這個攔截器是否適用這次請求,返回boolean
- beforeBodyRead:在轉換至Controller參數對象之前調用,加工請求頭和請求體
- afterBodyRead:在轉換至Controller參數對象之后調用,處理這個對象
- handleEmptyBody:當參數為空時調用,可以返回請求體,也可以返回null正常觸發Body為空的報錯
實現方式
我們的思路是這樣的,首先自定義一個注解@Encrypt
,用在被@RequestBody
標記的參數上。
然后我們實現RequestBodyAdvice
接口,首先實現supports
接口,通過判斷是否標注了我們的注解,來決定是否進行解密操作
@Override
public boolean supports(
MethodParameter methodParameter, Type type,
Class<? extends HttpMessageConverter<?>> aClass) {
return methodParameter.hasParameterAnnotation(Encrypt.class);
}
然后,我們在beforeBodyRead
方法中,實現我們解密的核心操作
@Override
public HttpInputMessage beforeBodyRead(
HttpInputMessage httpInputMessage,
MethodParameter methodParameter, Type type,
Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
return new HttpInputMessage() {
@Override
public InputStream getBody() throws IOException {
logger.info("請求頭參數:"+ httpInputMessage.getHeaders());
logger.info("在此處去掉請求參數外層data");
String body = IOUtils.toString(httpInputMessage.getBody());
JSONObject jasonObject = JSONObject.parseObject(body);
String content = (String)jasonObject.get("data");
//進行解密操作
String after = null;
try {
DESUtils desUtils = new DESUtils(desKey);
after = desUtils.decryptString(content);
} catch (Exception e) {
logger.error("解密失敗");
}
return new ByteArrayInputStream
(after.getBytes(StandardCharsets.UTF_8));
}
@Override
public HttpHeaders getHeaders() {
return httpInputMessage.getHeaders();
}
};
}
afterBodyRead
接口直接返回Object,不做任何其他處理
根據類文檔說明,要向讓這個自定義的RequestBodyAdvice
起作用,我們可以給它添加上@ControllerAdvice
注解,他就可以自動注冊到Spirng容器,而后注冊到RequestMappingHandlerAdapter
中
至此,我們就實現了我們的功能。
思考
我們可以看到,在SpringMVC中有很多類似的Adapter,它們大部分都為我們提供了簡單的擴展方式。通過探究這些接口在系統中生效的原理,也是我們看SpringMVC源碼很好的切入點