用户认证授权、日志记录MDC、编码解码、UA检查、多端对应等都需要通过拦截请求来共通处理,这时就需要Filter、Listener、Interceptor。而把非Spring Boot项目转换成Spring Boot项目需要沿用以前的这些代码,所以有必要了解这几个东西的用法。
通常来说,用户通过浏览器发起Request进入服务器后侧处理顺序如下:
[quote]Client -> Listener -> ServletContainer -> Filter -> Servlet -> Interceptor[/quote]
具体可以看看这里:[url=http://rensanning.iteye.com/blog/2355214]http://rensanning.iteye.com/blog/2355214[/url]
大部分框架采用一个servlet分发请求到不同controller去处理,只有极个别场景会定义多个servlet来处理比较特殊需求。而Filter、Listener、Interceptor按需求一般来说都会是多个。
[b](1)Servlet 2.5采用web.xml定义Servlet、Filter、Listener[/b]
[b](2)Servlet 3.0开始不再需要web.xml,可以通过注解或Java代码定义Servlet/Filter等。[/b]
[b]1)注解定义[/b]
[quote]Servlet规范不支持注解Filter的执行顺序,仍需在 web.xml 中定义,web.xml中定义的<filter-mapping>的顺序就是他们的执行顺序。
@WebFilter(filterName="filter1", urlPatterns="/url1/*")
public class Filter1 implements Filter {}
@WebFilter(filterName="filter2", urlPatterns="/url2/*")
public class Filter2 implements Filter {}
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern />
</filter-mapping>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern />
</filter-mapping>[/quote]
[b]2)动态注册[/b]
[b](3)Spring Boot也采用无web.xml,以Filter为例,添加方法如下:[/b]
[b]1)通过@Component让Spring扫描到即可处理拦截处理所有请求[/b]
[b]2)通过@Configuration + @Bean来管理未被扫描到的Filter[/b]
[b]3)通过@Configuration + @Bean + FilterRegistrationBean更灵活的设置Filter[/b]
[b]4)通过@ServletComponentScan自动扫描@WebServlet, @WebFilter, @WebListener[/b]
[b]SpringBoot默认已经为应用添加了以下Servlet/Filter[/b]
[quote]o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*][/quote]
[b]定义Interceptor[/b]
通常来说,用户通过浏览器发起Request进入服务器后侧处理顺序如下:
[quote]Client -> Listener -> ServletContainer -> Filter -> Servlet -> Interceptor[/quote]
具体可以看看这里:[url=http://rensanning.iteye.com/blog/2355214]http://rensanning.iteye.com/blog/2355214[/url]
大部分框架采用一个servlet分发请求到不同controller去处理,只有极个别场景会定义多个servlet来处理比较特殊需求。而Filter、Listener、Interceptor按需求一般来说都会是多个。
[b](1)Servlet 2.5采用web.xml定义Servlet、Filter、Listener[/b]
<web-app ...>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>com.rensanning.springtest.HelloWorldServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.rensanning.springtest.TestServletContextListener</listener-class>
</listener>
</web-app>
[b](2)Servlet 3.0开始不再需要web.xml,可以通过注解或Java代码定义Servlet/Filter等。[/b]
[b]1)注解定义[/b]
@WebServlet(name="HelloWorldServlet",urlPatterns={"/HelloWorld"},
initParams={@WebInitParam(name="name",value="rensanning")})
public class HelloWorldServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().print("Hello " + getInitParameter("name"));
}
}
@WebFilter(filterName="HelloWorldFilter", urlPatterns="/HelloWorld")
public class HelloWorldFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override public void init(FilterConfig filterConfig) throws ServletException {}
@Override public void destroy() {}
}
[quote]Servlet规范不支持注解Filter的执行顺序,仍需在 web.xml 中定义,web.xml中定义的<filter-mapping>的顺序就是他们的执行顺序。
@WebFilter(filterName="filter1", urlPatterns="/url1/*")
public class Filter1 implements Filter {}
@WebFilter(filterName="filter2", urlPatterns="/url2/*")
public class Filter2 implements Filter {}
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern />
</filter-mapping>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern />
</filter-mapping>[/quote]
@WebListener
public class TestServletContextListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent event) { }
@Override
public void contextInitialized(ServletContextEvent event) { }
}
[b]2)动态注册[/b]
public class WebInitializer implements WebApplicationInitializer {
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
// Servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.addMapping("/");
dispatcher.setLoadOnStartup(1);
dispatcher.setInitParameter("defaultHtmlEscape", "true");
// Filter
FilterRegistration.Dynamic filter = container.addFilter("encodingFilter", CharacterEncodingFilter.class);
filter.addMappingForUrlPatterns(null, false, "/*");
filter.setInitParameter("encoding", "UTF-8");
filter.setInitParameter("forceEncoding", "true");
// Listener
servletContext.addListener(TestServletContextListener.class);
}
}
[b](3)Spring Boot也采用无web.xml,以Filter为例,添加方法如下:[/b]
[b]1)通过@Component让Spring扫描到即可处理拦截处理所有请求[/b]
@Component
public class TestFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void destroy() { }
}
[b]2)通过@Configuration + @Bean来管理未被扫描到的Filter[/b]
public class MultipleFilter1 implements Filter { }
public class MultipleFilter2 implements Filter { }
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public Filter filter1() {
return new MultipleFilter1();
}
@Bean
public Filter filter2() {
return new MultipleFilter2();
}
}
[b]3)通过@Configuration + @Bean + FilterRegistrationBean更灵活的设置Filter[/b]
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public FilterRegistrationBean filter1() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new MultipleFilter1());
bean.setOrder(2);
return bean;
}
@Bean
public FilterRegistrationBean filter2() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new MultipleFilter2());
bean.setOrder(1);
return bean;
}
}
[b]4)通过@ServletComponentScan自动扫描@WebServlet, @WebFilter, @WebListener[/b]
@SpringBootApplication
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
[b]SpringBoot默认已经为应用添加了以下Servlet/Filter[/b]
[quote]o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*][/quote]
[b]定义Interceptor[/b]
public class TraceLoggingInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { }
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { }
}
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// <mvc:interceptors>
registry.addInterceptor(traceLoggingInterceptor())
.addPathPatterns("/**/*.do")
.addPathPatterns("/**/*.json");
}
}