一、問題
之前寫過一篇《SpringBoot 介面引數解密的實現方法(使用註解)》,程式碼一直跑著都沒問題,但是最近發現入參特別長的時候,inputMessage.getBody() 這段程式碼拿不到完整的入參,會被截斷。
看了下原始碼,好像預設它轉換的時候就截斷了。
而且只有線上有問題,本地測試無法復現該問題。
二、解決辦法
看了下原始碼,RequestBodyAdviceAdapter
這個靜態類除了 beforeBodyRead
這個方法外,還有個 afterBodyRead
方法,原來我一直以為 beforeBodyRead
是 Controller
層之前執行,afterBodyRead
是在 Controller
層之後執行,後來我發現我理解錯了,它們都是在 Controller
層之前執行。
並且,beforeBodyRead
方法是在 afterBodyRead
方法之前執行,走這兩個方法之前都會走一次 supports
方法來判斷是否執行。
於是我就把解密邏輯挪到了 afterBodyRead
方法裡,就不存在入參超長被截斷的問題了。
注意:剛剛另一個專案上線發現,afterBodyRead 讀取的是 Controller 中 RequestBody 的實體類,若實體類中有可為空並且設定了預設值的,比如分頁引數 pageNo 預設為1,如果客戶端沒傳,afterBodyRead 中讀取到的就是1,會解密失敗。
/**
* 請求引數解密
* http://www.zzvips.com/article/187109.html
* https://www.cnblogs.com/shamo89/p/16498217.html
*/
@ControllerAdvice
@Slf4j
public class DecryptRequest extends RequestBodyAdviceAdapter {
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return methodParameter.hasMethodAnnotation(Decrypt.class) || methodParameter.hasParameterAnnotation(Decrypt.class);
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
try {
String requestBody = JSONUtils.serializeObject(body);
// log.info("requestBody=" + requestBody);
// 轉換為物件
JSONObject bodyObj = JSONObject.parseObject(requestBody);
// 定義無需解密引數
List<String> noDecryptFiled = Arrays.asList("appClient", "channel", "version", "token", "projectId");
// 定義解密後引數map
HashMap<String, String> decryptParam = new HashMap<>();
// 迴圈請求物件
for (Map.Entry<String, Object> stringObjectEntry : bodyObj.entrySet()) {
if (stringObjectEntry.getValue() == null) {
continue;
}
String key = stringObjectEntry.getKey();
String value = stringObjectEntry.getValue().toString();
// 如果是開發環境,無需解密
if (Result.getEnv().equals("dev")) {
decryptParam.put(key, value);
continue;
}
// 若是無需解密引數,直接put進decryptParam
if (noDecryptFiled.contains(stringObjectEntry.getKey())) {
decryptParam.put(key, value);
continue;
}
// 解密
decryptParam.put(key, AESUtil.decrypt(value, Result.SALT));
}
body = JSONObject.parseObject(JSON.toJSONString(decryptParam), targetType);
} catch (IOException e) {
throw new BaseException(SystemErrorType.BUSINESS_ERROR, "引數解密失敗,請檢查");
}
// log.info("body=" + JSON.toJSONString(body));
return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
}
}
參考文章
SpringMvc裡的RequestBodyAdviceAdapter使用問題
本作品採用《CC 協議》,轉載必須註明作者和本文連結