Servlet中的过滤器和监听器
一、过滤器
过滤器:顾名思义就是要起到过滤的作用。所有的请求在真正到达servlet之前都会先经过过滤器过滤一遍。过滤器也是Servlet的一种,因此也有init和destroy方法,还有一个服务方法,只是这里提供的服务是过滤。
一般客户端发出请求以后会交给Servlet,如果过滤器的存在,则客户端发出的请求都是先交给过滤器处理之后,再交给Servlet去处理对应的业务逻辑。
一、创建过滤器的步骤
1.实现javax.servlet.Filter接口。
2.实现Filter接口中的三个方法:init、doFilter、destroy。
3.在web.xml中配置,让服务器知道过滤器的存在,否则是没有用的。
public class MyFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//放行请求 chain.doFilter(req, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
MyFilter
com.zk.filter.MyFilter
MyFilter
/*
写的是该过滤器类的名字,可以随意写。
写的是实现Filter接口的子类全路径名。
表示的是拦截的范围
过滤器拦截范围:
1.拦截所有 /*
2.拦截部分servlet请求 拦截请求的结尾 eg: .do /.action
3.拦截执行servlet请求 /指定的名字
介绍一下实现Filter接口的三个方法:
init()方法:服务器启动的时候就会调用,只会执行一次,在服务器启动的时候就会初始化。
doFilter()方法: 服务器在接收到浏览器发过来的请求后,先解析请求信息,创建对象request和response然后根据请求URL地址判断如果符合过滤器的过滤范围,则会调用过滤器中的doFilter来进行请求拦截,并将request和response对象作为实参传递给doFilter方法。可以在doFilter方法中声明过滤器拦截代码。 每次拦截请求都会调用。
destroy()方法:销毁方法,服务器自动调用,只会执行一次,在服务器关闭的时候触发。
过滤器链:
当web.xml中配置有多过滤器时,服务器会根据wem.xml中配置的顺序从上到下执行,谁先配置谁先执行,放行时,如果有下一个过滤器,会自动的放行到下一个过滤器,如果没有则放行到指定的资源。
过滤器可以用来干什么呢? 两个简单的应用:
1.统一设置字符集
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
}
再也不用担心中文乱码的问题了。
2.拦截URL,不登录不允许直接访问页面。
配合session对象,检测,如果用户登录进入页面,则在session中设置一个属性,在doFilter方法进行进行获取,如果为null,则重定向到登陆页面,再次过程中会将登录界面不做拦截,要不然就会陷入无限的死循环。
注:使用servlet3.0时,可以不需要在web.xml中配置,直接可以使用注解
可通过自带的servlet软件创建(listener和filter也都可以这么做)
@WebServlet("/s01") //可随意自定资源名public class Servlet01 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet01...");
}
}
自定义资源名建议和类同名,以见名知到是哪一个Servlet类。
二、监听器
监听器顾名思义就是监听某种事件的发生,即当某个事件发生时,就触发了某个设置好的监听器,但是这里触发的原因不同。例如地震监测仪监听地震的发生,大气检测仪,检测空气的变化以提供预警。
在Servlet中因监听对象的不同分为不同的监听器,这里指定的监听对象是application、session对象,request对象,每个对象都有各自的监听器。
实现监听的步骤:
1.继承相关对象对应的接口
//监听request对象的接口,和监听request对象属性接口ServletRequestListener, ServletRequestAttributeListener
//监听Session对象的接口,和监听Session对象属性接口HttpSessionListener,HttpSessionAttributeListener
//监听application对象的接口,和监听application对象属性接口ServletContextListener,ServletContextAttributeListener
2.在web.xml中配置实现该接口的子类信息,一个实现类,写一个标签,在中只能写一个。在servlet3.0以上也可以使用注解代替xml中的配置。后面的例子中可见。
com.zk.listener.MyListener2
示例
package com.zk.listener;
import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.*;
/*** @author zk* @title: MyListener* @projectName ListenerAndFilter* @description: TODO* @date 2019/8/28 9:17*/
//@WebListener("/myListener")public class MyListener implements ServletRequestListener, ServletRequestAttributeListener, HttpSessionListener, HttpSessionAttributeListener, ServletContextListener,ServletContextAttributeListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("request对象被销毁了");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("request对象被创建了");
}
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
//获取request设置的键和值 System.out.println(srae.getName() + "...." + srae.getValue());
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
//获取request移除的键和值 System.out.println(srae.getName() + "...." + srae.getValue());
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
//获取request替换的键和值 System.out.println(srae.getName() + "...." + srae.getValue());
}
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session对象被创建");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session对象被销毁");
}
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
HttpSession session = se.getSession();
System.out.println(se.getName() + "...." + se.getValue());
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
HttpSession session = se.getSession();
System.out.println(se.getName() + "...." + se.getValue());
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
HttpSession session = se.getSession();
System.out.println(se.getName() + "...." + se.getValue());
}
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println(scae.getName() + "...." + scae.getValue());
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println(scae.getName() + "...." + scae.getValue());
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println(scae.getName() + "...." + scae.getValue());
}
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext对象被创建");
System.out.println("ServletContext对象:"+ sce.getServletContext());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext对象被销毁");
}
}
1.application监听器:ServletContextListener
public void contextInitialized(ServletContextEvent sce); //在application创建时被调用
public void contextDestroyed(ServletContextEvent sce);//在application对象被销毁时调用
方法中的参数都可以获取监听application对象
2.application属性监听器:ServletContextAttributeListener
需要实现的方法:
public void attributeAdded(ServletContextAttributeEvent e); //当调用application.setAttribute()时调用
public void attributeRemoved(ServletContextAttributeEvent e); //当调用applcaition.removeAttribute()时调用
public void attributeReplaced(ServletContextAttributeEvent e); //当调用两次application.setAttribute()赋予相同属性时调用
参数ServletContextAttributeEvent可以获得触发该监听器的属性名称和属性值,方法有:
(1)getName(); 取得属性的名称;
(2)getValue(); 取得属性的值;(注意:返回的是Object,必须转型)
3.Session对象监听器:HttpSessionListener
需要实现的方法:
public void sessionCreated(HttpSessionEvent e); //当打开一个浏览器时,就会触发这个方法
public void sessionDestroyed(HttpSessionEvent e);//当调用session.invalidate()时,或超时掉哦那个HttpSessionEvent的方法getSession()获取触发监听器的session对象。
4.session属性监听器:HttpSessionAttributeListener
需要实现的方法:
public void attributeAdded(HttpSessionBindingEvent e); //当调用session.setAttribute()时调用
public void attributeRemoved(HttpSessionBindingEvent e);//当调用session.removeAttribute()时调用
public void attributeReplaced(**HttpSessionBindingEvent** e);//当调用两次session.setAttribute()赋予同一个属性对应的value时,该方法被触发调用。
属性时调用
HttpSessionBindingEvent 方法:
(1)getSession();//获取触发监听器的session
(2)getName();//获取属性名称
(3)getValue();//获取属性值
监听器应用的场景
ServletContextListener: 在任何Servlet提供服务之前执行、在Servlet销毁时执行,用于提前初始化一些资源,比如数据库的连接、销毁一些资源,比如数据库的连接:
ServletContextAttributeListener:上下文中添加、删除、替换了属性;
HttpSessionListener:多少个在线用户,即跟踪会话;
HttpSessionAttributeListener:会话属性添加、删除、替换;
案例:统计网站的在线人数
可以通过HttpSessionListener来监听session对象的变化,首先通过ServletContextListener监听,当服务器启动时,在contextInitialized方法中创建一个统计的标志count,将它设置进入ServletContext对象的域中,每当有session被创建出来count就自增1,在sessionCreated方法中通过监听到的新生session对象获取到ServletContext对象,把count值设置进入ServletContext域中,当有session销毁或者session时间超时时,通过sessionDestroyed方法获取销毁的session对象,通过该session对象获得ServletContext对象,把count自减一后设置入ServletContext对象的域中,这个页面就可以获得试试在线人数了。