• 过滤器Filter


    Filter过滤器

    1.过滤器是什么?

    过滤器: 可以把"不和谐"的东西给过滤掉/筛选掉/排除掉.

    生活中的过滤器:带有过滤功能的净水器,滤纸,香烟的过滤嘴,测试,丈母娘.
    程序中的过滤器:双向过滤器

    在Java中最小的程序单元是类,程序中的过滤器就是一个特殊的类.
    Servlet/Filter是Web的一个组件.

    2.过滤器的作用

    我们可以简单理解为:过滤器处于客户端和服务端之间

    过滤器可以对所有的请求或响应做拦截操作

    1. 以常规的方式调用资源(Servlet/JSP);

    2. 利用修改过的请求信息调用资源;

      (可以将请求过来的数据修改后 再取调用资源)

    3. 调用资源之后,但在响应到客户端之前,对响应做出修改;

      (可以将返回的响应修改后,交给客户端)

    4. 阻止当前资源调用,代之转到其他资源.

    3.过滤器的应用

    首先说明一下开发中常用的思想

    1. DRY原则

    Don't Repeat Yourself 开发中拒绝代码重复(重复会带来巨大的维护成本)

    2. 责任分离原则

    各自做各自最擅长的事情

    过滤器在开发中的运用:

    • 可以对请求中的字符做编码.

      有时候我们会给Servlet设置编码格式

      例如:request.setCharacterEncoding("UTF-8"); 但是要是很多Servlet都设置 造成了代码重复 所以我们可以在Filter中设置编码格式

    • 登陆验证过滤器.

      登陆验证操作 同样也是为了避免代码重复

      将登陆验证操作写在Filter中 后面请求Servlet资源就不需要验证了

    • 敏感字(非法文字)过滤.

      有时候请求来的数据中会带有一些敏感词汇

      经过Filter时 ,会将这些敏感词汇代替或者转义

    • 做MVC框架中的前端控制器.(处理所有请求共同的操作,再分发)

    4.过滤器的开发和使用

    因为Servlet和Filter都是Web的组件,这里可以使用 我们可以进行对比记忆。

    Servlet开发

    1:自定义一个类(XxxServlet),实现于javax.servlet.Servlet接口.
    2:实现Servlet接口中的方法(init(初始化方法),service(处理请求)).
    3:告诉Tomcat来帮我们管理该Servlet程序(1:使用web.xml 做配置,2:WebServlet("/资源名")).

    <servlet>
           <servlet-name>Servlet的别名</servlet-name>
           <servlet-class>自定义Servlet的全限定名</servlet-class>
      </servlet>
      <servlet-mapping>
           <servlet-name>Servlet的别名</servlet-name>
           <url-pattern>/资源名称</utl-pattern>
      </servlet-mapping>
    

    注意:此时的url-pattern的文本内容是外界访问是Servlet的资源名称.

    Filter开发

    1:自定义一个类(XxxFilter),实现于javax.servlet.Filter接口.
    2:实现Filter接口中的方法(init(初始化方法),doFilter(执行过滤操作)).

    在启动Tomcat的时候,就创建好对象,并调用init方法做初始化操作.

    3:告诉Tomcat来帮我们管理该Filter程序(1:使用web.xml做配置,2:WebFilter("/资源名")).

      <filter>
           <filter-name>Filter的别名</filter-name>
           <filter-class>自定义Filter的全限定名</filter-class>
      </filter>
      <filtert-mapping>
           <filter-name>Filter的别名</filter-name>
           <url-pattern>/资源名称</utl-pattern>
      </filter-mapping>
    

    注意:此时的url-pattern的文本内容是Filter对哪一些资源做过滤操作.
    如: /hello.jsp :说明当前Filter只会对/hello.jsp做拦截/过滤.
    /employee :说明当前Filter只会对/employee资源(Servlet)做过滤.
    /system/* :说明当前Filter只会对以/system/作为前缀的资源路径做拦截.

    FilterChain(过滤器链)

    ​ FilterChain(过滤器链):多个过滤器按照一定的顺序,排列起来.抽象的可以看为 多个过滤器组成一条链

    程序中,存在多个过滤器的时候,过滤器的先后执行顺序由谁来决定

    由在web.xml中:配置的的先后顺序来决定.

    过滤器的映射细节

    1:Filter中的url-pattern的文本内容是Filter对哪一些资源做过滤操作.
    如: /hello.jsp :说明当前Filter只会对/hello.jsp做拦截/过滤.
    /employee :说明当前Filter只会对/employee资源做过滤.
    /system/* :说明当前Filter只会对以/system/作为前缀的资源路径做拦截.
    /* :说明对所有的资源做过滤.
    注:url-pattern 可以有多个 可对很多资源同时做拦截操作

    2:Filter的dispatcher(表示对哪些动作做过滤).

    拦截器默认为只对请求做拦截

    5.请求编码过滤器

    CharacterEncodingFilter:

    请求编码过滤器就是在过滤器中设置请求的数据的编码格式

    这样就不需要在后面的Servlet中设置这一行代码了

    req.setCharacterEncoding("UTF-8");
    

    但是我们一般在源码中不能明文写自己设置的编码 存在硬编码问题

    应该将编码格式设置在初始化参数中,从初始化参数获取

    可以在web.xml中配置filter时 设置初始化参数 这样利于维护 只需要该配置文件即可

    <!-- 配置初始化参数 自定义编码 -->
      	<init-param>
      		<param-name>encoding</param-name>
      		<param-value>UTF-8</param-value>
      	</init-param>
    

    将encoding设置为成员变量 之后可以在请求编码过滤器Filter的init方法中取出这个encoding

    private String encoding;
    	@Override
    	public void init(FilterConfig config) throws ServletException {
    		// 编码要从配置web.xml中获取  不能用明文显示
    		this.encoding = config.getInitParameter("encoding");
    	}
    

    得到设置的编码格式之后,我们在doFilter中开始设置

    @Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		// 类型转换  转为http类型
    		HttpServletRequest req = (HttpServletRequest) request;
    		HttpServletResponse resp = (HttpServletResponse) response;
            // 应用中没有设置编码(req.getCharacterEncoding() == null 的情况)
            // 并且我自己设置了编码 则设置。  若为false,就使用默认编码(ISO8859-1)
    		if (hasLength(encoding) && req.getCharacterEncoding() == null) {
    			req.setCharacterEncoding(encoding);
    		}
    		
    		//放行
    		chain.doFilter(req, resp);
    	}
    

    上述问题是第一种情况:应用中没有设置编码并且我自己设置了编码 则设置

    但是我们还要考虑一种情况,就是之前已经有人设置了编码,我又定义了编码,此时是否使用我定义的编码

    这里要引出一个 是否强制编码的问题 (是否使用我的编码)

    是否强制编码问题

    这里我们还是可以在web.xml中filter中设置一个参数 表示是否强制编码 默认为false

    <!-- 设置是否强制编码  -->
      	<init-param>
      		<param-name>force</param-name>
      		<param-value>false</param-value>
      	</init-param>
    

    跟上述方法一样 将其设置为成员变量 从init方法中获取

    // 是否强制编码
    	private Boolean forceEncoding  = false;
    
    	@Override
    	public void init(FilterConfig config) throws ServletException {
    		// 编码要从配置web.xml中获取  不能用明文显示
    		this.encoding = config.getInitParameter("encoding");
    		forceEncoding = Boolean.valueOf(config.getInitParameter("force"));
    	}
    

    考虑这种情况时,设置编码的判断就要再加一项 判断是否要硬编码 这样就解决了编码问题

    @Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    			throws IOException, ServletException {
    		// 类型转换  转为http类型
    		HttpServletRequest req = (HttpServletRequest) request;
    		HttpServletResponse resp = (HttpServletResponse) response;
    		
    		// 设置编码
    		// 1.应用中没有设置编码(req.getCharacterEncoding() == null 的情况)并且我自己设置了编码
    		// 2.应用中已经存在编码但是要使用自定义的编码  : 强制使用
    		if (hasLength(encoding) && req.getCharacterEncoding() == null || forceEncoding) {
    			req.setCharacterEncoding(encoding);
    		}
    		
    		//放行
    		chain.doFilter(req, resp);
    	}
    

    6.登录验证过滤器

    CheckLoginFilter

    首先我们要明确 登录验证过滤器 是要过滤那些需要验证身份的页面

    而登录页面和接收登录请求的Servlet是不需要被过滤的

    所以,如果我们将CheckLoginFilter的url-pattern设置为 /* 则要将这两项去除过滤

    <filter>
     	<filter-name>CheckLoginFilter</filter-name>
     	<filter-class>com.yhnit._03_checklogin.CheckLoginFilter</filter-class>
     </filter>
     <filter-mapping>
     	<filter-name>CheckLoginFilter</filter-name>
     	<url-pattern>/*</url-pattern>
     </filter-mapping>
    

    我们可以将不需要过滤的资源定义在一个数组中,但是这里还是不严谨,不应该明文显示,应该从初始化参数中取出 但是这个过滤器用的不多,更多的是拦截器,所以我这里从简了

    // 定义不需要被过滤的资源
    // 其实这里不应该使用明文设置  应该从配置文件web.xml中获取初始化参数  后面要学拦截器
    	private String[]  UncheckUris = {"/login.jsp","/login"};
    

    doFilter方法 判断当前过滤资源是否是 不需要过滤的资源,如果是,则放行。 不是,则要身份判断。

    @Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		HttpServletRequest req = (HttpServletRequest) request;
    		HttpServletResponse resp = (HttpServletResponse) response;
    		
    		// 表示当前过滤的资源
    		String uri = req.getRequestURI();
    		System.out.println("当前被过滤的资源" + uri);
    		// 登陆页面和登陆Servlet不需要过滤
    		if (!Arrays.asList(UncheckUris).contains(uri)) {
    			Object user = req.getSession().getAttribute("USER_IN_SESSION");
    			if (user == null) {
    				resp.sendRedirect("/login.jsp");
    				return;
    			}
    		}
            // 已经登录 放行
    		chain.doFilter(req, resp);
    	}
    

    7.敏感字过滤器

    敏感字过滤器 主要是客户端(浏览器)填写表单数据等信息时,存在敏感字,提交数据时,过滤器可以先将敏感字进行处理,比如转义或者变为*符号,然后Servlet获取的参数就是过滤器处理后的数据值

    设计思想:

    这里最主要的是 重写getParameter 这个方法 让Servlet处理请求时,用这个重写的方法,
    因为重写的方法中有过滤功能

    定义一个包装类MessageRequestWapper 里面重写getParameter 这个方法 方法里有过滤功能

    在doFilter方法中将 请求req 包装为请求Servlet的请求

    HttpServletRequest requestWapper = new MessageRequestWapper(req); 
    

    当请求Servlet时,Servlet中的req参数其实就是现在的包装后的请求requestWapper

    然后调用包装类重写的getParameter 方法 即可完成过滤功能。
    过滤功能实现(将敏感字写在stopwords集合中):

  • 相关阅读:
    506. 相对排名 Relative Ranks
    500. 单词是否在键盘上的同一行 Keyboard Row
    openstack live migration性能分析
    libvirt/qemu特性之numa
    nova Scheduling 配置
    Specify compute hosts with SSDs
    nova conductor
    osprofiler
    watcher
    stacktach和ceilometer
  • 原文地址:https://www.cnblogs.com/yhnCoder/p/13202516.html
Copyright © 2020-2023  润新知