好得很程序员自学网

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

使用SpringMVC 重写、扩展HttpServletRequest请求参数

一、背景说明

由于在项目进行前后端分离改造时,请求由多种传参方式统一定义为JSON格式传输,在改造过程中需要前后版本兼容。如果能在Controller接收参数之前将JSON格式参数进行解析成原有参数,对Request请求参数进行重写,这样能可以大大减少开发成本。

二、调研

抱着对Request请求参数目标出发,对@InitBinder和HttpServletRequestWrapper进行了研究,最终使用HttpServletRequestWrapper解决了当前问题。

1、@InitBinder

初次接触时是用在对Date类型参数进行转换,常用方法如下所示:

?

1

2

3

4

5

6

7

8

9

@InitBinder

protected void initBinder(WebDataBinder binder) {

  SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd" );

  dateFormat.setLenient( true );

     //根据时间类型进行转换

  binder.registerCustomEditor(Date. class , new CustomDateEditor(dateFormat, true ));

     //指定参数字段名称进行转换

  binder.registerCustomEditor(Date. class , "registerDate" , new CustomDateEditor(dateFormat, true ));

}

注:如果Controller的方法没有一个参数时,@initBinder标注的方法并不会执行(这个也比较好理解)

也可以通过自定义Editor对参数进行解析,详见: http://HdhCmsTesttuohang.net/article/155117.html

但是通过@InitBinder并不能满足我的要求,因为registerCustomEditor需要知道将要转换成的参数类型,由于我得Controller参数类型因方法不同而不同。

2、HttpServletRequestWrapper

通过重写HttpServletRequest或者继承HttpServletRequestWrapper对HttpServletRequest进行装饰,可以对请求请求参数进行修改。

重写HttpServletRequest 工作量较大(其中方法较多),继承HttpServletRequestWrapper对HttpServletRequest进行装饰实现起来比较简单,仅需要对不满足你的需求接口进行重写就可以(首选)。

重写HttpServletRequest,代码如下所示:

?

1

2

3

4

5

6

7

8

9

public class MyHttpServletRequest implements HttpServletRequest {

     @Override

     public String getAuthType()

  @Override

      public Cookie[] getCookies()

  @Override

     public long getDateHeader(String s)

     //.......

}

自定义HttpServletRequest装饰器HttpServletRequestWrapper和Filter过滤器,代码如下所示:

?

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

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

package com.timer.web.interceptor;

import com.alibaba.fastjson.JSONObject;

import com.timer测试数据mon.utils.JsonUtil;

import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.util.Enumeration;

import java.util.Map;

import java.util.Vector;

import java.util.concurrent.ConcurrentHashMap;

 

public class MyParametersFilter extends OncePerRequestFilter {

     @Override

     protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

         MyParametersWrapper myParametersWrapper = new MyParametersWrapper(httpServletRequest);

         filterChain.doFilter(myParametersWrapper, httpServletResponse);

     }

 

     /**

      * 继承HttpServletRequestWrapper,创建装饰类,以达到修改HttpServletRequest参数的目的

      */

     private class MyParametersWrapper extends HttpServletRequestWrapper {

 

         private static final String  OTHER_PARAM = "other" ;

  

         private Map<String, String[]> parameterMap; // 所有参数的Map集合

 

         /**

          * other 参数所包含的参数信息

          */

         private Map<String, String[]> otherMap;

 

 

         public MyParametersWrapper(HttpServletRequest request) {

             super (request);

             parameterMap = request.getParameterMap();

             otherMap = new ConcurrentHashMap<>();

             /**

              * 判断other参数是否为空

              */

             if ( null != parameterMap.get(BODY_PARAM)){

                 otherConversion(parameterMap.get(BODY_PARAM));

             }

         }

 

         /**

          * 将other参数转为map参数

          * @param others

          */

         private void otherConversion(String[] others){

             if ( null != others && others.length > 0 ){

                 JSONObject obj = null ;

                 for (String other : others){

                     try {

                         obj = JsonUtil.parseObject(other);

                         if ( null != obj){

                             for (Map.Entry<String, Object> entry : obj.entrySet()){

                                 otherMap.put(entry.getKey(), new String []{String.valueOf(entry.getValue())});

                             }

                         }

                     } catch (Throwable e){

                         logger.error( "otherConversion.is.system.error" ,e);

                     }

                 }

             }

         }

 

         // 重写几个HttpServletRequestWrapper中的方法

         /**

          * 获取所有参数名

          *

          * @return 返回所有参数名

          */

         @Override

         public Enumeration<String> getParameterNames() {

             Vector<String> vector = new Vector<String>(parameterMap.keySet());

             vector.addAll(otherMap.keySet());

             return vector.elements();

         }

 

         /**

          * 获取指定参数名的值,如果有多个参数时默认取第一个

          *

          * @param name 指定参数名

          * @return 指定参数名的值

          */

         @Override

         public String getParameter(String name) {

             String[] values = parameterMap.get(name);

             try {

                 if (values == null ) {

                     if ( null != otherMap) {

                         values = otherMap.get(name);

                     }

                 }

             } catch (Throwable e){

                 logger.error( "getParameter.is.system.error" ,e);

             }

             if ( null == values){

                 return null ;

             }

             return values.length > 0 ? values[ 0 ] : super .getParameter(name);

         }

 

         /**

          * 获取指定参数名的所有值的数组

          */

         @Override

         public String[] getParameterValues(String name) {

             String[] values = parameterMap.get(name);

             try {

                 if (values == null ) {

                     if ( null != otherMap){

                         values = otherMap.get(name);

                     }

                 }

             } catch (Throwable e){

                 logger.error( "getParameterValues.is.system.error" ,e);

             }

             return values != null ? values : super .getParameterValues(name);

         }

     }

}

疑问一:为什么要单独定义一个otherMap用于存储解析后的参数

因为request.getParameterMap() 获取到的继承了ParameterMap类,该类由于防止并发问题单独定义了boolean locked属性,如果贸然向其中进行新增值时会出现parameterMap.locked异常

疑问二:getParameterNames、getParameter、getParameterValues三个方法都在哪里会用到

1) getParameterNames方法:

getParameterNames会用在Controller的方法参数是自定义实体时使用到,例子如下所示:

?

1

2

3

4

5

@RequestMapping (value = "/index" )

@ResponseBody

public String index(MyVo param) {

  //......

}

在进行HttpServletRequest参数转为MyVo实体时会用到 getParameterNames方法,所以在以上代码中需要将OtherMap的keys赋正常返回。

2) getParameter方法:

getParameter方法会在使用@RequestParam()注解和 request.getParameter("")时用到,间接调用getParameter方法。

3) getParameterValues方法:

getParameterValues方法会在使用request.getParameterValues("")时用到,间接调用getParameterValues方法。

其中JsonUtil如下所示:

?

1

2

3

4

5

6

7

8

9

10

11

import com.alibaba.fastjson.JSON;

public class JsonUtil {

  public static JSONObject parseObject(String jsonText) {

   try {

    return JSON.parseObject(jsonText);

   } catch (Exception e) {

    logger.error( "解析字符串:{} json出错:{}" , jsonText, e);

   }

   return null ;

  }

}

使用过滤器:

?

1

2

3

4

5

6

7

8

< filter >

    < filter-name >myParametersFilter</ filter-name >

    < filter-class >com.timer.web.interceptor.MyParametersFilter</ filter-class >

</ filter >

< filter-mapping >

    < filter-name >myParametersFilter</ filter-name >

    < url-pattern >/*</ url-pattern >

</ filter-mapping >

三、总结

HttpServletRequestWrapper 装饰器可以在请求Controller方法前,对方法参数进行修改,可用于修改参数前缀、添加公参、参数格式重新排版等。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/TimerBin/article/details/83067915

查看更多关于使用SpringMVC 重写、扩展HttpServletRequest请求参数的详细内容...

  阅读:35次