好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

实际工作中学习技术是最快、最深刻的。当然,自身的持续学习意识是必须的

技术栈版本:

spring boot 2.0.2

遇到事儿了

近来做业务需求,前端同学fe将 userId 和 userName 放到 request header 中了。

后端api接口要想使用 userId 和 userName ,每个接口都要从 header 中获取。

试想一下,如果你有十个接口,那么每个接口都要写一遍

?

1

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

正如下面代码段

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

@RestController

@Validated

@RequestMapping ( "/template" )

public class TemplateController {

     // 一个feign client

     @Autowired

     TemplateClient templateClient

     @PostMapping (value = "/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();

     }

}  

@Data

public class TemplateParam{

     private Long templateId;

     private Long userId;

     private String userName;

}

解决办法

大家都知道的两大利器,

tomcat 的 Filter 和 spring 的 Intercepter (具体为 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 。

如上文 controller 中 create 方法的入参: TemplateParam ,继承 UserInfoParam

?

1

2

3

4

5

6

7

8

9

10

11

12

13

@Data

public class TemplateParam extends UserInfoParam{

     private Long templateId;

     // private Long userId;

     // private String userName;

}

@Data

public class UserInfoParam {

// 用户id

private Long userId;

// 用户名称

private String userName;

}

定义Filter实现类: UserInfoFilter

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@Slf4j

public class UserInfoFilter implements Filter {

     @Override

     public 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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

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();

     }

     @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;

     }

     // 赋值给body字段

     public void setBody(String body) {

         this .body = body;

     }

}

HandlerIntercepter 的实现类: CustomInterceptor

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

@Slf4j

public class CustomInterceptor implements HandlerInterceptor {

     @Override

     public 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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@Configuration

public class CustomWebMvcConfigurer implements WebMvcConfigurer {

     @Override

     public void addInterceptors(InterceptorRegistry registry) {

         CustomInterceptor customInterceptor= new CustomInterceptor();

         registry.addInterceptor(customInterceptor);

     }

     @Bean

     public FilterRegistrationBean servletRegistrationBean() {

         UserInfoFilter userInfoFilter = new UserInfoFilter();

         FilterRegistrationBean<UserInfoFilter> bean = new FilterRegistrationBean<>();

         bean.setFilter(userInfoFilter);

         bean.setName( "userInfoFilter" );

         bean.addUrlPatterns( "/*" );

         bean.setOrder(Ordered.LOWEST_PRECEDENCE);

         return bean;

     }

}

到此,实现功能的代码撸完了。启动 spring boot App ,就可以 curl 访问 restful 接口了

http访问

?

1

2

3

4

5

6

7

curl -X POST \

   http: //localhost:8080/template/create

   -H 'Content-Type: application/json'

   -H 'username: tiankong天空'

   -H 'userId: 11'

   -d '{

   "templateId" : 1000 }

效果

可以看到 TemplateController.create(…) 打出的信息, userId 和 username 的值正是 header 中传的值

toDo

剩下的就看你的了,以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://yaoyuanyy.github.io/

查看更多关于springboot HandlerIntercepter拦截器修改request body数据的操的详细内容...

  阅读:61次