Servlet之过滤器(Filter)和监听器(Listener)

过滤器

过滤器是一个java组件,可以拦截发送至某个servlet,jsp页面或静态页面的请求,可以在响应发送到客户之前进行拦截

工作原理:

过滤器类必须实现 Filter 接口,包含的方法如下:

void destroy()	 //销毁方法

void init(FilterConfig filterConfig) throws ServletException  //初始化方法

//主要的工作方法 	
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
    //这里写request的相关代码
    chain.doFilter(request, resp);
    //这里写response的相关代码
}

FilterChain chain 过滤器链

FilterChain 接口用于调用过滤器链中的下一个过滤器或调用过滤器结束后的资源

过滤器链如图:

过滤器生命周期的各个阶段:

实例化:Web容器在不是web应用程序的时候对所有过滤器进行实例化

	web容器回调它的无参构造方法

初始化:实例化完成之后,马上进行初始化工作

	web容器回调init方法

过滤:请求路径匹配过滤器的URL映射

	web容器回调 doFilter方法  --> 主要工作方法 

销毁:web容器在卸载web应用之前

	web容器回调 destroy方法

过滤器的实际应用:

1.对请求消息体中的数据设置统一的编码

2.阻止非法用户的请求

3.过滤非法数据

注意:

过滤器使用时需要在web.xml中配置,需要在“url-pattern”标签中指明过滤的对象 如“/*”过滤项目中所有文件,代码如下:

<filter>
	<display-name>OurFilter</display-name>
	<filter-name>OurFilter</filter-name>
        <filter-class>nm.filter.OurFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>OurFilter</filter-name>
	<url-pattern>/show.do</url-pattern>
</filter-mapping>

过滤器的简单实例应用

  我们都知道当我们百度搜索关键词的时候,搜索出的关键词会变成着重飘红。

接下来的通过过滤器,来简单的模仿百度的这种功能:

  • 用户请求的页面
package nm.filter;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse;

public class OurServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
 
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");

		PrintWriter out = response.getWriter();
                //这里我们向页面输出4段带"我们"的句子
		out.println("我们去玩吧<br/>");
		out.println("你打不过我们<br/>");
		out.println("我们一起吃饭去<br/>");
		out.println("看我们的儿子<br/>");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
		doGet(request, response);
	}

}

  • 在这里我们写一个MyWriter类继承PrintWriter类 重写里面的write方法,将原来输出字符串的方法,改变成保存字符串的方法,另外再写一个获取字符串的方法,如下:
package nm.filter;

import java.io.PrintWriter;
import java.io.Writer;

public class MyWriter extends PrintWriter{
	private StringBuilder buffer;
	
	public MyWriter(Writer out) {
		super(out);
		buffer = new StringBuilder();
	}
	
	@Override
	public void write(String s) {
		buffer.append(s);
	}
	
	// 将write流中的内容全部转换为String
	public String getContent(){
		return buffer.toString();
	}

	
	

}

  • 这里我们写一个MyResponse类继承HttpServletResponseWrapper类(HttpServletResponse接口的实现类),来获取我们上面所写的MyWriter类:
package nm.filter;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;



public class MyResponse extends HttpServletResponseWrapper{
	private MyWriter myWriter;

	
	public MyResponse(HttpServletResponse response) {
		super(response);

	}
	
	@Override
	public MyWriter getWriter() throws IOException {
		myWriter = new MyWriter(super.getWriter());
		
		return myWriter;
	}
	
	public MyWriter getMyWriter(){
		return myWriter;
	}

	
}

  • 完成上面两个类之后,我们来写过滤器。通过过滤器我们将用户访问的页面拦截,将原本输出的信息用我们所写的类和方法代替,将里面的关键词“我们”进行修改,之后再利用原始的类和方法将信息输出:
package nm.filter;

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.HttpServletResponse;

public class OurFilter implements Filter {

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		MyResponse resp = new MyResponse((HttpServletResponse)response);
		chain.doFilter(request, resp);
		
		MyWriter writer = resp.getMyWriter();
		if(writer!=null){
			String  content = writer.getContent();
			String new_content = content.replace("我们","<span style='color:red'>我们</span>");

			response.getWriter().write(new_content);
		}
		
		
	}

	public void init(FilterConfig fConfig) throws ServletException {
		
	}

}

最终的结果如图:


监听器

Listener 用于监听java web程序中的事件,比如 创建,修改,删除 Session,request,context等 ,并触发响应的事件

观察者模式:事件发生的时候会自动触发该事件对应 的Listener

Listener 主要对于 Session,request,context 进行监控

具体如下:

不同功能Listener需要实现的不同的Listener接口
一个Listener也可以实现多个接口,这样可以多种功能的监听器一起工作

8种监听器 分为三类

  1.监听Session,request,context的创建 和 销毁

       	HttpSessionListener  :监听Session的创建和销毁 

	        创建Session的时候执行 sessionCreate 方法 

	        当session的执行invalidate方法的时候,触发SessionDestroyed 方法


        ServletRequestListener  : 监听Request的创建和销毁

	        每次用户请求request都会执行requestInitialized方法

	        request处理完毕之后销毁之前执行 requestDestroyed 

	        注意:如果一个HTML页面中有多个图片,则每请求一次HTML页面可能会触发request事件


        ServletContextListener :监听Context的创建和销毁

	        服务器启动的时候 执行 contextInitialized 方法

	        服务器关闭或项目卸载 执行 contextDestroyed 方法

  2.监听对象属性编号 分别:

        Session属性变化	HttpSessionAttributeListener   

        Context属性变化	        ServletContextAttributeListener

        Request属性变化        ServletRequestAttributeListener

	        XXXXAdded();

	        XXXXReplaced();

	        XXXXRemoved() ;

	        说明:XXXX表示 Session context request

  3.监听Session内的对象

    	HttpSessionBindingListener

	        当对象被放到Session里执行  valueBound 方法

	        当对象从Session中移除执行  valueUnbound 方法

        HttpSessionActivationListener

	        服务器关闭的时候,会将Sessioin里的内容保存到硬盘上,这个过程叫 钝化

	        服务器重新启动的时候,会将session内容从硬盘中重新加载。

	        当Session中的对象被钝化的时候 sessionWillPassivate

	        当session中的对象被重新加载 执行sessionDidActivate

	        常用于session内的对象对session监听

         注意: 是Session内的对象,而不是Session本身,不需要web.xml配置

实现web.xml 的Listener 配置

 1. <listener> 标签 和 <listener-class>
 2. <listener> 一般配置在 <servlet> 标签的前面


  具体代码如下:

<listener>
	<listener-class>nm.listener.TestListener</listener-class>
</listener>

监听器简单的应用实例

  接下来,我们通过监听器来实现一个简单的统计用户在线人数的简单实例,具体代码如下:

  • 用户登录界面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户登录界面</title>
</head>
<body>
	<h1>用户登录界面</h1>
	<form action="login.do" method="post">
		用户名:<input type="text" name="uname" /><br/><br/><br/>
		密 码:<input type="password" name="upwd" /><br/><br/><br/>
		<input type="submit" value="提交"/>
		<input type="reset" value="重置"/>
		
	</form>
</body>
</html>
  • 用户登录的简单处理程序,用户名为admin密码为123456
package servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
  
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		String uname = request.getParameter("uname");
		String upwd = request.getParameter("upwd");
		HttpSession session = request.getSession();
            //登陆成功后向页面输出当前在线人数 
		if(uname.equals("admin") && upwd.equals("123456")) {		
			response.getWriter().println("登陆成功~<br/>");
			response.getWriter().println("当前在线人数 :"+(Integer)session.getServletContext().getAttribute("uerNumber")+"<br/>");
			response.getWriter().println("<a href='DistoryServlet'>点击退出</a>");
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

  • 用户点击退出后的处理程序,这里的处理是删除会话session并重定向到登陆界面
package servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DistoryServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
   
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //清除session并重定向到登陆界面
		request.getSession().invalidate();
		response.sendRedirect("login.html");
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

  • 监听器处理程序,用一个变量来统计在线人数,每建立一个会话我们就让变量增加1,每销毁一个会话我们就让变量减少1
package listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class LoginListener implements HttpSessionListener {
	
	int uerNumber = 0; //用来统计在线人数的变量
	
    public void sessionCreated(HttpSessionEvent arg0)  { 
    	uerNumber++;
        //将变量设为应用上下文的属性,便于在整个项目都可以访问到在线人数
    	arg0.getSession().getServletContext().setAttribute("uerNumber", uerNumber);
    	System.out.println("当前在线用户:"+uerNumber);
    }

    public void sessionDestroyed(HttpSessionEvent arg0)  { 
    	uerNumber--;
          //将变量设为应用上下文的属性,便于在整个项目都可以访问到在线人数
    	arg0.getSession().getServletContext().setAttribute("uerNumber", uerNumber);
    	System.out.println("当前在线用户:"+uerNumber);
    }
	
}

结果如图:


以上就是Servlet中的

过滤器(Filter)和监听器(Listener)

原文地址:https://www.cnblogs.com/nm666/p/7986243.html