过滤与监听
2023-12-26 13:11:24
过滤与监听
一.过滤器Filter
1.概述
(1)概念
- 过滤器是一个服务器端的组件,它可以截取客户端的请求和服务端的响应信息,并对这些信息进行过滤。
(2)原理
- 先过滤,后放行
(3)应用场景
- 统一处理中文编码
- 统一处理登录控制
2.创建Filter过滤器
(1)方式1
- web.xml注册过滤器
a.创建一个普通类实现Filter接口,并重写Filter接口中的三个方法
package com.lfg.filter;
import javax.servlet.*;
import java.io.IOException;
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter");
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("filter destroy");
}
}
b.在web.xml文件中注册过滤器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--注册过滤器-->
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>com.lfg.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<!--配置过滤路径-->
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
</web-app>
(2)方式2
- 注解方式注册过滤器
a.创建一个普通类实现Filter接口,并重写Filter接口中的三个方法,再使用注解注册过滤器
- @WebFilter(“/index.jsp”)
package com.lfg.filter;
import javax.servlet.*;
import java.io.IOException;
@WebFilter("/index.jsp")
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter");
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("filter destroy");
}
}
3.常用路径配置格式
格式 | 描述 |
---|---|
/* | 过滤所有的服务器端资源 |
*.jsp | 过滤所有以.jsp结尾的服务器端资源 |
/studentServlet | 只能过滤studentServlet这个路径的服务器端资源 |
4.过滤器的生命周期
生命周期 | 描述 |
---|---|
init() | 调用init() 方法初始化实例,在服务器启动时只调用一次 |
doFilter() | 每次访问请求,如果被访问的请求符合过滤条件都会调用doFilter() 方法进行真正的过滤处理 |
destroy() | 停止服务器调用destroy() 方法,销毁实例,释放资源,只执行一次 |
5.过滤器特点
(1)一个过滤器可以过滤多个servlet或者请求路径
a.web.xml
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>com.lfg.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<!--配置过滤路径-->
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<!--配置过滤路径-->
<url-pattern>/studentServlet</url-pattern>
</filter-mapping>
b.注解
@WebFilter(filterName = "FirstFilter",urlPatterns = {"/index.jsp","/studentServlet"})
(2)过滤器默认情况下只过滤重定向的路径(地址栏中的路径),不过滤转发路径
- 配置过滤转发路径
a.web.xml
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<!--配置过滤路径-->
<url-pattern>/test.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
b.注解
@WebFilter(filterName = "FirstFilter",urlPatterns = "/test.jsp",dispatcherTypes = DispatcherType.FORWARD)
6.过滤器实现统一编码
package com.lfg.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("filter destroy");
}
}
7.登录控制
(1)login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="loginServlet" method="post">
账号:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
(2)LoginServlet.java
package com.lfg.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
//默认登录成功
boolean res = true;
if (res) {
HttpSession session = req.getSession();
session.setAttribute("username",username);
resp.sendRedirect("index.jsp");
} else {
resp.sendRedirect("login.jsp");
}
}
}
(3)LoginFilter.java
package com.lfg.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/index.jsp")
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)servletRequest;
HttpServletResponse resp = (HttpServletResponse)servletResponse;
HttpSession session = req.getSession();
Object username = session.getAttribute("username");
if (username == null) {
resp.sendRedirect("login.jsp");
} else {
filterChain.doFilter(req, resp);
}
}
@Override
public void destroy() {
}
}
(4)index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
欢迎您${sessionScope.username}
</body>
</html>
二.监听器Listener
1.概述
(1)概念
- 监听器就是一个实现了特定接口的Java类,主要用于监听某个对象的状态变化的组件
(2)分类
依据(域对象) | ServletContext域 | HttpSession域 | ServletRequest域 |
---|---|---|---|
创建与销毁 | ServletContextListener | HttpSessionListener | ServletRequestListener |
属性变化 | ServletContextAttributeListener | HttpSessionAttributeListener | ServletRequestAttributeListener |
绑定到HttpSession域中某个对象的状态 | HttpSessionBindingListener HttpSessionActivationListener |
(3)原理
- 实现了特定接口的类为监听器,用来监听另一个Java类的方法调用或者属性改变;
- 当被监听的对象发生了方法调用或者属性改变后,监听器的对应方法就会立即执行
(4)涉及组成部分
a.事件源
- 被监听的对象,即:request、session、servletContext三大域对象。
b.监听器
- 监听事件源对象,事件源对象状态的变化都会触发监听器。
c.注册监听器
- 将监听器与事件源进行绑定,有两种注册方式:web.xml 或 @WebListener注解
d.时间
- 域对象发生改变
(5)应用场景
- 统计网站在线人数
- 实现任务调度,启动定时程序
(6)创建方法
(1)定义一个普通类实现监听器接口;
(2)重写监听器接口方法;
(3)注册监听器:配置 web.xml 或 @WebListener注解;
2.监听域对象的创建与销毁
2.1.ServletContextListener
(1)概述
- ServletContextListener监听器,用来监听ServletContext域对象的创建域销毁
- ServletContext域对象:代表全局唯一对象,每个web工程会产生一个ServletContext对象。
- 创建:服务器启动时
- 销毁:服务器关闭时
(2)创建ServletContextListener监听器
a.创建一个普通类
- 实现ServletContextListener接口
- 重写内部的两个方法
package com.lfg.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ApplicationListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext init");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext Destroyed");
}
}
b.注册监听器(web.xml)
<listener>
<listener-class>com.lfg.listener.ApplicationListener</listener-class>
</listener>
c.测试监听器
当tomcat服务器开启时执行被创建的方法contextInitialized,服务器被关闭时执行被销毁的方法contextDestroyed
2.2.HttpSessionListener
(1)概述
- HttpSessionListener监听器:用来监听HttpSesssion域对象的创建域销毁
- HttpSesssion域对象:
- Session创建:Servlet中是request.getSession() ,JSP页面中自带Session
- Session销毁:非正常关闭服务器,Session过期,session.invalidate()
(2)HttpSessionListenerHttpSessionListener监听器
a.创建一个普通类
- 实现HttpSessionListener接口
- 重写内部的两个方法
package com.lfg.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session create");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session destroy");
}
}
b.注册监听器(注解)
@WebListener
c.测试监听器
测试创建:
-
创建一个jsp页面test.jsp
-
直接访问index.jsp页面,由于session是jsp的内置对象,意味着在访问index.jsp页面时创建了session对象,因此会触发监听器的创建方法
测试销毁:
- 执行session.invalidate()方法强制销毁session
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
session.invalidate();
%>
</body>
</html>
2.3.ServletRequestListener
(1)概述
- ServletRequestListener监听器:用来监听ServletRequest域对象的创建和销毁
- Request创建:请求发起时创建
- Request销毁:响应结束时销毁
(2)创建ServletRequestListener监听器
a.创建一个普通类
- 实现ServletRequestListener接口
- 重写内部的两个方法
package com.lfg.listener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class RequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("request destroy");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("request init");
}
}
b.注册监听器
@WebListener
c.测试监听器
运行JSP文件即可
3.监听域对象属性改变
- 对域对象添加数据、修改数据、移除数据
(1)分类
监听器 | 描述 |
---|---|
ServletContextAttributeListener | 监听ServletContext中属性的变化 |
HttpSessionAttributeListener | 监听HttpSession中属性的变化 |
ServletRequestAttributeListener | 监听ServletRequest中属性的变化 |
(2)不同操作触发的方法
操作 | 描述 |
---|---|
attributeAdded | 监听属性添加-当数据范围对象没有该属性,第一次添加时会自动触发调用执行 |
attributeRemoved | 监听属性移除- 从一个数据范围对象删除一个已经存在的属性时会自动触发执行 |
ttributeReplaced | 监听属性替换 -当一个数据范围已经存在一个属性,向数据范围添加相同名称属性时自动触发替换方法 |
(3)以ServletContextAttributeListener为例
a.创建ServletContextAttributeListener监听器
- 实现ServletContextAttributeListener接口
- 重写内部的三个方法
package com.lfg.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class AttributeListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("ServletContext add attribute");
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("ServletContext removed attribute");
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("ServletContext replaced attribute");
}
}
b.注册监听器
WebListener
c.测试监听器
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
application.setAttribute("color","red");
application.setAttribute("color","green");
application.removeAttribute("color");
%>
</body>WebListener
</html>
4.监听绑定到HttpSession域中某个对象状态
(1)概述
- 监听器是Servlet中比较特殊的监听器, 主要用来监听绑定到Session域中特定对象的状态
- 绑定:将Java对象绑定到session中。
- 解除绑定:将Java对象从session中解除绑定
(2)HttpSessionBindingListener
- 实现HttpSessionBindingListener接口的Java对象,可以感知自身被绑定到Session或者从Session中解除绑定
a.创建HttpSessionBindingListener监听器
- 创建一个学生类Student实现HttpSessionBindingListener接口
- 重写内部两个方法
- 注意:这个监听器不需要注册
package com.lfg.entity;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class Student implements HttpSessionBindingListener {
private int id;
private String name;
public Student() {
}
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("学生对象被绑定到session中了");
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("学生对象被从session中移除了");
}
}
b.测试
- 创建一个jsp页面,创建学生对象并分别绑定和移除Session进行测试
<%@ page import="com.lfg.entity.Student" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
Student student = new Student(1,"mary");
session.setAttribute("stu",student);
session.removeAttribute("stu");
%>
</body>
</html>
(3)HttpSessionActivationListener
- 实现HttpSessionActivationListener接口的Java对象,可以感知从内存被钝化到硬盘,从硬盘活化到内存中
- 钝化时机:服务器关闭或重启,指定时间内(长时间)不操作服务器。
- 活化时机:服务器再次开启。
a.创建HttpSessionActivationListener监听器
- 创建一个老师类实现HttpSessionActivationListener接口
- 重写内部两个方法
- 注意:这个监听器不需要注册
package com.lfg.entity;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import java.io.Serializable;
public class Teacher implements HttpSessionActivationListener, Serializable {
private int id;
private String name;
public Teacher() {
}
public Teacher(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void sessionWillPassivate(HttpSessionEvent se) {
System.out.println("数据钝化到磁盘中了");
}
@Override
public void sessionDidActivate(HttpSessionEvent se) {
System.out.println("数据活化到内存中了");
}
}
b.配置Tomcat conf中context.xml文件
directory="d:\test"表示自定义钝化文件的存储路径,maxIdleSwap="1"表示超过1分钟未操作服务器会自动钝化。
<Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="d:\test"/>
</Manager>
c. 测试
- 创建一个test1.jsp页面,向session中保存一个老师对象
<%@ page import="com.etime.lfg.Student" %>
<%@ page import="com.etime.lfg.Teacher" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
Teacher teacher = new Teacher(1,"mary");
session.setAttribute("teacher",teacher);
%>
</body>
</html>
- 创建一个test2.jsp页面获取活化后session中的数据是否存在
<%@ page import="com.etime.lfg.Teacher" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
Teacher teacher = (Teacher)session.getAttribute("teacher");
out.print(teacher.getName());
%>
</body>
</html>
- 测试步骤
- 首先运行test1.jsp页面,向session中存入老师信息
- 然后关闭服务器或通过设置maxIdleSwap="1"等待1分钟不操作服务器或者关闭服务器, 都会触发钝化方法执行
- 同时在指定的路径d:\test下会看到一个.session文件,将session中的数据钝化到该文件中
(4)特别注意
- 实现这两个接口的类不需要有 web.xml 文件或注解中进行注册监听器,都是由Session自主完成的
三.综合案列
1.分析
通过ServletContextListener监听,当Web应用上下文启动时,在ServletContext中添加一个List集合,用来准备存放在线的用户名;然后,可以通过HttpSessionAttributeListener监听器,当用户登录成功,把用户名设置到Session中时,同时将用户名存放到ServletContext中的List列表中;最后通过HttpSessionListener监听,当用户注销会话时,将用户名从应用上下文范围中的List列表中删除。
2.步骤
(1)创建登录页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="loginServlet" method="post"> 账号:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="登录"> </form> </body> </html>
(2)创建用户登录的Servlet
package com.lfg.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/loginServlet") public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); //默认登录成功 boolean res = true; if (res) { HttpSession session = req.getSession(); session.setAttribute("username",username); resp.sendRedirect("index.jsp"); } else { resp.sendRedirect("login.jsp"); } } }
(3)创建用户退出登录的Servlet
package com.lfg.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/logoutServlet") public class LogoutServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); session.invalidate(); resp.sendRedirect("login.jsp"); } }
(4)创建监听器
package com.lfg.listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; import javax.servlet.http.*; import java.util.ArrayList; import java.util.List; @WebListener public class UserListener implements ServletContextListener, HttpSessionAttributeListener, HttpSessionListener { ServletContext servletContext = null; @Override public void contextInitialized(ServletContextEvent sce) { //监听ServletContext对象的创建 //创建集合放入ServletContext对象中 List<String> list = new ArrayList<>(); servletContext = sce.getServletContext(); servletContext.setAttribute("users",list); } @Override public void attributeAdded(HttpSessionBindingEvent se) { //监听session中放入数据 //getName获取当前放入session中数据的key String name = se.getName(); if ("username".equals(name)) { //getValue获取当前放入session中数据的value String value = (String)se.getValue(); List<String> list = (List<String>)servletContext.getAttribute("users"); list.add(value); servletContext.setAttribute("users",list); } } @Override public void sessionDestroyed(HttpSessionEvent se) { //监听session的销毁 //退出登录时,将登录信息从ServletContext中的list里面移除掉 HttpSession session = se.getSession(); String username = (String)session.getAttribute("username"); List<String> list = (List<String>)servletContext.getAttribute("users"); list.remove(username); servletContext.setAttribute("users",list); } }
(5)创建显示在线用户页面index.jsp
<%@ page import="java.util.List" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> 欢迎您${sessionScope.username}<a href="logoutServlet">退出登录</a><br> 当前登录的用户有: <% List<String> users = (List<String>)application.getAttribute("users"); for (String user:users) { out.print(user+"<br>"); } %> </body> </html>
文章来源:https://blog.csdn.net/weixin_53903929/article/details/135218357
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!