过滤器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集合中):

posted @ 2020-06-28 13:51  YhnCoder  阅读(204)  评论(0编辑  收藏  举报