本文代码下载地址:https://pan.baidu.com/s/10rjpwU2B3Pq7ZVWQkz0DUA 提取码:8mx3
本文的监听器为Java web的监听器,不是设计模式中的监听器模式
①WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等 一些高级功能。
②过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等操作,便于代码重用,不必每个servlet中还要进行相应的操作。
③注意:chain.doFilter() 起放行作用,不能中断,即每次进入过滤器都要执行这个操作才能退出,否则报错。
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);
}
}
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);
}
}
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执行 |
① 请求到达 DispatcherServlet
② DispatcherServlet 发送至 Interceptor ,执行 preHandle
③ 请求达到 Controller
④ 请求结束后,postHandle 执行
① preHandle() – 在handler执行之前,返回 boolean 值,true 表示继续执行,false 为停止执行并返回。
② postHandle() – 在handler执行之后, 可以在返回之前对返回的结果进行修改
③ afterCompletion() – 在请求完全结束后调用,可以用来统计请求耗时等等
① 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);
}
}
①监听器能够达到实时实现一些通知操作,比如监听session和request的生命周期,使用spring的一些接口可以很方便的实现某些功能的监听。
②自定义的监听器就是老大(本人)找一个警察(监听者)去监视某个小偷(被监听者),当小偷(被监听者)偷东西(触发了事件1),然后警察(监听者)汇报给老大(触发了事件2),老大(本人)就宣布他被捕(实现自己想要的操作)。这就为一个普通的监听过程,触发事件2在事件1中,所以小偷需要有一个警察的实例,这样才能够调用该警察(监听者)的汇报功能。可以在一个小偷类里面,分配多个不一样警察对象,当触发一个情况时,再把情况发送给对应警察的对应方法,这样就可以实现多警察(监听者)多方法(不一样的实现)。可以应用在某些具有关联(连带)的操作上。
① 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
① 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