需求場景:
公司對APP調用的后台接口有個公用格式如下,外層包含了一些設備、版本、簽名信息,主要的業務參數是在body里,外層信息都是在網關解決,驗證簽名后,在轉發body到后台服務。
{
"appVersion":"1.0.0",
"equipmentNo":"***********",
"equipmentType":"ios",
"mobile":"134*******",
"registrationId":"*******",
"sign":"**********",
"token":"*************",
"body":"{*****}"
}
目前開發一個新的APP后台,要先提供接口與移動端聯調,網關開發延后,這時的服務端接口是不能直接拿到body的,也不方便在@RequestBody參數都包裝上外層的字段。
解決方法1:使用攔截器從HttpServletRequest獲取POST數據,取出body數據,再替換HttpServletRequest的參數。
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
StringBuffer jb = new StringBuffer();
String line = null;
BufferedReader reader = null;
PrintWriter out = null;
try {
reader = request.getReader();
while ((line = reader.readLine()) != null){
jb.append(line);
}
JSONObject object = JSON.parseObject(jb.toString());
String body = object.getString("body");
out = response.getWriter();
out.append(body);
} catch (Exception e) {
e.printStackTrace();
if(reader != null){
reader.close();
}
if(out != null){
out.close();
}
}
}
這種方式可以提取POST傳入的對象,並替換,但會報以下錯誤,所以還不建議使用。
getReader() has already been called for this request
解決方案二:使用AOP,攔截所有Controller
@Around(value = "allController()") private void doAround(ProceedingJoinPoint joinPoint) { try { //所有參數 Object[] args = joinPoint.getArgs(); if(args != null && args.length > 0 ){ Object obj = args[0]; //記錄@RequestBody注解的對象類型 Class<?> aClass = obj.getClass(); JSONObject object = JSON.parseObject(JSONUtil.toJson(obj)); //提取body, String body = object.getString("body"); if(StringUtils.isNotBlank(body)){ //替換參數,並回寫 body = body.replaceAll("\\\\",""); JSONObject bodyStr = JSON.parseObject(body); args[0] = JSONUtil.fromJson(bodyStr.toJSONString(), aClass); joinPoint.proceed(args); } } } catch (Exception e) { e.printStackTrace(); } catch (Throwable throwable) { throwable.printStackTrace(); } }
這個方式順利解決當前的問題,不過因為使用AOP,Spring框架已經對接收到的參數進行了轉換,是拿不到body的值的。所以在所有Controller接口的請求參數類,都加一個String body 屬性,才能接收到body的值。我是定義了一個公共對象,只有一個String body屬性,讓參數類集成這個公共對象,以后不用再刪除就好了。