目录

JAVAWEB过滤器、拦截器的作用及使用

过滤器Filter

什么是过滤器

  • 过滤器是运行在服务端的程序
  • 过滤器是在达到目标资源前的预处理操作(servlet、jsp、html等)
  • 过滤器是在请求即将离开服务器之前的处理程序
  • 多个过滤器可以组合使用,形成一个过滤链

为什么要使用过滤器(过滤器所能解决的问题)

  • 为了解决大量重复代码的出现
  • 例如配置项目的编码
  • 例如登录的拦截(如果每个servlet中都写一个是否登录判断,代码量将非常多)

配置一个过滤器完成编码的过滤

编写一个EncodingFilter(名称自定义)

  1. import javax.servlet.*;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import java.io.IOException;
  5. public class EncodingFilter implements Filter {
  6. private String charset;
  7. @Override
  8. public void init(FilterConfig filterConfig) throws ServletException {
  9. // 从配置中读取编码
  10. charset = filterConfig.getInitParameter("charset");
  11. }
  12. @Override
  13. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  14. // 将req和resp对象转换为带Http协议的
  15. HttpServletRequest req = (HttpServletRequest)servletRequest;
  16. HttpServletResponse resp = (HttpServletResponse)servletResponse;
  17. // 配置请求post编码过滤
  18. req.setCharacterEncoding(charset);
  19. // 配置默认相应类型及编码
  20. resp.setContentType("text/html; charset=" + charset);
  21. // 执行下一个过滤器或者目标资源,理解为放行
  22. filterChain.doFilter(req, resp);
  23. }
  24. @Override
  25. public void destroy() {
  26. System.out.println("EncodingFilter 过滤器已销毁");
  27. }
  28. }

在web.xml中配置过滤器

  1. <filter>
  2. <filter-name>myEncodingFilter</filter-name>
  3. <filter-class>com.oa.filter.EncodingFilter</filter-class>
  4. <init-param>
  5. <param-name>charset</param-name>
  6. <param-value>UTF-8</param-value>
  7. </init-param>
  8. </filter>
  9. <filter-mapping>
  10. <filter-name>myEncodingFilter</filter-name>
  11. <!-- 意思是拦截/abc下的所有资源,可以为Servlet指定前缀(例如abc),因为编码过滤只需要涉及到Servlet -->
  12. <url-pattern>/abc/*</url-pattern>
  13. </filter-mapping>

配置一个测试的Servlet

  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. @WebServlet("/abc/encoding/demo")
  8. public class EncodingServlet extends HttpServlet {
  9. @Override
  10. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  11. // 未配置过滤器前是null,配置后是 UTF-8
  12. System.out.println(req.getCharacterEncoding());
  13. }
  14. }

配置项目的登录控制(如果未登录不让访问资源)

配置一个Filter并使用注解的方式注册Filter

  1. import com.oa.entity.Employee;
  2. import javax.servlet.*;
  3. import javax.servlet.annotation.WebFilter;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import javax.servlet.http.HttpSession;
  7. import java.io.IOException;
  8. // 表示拦截所有/abc路径下的资源、以及所有的jsp和html
  9. @WebFilter(urlPatterns = {"/abc/*","*.jsp","*.html"})
  10. public class LoginFilter implements Filter {
  11. @Override
  12. public void init(FilterConfig filterConfig) throws ServletException {
  13. }
  14. @Override
  15. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  16. // 将req和resp对象转换为带Http协议的
  17. HttpServletRequest req = (HttpServletRequest)servletRequest;
  18. HttpServletResponse resp = (HttpServletResponse)servletResponse;
  19. // 判断当前请求的路径是否为登录页面或登录提交的Servlet
  20. String requestUri = req.getRequestURI();
  21. String loginPage = req.getContextPath() + "/login.jsp";
  22. String loginServlet = req.getContextPath() + "/sys/login";
  23. if(loginPage.equals(requestUri)|| loginServlet.equals(requestUri)){
  24. filterChain.doFilter(req, resp);
  25. }else {
  26. // 获取到Session对象,并通过session从session域中获取用户
  27. HttpSession session = req.getSession();
  28. Employee employee = (Employee)session.getAttribute("user");
  29. // 处理结果
  30. if(employee == null) {
  31. resp.sendRedirect(req.getContextPath() + "/login.jsp");
  32. }else {
  33. // 放行
  34. filterChain.doFilter(req, resp);
  35. }
  36. }
  37. }
  38. @Override
  39. public void destroy() {
  40. }
  41. }

关于过滤器的几个小问题

  • 多个过滤器执行的顺序如何确定

    答:通过filter-mapping配置的顺序执行

  • 每个请求或响应都需要经过过滤器吗

    答:通过url-pattern决定

  • 请求和响应是否将过滤器代码从头到尾执行

    答:不是,会先执行预处理操作,然后放行到下一个资源或过滤器,最后再执行后处理操作

  • 在过滤器中是否可以跳转到任意资源

    答:可以,因为重定向可以写绝对路径

  • 重定向和转发是否经过过滤器

    答:重定向经过过滤器,而转发默认不经过过滤器

    可以通过配置过滤器的filter-mapping中的dispatcher属性来让转发也经过过滤器(不推荐,基本不会这么做)

  1. <filter-mapping>
  2. <filter-name>myEncodingFilter</filter-name>
  3. <url-pattern>/abc/*</url-pattern>
  4. <dispatcher>FORWARD</dispatcher>
  5. </filter-mapping>

Filter的执行顺序

  • Filter会按照配置的filter-mapping的先后顺序执行相同的过滤
  • Filter过滤链在执行时会先进后出(在执行到filterChain.doFilter(req, resp)时)
  1. // 执行到该行时,会先执行完下一个过滤器的filterChain.doFilter(req, resp);后的语句,才会执行到该过滤器的System.out.println("我是一个过滤器");
  2. filterChain.doFilter(req, resp);
  3. System.out.println("我是一个过滤器");

监听器Listener

什么是监听器?监听器的作用是什么?

  • 什么是监听器

    监听器是以观察者设计模式实现的,相当于一个监视者,监视着你的动作并做出响应
  • 监听器的作用

    javaweb为我们提供的监听器一共有8个,可以分别用来监听request、session、application作用域的创建、销毁、内容的创建

javax中所提供的监听器(都是接口)

  • ServletRequestListener

    监听request请求的建立和销毁(2个方法)

  • ServletRequestAttributeListener

    监听Request的作用域中属性的存入、删除、替换(当request销毁时也会进入删除的方法)

  • ServletContextListener

    监听application的建立和销毁(2个方法)

  • ServletContextAttributeListener

    监听Application的作用域中属性的存入、删除、替换(当application销毁时也会进入删除的方法)

  • HttpSessionListener

    监听Session的建立和销毁

  • HttpSessionAttributeListener

    监听Session的作用域中属性的存入、删除、替换(当session销毁时也会进入删除的方法)

  • HttpSessionActivationListener(无需在web.xml中配置)

    监听Session作用域中监听了该对象的钝化和活化(序列化、反序列化)

  • HttpSessionBindingListener(无需在web.xml中配置)

    监听Session作用域中监听对象的绑定与解绑(存入session作用域、在session作用域中删除),这个跟HttpSessionAttributeListener很像,不过这个是针对单个对象的

使用监听器实现在线人数的统计

分析:

  • 每次用户登录成功后就有了一位在线人数(session存入了user一个对象)

    可以使用HttpSessionAttributeListener监听存入
  • 每当用户点击注销时(session销毁时)

    可以使用HttpSessionListener监听销毁
  • 在线人数存放在哪??

    在线人数存在Appliction作用域,也就是ServletContext对象中

编写统计在线人数的监听器

  1. import javax.servlet.ServletContext;
  2. import javax.servlet.http.*;
  3. public class OnLineListener implements HttpSessionAttributeListener, HttpSessionListener {
  4. @Override
  5. public void attributeAdded(HttpSessionBindingEvent event) {
  6. // 当前存入到session作用域中的key值
  7. String name = event.getName();
  8. // 判断是否是user
  9. if ("user".equals(name)) {
  10. // 获得容器对象
  11. ServletContext servletContext = event.getSession().getServletContext();
  12. // 获取在线统计人数
  13. Integer online = (Integer) servletContext.getAttribute("online");
  14. if (online == null) {
  15. online = 1;
  16. } else {
  17. online ++;
  18. }
  19. servletContext.setAttribute("online", online);
  20. }
  21. }
  22. @Override
  23. public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
  24. }
  25. @Override
  26. public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
  27. }
  28. @Override
  29. public void sessionCreated(HttpSessionEvent httpSessionEvent) {
  30. }
  31. // session容器销毁时
  32. @Override
  33. public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
  34. // 判断当前用户是否已经登录
  35. HttpSession session = httpSessionEvent.getSession();
  36. Object user = session.getAttribute("user");
  37. // 不等于null说明登录了
  38. if(user != null) {
  39. // 获得容器对象
  40. ServletContext servletContext = session.getServletContext();
  41. // 获取在线统计人数
  42. Integer online = (Integer) servletContext.getAttribute("online");
  43. if (online == null) {
  44. online = 0;
  45. } else {
  46. online --;
  47. }
  48. servletContext.setAttribute("online", online);
  49. }
  50. }
  51. }

在web.xml中配置监听器

  1. <listener>
  2. <listener-class>com.oa.listener.OnLineListener</listener-class>
  3. </listener>

在jsp页面中获取在线人数

<span>当前在线人数为:${applicationScope.online}</span>

HttpSessionBindingListener监听器的使用(监听单个Class,无需配置web.xml)

  1. import lombok.AllArgsConstructor;
  2. import lombok.Data;
  3. import lombok.NoArgsConstructor;
  4. import javax.servlet.http.HttpSessionBindingEvent;
  5. import javax.servlet.http.HttpSessionBindingListener;
  6. import java.io.Serializable;
  7. @Data
  8. @AllArgsConstructor
  9. @NoArgsConstructor
  10. public class People implements Serializable, HttpSessionBindingListener {
  11. private String name;
  12. private int age;
  13. @Override
  14. public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
  15. // 当该类被实例化绑定到Seesion中时执行(session.setAttribute)
  16. System.out.println("People被存到了session作用域中");
  17. }
  18. @Override
  19. public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
  20. // 当该类的对象从Session中解绑时执行(session.removeAttribute)
  21. System.out.println("People从session作用域中被移除");
  22. }
  23. }

使用HttpSessionActivationListener监听Session作用域中该JavaBean的钝化与活化

解析:

钝化:序列化到硬盘中

活化:反序列化到服务器中

所以需要钝化和活化的实体需要实现Serializable接口

配置tomcat的conf文件夹中的context.xml来开启钝化与活化功能

  • 该功能开启后,服务器一旦关闭,那么在关闭时会将所有存入到了Session中的值钝化(序列化)到服务器上
  • 并在服务器启动时将数据活化(反序列化)到服务器中。
  • 钝化后可以在相应位置看到以 .sessioin为后缀的文件
  1. <Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true">
  2. <!-- 这里的directory实质上跑在服务器中的时候应该写相对路径,
  3. 我这里由于使用idea演示,每次idea启动时都会复制一份新的tomcat
  4. 这会导致钝化的session数据都消失掉了。
  5. -->
  6. <Store className="org.apache.catalina.session.FileStore" directory="D:\my_dev_tools\apache-tomcat-8.5.66-windows-x64\apache-tomcat-8.5.66\conf"/>
  7. </Manager>

配置一个JavaBean作为测试继承HTTP


  1. import lombok.AllArgsConstructor;
  2. import lombok.Data;
  3. import lombok.NoArgsConstructor;
  4. import javax.servlet.http.HttpSessionActivationListener;
  5. import javax.servlet.http.HttpSessionEvent;
  6. import java.io.Serializable;
  7. @Data
  8. @AllArgsConstructor
  9. @NoArgsConstructor
  10. public class People implements Serializable,HttpSessionActivationListener {
  11. private String name;
  12. private int age;
  13. @Override
  14. public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) {
  15. // 钝化(序列化)
  16. System.out.println("钝化");
  17. }
  18. @Override
  19. public void sessionDidActivate(HttpSessionEvent httpSessionEvent) {
  20. // 活化(反序列化)
  21. System.out.println("活化");
  22. }
  23. }

这里给个小建议,开发Servlet时,使用统一的前缀目录,这样更方便使用Filter拦截

例如:

  • /abc/employee/findOne
  • /abc/dept/findAll

JAVAWEB过滤器、监听器的作用及使用>从零开始学JAVA系列的更多相关文章

  1. JAVAWEB的基本入门(JSP、Tomcat)>从零开始学JAVA系列

    目录 JAVAWEB的基本入门(JSP.Tomcat) 使用idea创建web项目的两种方式 1.直接创建一个web项目(这样创建好的项目可以直接运行) 2.创建一个普通的java项目并配置web模块 ...

  2. JAVAWEB - Servlet原理及其使用>从零开始学JAVA系列

    目录 Servlet原理及其使用 什么是Servlet Servlet的使用 编写一个Servlet,使用继承HttpServlet的方式 配置web.xml 很简单的几个JSP文件 小提示,如果继承 ...

  3. spring框架的学习->从零开始学JAVA系列

    目录 Spring框架的学习 框架的概念 框架的使用 Spring框架的引入 概念 作用 内容 SpringIOC的学习 概念 作用 基本使用流程 SpringIOC创建对象的三种方式 通过构造器方式 ...

  4. JAVA虚拟机的组成>从零开始学java系列

    目录 JAVA虚拟机的组成 什么是虚拟机? JAVA虚拟机的组成部分 堆区(堆内存) 方法区 虚拟机栈 本地方法栈 程序计数器 字符串常量池 JAVA虚拟机的组成 什么是虚拟机? 虚拟机是运行在隔离环 ...

  5. JSP的执行原理、JSP的内置对象、四大作用域解析、MVC模式理解>从零开始学JAVA系列

    目录 JSP的执行原理.JSP的内置对象.四大作用域解析.MVC模式理解 JSP的执行原理 这里拿一个小例子来解析JSP是如何被访问到的 首先将该项目部署到tomcat,并且通过tomcat启动 通过 ...

  6. Session与Cookie的原理以及使用小案例>从零开始学JAVA系列

    目录 Session与Cookie的原理以及使用小案例 Cookie和Session所解决的问题 Session与Cookie的原理 Cookie的原理 Cookie的失效时机 小提示 Session ...

  7. JAVA数组的基础入门>从零开始学java系列

    目录 JAVA数组的基础入门 什么是数组,什么情况下使用数组 数组的创建方式 获取数组的数据 数组的内存模型 为什么数组查询修改快,而增删慢? 查询快的原因 增删慢的原因 数组的两种遍历方式以及区别 ...

  8. IDEA使用Tomcat时控制台乱码的解决方案>从零开始学JAVA系列

    IDEA使用Tomcat时控制台乱码的解决方案 解决方案1,修改启动时虚拟机参数 解决方案2,修改idea的设置 解决方案3,修改idea配置文件 在最后添加一行 '-Dfile.encoding=U ...

  9. 数据库建模、面向对象建模>从零开始学java系列

    目录 数据库建模 前置知识 使用PowerDesigner数据库建模设计 一对多CDM概念数据模型设计 多对多的PDM物理数据模型设计(针对mysql) PowerDesigner将不同的模型进行转换 ...

随机推荐

  1. mycat高可用-安全管理-监控 看这一篇就够了

    ​ 在之前的操作中,我们已经实现了mysql机器的高可用,可以动态切换master,那么如果mycat崩溃了呢?我们应该如何处理呢?所以此时就需要搭建mycat的高可用集群了. ​ 在mycat的权威 ...

  2. 一个SDK给我干懵逼了?大厂的SDK就这?

    活久见 .org.jboss.netty 和 io.netty 你分的清吗? 大家好,我是小猿来也,一个热衷写 bug 的程序猿. 一天我正在专心致志写 Bug 的时候,一个同事跑过来找我. 说有个很 ...

  3. 02 Linux系统发送告警邮件

    # yum install mailx -y # vim /etc/mail.rc set from=hyjy2504164765@163.com smtp=smtp.163.com set smtp ...

  4. 9、make和make install的区别

    简单来说,make 是编译,make install 是安装. 9.1.configure: 这一步一般用来生成 Makefile,为下一步的编译做准备,你可以通过在 configure 后加上参数来 ...

  5. 44、wget和curl的常用参数

    1.wget: wget是文件下载的工具: 不加任何参数是直接下载该文件: (1)-O: 将下载的文件指定为特定的文件名: wget -O baidu.html www.baidu.com --201 ...

  6. Docker搭建Jenkins+Maven/Gradle——代码自动化运维部署平台(二)

    一.简介 1.Jenkins 概述: Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins ...

  7. CentOS-关闭防火墙和禁用安全策略

    关闭防火墙 默认使用的是firewall作为防火墙 查看防火墙状态 $ firewall-cmd --state 停止firewall $ systemctl stop firewalld.servi ...

  8. 所有的Java虚拟机必须实现在每个类或接口被Java程序 “ 首次主动使用 ” 时才初始化他们

    原文:https://www.cnblogs.com/fanjie/p/6916784.html Java程序对类的使用方式可分为两种– 主动使用– 被动使用 被动使用以后再讲,这里说说什么是主动使用 ...

  9. Java实验项目三——采用面向对象的方式设计线性表

    Program: 采用面向对象的方法设计一个线性表,目的是为其他需要用线性表的应用提供线性表对象. 1.list包中,定义线性表类 1 /* 2 * Description:定义线性表类 3 * 4 ...

  10. Java 在Word中创建邮件合并模板并合并文本和图片

    Word里面的邮件合并功能是一种可以快速批量操作同类型数据的方式,常见的如数据填充.打印等.其中必不可少的步骤包括用于填充的模板文档.填充的数据源以及实现邮件合并的功能.下面,通过Java程序展示如何 ...