前言:
日常开发中,我们常常需要对接口接入的数据参数进行处理,比如解密,关于@RequestBody这类流参数处理,上一章已经有处理方法,链接:RequestBodyAdvice 和 ResponseBodyAdvice增强器使用,这篇主要讲对request的参数进行处理。
实现步骤
众所周知,获取request的参数无非三种方式:
(1)getParameter(String name)
获取name对应的value,如果有多个,返回第一个。
(2)getParameterNames()
获取request里所有的name,返回Enumeration类型。
(3)getParameterValues(String name)
获取name对应的所有value。
但是request并没有提供类似于setParameter(String name,Object value)的方法,所以必须找到一个可以重写的类或者可实现的接口来重写以上三种获取参数方式。
实现方式
翻看了半天源码找到了两种方式:
(1)实现HttpServletRequest接口
(2)继承HttpServletRequestWrapper重写request的三个方法
这里不得不提一句,方式(1)实现接口的方式,需要实现的方法太多了,果断抛弃。
代码演示
/**
* @author:lis
* @createTime:2019-11-20 15:54
* @description:自定义RequestWrapper
* @modifyTime:
* @modifyDescription:
*/
public class CustomRequestWrapper extends HttpServletRequestWrapper {
private Map<String, String[]> params;//定义参数集合
public CustomRequestWrapper(HttpServletRequest request) {
super(request);
this.params = request.getParameterMap();
}
@Override
public String getParameter(String name) {
String[] vs = params.get(name);
if (vs == null || vs.length < 1)
return null;
return vs[0];
}
@Override
public Enumeration getParameterNames() {
return new Vector(params.keySet()).elements();
}
@Override
public String[] getParameterValues(String name) {
String[] vs = params.get(name);
if (vs == null || vs.length < 1)
return null;
return vs;
}
}
处理时机
关于数据处理实际,秉承一点:必须在Spring MVC处理之前,所以可以实现的方式有很多种,这里我接触到的有两种:
(1)使用过滤器Filter
优点:可以实现
缺点:系统中各处理执行顺序为:过滤器>拦截器>AOP;RequestBodyAdvice增强器本质属于AOP,既然body的数据处理在最后,而采取过滤器这种方式又在最前边,对于我这种重度晚期强迫症患者是肯定不能忍的。
(2)扩展前置控制器DispatcherServlet
这种方式最为推荐,它的执行顺序介于过滤器和拦截器之间,是我们理想的方式。
两种方式代码实现
使用Filter方式
/**
* @author:lis
* @createTime:2019-11-20 15:54
* @description:过滤器
* @modifyTime:
* @modifyDescription:
*/
@WebFilter(filterName = "testFilter",urlPatterns = "/**")
public class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("testFilter init......");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("testFilter filter start ......");
servletRequest = new CustomRequestWrapper((HttpServletRequest) servletRequest);
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("testFilter filter end ......");
}
}
自定义扩展前置控制器DispatcherServlet方式
重写doDispatch方法
/**
* @author:lis
* @createTime:2019-11-20 15:55
* @description:自定义扩展前置控制器
* @modifyTime:
* @modifyDescription:
*/
public class CustomDispatcherServlet extends DispatcherServlet {
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
/**
* 这里如果需要判断是否解密,加入逻辑,如果不需要解密写法:
* super.doDispatch(request, response);
*/
super.doDispatch(new CustomRequestWrapper(request), response);
}
}
注册自定义扩展前置控制器DispatcherServlet
@Configuration
public class CustomConfiguration {
/**
* 注册自定义DispatcherServlet配置
*/
@Bean
@Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
return new CustomDispatcherServlet();
}
}
@Qualifier:Qualifier的意思是合格者,通过这个标识,表明了哪个实现类才是我们所需要的,添加@Qualifier注解,需要注意的是@Qualifier的参数名称为我们之前定义@Service注解的名称之一。
当然也可以不加此注解,直接在@Bean指明需要实现的类:
@Bean(value = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)