Spring拦截器获取request请求体中的json数据,并转换成Java对象的解决办法

1,115 阅读2分钟

1、要被拦截的Controller接口

我们需要一个更新用户信息接口,请求方式为POST,参数类型为对象类型(UserInfo),代码如下:

@Resource
private UserService userService;

/**
 * 更新用户信息
 *
 * @param request
 * @param userInfo
 * @return
 */
@RequestMapping(value = "/updateUserInfo", produces = "application/json;charset=UTF-8",
    method = RequestMethod.POST)
public JSONObject updateUserInfo(HttpServletRequest request, @RequestBody UserInfo userInfo) {
  	...
    userService.updateUserInfo(userInfo);  
    ...
}

2、拦截器

我们要在拦截器中拦截该接口,并获取其请求参数UserInfo对象。

如果只是获取普通的请求对象(eg:用户ID -> userId),我们可以直接在拦截器中,通过如下代码即可获取request请求体中的参数数据:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {
	  ......
      // user ID为string类型,所以可以直接拿到数据,
	  // 但是如果参数是对象类型/JSON类型数据,则无法通过这种方式获取!
	  String userId = request.getParameter("userId");
	  
	  .....
}

3、HttpServletRequestWrapper解决这一问题

在拦截器中写一个内部类 RequestWrapper ,让其继承 HttpServletRequestWrapper:

class RequestWrapper extends HttpServletRequestWrapper {

RequestWrapper 重写父类方法,最终完整的拦截器代码如下:

/**
 * 拦截器: 
 *
 * @author csp
 * @date 2022-01-06 15:36:41
 */
public class UserInterceptor implements HandlerInterceptor {

    private final static Logger logger = LoggerFactory.getLogger(UserInterceptor.class);

    @Resource
    private UserService userService;

    /**
     * 前置拦截
     *
     * @param request
     * @param response
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        // 从request请求体中拿到body中的JSON对象参数
        RequestWrapper requestWrapper = new RequestWrapper(request);
        String jsonBody = requestWrapper.getBody();
        UserInfo userInfo = JSONObject.toJavaObject(JSONObject.parseObject(jsonBody), UserInfo.class);

        // 根据userInfo校验是否具备权限
        Boolean isAuth = userService.getAuthByUserInfo(userInfo);
        if (!isAuth) {
            // response响应给浏览器无权限,代码略
          	...
            return false;
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception {}

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {}

    // RequestWrapper 内部类
    class RequestWrapper extends HttpServletRequestWrapper {
        private final String body;

        public RequestWrapper(HttpServletRequest request) {
            super(request);
            StringBuilder stringBuilder = new StringBuilder();
            BufferedReader bufferedReader = null;
            InputStream inputStream = null;
            try {
                inputStream = request.getInputStream();
                if (inputStream != null) {
                    bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                    char[] charBuffer = new char[128];
                    int bytesRead = -1;
                    while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                        stringBuilder.append(charBuffer, 0, bytesRead);
                    }
                } else {
                    stringBuilder.append("");
                }
            } catch (IOException ex) {

            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (bufferedReader != null) {
                    try {
                        bufferedReader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            body = stringBuilder.toString();
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
            ServletInputStream servletInputStream = new ServletInputStream() {
                @Override
                public boolean isFinished() {
                    return false;
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setReadListener(ReadListener readListener) {
                }

                @Override
                public int read() throws IOException {
                    return byteArrayInputStream.read();
                }
            };
            return servletInputStream;

        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(this.getInputStream()));
        }

        public String getBody() {
            return this.body;
        }
    }
}

这样,就可以在拦截器中,拦截request请求,并获取request请求体中的json/对象类型的参数啦!