正文
动态修改HttpServletRequest的Post请求参数
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
需求场景:
公司对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属性,让参数类集成这个公共对象,以后不用再删除就好了。