springboot|springboot HandlerIntercepter拦截器修改request body数据的操作

实际工作中学习技术是最快、最深刻的。当然,自身的持续学习意识是必须的
技术栈版本:
spring boot 2.0.2
遇到事儿了 近来做业务需求,前端同学fe将userIduserName放到request header中了。
后端api接口要想使用userIduserName,每个接口都要从header中获取。
试想一下,如果你有十个接口,那么每个接口都要写一遍

Object.setUserId(request.getHeader("userId"))

正如下面代码段
@RestController@Validated@RequestMapping("/template")public class TemplateController {// 一个feign client@Autowired TemplateClient templateClient@PostMapping(value = "https://www.it610.com/create", produces = MediaType.APPLICATION_JSON_VALUE)public ResultVO create(@RequestBody @Valid TemplateParam param, HttpServletRequest request) {// 每个接口都要写一遍setXXX()方法param.setUserId(request.getHeader("userId")); param.setUserName(request.getHeader("userName")); return templateClient.createTemplate(param).toResultVO(); }}@Datapublic class TemplateParam{private Long templateId; private Long userId; private String userName; }

解决办法 大家都知道的两大利器,
tomcatFilterspringIntercepter(具体为HandlerIntercepter)
实现原理 具体方法为定义一个Filter实现类和一个HandlerIntercepter的实现类。再定义一个HttpServletRequest实现类,其作用分别为
Filter实现类:UserInfoFilter
创建一个入口,在这个入口中定义一个机会:将我们自定义的CustomHttpServletRequestWrapper代替HttpServletRequest随着请求传递下去
HttpServletRequest实现类:customHttpServletRequestWrapper
因为HttpServletRequest对象的body数据只能get,不能set,即不能再次赋值。
而我们的需求是需要给HttpServletRequest赋值,所以需要定义一个HttpServletRequest实现类:customHttpServletRequestWrapper,这个实现类可以被赋值来满足我们的需求。
HandlerIntercepter的实现类:CustomInterceptor
拦截请求,获取接口方法相关信息(方法名,参数,返回值等)。从而实现统一的给request body动态赋值
实现思路如上所述,具体的实现代码如下
代码实现
声明基础bean: UserInfoParam
UserInfoParam:定义了包含userId,userName的实体bean,要想将用户信息注入进入,需要入参对象XXXParam继承UserInfoParam,拦截器中只处理@Requestbody中实现了UserInfoParam类的bean
如上文controllercreate方法的入参:TemplateParam,继承UserInfoParam
@Datapublic class TemplateParam extends UserInfoParam{private Long templateId; // private Long userId; // private String userName; }@Datapublic class UserInfoParam {// 用户idprivate Long userId; // 用户名称private String userName; }

定义Filter实现类: UserInfoFilter
@Slf4jpublic class UserInfoFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {CustomHttpServletRequestWrapper customHttpServletRequestWrapper = null; try {HttpServletRequest req = (HttpServletRequest)request; customHttpServletRequestWrapper = new CustomHttpServletRequestWrapper(req); }catch (Exception e){log.warn("customHttpServletRequestWrapper Error:", e); }chain.doFilter((Objects.isNull(customHttpServletRequestWrapper) ? request : customHttpServletRequestWrapper), response); }}

HttpServletRequest实现类:CustomHttpServletRequestWrapper
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {// 保存request body的数据private String body; // 解析request的inputStream(即body)数据,转成字符串public CustomHttpServletRequestWrapper(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(); }@Overridepublic ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); ServletInputStream servletInputStream = new ServletInputStream() {@Overridepublic boolean isFinished() {return false; }@Overridepublic boolean isReady() {return false; }@Overridepublic void setReadListener(ReadListener readListener) {}@Overridepublic int read() throws IOException {return byteArrayInputStream.read(); }}; return servletInputStream; }@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(this.getInputStream())); }public String getBody() {return this.body; }// 赋值给body字段public void setBody(String body) {this.body = body; }}

HandlerIntercepter的实现类:CustomInterceptor
@Slf4jpublic class CustomInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {if (!(handler instanceof HandlerMethod)) {return true; }HandlerMethod handlerMethod = (HandlerMethod)handler; pushUserInfo2Body(request, handlerMethod); return true; }private void pushUserInfo2Body(HttpServletRequest request, HandlerMethod handlerMethod) {try{String userId = request.getHeader("userId"); String userName = request.getHeader("userName"); MethodParameter[] methodParameters = handlerMethod.getMethodParameters(); if(ArrayUtils.isEmpty(methodParameters)) {return; }for (MethodParameter methodParameter : methodParameters) {Class clazz = methodParameter.getParameterType(); if(ClassUtils.isAssignable(UserInfoParam.class, clazz)){if(request instanceof CustomHttpServletRequestWrapper){CustomHttpServletRequestWrapper requestWrapper = (CustomHttpServletRequestWrapper)request; String body = requestWrapper.getBody(); JSONObject param = JSONObject.parseObject(body); param.put("userId", userId); param.put("userName", Objects.isNull(userName) ? null : URLDecoder.decode(userName, "UTF-8")); requestWrapper.setBody(JSON.toJSONString(param)); }}}}catch (Exception e){log.warn("fill userInfo to request body Error ", e); }}

定义Configuration class,增加拦截器和过滤器的配置
WebMvcConfigurer子类:CustomWebMvcConfigurer
@Configurationpublic class CustomWebMvcConfigurer implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {CustomInterceptor customInterceptor= new CustomInterceptor(); registry.addInterceptor(customInterceptor); }@Beanpublic FilterRegistrationBean servletRegistrationBean() {UserInfoFilter userInfoFilter = new UserInfoFilter(); FilterRegistrationBean bean = new FilterRegistrationBean<>(); bean.setFilter(userInfoFilter); bean.setName("userInfoFilter"); bean.addUrlPatterns("/*"); bean.setOrder(Ordered.LOWEST_PRECEDENCE); return bean; }}

到此,实现功能的代码撸完了。启动spring boot App,就可以curl访问restful接口了
http访问
curl -X POST \http://localhost:8080/template/create-H 'Content-Type: application/json'-H 'username: tiankong天空'-H 'userId: 11'-d '{"templateId": 1000}

效果 可以看到TemplateController.create(…)打出的信息,userIdusername的值正是header中传的值
toDo
【springboot|springboot HandlerIntercepter拦截器修改request body数据的操作】剩下的就看你的了,以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

    推荐阅读