一、过滤器
(1.) 简介:
Filter是在Servlet 2.3之后增加的新功能,当需要限制用户访问某些资源或者在处理请求时提前处理某些资源的时候,就可以使用过滤器完成。
过滤器是以一种组件的形式绑定到WEB应用程序当中的,与其他的WEB应用程序组件不同的是,过滤器是采用了“链”的方式进行处理的。
(2.) Filter的作用:
对用户请求进行身份认证
对用户发送到数据进行过滤或者替换
转换图像数据格式
数据压缩
数据加密
XML数据的转换
修改请求数据的字符串
(3). 实现过滤器
在Servlet中,如果要定义一个过滤器,则直接让一个类实现javax.servlet.Filter接口即可,此接口定义了三个操作方法:
- public void init(FilterConfig filterConfig) throws ServletException
- public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException
- public void destroy()
(4)FilterChain
FilterChain接口的主要作用是将用户的请求向下传递给其他的过滤器或者是Servlet: - public void doFilter(ServletRequest request,ServletResponse response) throws IOException,ServletException
在FilterChain接口中依然定义了一个同样的doFilter()
方法,这是因为在一个过滤器后面可能存在着另外一个过滤器,也可能是请求的最终目标(Servlet),这样就通过FilterChain形成了一个“过滤链”的操作,所谓的过滤链就类似于生活中玩的击鼓传花游戏
(5)定义一个简单的过滤器 —— SimpleFilter.java
package org.lxh.filterdemo;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class SimpleFilter implements Filter {
public void init(FilterConfig config) throws ServletException { // 初始化过滤器
String initParam = config.getInitParameter("ref"); // 取得初始化参数
System.out.println("** 过滤器初始化,初始化参数 = " + initParam);
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException { // 执行过滤
System.out.println("** 执行doFilter()方法之前。");
chain.doFilter(request, response); // 将请求继续传递
System.out.println("** 执行doFilter()方法之后。");
}
public void destroy() { // 销毁过滤
System.out.println("** 过滤器销毁。");
}
}
配置Web.xml
<filter>
<filter-name>simple</filter-name>
<filter-class>org.lxh.filterdemo.SimpleFilter</filter-class>
<init-param>
<param-name>ref</param-name>
<param-value>HELLOMLDN</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>simple</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(6)过滤器的应用 —— 编码过滤
在进行WEB开发中,编码过滤是必不可少的操作,如果按照之前的做法,在每一个JSP或者是Servlet中都重复编写“request.setCharacterEncoding(“GBK”)”的语句肯定是不可取的,会造成大量的代码重复,那么此时就可以通过过滤器完成这种编码过滤。
package org.lxh.filterdemo;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class EncodingFilter implements Filter {
private String charSet; // 设置字符编码
public void init(FilterConfig config) throws ServletException {
this.charSet = config.getInitParameter("charset"); // 取得初始化参数
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding(this.charSet); // 设置统一编码
}
public void destroy() {
}
}
配置Web.xml
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.lxh.filterdemo.EncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(7)登陆验证
登陆验证是所有WEB开发中不可缺少的部分,最早的做法是通过验证session的方式完成,但是如果每个页面都这样做的话,则肯定会造成大量的代码重复,而通过过滤器的方式就可以避免这种重复的操作。
在这里需要注意的是,session本身是属于HTTP协议的范畴,但是doFilter()方法中定义的是ServletRequest类型的对象,那么要想取得session,则必须进行向下转型,将ServletRequest变为HttpServletRequest接口对象,才能够通过getSession()方法取得session对象。
登陆验证
package org.lxh.filterdemo;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class LoginFilter implements Filter {
public void init(FilterConfig config) throws ServletException {} // 初始化过滤器
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException { // 执行过滤
HttpServletRequest req = (HttpServletRequest) request ; // 向下转型
HttpSession ses = req.getSession() ; // 取得session
if (ses.getAttribute("userid") != null) { // 判断是否登陆
chain.doFilter(request, response); // 传递请求
} else { // 没有登陆
request.getRequestDispatcher("login.jsp")
.forward(request, response); // 跳转到登陆页
}
}
public void destroy() {} // 销毁过滤
}
二、监听器
第三种Servlet程序称为监听Servlet,主要的功能是负责监听WEB的各种操作,当相关的事件触发之后将产生事件,并对此事件进行处理,在WEB中可以对application、session、request三种操作进行监听。
对application监听
对application监听,实际上就是对ServletContext(Servlet上下文)监听,主要使用以下两个接口:
ServletContextListener
ServletContextAttributeListener
上下文状态监听:ServletContextListener接口
对Servlet上下文状态监听可以使用javax.servlet.ServletContextListener,主要方法
public void contextInitialized(ServletContextEvent sce)
public void contextDestroyed(ServletContextEvent sce)
在上下文状态监听操作中,一旦触发了ServletContextListener接口中定义的事件之后,可以通过ServletContextEvent进行事件的处理
public ServletContext getServletContext()
对Servlet上下文状态监听
配置web.xml
上下文属性监听:ServletContextAttributeListener接口
对Servlet上下文属性操作监听,可以使用javax.servlet.ServletContextAttributeListener接口,主要方法
public void attributeAdded(ServletContextAttributeEvent scab)
public void attributeRemoved(ServletContextAttributeEvent scab)
public void attributeReplaced(ServletContextAttributeEvent scab)
在上下文属性监听中,一旦触发了ServletContextAttributeListener接口中定义的事件之后,可以通过ServletContextAttributeEvent进行事件的处理,事件处理中定义的方法
public String getName()
public Object getValue()
对Servlet上下文属性监听
配置web.xml
对session监听
在监听器中,针对于session的监听操作提供了三个接口:
HttpSessionListener
HttpSessionAttributeListener
HttpSessionBindingListener
session状态监听:HttpSessionListener接口
当需要对创建或销毁session的操作进行监听的时候,可以实现javax.servlet.http.HttpSessionListener接口,此接口定义的方法如下:
public void sessionCreated(HttpSessionEvent se)
public void sessionDestroyed(HttpSessionEvent se)
当session创建或销毁后,将产生HttpSessionEvent事件,此事件定义的操作如下:
public HttpSession getSession()
对session监听
配置web.xml
session销毁的操作
当一个新用户打开一个动态页时,服务器是会为新用户分配session,并且触发HttpSessionListener接口中的sessionCreated()事件,但是在用户销毁时却有两种不同的方式来触发sessionDestroyed()事件:
方式一:调用HttpSession接口的invalidate()方法,让一个session失效。
方式二:超过了配置的session超时时间,session超时时间,可以直接在项目中的web.xml配置。
session属性监听:HttpSessionAttributeListener接口
在session监听中也可以对session的属性操作进行监听,这一点与监听上下文属性的道理是一样的,要对session的属性操作监听,则可以使用javax.servlet.http.HttpSessionAttributeListener接口完成,此接口的方法如下:
public void attributeAdded(HttpSessionBindingEvent se)
public void attributeRemoved(HttpSessionBindingEvent se)
public void attributeReplaced(HttpSessionBindingEvent se)
当进行属性操作时,将根据属性的操作触发HttpSessionAttributeListener接口中的方法,每个操作方法都将产生HttpSessionBindingEvent事件,此事件定义操作如下:
public HttpSession getSession()
public String getName()
public Object getValue()
对session的属性操作监听
配置web.xml
session属监听:HttpSessionBindingListener接口
在session监听中也可以对session的属性操作进行监听,这一点与监听上下文属性的道理是一样的,要对session的属性操作监听,则可以使用javax.servlet.http.HttpSessionAttributeListener接口完成:
public void attributeAdded(HttpSessionBindingEvent se)
public void attributeRemoved(HttpSessionBindingEvent se)
public void attributeReplaced(HttpSessionBindingEvent se)
当进行属性操作时,将根据属性的操作触发HttpSessionAttributeListener接口中的方法,每个操作方法都将产生HttpSessionBindingEvent事件
public HttpSession getSession()
public String getName()
public Object getValue()
对session的属性操作监听
配置web.xml
session属性监听:HttpSessionBindingListener接口
在WEB里也提供了一个javax.servlet.http.HttpSessionBindingListener接口,通过此接口实现的监听程序可以不用配置而直接使用,此接口定义的方法如下:
public void valueBound(HttpSessionBindingEvent event)
public void valueUnbound(HttpSessionBindingEvent event)
用户登陆状态监听
向session中增加LoginUser对象
对request监听
在Servlet 2.4之后增加了对request操作的监听,主要使用ServletRequestListener、ServletRequestAttributeListener两个接口。
请求状态监听:ServletRequestListener接口
当需要对用户的每次请求进行监听的时候,可以使用javax.servlet.ServletRequestListener接口,此接口定义方法如下:
public void requestInitialized(ServletRequestEvent sre)
public void requestDestroyed(ServletRequestEvent sre)
ServletRequestListener接口一旦监听到事件之后,将产生ServletRequestEvent的事件处理对象,此事件类定义的操作方法如下:
public ServletRequest getServletRequest()
public ServletContext getServletContext()
对用户请求request监听
配置web.xml
request属性监听:ServletRequestAttributeListener接口
对request范围属性的监听可以使用javax.servlet.ServletRequestAttributeListener接口,此接口定义的方法如下所示:
public void attributeAdded(ServletRequestAttributeEvent srae)
public void attributeReplaced(ServletRequestAttributeEvent srae)
public void attributeRemoved(ServletRequestAttributeEvent srae)
加入监听器之后request属性的操作都会产生ServletRequestAttributeEvent事件,此事件的定义的方法如下:
public String getName()
public Object getValue()
监听request属性操作
配置web.xml
监听器实例 —— 在线人员统计
在线人员列表是一个较为常见的功能,每当用户登陆成功之后,就会在列表中增加此用户名称,这样就可以知道当前在线的用户有那些了,这个功能在WEB中只能靠监听器实现。
使用接口
要完成在线用户列表的监听器,需要使用如下几个接口:
ServletContextListener接口:在上下文初始化时设置一个空的集合到application之中;
HttpSessionAttributeListener接口:用户增加session属性时,表示新用户登陆,从sesion中取出此用户的登陆名,之后将此用户保存在列表之中;
HttpSessionListener接口:当用户注销(手工注销、会话超时)将此用户列表中删除此用户。
小结
使用监听器可以对application、session、request的属性范围进行监听;
在WEB中可以配置每一个session的超时时间;
定义:监听器就是应用监听事件来监听请求中的行为而创建的一组类。
监听接口和事件类:
注入的方式注入监听类
@WebListener
public class MyHttpSessionListener implements HttpSessionListener{
……
}
方法:
在web.xml中配置
<listener>
<listener-class>
com.eshore. MyHttpSessionListener
</listener-class>
</listener>
@WebListener
public class MyHttpSessionListener implements HttpSessionListener{
private static int count;//统计数
public static int getCount() {
return count;
}
public void sessionCreated(HttpSessionEvent se) {
MyHttpSessionListener.count++;
}
public void sessionDestroyed(HttpSessionEvent se) {
MyHttpSessionListener.count--;
}
}
例子:
@WebListener
public class MyRequestListener implements ServletRequestListener,
ServletRequestAttributeListener {
private static Logger log = Logger.getLogger("MyRequestListener");
public void requestDestroyed(ServletRequestEvent arg0) {
log.debug("一个请求消亡");
}
public void requestInitialized(ServletRequestEvent arg0) {
log.debug("产生一个新的请求");
}
public void attributeAdded(ServletRequestAttributeEvent arg0) {
log.debug("加入一个request范围的属性,名称为:"+
arg0.getName()+",其值为:"+arg0.getValue());
}
public void attributeRemoved(ServletRequestAttributeEvent arg0) {
log.debug("移除一个request范围的属性,名称为:"+arg0.getName());
}
public void attributeReplaced(ServletRequestAttributeEvent arg0) {
log.debug("修改一个request范围的属性,名称为:"+
arg0.getName()+",修改前的值为:"+arg0.getValue());
}
}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>使用RequestListener监听器</title>
</head>
<body>
使用RequestListener监听器<br/>
<c:set value="zhangsan" var="username" scope="request"/>
姓名为:<c:out value="${requestScope.username}"/>
<c:remove var="username" scope="request"/>
</body>
</html>
运行结果: