SpringMVC之DispatchserServlet
SpringBoot对原生Servlet的支持
0、总结
- 过滤器首先是要配置拦截的路径,如果对应的路径被拦截了,才会走拦截方法,需要根据条件判断是否需要拦截。如果不需要拦截,会放行;如果不满足条件,将会直接返回;
- 过滤器可以根据指定的servlet的路径来进行拦截,也就是servlet配置的是什么路径,过滤器拦截的就是什么路径;
- 过滤器的拦截早于拦截器的拦截;
- 自定义的servlet将不会指定拦截器中的方法,因为springmvc中只针对DispatchserServlet才配置了拦截器;
1、注解支持
关于Servlet中原生的servlet、filter和ServletContextListener的配置
SpringBoot官网文档中提到了有两种方式来来进行操作:
- When using an embedded container, automatic registration of classes annotated with
@WebServlet
,@WebFilter
, and@WebListener
can be enabled by using@ServletComponentScan
. - If convention-based mapping is not flexible enough, you can use the
ServletRegistrationBean
,FilterRegistrationBean
, andServletListenerRegistrationBean
classes for complete control.
第一种方式是使用注解版来进行配置,对于servlet和fitler可以来配置对应的请求路径和拦截路径。
第二种方式可以来使用java编写来进行配置。
下面分别来进行演示下对应的案例:
1.1、servlet
@WebServlet(urlPatterns = "/hello")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello,myservlet");
}
}
1.2、filter
/**
*
* 过滤器应该是在拦截对应的路径之后,针对什么条件下会来进行过滤。所以这里的过滤条件很重要
* 这里需要注意的是:/*单个*是servlet的写法,而/**是spring全家桶的写法
* 如果是/*,那么表示的是将会拦截一切
*/
@WebFilter(urlPatterns = {"/*"})
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 如果这里没有过滤掉,那么将会被拦截,页面上什么都么有输出
System.out.println("过滤掉对应的请求信息.........");
chain.doFilter(request,response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("拦截器开始执行");
}
@Override
public void destroy() {
System.out.println("项目正在被销毁..........");
}
}
1.3、listener
@WebListener
public class MyWebListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("项目初始化完成......");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// 只有正常销毁的时候才会执行。直接点解idea是不行的
System.out.println("项目销毁......");
}
}
1.4、配置注解
安装官方文档说明:需要在添加上@ServletComponentScan,那么在配置类上添加一下:
@SpringBootApplication
@ServletComponentScan(basePackages={"com.guang.springbootspringmvcorigin.servlet","com.guang.springbootspringmvcorigin.filter","com.guang.springbootspringmvcorigin.listener"})
public class SpringbootSpringmvcOriginApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootSpringmvcOriginApplication.class, args);
}
}
1.5、检测自定义的servlet是否执行了拦截器
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前置处理");
String requestURI = request.getRequestURI();
System.out.println("-----hello----");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("处理完成之后。。。。。。。。。。");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("视图渲染之后执行");
}
}
将拦截器配置到WebMvc中来:
@Configuration(proxyBeanMethods=true)
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
}
经过测试,发现自定义的servlet处理不会经过拦截器的方法。
2、配置版
SpringBoot中也提供了对应的配置信息
If convention-based mapping is not flexible enough, you can use the ServletRegistrationBean
, FilterRegistrationBean
, and ServletListenerRegistrationBean
classes for complete control.
下面也来操作一下,只需要将上述的注解去掉,然后在配置类类中来进行添加即可。
// 这里要加上proxyBeanMethods = true为FALSE,因为下面的配置信息中有会获取得到上面的servlet的路径信息
@Configuration(proxyBeanMethods = true)
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean<MyServlet> myServletServletRegistrationBean = new ServletRegistrationBean<>(new MyServlet(), "/my", "/my01");
return myServletServletRegistrationBean;
}
@Bean
public FilterRegistrationBean myFilterRegistrationBean(){
FilterRegistrationBean<MyFilter> myFilterFilterRegistrationBean = new FilterRegistrationBean<>(new MyFilter(), myServlet());
myFilterFilterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return myFilterFilterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myServletListenerRegistrationBean(){
ServletListenerRegistrationBean<MyWebListener> myFilterFilterRegistrationBean = new ServletListenerRegistrationBean<MyWebListener>(new MyWebListener());
return myFilterFilterRegistrationBean;
}
}
注意
- 我在测试的时候发现,如果是自定义的servlet无法来进行处理的时候,DispatchserServlet开始执行了,因为这个是缺省匹配的;
- 在配置自定义servlet的时候,发现路径中如果没有/,那么将会导致启动失败错误,所以以后还是直接添加上的比较好;
3、DispatcherServlet的配置
在DispatcherServletAutoConfiguration中可以看到,可以自己来对DispatcherServletAutoConfiguration来进行配置。
前缀是:spring.mvc
注册的时候,采用的也是上面的配置版中的servlet的配置来进行配置的,DispatcherServletAutoConfiguration默认的路径是/,这个可以在对应的配置中是可以看到的。
从理论中来,到实践中去,最终回归理论