前言:
日常開發中,我們常常需要對接口接入的數據參數進行處理,比如解密,關於@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)