过滤器和监听器

过滤器

介绍

​ Filter 即为过滤,用于在 Servlet 之外对 Request 或者 Response 进行修改。它主要用于对用户请求进行预处理,也可以对 HttpServletResponse 进行后处理。使用 Filter的完整流程: Filter 对用户请求进行预处理,接着将请求交给 Servlet 进行处理并生成响应,最后 Filter 再 对服务器响应进行后处理。在一个 web 应用中,可以开发编写多个Filter,这些 Filter 组合 起来称之为一个 Filter 链。

实现

  1. 新建普通Java类

  2. 实现javax.servlet.Filter接口

  3. 实现对应的方法

  4. 配置web.xml

    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;
    
    /**
     * 实现过滤器
     * 	1、新建普通Java类
     * 	2、实现javax.servlet.Filter接口
     * 	3、实现对应的方法
     * 	4、配置web.xml
     */
    public class Filter01 implements Filter {
    
    	/**
    	 * 初始化
    	 */
    	@Override
    	public void init(FilterConfig filterConfig) throws ServletException {
    		System.out.println("Filter01 init...");		
    	}
    
    	/**
    	 * 过滤/拦截
    	 */
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		System.out.println("Filter01 filter...");		
    		// 拦截请求		
    		// 放行资源
    		chain.doFilter(request, response);		
    		// 过滤响应数据
    		System.out.println("Filter01 过滤响应...");
    	}
    
    	@Override
    	public void destroy() {
    		System.out.println("Filter01 destroy...");		
    	}
    }
    
    <filter>
        <filter-name>Filter01</filter-name>
        <filter-class>com.demo.filter.Filter01</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter01</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

执行顺序

  • 通过观察 web.xml 中的配置和各个 filter 的执行顺序,找出 filter 执行先后的依据。
  • 根据之前观察 Servlet 生命周期的的方式,观察一下过滤器的生命周期。

过滤器实例

用户非法登录拦截

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

/**
 * 非法访问拦截
 * 	拦截的资源:
 * 		拦截所有资源    /* 
 * 
 *  得到访问的路径:
 *  	request.getRequestURI(); 返回的是部分资源路径,从端口后面,到"?"前面
 * 
 * 	放行的资源:(无需登录即可访问的资源)
 * 		1、放行指定页面 (无需登录即可访问的页面;例如:登录页面login.html、注册页面register.html等)
 * 		2、放行静态资源 (无需登录即可访问的资源,放置在statics目录下的资源;例如:css、js、images、前端插件等)
 * 		3、放行执行操作  (无需登录即可执行的操作;例如:登录操作、注册操作等)
 * 		4、判断是否是登录状态  (session作用域中的数据不为空)
 */
public class LoginAccessFilter implements Filter {
    
    public LoginAccessFilter() { }
	
	/**
	 * 处理拦截
	 */
	public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
		
		// 基于HTPP
		HttpServletRequest request= (HttpServletRequest) arg0;
		HttpServletResponse response= (HttpServletResponse) arg1;
		
		// 获取请求的路径
		String path = request.getRequestURI();
		
		// 1、放行指定页面 (无需登录即可访问的页面;例如:登录页面login.html、注册页面register.html等)
		if (path.contains("/login.html")) {
			chain.doFilter(request, response);
			return;
		}
		
		// 2、放行静态资源(无需登录即可访问的资源,放置在statics目录下的资源;例如:css、js、images、前端插件等)
		if (path.contains("/statics")) {
			chain.doFilter(request, response);
			return;
		}
		
		// 3、放行执行操作(无需登录即可执行的操作;例如:登录操作、注册操作等)
		if (path.contains("/loginServlet")) {
			chain.doFilter(request, response);
			return;
		}
		
		// 4、判断是否是登录状态(session作用域中的数据不为空)
		// 获取session作用域中的值
		String uname = (String) request.getSession().getAttribute("user");		
		if (uname != null && !"".equals(uname)) {
			chain.doFilter(request, response);
			return;
		}
		
		// 拦截跳转到登录页面
		response.sendRedirect("login.html");
	}
	
	public void init(FilterConfig fConfig) throws ServletException { }
    
    public void destroy() { }

}

请求乱码处理

  • 出现乱码的情况

    Tomcat版本请求方式是否乱码解决方法
    Tomcat8及以上版本POST乱码request.setCharacterEncoding(“UTF-8”);
    Tomcat8及以上版本GET不乱码——
    Tomcat7及以下版本POST乱码request.setCharacterEncoding(“UTF-8”);
    Tomcat7及以下版本GET乱码解决方法new String(request.getParameter(“参数名”).getBytes(“ISO-8859-1”),“UTF-8”);
  • 解决方案:

    • POST请求:
      • 无论Tomcat7及以下版本还是Tomcat8及以上版本都会乱码
      • request.setCharacterEncoding(“UTF-8”);(只针对于POST请求,GET请求不受影响)
    • GET请求:(如果字符串本身不乱码,处理之后反而会乱码)
      • 判断Tomcat的版本是否在7或以下
      • 判断请求方式是否为GET请求
      • 处理乱码:
        • 乱码原因:request.getParameter(“参数名”)
        • 具体解决方案:重写getParameter()方法(需要继承包装类HttpServletRequestWapper)
          1. 定义内部类
          2. 继承包装类HttpServletRequestWapper
          3. 需要实现带参构造
          4. 重写getParameter()方法,处理乱码问题
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

/**
 * 请求乱码处理
 */
public class AEncodingFilter implements Filter {

	public AEncodingFilter() { }

	public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {

		// 基于HTPP
		HttpServletRequest request = (HttpServletRequest) arg0;
		HttpServletResponse response = (HttpServletResponse) arg1;

		/**
		 * POST请求乱码
		 * 		无论Tomcat7及以下版本还是Tomcat8及以上版本都会乱码
		 * 		只针对于POSTQ请求无效,GET请求不受影响
		 */
		request.setCharacterEncoding("UTF-8");

		/**
		 * GET请求乱码问题 (如果字符串本身不乱码,处理之后反而会乱码) 
		 * 		1、请求方式为GET请求
		 * 		2、Tomcat的版本在7或者7以下
		 * 		3、处理乱码 乱码原因: request.getParameter("参数名") 
		 * 	具体解决方案: 重写getParameter()方法
		 * 		(重写Parameter()方法需要继承包装类HttpServletRequestWapper) 
		 * 		1、定义内部类
		 * 		2、继承包装类HttpServletRequestWapper 
		 * 		3、需要实现带参构造
		 * 		4、重写getParameter()方法,处理乱码问题
		 */
		// 获取请求类型 (GET/POST)
		String method = request.getMethod();
		// 判断是否是GET请求
		if ("GET".equalsIgnoreCase(method)) {
			// 得到服务器的版本信息
			String serverInfo = request.getServletContext().getServerInfo();
			// 得到具体的版本号
			String version = serverInfo.substring(serverInfo.indexOf("/") + 1, serverInfo.indexOf("."));
			// 判断是否是Tomcat7及以下版本
			if (Integer.parseInt(version) < 8) {
				// 处理乱码
				HttpServletRequest myRequest = new MyWapper(request);

				chain.doFilter(myRequest, response);
				return;
			}
		}
		chain.doFilter(request, response);
	}

	/**
	 * 重写getParameter()方法 (需要继承包装类HttpServletRequestWapper)
	 * 		1、定义内部类 
	 * 		2、继承包装类HttpServletRequestWapper
	 * 		3、需要实现带参构造
	 * 		4、重写getParameter()方法,处理乱码问题
	 */
	class MyWapper extends HttpServletRequestWrapper {

		// 定义全局变量,提升作用域
		HttpServletRequest request;

		public MyWapper(HttpServletRequest request) {
			super(request);
			// 将构造器中的request对象赋值给成员变量,给重写的getParameter()方法使用
			this.request = request;
		}

		@Override
		public String getParameter(String name) {
			// 获取请求的参数值
			String value = request.getParameter(name);
			try {
				if (value != null && !"".equals(value)) {
					value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			return value;
		}
	}

	public void init(FilterConfig fConfig) throws ServletException { }

	public void destroy() { }
}

监听器

介绍

​ web 监听器 Listener 是一种 Servlet 中的特殊的类,它们能帮助开发者监听 web 中的特定事件, 比如 ServletContext,HttpSession,ServletRequest 的创建和销毁;变量的创建、销毁和修改等。 可以在某些动作前后增加处理,实现监控,例如可以用来统计在线人数等。

实现

  • 监听器有三类 8 种:

    1. 监听生命周期:
      • ServletRequestListener
      • HttpSessionListener
      • ServletContextListener
    2. 监听值的变化:
      • ServletRequestAttributeListener
      • HttpSessionAttributeListener
      • ServletContextAttributeListener
    3. 针对 session 中的对象:
      • 监听 session 中的 java 对象(javaBean) 是 javaBean 直接实现监听器的接口。
  • 实现步骤:

    1. 创建普通的Java类
    2. 实现监听的接口
    3. 实现监听的方法
    4. 配置web.xml
    import javax.servlet.http.HttpSessionAttributeListener;
    import javax.servlet.http.HttpSessionBindingEvent;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    /**
     * 监听器的实现
     * 	1、创建普通的Java类
     * 	2、实现监听的监听
     * 	3、实现监听的方法
     * 	4、配置web.xml
     */
    public class Listener01 implements HttpSessionAttributeListener,HttpSessionListener {	
    	/**
    	 * Session的创建
    	 */
    	@Override
    	public void sessionCreated(HttpSessionEvent se) {
    		System.out.println("Session的创建...");		
    	}
    
    	/**
    	 * session的销毁
    	 */
    	@Override
    	public void sessionDestroyed(HttpSessionEvent se) {
    		System.out.println("Session的销毁...");		
    	}
    	
    	/**
    	 * 创建session域对象
    	 */
    	@Override
    	public void attributeAdded(HttpSessionBindingEvent se) {
    		System.out.println("Session域对象的创建...");		
    	}
    
    	/**
    	 * 删除session域对象
    	 */
    	@Override
    	public void attributeRemoved(HttpSessionBindingEvent se) {
    		System.out.println("Session域对象的删除...");		
    	}
    
    	/**
    	 * 修改Session域对象
    	 */
    	@Override
    	public void attributeReplaced(HttpSessionBindingEvent se) {
    		System.out.println("Session域对象的修改...");		
    	}
    
    }
    
     <listener>
         <listener-class>com.demo.listener.Listener01</listener-class>
    </listener>
    

监听器实例

  • 统计在线人数

    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    /**
     * 监听在线人数
     * 	当有用户访问时,创建session对象,在线人数加1
     * 	当有用户退出时,销毁session对象,在线人数减1
     *
     */
    public class OnloineListener implements HttpSessionListener {
    
    	// 默认在线人数
    	private Integer onlineNumber = 0;
        
        public OnloineListener() { }
    
    	/**
         * 当有用户访问时,创建session对象,在线人数加1
         */
        public void sessionCreated(HttpSessionEvent se)  { 
             // 在线人数加1
        	onlineNumber++;
        	// 将在线人数存到sessio作用域中
        	// se.getSession().setAttribute("onlineNumber", onlineNumber);
        	// 由于每个用户的session对象都是独立的,所有每个用户只能看到本来的在线人数,不能看到更新后的在线人数,所以需要扩大域范围
        	se.getSession().getServletContext().setAttribute("onlineNumber", onlineNumber);
        }
    
    	/**
         * 当有用户退出时,销毁session对象,在线人数减1
         */
        public void sessionDestroyed(HttpSessionEvent se)  { 
             // 在线人数减1
        	onlineNumber--;
        	// 将在线人数存到sessio作用域中
        	// se.getSession().setAttribute("onlineNumber", onlineNumber);
        	se.getSession().getServletContext().setAttribute("onlineNumber", onlineNumber);
        }	
    }
    
    <listener>
        <listener-class>com.demo.listener.OnloineListener</listener-class>
    </listener>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值