Filter过滤器详解

Filter是什么

Java Web开发中的过滤器(filter)是从Servlet 2.3规范开始增加的功能,并在Servlet 2.4规范中得到增强。对Web应用来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器之间的请求与响应信息,并对这些信息进行过滤。当Web容器接受到一个对资源的请求时,它将判断是否有过滤器与这个资源相关联。如果有,那么容器将把请求交给过滤器进行处理。在过滤器中,你可以改变请求的内容,或者重新设置请求的报头信息,然后再将请求发送给目标资源。当目标资源对请求作出响应时候,容器同样会将响应先转发给过滤器,在过滤器中你可以对响应的内容进行转换,然后再将响应发送到客户端。

过滤器相关的接口主要有:Filter、FilterConfig和FilterChain。

过滤器 , 其实就是对客户端发出来的请求进行过滤。 浏览器发出, 然后服务器派servlet处理。 在中间就可以过滤, 其实过滤器起到的是拦截的作用。

Filter常见作用

  1. 对一些敏感词汇进行过滤
    2. 统一设置编码
    3. 自动登录
    4. 对用户的访问请求进行记录和审核、对用户发送的数据进行过滤或替换、转换图象格式、对响 应内容进行压缩以减少传输量、对请求或响应进行加解密处理、触发资源访问事件、对XML的输出应用XSLT等

如何使用Filter

  1. 定义一个类, 实现Filter
		public class FilterDemo implements Filter {

			public void destroy() {
			}
		
			public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
				System.out.println("来到过虑器了。。。");
				chain.doFilter(request, response);
			}
		
			public void init(FilterConfig fConfig) throws ServletException {
			}
		
		}
  1. 注册过滤器

在web.xml里面注册,注册的手法与servlet基本一样。

          <filter>
		      <display-name>FilterDemo</display-name>
		      <filter-name>FilterDemo</filter-name>
		      <filter-class>com.itheima.filter.FilterDemo</filter-class>
		  </filter>
		  
		  <filter-mapping>
		      <filter-name>FilterDemo</filter-name>
		      <url-pattern>/*</url-pattern>
		  </filter-mapping>

Filter的生命周期

  • 创建

在服务器启动的时候就创建。

  • 销毁

服务器停止的时候。

init(FilterConfig):在服务器启动时会创建Filter实例,并且每个类型的Filter只创建一个实例,从此不再创建!在创建完Filter实例后,会马上调用init()方法完成初始化工作,这个方法只会被执行一次;

doFilter(ServletRequest req,ServletResponse res,FilterChain chain):这个方法会在用户每次访问“目标资源(pattern>index.jsp)”时执行,如果需要“放行”,那么需要调用FilterChain的doFilter(ServletRequest,ServletResponse)方法,如果不调用FilterChain的doFilter()方法,那么目标资源将无法执行;

destroy():服务器会在创建Filter对象之后,把Filter放到缓存中一直使用,通常不会销毁它。一般会在服务器关闭时销毁Filter对象,在销毁Filter对象之前,服务器会调用Filter对象的destory()方法。

FilterConfig

Filter接口中的init()方法的参数类型为FilterConfig类型。它的功能与ServletConfig相似,与web.xml文件中的配置信息对应。下面是FilterConfig的功能介绍:

ServletContext getServletContext():获取ServletContext的方法;

String getFilterName():获取Filter的配置名称;与元素对应;

String getInitParameter(String name):获取Filter的初始化配置,与元素对应;

Enumeration getInitParameterNames():获取所有初始化参数的名称。
在这里插入图片描述

FilterChain

doFilter()方法的参数中有一个类型为FilterChain的参数,它只有一个方法:doFilter(ServletRequest,ServletResponse)
filterChain.doFilter(request, response); // 放行

Filter执行顺序

  1. 客户端发出请求,先经过过滤器, 如果过滤器放行,那么才能到servlet

  2. 如果有多个过滤器, 那么他们会按照注册的映射顺序 来 排队。 只要有一个过滤器, 不放行,那么后面排队的过滤器以及咱们的servlet都不会收到请求。

Filter细节:

  1. init方法的参数 FilterConfig , 可以用于获取filter在注册的名字 以及初始化参数。 其实这里的设计的初衷与ServletConfig是一样的。

  2. 如果想放行,那么在doFilter 方法里面操作,使用参数 chain

	chain.doFilter(request, response); 放行, 让请求到达下一个目标。
  1. < url-pattern > /* < /url-pattern > 写法格式与servlet一样。

    全路径匹配 以 / 开始

    /LoginServlet

  2. 以目录匹配 以 / 开始 以 * 结束

    /demo01/*

  3. 以后缀名匹配 以 * 开始 以后缀名结束

    *.jsp *.html *.do

  4. 针对 dispatcher 设置

     REQUEST : 只要是请求过来,都拦截,默认就是REQUEST 
     FORWARD : 只要是转发都拦截。 
     ERROR : 页面出错发生跳转 
     INCLUDE : 包含页面的时候就拦截。
    

Filter自动登录案例

  • 需求分析
    在这里插入图片描述
1. 搭建环境
  1. 搭建数据库

  2. 搭建页面

###登录servlet代码

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

		try {
			String userName = request.getParameter("username");
			String password = request.getParameter("password");
			String autoLogin = request.getParameter("auto_login");
			UserBean user = new UserBean();
			user.setUsername(userName);
			user.setPassword(password);
			
			UserDao dao = new UserDaoImpl();
			UserBean userBean = dao.login(user);
			
			if(userBean != null){
				//成功了,进入首页
				request.getSession().setAttribute("userBean", userBean);
				response.sendRedirect("index.jsp");
			}else{
				//不成功...
				request.getRequestDispatcher("login.jsp").forward(request, response);
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

##过滤器代码

过滤器的核心不是完成拦截不给 , 还是放行显示。 它的核心是在放行之前,帮用户完成登录的功能。

  • 实现思路
  1. 先判断session是否有效, 如果有效,就不用取cookie了,直接放行。

  2. 如果session失效了,那么就取 cookie。

    1. 没有cookie 放行

    2. 有cookie
      取出来cookie的值,然后完成登录
      把这个用户的值存储到session中
      放行。

   /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
    */
			public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException {
	
			try {
				HttpServletRequest request = (HttpServletRequest) req;
				
				//先判断,现在session中还有没有那个userBean.
				UserBean userBean = (UserBean) request.getSession().getAttribute("userBean");
				//还有,有效。
				if(userBean != null){
					chain.doFilter(request, response);
				}else{
					//代表session失效了。
					
					//2. 看cookie。
					
					//1. 来请求的时候,先从请求里面取出cookie , 但是cookie有很多的key-value
					Cookie[] cookies = request.getCookies();
					//2. 从一堆的cookie里面找出我们以前给浏览器发的那个cookie
					Cookie cookie = CookieUtil.findCookie(cookies, "auto_login");
					
					//第一次来
					if(cookie  == null){
						chain.doFilter(request, response);
					}else{
						
						//不是第一次。
						
						String value = cookie.getValue();
						String username = value.split("#")[0];
						String password = value.split("#")[1];
	
						//完成登录
						UserBean user = new UserBean();
						user.setUsername(username);
						user.setPassword(password);
	
						UserDao dao = new UserDaoImpl();
						userBean = dao.login(user);
						
						//使用session存这个值到域中,方便下一次未过期前还可以用。
						request.getSession().setAttribute("userBean", userBean);
						
						chain.doFilter(request, response);
					}
					
				}
				
				} catch (Exception e) {
					e.printStackTrace();
					chain.doFilter(req, response);
				}
				}

编码过滤器的例子

@WebFilter(urlPatterns = { "*" }, 
        initParams = {@WebInitParam(name="encoding", value="utf-8")})
public class CodingFilter implements Filter {
    private String defaultEncoding = "utf-8";

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        req.setCharacterEncoding(defaultEncoding);
        resp.setCharacterEncoding(defaultEncoding);
        chain.doFilter(req, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        String encoding = config.getInitParameter("encoding");
        if (encoding != null) {
            defaultEncoding = encoding;
        }
    }
}

下载计数过滤器的例子

@WebFilter(urlPatterns = {"/*"})
public class DownloadCounterFilter implements Filter {

    private ExecutorService executorService = Executors.newSingleThreadExecutor();
    private Properties downloadLog;
    private File logFile;

    @Override
    public void destroy() {
        executorService.shutdown();
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        final String uri = request.getRequestURI();
        executorService.execute(new Runnable() {

            @Override
            public void run() {
                String value = downloadLog.getProperty(uri);
                if(value == null) {
                    downloadLog.setProperty(uri, "1");
                }
                else {
                    int count = Integer.parseInt(value);
                    downloadLog.setProperty(uri, String.valueOf(++count));
                }
                try {
                    downloadLog.store(new FileWriter(logFile), "");
                } 
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        chain.doFilter(req, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        String appPath = config.getServletContext().getRealPath("/");
        logFile = new File(appPath, "downloadLog.txt");
        if(!logFile.exists()) {
            try {
                logFile.createNewFile();
            } 
            catch(IOException e) {
                e.printStackTrace();
            }
        }
        downloadLog = new Properties();
        try {
            downloadLog.load(new FileReader(logFile));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宜春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值