过滤器
Filter译为过滤器。 由于 Servlet 规范是开放的,借助于公众与开源社区的力量, Servlet 规范越来越科学,功能也越来越强大。
运行原理:
当客户端向服务器端发送一个请求时,如果有对应的过滤器进行拦截,过滤器可以改变请求的内容、或者重新设置请求协议的相关信息等,然后再将请求发送给服务器端的Servlet进行处理。当Servlet对客户端做出响应时,过滤器同样可以进行拦截,将响应内容进行修改或者重新设置后,再响应给客户端浏览器。在上述过程中,客户端与服务器端并不需要知道过滤器的存在 在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到服务器端的Servlet。具体执行流程如下:
快速入门
1.编写一个类实现Filter过滤接口
2.重写接口中的方法
package com.bhf.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 过滤器的生命周期
* 创建对象 LoginFilter() 服务器启动时 调用一次
* 初始化 init 对象创建完成后 调用一次
* 执行过滤的方法 doFilter 一次请求执行一次
* 销毁方法 destroy 服务器关闭时 被调用 调用一次
*/
// "/*"表示拦截所有请求,进入doFilter,
// 执行filterChain.doFilter(servletRequest,servletResponse);放行请求
@WebFilter("/*")
public class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
应用的实例
1.解决请求参数的乱码问题
2.非法访问的拦截(当用户未登录时,拦截请求到登录页面)
拦截所有资源: /*
需要被放行的资源: 不需要登录即可访问的资源
1、放行指定页面:不需要登录可以访问的页面(例如:登录页面、注册页面等)
2、放行静态资源: (例如: css. js. image等资源)
3、放行指定操作:不需要登录即可执行的操作(例如:登录操作、注册操作等)
4、登录状态放行(如果存在指定session对象。则为登录状态)
package com.bhf.filter;
import com.bhf.pojo.User;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*")
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;
//处理中文乱码
req.setCharacterEncoding("utf-8");
//放行特定页面
String servletPath = req.getServletPath();
System.out.println("servletPath"+servletPath);
if("/login.jsp".equals(servletPath)||"/register.jsp".equals(servletPath)){
filterChain.doFilter(req,resp);
return;
}
//放行特定的请求 /user method=getCode
String method = req.getParameter("method");
if("getCode".equals(method)||"login".equals(method)||"register".equals(method)||"checkUserName".equals(method)){
filterChain.doFilter(req,resp);
return;
}
//放行特定静态资源 .css .js .img
if(servletPath.startsWith("/static")) {
filterChain.doFilter(req,resp);
return;
}
//1.判断session中是否有user对象
User user = (User) req.getSession().getAttribute("user");
//2.判断user是否为null
if(user==null){
//没有登录跳转
req.setAttribute("login_msg","您未登录");
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
filterChain.doFilter(req,resp);
}
@Override
public void destroy() {
}
}
监听器
web监听器由servlet规范提供的,它可以监听客户端的请求,服务端的操作,监听的对象包括:
-
ServletContext
-
HttpSession
-
ServletRequest
三个域对象(内置对象),分别对应aplication,session,request
Web监听器概念 Servlet规范中定义的一种特殊类,用于监听ServletContext,HttpSession和ServletRequest等域对象的创建与销毁事件,用于监听域对象的属性发生增、删、改的事件,可以在事件发生前,发生后做一些必要的处理
监听三个对象的创建和销毁
1.application域对象的监听器
package com.aiit.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* application域对象的监听器
* 1.监听域对象的创建和销毁
* ServletContextListener
*/
@WebListener
public class ApplicationListener implements ServletContextListener {
// 一旦有application对象被创建 则该方法会被自动调用
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("application对象被创建");
}
// 一旦有application对象被销毁 则该方法会被自动调用
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("application对象被销毁");
}
}
2.session对象的监听器
package com.aiit.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* session对象的创建和销毁的监听
*
* session 对象 什么时候被创建
* 浏览器向服服务器成功发送一次请求 则会话对象被创建 同一次会话只会创建一个会话对象 Cookie
* session 对象 什么时候被销毁
* 1. 手动销毁
* 2. 默认销毁 浏览器在30分钟之内没有向服务器发送请求 则会话对象自动销毁
*/
@WebListener
public class SessionListener implements HttpSessionListener {
//会话对象被创建
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("sessionCreated");
}
//会话对象被销毁
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("sessionDestroyed");
}
}
3.request对象的监听器
package com.aiit.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("requestDestroyed");
}
//会话对象被销毁
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("requestInitialized");
}
}
监听三个对象中值的变化
1.监听域对象中值的改变,实现ServletContextAttributeListener接口
package com.aiit.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;
/**
* application域对象的监听器
*2.监听域对象中值的改变
* ServletContextAttributeListener
*
*/
@WebListener
public class ApplicationAttributeListener implements ServletContextAttributeListener {
//application中有值被添加
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
String name = event.getName();
System.out.println("name = " + name);
Object value = event.getValue();
System.out.println("value = " + value);
System.out.println("application attributeAdded");
}
//application中有值被删除
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
System.out.println("application attributeRemoved");
}
//application中有值被替换
@Override
public void attributeReplaced(ServletContextAttributeEvent event) {
System.out.println("application attributeReplaced");
}
}
2.监听域对象中值的改变,实现HttpSessionAttributeListener接口
与1相同省略
3.监听域对象中值的改变,实现ServletRequestAttributeListener接口
与1相同省略
使用监听器防止一个账号多段登录
单点登录思路分析 1.用户登录成功后会向session域中添加一个key --> user 2.向session对象中添加值时会被HttpSessionAttributeListener attributeAdded 获取到 3.判断改登录的用户是否已经登录过一次了 -->Map<String(username),HttpSession(session) > tom session ;jack session 4.用户已经登录则根据用户名在map集合中取出对应的session并销毁 第一次登录的用户就会被剔除 再次请求后台接口是就会被拦截到登录页面 5.将第二次登录的用户相关信息存入map集合 user session
@WebListener
public class LoginListener implements HttpSessionAttributeListener {
private Map<String, HttpSession> sessions = new HashMap<String, HttpSession>();
public void attributeReplaced(HttpSessionBindingEvent arg0) {
}
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println("session值被添加");
//获取添加session的名字
String name = event.getName();
System.out.println(name);
if("username".equals(name)) {//该用户的session 已存在 在map中移出
String username =(String)event.getValue();
if(sessions.containsKey(username)) {
HttpSession httpSession = sessions.get(username);
//设置session失效
httpSession.invalidate();
System.out.println("session被移出");
}
//将刚生成的session放入 集合
sessions.put(username, event.getSession());
}
}
public void attributeRemoved(HttpSessionBindingEvent event) { }
public void attributeReplaced(HttpSessionBindingEvent event) { }
}
Web监听器的常用用途
-
统计在线人数
-
系统启动时加载初始化信息
实例1
/**
* 使用session监听器实现统计在线人数
* @author USER
* date 2021年7月13日
* @version 1.0
*/
@WebListener
public class SessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("session监听器初始化完毕");
CountUtil.add();
arg0.getSession().getServletContext().setAttribute("online", CountUtil.getCount());
}
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("session监听器销毁完毕");
CountUtil.sub();
arg0.getSession().getServletContext().setAttribute("online", CountUtil.getCount());
}
}
实例2
/**
* Application域生命周期的监听 设置全局的路径
* @author USER
* date 2021年7月12日
* @version 1.0
*/
@WebListener
public class ApplicationListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("上下文销毁化完毕");
}
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("上下文初始化完毕");
arg0.getServletContext().setAttribute("bp", arg0.getServletContext().getContextPath());
}
}