【SpringBoot】学习SptingBoot使用过滤器&拦截器&监听器 包括一些理解

本文代码下载地址:https://pan.baidu.com/s/10rjpwU2B3Pq7ZVWQkz0DUA 提取码:8mx3
本文的监听器为Java web的监听器,不是设计模式中的监听器模式
【SpringBoot】学习SptingBoot使用过滤器&拦截器&监听器 包括一些理解_第1张图片

一、过滤器

1、过滤器(Filter)是什么?有什么用?

​ ​ ​ ​ ​ ​ ​ ①WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等 一些高级功能。

​ ​ ​ ​ ​ ​ ​ ②过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等操作,便于代码重用,不必每个servlet中还要进行相应的操作。

​ ​ ​ ​ ​ ​ ​ ③注意:chain.doFilter() 起放行作用,不能中断,即每次进入过滤器都要执行这个操作才能退出,否则报错。

2、SpringBoot使用过滤器实现登陆过滤(未登录无法进入主页)

① controller代码:
package com.tangxz.filter;

import com.tangxz.common.MyCookie;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/11 14:12
 * 过滤器测试
 */
@Controller
@RequestMapping("/filter")
public class ControllerTest {
    @GetMapping("/to_login")
    public String toLogin() {
        return "login.html";
    }

    @RequestMapping("/do_login")
    public String doLogin(HttpServletRequest request,HttpServletResponse response) {
        String name = request.getParameter("name");
        String password = request.getParameter("password");
        MyCookie.setCookie(request,response,"name",name);
        MyCookie.setCookie(request,response,"password",password);
        System.out.println(name + password);
        return "index.html";
    }

    @ResponseBody
    @GetMapping("/to_index")
    public String toIndex(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        String name = MyCookie.getCookieByKey(request,response,"name");
        String password = MyCookie.getCookieByKey(request,response,"password");
        System.out.println(name+password);
        return name + password;
    }
}

② 过滤器代码:
package com.tangxz.filter;

import com.tangxz.common.MyCookie;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/11 14:12
 * 过滤器实现
 */
//filterName为过滤器名字,urlPatterns为过滤的url地址
@WebFilter(filterName = "filterTest", urlPatterns = "/filter/*")
public class FilterTest 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 {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        request.setCharacterEncoding("UTF-8");//设置字符编码
        response.setCharacterEncoding("UTF-8"); //设置字符编码
        String requestURI = request.getRequestURI();//得到被过滤的请求地址
        //将不需要过滤的请求地址踢出
        if ("/filter/to_login".equals(requestURI)||"/filter/do_login".equals(requestURI)){
        	System.out.println("------- 踢出 ------>过滤器:请求地址" + requestURI);
            filterChain.doFilter(request, response);//放行
            return;
        }
        System.out.println("------- 开始过滤 ------>过滤器:请求地址" + requestURI);
        String name = MyCookie.getCookieByKey(request,response,"name");
        String password = MyCookie.getCookieByKey(request,response,"password");
        if (password == null || name == null) {
            //两种重定向方法
            request.getRequestDispatcher("/filter/to_login").forward(request, response);
            //response.sendRedirect("login.jsp");
        }
        filterChain.doFilter(request, response);//放行
    }

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

③ 主函数代码:
package com.tangxz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ServletComponentScan(basePackages = "com.tangxz")
@ComponentScan
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}
④ 操作cookie的方法:
package com.tangxz.common;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/12 10:05
 */
public class MyCookie {
    public static String getCookieByKey(HttpServletRequest request, HttpServletResponse response, String key) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            request.getRequestDispatcher("/filter/to_login").forward(request, response);
        }
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(key)) {
                return cookie.getValue();
            }
        }
        return null;
    }

    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String key, String value) {
        Cookie cookie1 = new Cookie(key, value);
        cookie1.setMaxAge(60 * 60 * 24);
        response.addCookie(cookie1);
    }
}

二、拦截器

1、 拦截器(Interceptor)和过滤器(Filter)的区别

Spring的Interceptor(拦截器)与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。不同的是:
Filter Interceptor Summary
Filter 接口定义在 javax.servlet 包中 接口 HandlerInterceptor 定义在org.springframework.web.servlet 包中
Filter 定义在 web.xml 中
Filter在只在 Servlet 前后起作用。Filters 通常将 请求和响应(request/response) 当做黑盒子,Filter 通常不考虑servlet 的实现。 拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户介入(hook into)请求的生命周期,在请求过程中获取信息,Interceptor 通常和请求更加耦合。 在Spring构架的程序中,要优先使用拦截器。几乎所有 Filter 能够做的事情, interceptor 都能够轻松的实现
Filter 是 Servlet 规范规定的。 而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。 使用范围不同
Filter 是在 Servlet 规范中定义的,是 Servlet 容器支持的。 而拦截器是在 Spring容器内的,是Spring框架支持的。 规范不同
Filter 不能够使用 Spring 容器资源 拦截器是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如 Service对象、数据源、事务管理等,通过IoC注入到拦截器即可 Spring 中使用 interceptor 更容易
Filter 是被 Server(like Tomcat) 调用 Interceptor 是被 Spring 调用 因此 Filter 总是优先于 Interceptor 执行,晚于Interceptor执行

2、interceptor 的执行顺序大致为:

​ ​ ​ ​ ​ ​ ​ ① 请求到达 DispatcherServlet

​ ​ ​ ​ ​ ​ ​ ② DispatcherServlet 发送至 Interceptor ,执行 preHandle

​ ​ ​ ​ ​ ​ ​ ③ 请求达到 Controller

​ ​ ​ ​ ​ ​ ​ ④ 请求结束后,postHandle 执行

3、Spring 中主要通过 HandlerInterceptor 接口来实现请求的拦截,实现 HandlerInterceptor 接口需要实现下面三个方法:

​ ​ ​ ​ ​ ​ ​ ① preHandle() – 在handler执行之前,返回 boolean 值,true 表示继续执行,false 为停止执行并返回。

​ ​ ​ ​ ​ ​ ​ ② postHandle() – 在handler执行之后, 可以在返回之前对返回的结果进行修改

​ ​ ​ ​ ​ ​ ​ ③ afterCompletion() – 在请求完全结束后调用,可以用来统计请求耗时等等

4、SpringBoot使用拦截器实现未登陆拦截(未登录无法进入主页)

① controller代码:

package com.tangxz.interceptor;

import com.tangxz.common.MyCookie;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/11 14:13
 * 拦截器测试
 */
@Controller
@RequestMapping("/interceptors")
public class ControllerTest {
    @GetMapping("/to_login")
    public String toLogin() {
        return "login.html";
    }

    @RequestMapping("/do_login")
    public String doLogin(HttpServletRequest request, HttpServletResponse response) {
        String name = request.getParameter("name");
        String password = request.getParameter("password");
        MyCookie.setCookie(request,response,"name",name);
        MyCookie.setCookie(request,response,"password",password);
        System.out.println(name + password);
        return "index.html";
    }

    @ResponseBody
    @GetMapping("/to_index")
    public String toIndex(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        String name = MyCookie.getCookieByKey(request,response,"name");
        String password = MyCookie.getCookieByKey(request,response,"password");
        System.out.println(name+password);
        return name + password;
    }
}

② configurer拦截配置类代码:

package com.tangxz.interceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/11 21:13
 * 拦截配置类,配置静态资源以及拦截的请求
 */
@Configuration
public class Configurer implements WebMvcConfigurer {
    @Autowired
    private InterceptorTest interceptorTest;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//        addPathPatterns("/**"); //表示拦截所有的请求,
//        registry.excludePathPatterns("/login", "/register");//表示除了登陆与注册之外,因为登陆注册不需要登陆也可以访问
        registry.addInterceptor(interceptorTest).addPathPatterns("/interceptors/*").excludePathPatterns("/interceptors/to_login", "/interceptors/do_login");
    }

    // 这个方法是用来配置静态资源的,比如html,js,css,等等
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }
}

③ 拦截器功能实现代码:

package com.tangxz.interceptor;

import com.tangxz.common.MyCookie;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/11 14:13
 * 拦截器实现
 */
@Component
public class InterceptorTest  implements HandlerInterceptor {
    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     * 预处理回调方法,实现处理器的预处理
     * 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或处理器
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("开始拦截.........");
        String name = MyCookie.getCookieByKey(request,response,"name");
        String password = MyCookie.getCookieByKey(request,response,"password");
        //如果session中没有user,表示没登陆
        if (password == null|| name == null){
            //这个方法返回false表示忽略当前请求,如果一个用户调用了需要登陆才能使用的接口,如果他没有登陆这里会直接忽略掉
            //当然你可以利用response给用户返回一些提示信息,告诉他没登陆
            request.getRequestDispatcher("/interceptor/to_login").forward(request, response);
            return false;
        }else {
            return true;//放行
        }
    }

    /**
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     * 后处理回调方法,实现处理器(controller)的后处理,但在渲染视图之前
     * 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("return前");

    }
    /**
     * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
     * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,
     * 如性能监控中我们可以在此记录结束时间并输出消耗时间,
     * 还可以进行一些资源清理,类似于try-catch-finally中的finally,
     * 但仅调用处理器执行链中
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("操作完之后,可以用于资源清理");

    }
}

④ 主函数代码:

package com.tangxz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ServletComponentScan(basePackages = "com.tangxz")
@ComponentScan
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

⑤ 操作cookie的代码:

package com.tangxz.common;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/12 10:05
 */
public class MyCookie {
    public static String getCookieByKey(HttpServletRequest request, HttpServletResponse response, String key) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            request.getRequestDispatcher("/filter/to_login").forward(request, response);
        }
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(key)) {
                return cookie.getValue();
            }
        }
        return null;
    }

    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String key, String value) {
        Cookie cookie1 = new Cookie(key, value);
        cookie1.setMaxAge(60 * 60 * 24);
        response.addCookie(cookie1);
    }
}

三、监听器

1、监听器(Listener)是什么?有什么用?

​ ​ ​ ​ ​ ​ ​ ①监听器能够达到实时实现一些通知操作,比如监听session和request的生命周期,使用spring的一些接口可以很方便的实现某些功能的监听。
​ ​ ​ ​ ​ ​ ​ ②自定义的监听器就是老大(本人)找一个警察(监听者)去监视某个小偷(被监听者),当小偷(被监听者)偷东西(触发了事件1),然后警察(监听者)汇报给老大(触发了事件2),老大(本人)就宣布他被捕(实现自己想要的操作)。这就为一个普通的监听过程,触发事件2在事件1中,所以小偷需要有一个警察的实例,这样才能够调用该警察(监听者)的汇报功能。可以在一个小偷类里面,分配多个不一样警察对象,当触发一个情况时,再把情况发送给对应警察的对应方法,这样就可以实现多警察(监听者)多方法(不一样的实现)。可以应用在某些具有关联(连带)的操作上。

2、常用的监听器接口:

① ServletContextListener – 监听servletContext对象的创建以及销毁

1.1    contextInitialized(ServletContextEvent arg0)   -- 创建时执行

1.2    contextDestroyed(ServletContextEvent arg0)  -- 销毁时执行

② HttpSessionListener – 监听session对象的创建以及销毁

2.2   sessionCreated(HttpSessionEvent se)   -- 创建时执行

2.2   sessionDestroyed(HttpSessionEvent se) -- 销毁时执行

③ ServletRequestListener – 监听request对象的创建以及销毁

3.1    requestInitialized(ServletRequestEvent sre) -- 创建时执行

3.2    requestDestroyed(ServletRequestEvent sre) -- 销毁时执行

④ ServletContextAttributeListener – 监听servletContext对象中属性的改变

4.1    attributeAdded(ServletContextAttributeEvent event) -- 添加属性时执行

4.2    attributeReplaced(ServletContextAttributeEvent event) -- 修改属性时执行

4.3    attributeRemoved(ServletContextAttributeEvent event) -- 删除属性时执行

⑤ HttpSessionAttributeListener --监听session对象中属性的改变

5.1    attributeAdded(HttpSessionBindingEvent event) -- 添加属性时执行

5.2    attributeReplaced(HttpSessionBindingEvent event) -- 修改属性时执行

5.3    attributeRemoved(HttpSessionBindingEvent event) -- 删除属性时执行

⑥ ServletRequestAttributeListener --监听request对象中属性的改变

6.1    attributeAdded(ServletRequestAttributeEvent srae) -- 添加属性时执行

6.2    attributeReplaced(ServletRequestAttributeEvent srae) -- 修改属性时执行

6.3    attributeRemoved(ServletRequestAttributeEvent srae) -- 删除属性时执行

补充监听器接口部分的原文链接:https://blog.csdn.net/m0_38075425/article/details/81164501

3、SpringBoot使用监听器监听当前登陆用户

① controller部分:

package com.tangxz.listener;

import com.tangxz.common.MyCookie;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/11 14:13
 * 监听器测试
 */
@Controller
@RequestMapping("/listener")
public class ControllerTest {
    @GetMapping("/to_login")
    public String toLogin() {
        return "login.html";
    }

    @RequestMapping("/do_login")
    public String doLogin(HttpServletRequest request, HttpServletResponse response) {
        String name = request.getParameter("name");
        String password = request.getParameter("password");
        request.getSession().setAttribute("name", name);
        request.getSession().setAttribute("password", password);
        MyCookie.setCookie(request, response, "name", name);
        MyCookie.setCookie(request, response, "password", password);
        System.out.println(name + password);
        return "index.html";
    }

    @ResponseBody
    @GetMapping("/do_removeLogin")
    public String doRemoveLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String key = request.getParameter("key");
        request.getSession().removeAttribute(key);
        return key+"已注销";
    }

    @ResponseBody
    @GetMapping("/to_index")
    public String toIndex(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = MyCookie.getCookieByKey(request, response, "name");
        String password = MyCookie.getCookieByKey(request, response, "password");
        System.out.println(name + password);
        return name + password;
    }
}

② 监听器实现部分:

package com.tangxz.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * @Author 唐小尊
 * @Date: Created in 2019/8/11 14:13
 * 实现事件监听器
 * 监听当前在线人数
 */

@WebListener
public class ListenerTest implements HttpSessionListener {
    public int count = 0;//记录session的数量

    @Override
    public void sessionCreated(HttpSessionEvent arg0) {//监听session的创建
        count++;
        arg0.getSession().getServletContext().setAttribute("Count", count);

    }

    @Override
    public void sessionDestroyed(HttpSessionEvent arg0) {//监听session的撤销
        count--;
        arg0.getSession().getServletContext().setAttribute("Count", count);
    }

}

③ 主函数代码:

package com.tangxz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ServletComponentScan(basePackages = "com.tangxz")
@ComponentScan
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

参考部分
过滤器部分参考博客:https://blog.csdn.net/mouxianbiao/article/details/82194021
拦截器部分参考博客:https://blog.csdn.net/u010142437/article/details/82558176

你可能感兴趣的:(【SpringBoot】学习SptingBoot使用过滤器&拦截器&监听器 包括一些理解)