Filter和Listener
过滤器 Filter
Servlet 标准中定义了过滤器,可以拦截任意的服务器请求和响应。
实现过滤器的步骤:
-
创建一个过滤器类实现javax.servlet.Filter接口
- 重写(实现)全部抽象方法
- 业务逻辑写到 doFilter中
- 如果在doFilter中调用了 chain.doFilter方法则处理后续逻辑,如果不执行这个方法,表示对后续逻辑的拦截。
-
在web.xml(部署描述文件)配置filter,将filter配置到请求之前。
-
可以配置多个filter-mapping,这样可以复用同一个Filter
-
可以使用 .png 或者 / 过滤一组url
-
当有多个过滤器过滤同一个资源时候,按照配置的先后执行。
<filter> <filter-name>demo</filter-name> <filter-class>web.DemoFilter</filter-class> </filter> <filter-mapping> <filter-name>demo</filter-name> <url-pattern>/img.png</url-pattern> </filter-mapping>
-
-
过滤器方法参数 ServletRequest 和 ServletResponse,是 HttpServletRequest 和 HttpServletResponse 的父类型,方法比较少! 如果需要使用HttpServletRequest 和 HttpServletResponse 的方法,需要进行强制类型转换!
-
比如需要使用 request.getSession() 方法:
HttpServletRequest req = (HttpServletRequest)request; HttpSession session = req.getSession();
-
-
利用 web.xml 可以向Filter 传递初始化参数。
<init-param> <param-name>start</param-name> <param-value>8</param-value> </init-param> <init-param> <param-name>end</param-name> <param-value>17</param-value> </init-param> config.getInitParamter("start"); config.getInitParamter("end");
-
Filter 对象的生命周期
- 在Web容器启动时候创建Filter对象,Filter对象是单例的(只创建一个Filter对象)!
- 创建以后,立即执行init()方法,只执行一次
- 在有url请求时候,会执行匹配的doFilter(),doFilter()是并发执行的。
- Filter对象在容器关闭时候销毁,销毁时候执行destroy()
基本过滤器步骤:
-
编写过滤器类:
/** * 过滤器 Hello World! */ public class DemoFilter implements Filter { public void init(FilterConfig cfg) throws ServletException { } public void destroy() { } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { req.setAttribute("test", "试试"); System.out.println("Hello World!"); //处理后续请求:如果执行doFilter就正常处理后续 //Web请求和响应,如果不执行doFilter就意味着 //不处理后续请求和响应(也就是请求被拦截了!) chain.doFilter(req, res); } }
-
配置web.xml:
<filter> <filter-name>demo</filter-name> <filter-class>web.DemoFilter</filter-class> </filter> <filter-mapping> <filter-name>demo</filter-name> <url-pattern>/img.png</url-pattern> </filter-mapping> <filter-mapping> <filter-name>demo</filter-name> <url-pattern>/test.html</url-pattern> </filter-mapping> <filter-mapping> <filter-name>demo</filter-name> <url-pattern>*.png</url-pattern> </filter-mapping>
多个过滤可以连接使用:
-
编写Servlet
/** * 演示过滤器执行顺序 */ public class TestFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String test = (String)request.getAttribute("test"); System.out.println("Test Filter:"+test); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { } }
-
配置web.xml:
<filter> <display-name>TestFilter</display-name> <filter-name>TestFilter</filter-name> <filter-class>web.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>*.png</url-pattern> </filter-mapping>
利用过滤器限制图片的访问:
-
编写过滤器
public class ImageFilter implements Filter { private int start, end; public void destroy() { System.out.println("我还会回来的!"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //获取当前的时间 Calendar cal = Calendar.getInstance(); //获取小时分量 int hour = cal.get(Calendar.HOUR_OF_DAY); //在start到下午end之前,可以看见图片 if(hour>start && hour<end) { chain.doFilter(request, response); }else { response.setContentType( "text/html; charset=UTF-8"); response.getWriter().println("系统繁忙!"); } } public void init(FilterConfig fConfig) throws ServletException { //读取web.xml文件中的配置参数 String s1=fConfig.getInitParameter("start"); String s2=fConfig.getInitParameter("end"); start = Integer.parseInt(s1); end = Integer.parseInt(s2); System.out.println(start+","+end); } }
-
配置 web.xml
<filter> <display-name>ImageFilter</display-name> <filter-name>ImageFilter</filter-name> <filter-class>web.ImageFilter</filter-class> <init-param> <param-name>start</param-name> <param-value>8</param-value> </init-param> <init-param> <param-name>end</param-name> <param-value>17</param-value> </init-param> </filter> <filter-mapping> <filter-name>ImageFilter</filter-name> <url-pattern>*.png</url-pattern> </filter-mapping>
***
在Web容器的工作时候,在出现特定情况下,会自动的执行用户定义的***程序。利用***程序,可以将用户 程序嵌入到Web容器中工作。
特定情况包括:
- 对象创建情况:
- request对象,response对象,session对象,ServletContext对象等。
- 对象的创建和销毁时候执行 事件代码。
- 在对象中添加、删除数据时候(setAttribute,removeAttribute)
- 其他的工作状态改变的时候。
如使用: HttpSessionListener
- 创建 类 实现HttpSessionListener
- 重写方法 sessionCreated()
- 重写方法 sessionDestroyed()
- 在web.xml 中配置
- 启动web容器
- 当web容器工作期间创建了session对象时候,会自动执行 sessionCreated()
- 当web容器工作期间销毁了session对象时候, 会自动执行sessionDestroyed()
案例:
/** * Listener演示案例 */ public class DemoListener implements HttpSessionListener { //在Session对象创建以后执行 public void sessionCreated(HttpSessionEvent e) { System.out.println("Hello Session Created"); //e 代表当前事件发生时候的相关数据。 HttpSession s = e.getSession(); System.out.println("SID:"+s.getId()); } //在Session对象销毁以后执行 public void sessionDestroyed(HttpSessionEvent e) { System.out.println("Hello Session Destroyed"); } } <listener> <listener-class>web.DemoListener</listener-class> </listener>
如上功能的意义:在session创建销毁时候插入用户自定义的代码。
最重要的Listener:ServletContextListener
- contextInitialized() 会在Web服务器启动时候执行。 在软件中需要初始化的程序写到这个方法中。
- contextDestoryed() 会在Web服务器关闭时候执行。如果需要在关闭时候清除的资源,可以写到这个方法中。
案例:
public class InitListener implements ServletContextListener { //在web服务器关闭时候执行 public void contextDestroyed(ServletContextEvent e) { System.out.println("Hello contextDestroyed"); } //在web服务器启动时候执行,用于初始化资源 public void contextInitialized(ServletContextEvent e) { System.out.println("Hello contextInitialized"); } } <listener> <listener-class>web.InitListener</listener-class> </listener>