Spring Boot 的Servlet、Filter 、 Listener和Interceptor
  Op9yysgqYUmV 2023年11月02日 66 0


先上两个网上找到的图,大家先有个大概认识

Spring Boot 的Servlet、Filter 、 Listener和Interceptor_Java

Spring Boot 的Servlet、Filter 、 Listener和Interceptor_ide_02

1、Servlet

回顾下javaEE的开发步骤(这里是大致配置和流程):

             1.在web.xml中配置servlet和servletMapping

             2.书写servlet标签里面配置的类,类需要继承HttpServlet,然后复写里面的doGet,doPost方法(当然还有init,destory方法)

             3.启动tomcat服务器,访问对应的路径就能访问到对应的doGet,doPost方法 

但是这个web.xml和对应的类以及tomcat到底有什么关系呢?在后面到底做了什么呢?

首先我们要理清一个逻辑:浏览器http请求------>tomcat服务器------->到达servlet----->执行doGet,doPost方法---->返回数据

从这个逻辑可以看出tomcat才是和客户端打交道的:

他监听了端口,请求过来后,根据url信息和web.xml配置文件匹配,确定要将请求交给哪个servlet去处理,servlet处理请求然后返回给tomcat,tomcat在把数据返回给用户。

也就是说Servlet接口是处理网络请求的一套规范,他负责连接web服务器(如tomcat服务器),交互式的生成动态的web内容

2、过滤器

过滤器是在请求进入tomcat容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。

理解上面这句话我们就可以知道,进入servlet之前,主要是两个参数:ServletRequest,ServletResponse  那我们得到这两个测试可以干哪些事呢?

我们可以通过ServletRequest得到HttpServletRequest,此时你就可以请求或响应(Request、Response),就可以对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息、字符集统一等一些高级功能。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。(每次热部署后,都会销毁)。

3、拦截器

从上图我们可以看出过滤器只在servlet前后起作用,所以它既不能捕获异常,获得bean对象等,这些是只能是进入servlet里面的拦截器能过做到。拦截器中用于在某个方法或字段被访问之前,进行拦截然后,在之前或之后加入某些操作。比如日志,安全等。一般拦截器方法都是通过动态代理的方式实现。可以通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。

对比一下其实我们可以发现,过滤器能做的事拦截器都能做,拦截器做的事过滤器不一定做的了。

4、监听器

listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。其主要可用于以下方面:

  • 统计在线人数和在线用户
  • 系统启动时加载初始化信息
  • 统计网站访问量
  • 记录用户访问路径。

常用的监听器 servletContextListener、httpSessionListener、servletRequestListener

spring boot使用Servlet

两种方式:

1、使用spring boot提供的ServletRegistrationBean 注册Servlet

2、使用原生servlet注解定义Servlet

两种方式的本质都是一样的,都是去ServletRegistrationBean 注册自定义Servlet

方式一:

①、先定义Servlet:

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doGet()<<<<<<<<<<<");
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doPost()<<<<<<<<<<<");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.write("自定义 Servlet");
    }
}

②、注册 Servlet

将 Servelt 注册成 Bean。在上文创建的 WebConfig 类中添加如下代码:

@Configuration
public class WebConfig {
@Bean
public ServletRegistrationBean servletRegistrationBean() {
    return new ServletRegistrationBean(new MyServlet(), "/mv");//匹配要处理的url
} 

}

结果如下:

Spring Boot 的Servlet、Filter 、 Listener和Interceptor_SpringBoot_03

方式二:

1)启动类里面增加 @ServletComponentScan,进行扫描

2)新建一个Servlet类,extends HttpServlet ,并实现对应的接口

3)@WebServlet标记一个类为servlet,被spring进行扫描

@Component
@WebServlet(urlPatterns = "/map", description = "Servlet的说明")
public class MyServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doGet()<<<<<<<<<<<");
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doPost()<<<<<<<<<<<");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Hello World</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>大家好,我的名字叫Servlet</h1>");
        out.println("</body>");
        out.println("</html>");
    }
}

Spring Boot 的Servlet、Filter 、 Listener和Interceptor_ide_04

spring boot 使用过滤器

两种方式: 

1、使用spring boot提供的FilterRegistrationBean注册Filter 

2、使用原生servlet注解定义Filter 

两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter

方式一: 

①、先定义Filter:

public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("=======初始化过滤器MyFilter =========");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        long start = System.currentTimeMillis();
        filterChain.doFilter(request, response);
        System.out.println("filter 耗时:" + (System.currentTimeMillis() - start));
    }

    @Override
    public void destroy() {
        System.out.println("=======销毁过滤器MyFilter =========");
    }

}

②、注册自定义Filter

@Configuration
public class WebConfig{
    @Bean
    public FilterRegistrationBean registrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
        filterRegistrationBean.addUrlPatterns("/mv");
        return filterRegistrationBean;
    }
}

方式二:

1)启动类里面增加 @ServletComponentScan,进行扫描

2)新建一个Filter类,implements Filter,并实现对应的接口

3) @WebFilter 标记一个类为filter,被spring进行扫描

@WebFilter(filterName = "myFilter2", urlPatterns = "/map")
public class MyFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("执行过滤操作");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}

    return registrationBean;

}

spring boot 使用监听器

同样也是两种方式,不废话了

①、编写监听器

public class MyHttpSessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("Session 被创建");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("ServletContex初始化");
    }
}

 

 

②、注册监听器

注册监听器为 Bean,在 WebConfig 配置类中添加如下代码:

@Bean
public ServletListenerRegistrationBean<MyHttpSessionListener> listenerRegistrationBean() {
    return new ServletListenerRegistrationBean<>(new MyHttpSessionListener());
}

方式二:

@WebListener //使用注解方式注册
public class MyServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContex初始化");
        System.out.println(servletContextEvent.getServletContext().getServerInfo());
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContex销毁");
    }
}

spring boot 使用拦截器

1、创建我们自己的拦截器类并实现 HandlerInterceptor 接口。

2、创建一个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptors 方法。

3、实例化我们自定义的拦截器,然后将对像手动添加到拦截器链中(在addInterceptors方法中添加)。

①、定义拦截器:

public class MyInterceptor implements HandlerInterceptor {
  
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        
        System.out.println("========preHandle=========");
        System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
        System.out.println(((HandlerMethod)handler).getMethod().getName());
        
        request.setAttribute("startTime", System.currentTimeMillis());
     
        return true;

    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
        System.out.println("========postHandle=========");
        Long start = (Long) request.getAttribute("startTime");
        System.out.println("耗时:"+(System.currentTimeMillis() - start));
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
            throws Exception {
        System.out.println("========afterCompletion=========");
        Long start = (Long) request.getAttribute("startTime");
        System.out.println("耗时:"+(System.currentTimeMillis() - start));     
        System.out.println(exception);
    }
}

②、注册拦截器

编写拦截器后,我们还需要将其注册到拦截器链中,如下配置:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{

    @Autowired
    private TimeInterceptor timeInterceptor;
  
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor);
    }

}

请求一个 controller ,结果如下:

 

Spring Boot 的Servlet、Filter 、 Listener和Interceptor_拦截器_05

最后说明下,我们上面用到的 WebMvcConfigurerAdapter 并非只是注册添加拦截器使用,其顾名思义是做Web配置用的,它还可以有很多其他作用,通过下面截图便可以大概了解,具体每个方法都是干什么用的,留给大家自己研究(其实都大同小异也很简单)。

 

Spring Boot 的Servlet、Filter 、 Listener和Interceptor_Java_06

针对自定义 Servlet、Filter 和 Listener 的配置,还有另一种方式:

@SpringBootApplication
public class SpringbootWebApplication implements ServletContextInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // 配置 Servlet
        servletContext.addServlet("servlet",new MyServlet())
                      .addMapping("/**");
        // 配置过滤器
        servletContext.addFilter("filter",new MyFilter())                      .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),true,"/**");

        // 配置监听器
        servletContext.addListener(new ListenerTest());
    }


    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebApplication.class, args);
    }
}

最后强调一点:只有经过DispatcherServlet 的请求,才会走拦截器链,我们自定义的Servlet 请求是不会被拦截的,比如我们自定义的Servlet地址 http://localhost:8080/myservlet 是不会被拦截器拦截的。不管是属于哪个Servlet 只要符合过滤器的过滤规则,过滤器都会拦截。

 

源码




 

 

 

 

 

 

 

 

 

 

 

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

上一篇: BIO编程学习 下一篇: gokit学习
  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
Op9yysgqYUmV