动态修改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属性,让参数类集成这个公共对象,以后不用再删除就好了。

 

 

 

posted @ 2019-11-19 20:19  闲人鹤  阅读(8743)  评论(0编辑  收藏  举报