学习Java的日子 Day62 Filter过滤器

Day62 Filter过滤器

简介

Filter:过滤器,通过Filter可以拦截访问web资源的请求与响应操作。

Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器。他可以拦截Jsp、Servlet、 静态图片文件、静态 html文件等,从而实现一些特殊的功能。

例如:实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

服务器发送请求,通过层层过滤器,才能访问资源

创建步骤
  1. 创建过滤器类并实现Filter接口
  2. 在web.xml文件中配置Filter

javax.servlet.Filter接口中的方法介绍:

方法 描述
init(FilterConfig fConfig) 初始化方法
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 过滤方法
destroy() 销毁方法

1.初始Filter过滤器

创建过滤器的步骤:

1.创建Java类,实现Filter接口(javax.servlet.Filter)

2.在web.xml中配置

操作

Welcome.html

导包servlet-api.jar,在web.xml中配置首页

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎页面</h1>
    
<a href="ser01">向Servlet01发送一个请求</a>
    
</body>
</html>

Filter01

java 复制代码
package com.qf.filter;

public class Filter01 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("Filter01 -- doFilter() -- 前");
        //chain过滤器链
        //注意:如果拦截后不调用doFilter(),请求将无法传到下一个过滤器或服务器里
        //放行
        filterChain.doFilter(servletRequest,servletResponse);

        System.out.println("Filter01 -- doFilter() -- 后");
    }

    @Override
    public void destroy() {

    }
}

Servlet01

java 复制代码
package com.qf.servlet;

@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("Servlet01收到了一个请求");
    }
}

在web.xml配置文件中配置过滤器信息

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <welcome-file-list>
        <welcome-file>Welcome.html</welcome-file>
    </welcome-file-list>

    <filter>
        <filter-name>Filter01</filter-name>
        <filter-class>com.qf.filter.Filter01</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter01</filter-name>
        <url-pattern>/*</url-pattern><!-- 拦截所有请求 -->
    </filter-mapping>
    
</web-app>

2.过滤器链

客户端对服务器请求之后,服务器在调用Servlet之前,会执行一组过滤器(多个过滤器),那么这组过滤器就称为一条过滤器链。

过滤器链是指在一个Web应用,可以配置多个过滤器,这多个过滤器称为过滤器链。

3.Filter的生命周期

3.1生命周期 - 单个过滤器

单个过滤器的生命周期:

​ 创建:项目启动时 -- 无参构造、init()

​ 销毁:服务器正常关闭时 -- destroy()

java 复制代码
package com.qf.filter;

public class Filter01 implements Filter {

    public Filter01(){
        System.out.println("Filter01 -- Filter01()");
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        String code = filterConfig.getInitParameter("code");
        System.out.println("Filter01 -- init() -- " + code);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("Filter01 -- doFilter() -- 前");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);

        System.out.println("Filter01 -- doFilter() -- 后");
    }

    @Override
    public void destroy() {
        System.out.println("Filter01 -- destroy()");
    }
}

在web.xml配置文件中配置初始化参数信息 code-UTF-8

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <welcome-file-list>
        <welcome-file>Welcome.html</welcome-file>
    </welcome-file-list>

    <filter>
        <filter-name>Filter01</filter-name>
        <filter-class>com.qf.filter.Filter01</filter-class>
        <init-param>
            <param-name>code</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>Filter01</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

运行结果:

3.2 生命周期 - 多个过滤器

Filter的生命周期:

​ 创建:项目启动时 -- 无参构造、init()

​ 销毁:服务器正常关闭时 -- destroy()
Filter的创建顺序 -- 不用关注:

​ 多线程抢资源(创建顺序无序)
Filter的调用顺序 -- 关注:

​ web.xml配置 ------> 按照配置顺序

​ @WebFilter配置 --> 按照类名的字典排序

经验:一般使用web.xml配置

是单例模式

java 复制代码
//----------- Filter01 -----------------------
public class Filter01 implements Filter {
    public Filter01() {
    	System.out.println("Filter01 - Filter01()");
    }
    public void init(FilterConfig fConfig) throws ServletException {
    	System.out.println("Filter01 - init()");
	}
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    	System.out.println("Filter01执行前");
    	chain.doFilter(request, response);//放行
    	System.out.println("Filter01执行后");
	}
    
	public void destroy() { 
		System.out.println("Filter01 - destroy()");
	}
}

//----------- Filter02 -----------------------
public class Filter02 implements Filter {

	public Filter02() {
		System.out.println("Filter02 - Filter02()");
	}

	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("Filter02 - init()");
	}
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		System.out.println("Filter02执行前");
		chain.doFilter(request, response);//放行
		System.out.println("Filter02执行后");
	}
	public void destroy() { 
		System.out.println("Filter02 - destroy()");
	}
}

//----------- Filter03 -----------------------
public class Filter03 implements Filter {

	public Filter03() {
		System.out.println("Filter03 - Filter03()");
	}

	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("Filter03 - init()");
	}
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		System.out.println("Filter03执行前");
		chain.doFilter(request, response);//放行
		System.out.println("Filter03执行后");
	}
	public void destroy() { 
		System.out.println("Filter03 - destroy()");
	}
}

2.在web.xml配置文件中配置过滤器信息

xml 复制代码
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
    
    <welcome-file-list>
        <welcome-file>welcome.html</welcome-file>
    </welcome-file-list>
    
         <filter> 
             <filter-name>Filter01</filter-name> 
             <filter-class>com.qf.filter.Filter01</filter-class> 
             <init-param> 
                 <param-name>code</param-name> 
                 <param-value>UTF-8</param-value> 
             </init-param> 
         </filter> 
         <filter-mapping> 
             <filter-name>Filter01</filter-name> 
             <url-pattern>/*</url-pattern> 
         </filter-mapping> 
    
         <filter> 
             <filter-name>Filter02</filter-name> 
             <filter-class>com.qf.filter.Filter02</filter-class> 
             <init-param> 
                 <param-name>code</param-name> 
                 <param-value>UTF-8</param-value> 
             </init-param> 
         </filter> 
         <filter-mapping> 
             <filter-name>Filter02</filter-name> 
             <url-pattern>/*</url-pattern> 
         </filter-mapping> 
    
         <filter> 
             <filter-name>Filter03</filter-name> 
             <filter-class>com.qf.filter.Filter03</filter-class> 
             <init-param> 
                 <param-name>code</param-name> 
                 <param-value>UTF-8</param-value> 
             </init-param> 
         </filter> 
         <filter-mapping> 
             <filter-name>Filter03</filter-name> 
             <url-pattern>/*</url-pattern> 
         </filter-mapping> 
    
</web-app>

3.3 注解配置过滤器(简化配置)

创建顺序:创建顺序无序

执行顺序:按照类名的顺序执行

注意:一般不使用这个

java 复制代码
@WebFilter(value="/*",initParams={@WebInitParam(name="encode",value="UTF-8")})
public class EncodeFilter implements Filter {
    ...
}

4.案例

4.1 案例一:编码过滤器

解决请求和响应乱码问题

java 复制代码
package com.qf.filter;

public class CodeFilter implements Filter {
    private String code;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        //获取web.xml中该过滤器的初始化属性
         code = filterConfig.getInitParameter("code");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        servletRequest.setCharacterEncoding(code);
        servletResponse.setContentType("text/html;charset="+code);
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}
xml 复制代码
   <filter>
        <filter-name>CodeFilter</filter-name>
        <filter-class>com.qf.filter.CodeFilter</filter-class>
        <init-param>
            <param-name>code</param-name><!-- 初始化参数名 -->
            <param-value>UTF-8</param-value><!-- 初始化参数值 -->
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CodeFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

4.2 案例二:登录权限过滤器

解决权限的统一控制问题,没有登录,就不能直接跳转到其他详情页面

java 复制代码
package com.qf.filter;

public class LoginFilter implements Filter {
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {

   }

   @Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

       //强转
       HttpServletRequest request= (HttpServletRequest) servletRequest;
       HttpServletResponse response= (HttpServletResponse) servletResponse;

       //获取请求地址
       String uri = request.getRequestURI();
       
       if (uri.equals("/Day19_war_exploded/")   ||
               uri.contains("register.jsp")   ||
               uri.contains("RegisterServlet")   ||
               uri.contains("welcome.html")   ||
               uri.contains("login.jsp")   ||
               uri.contains("CodeServlet")   ||
               uri.contains("LoginServlet") ){
           filterChain.doFilter(request,response);
       }else {
           //如果登录成功,会存储session凭证
           HttpSession session = request.getSession();
           String username = (String) session.getAttribute("username");
           String name = (String) session.getAttribute("name");
           String role = (String) session.getAttribute("role");

           if (username==null||name==null||role==null){//session凭证为空,不允许登录
               response.sendRedirect("login.jsp");
           }else {
               if(!role.equals("teacher") && uri.contains("GetStuListServlet")){
                   response.sendRedirect("login.jsp");
               }else{
                   filterChain.doFilter(request,response);
               }
           }
       }

   }

   @Override
   public void destroy() {

   }
}
xml 复制代码
    <filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>com.qf.filter.LoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

4.3 案例三:关键字过滤器

解决文档内的一个敏感词汇
Welcome.html,提交建议

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <a href="proposal.jsp">提交建议</a>
</body>
</html>

proposal.jsp

jsp 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    
<h1>建议页面</h1>
<form action="ProposalServlet" method="post">
    建议:<input type="text" name="info"><br>
    <input type="submit" value="提交"/>
    <input type="button" value="返回" οnclick="goIndex()"/>
</form>

<script type="text/javascript">
    function goIndex(){
        window.location = "Welcome.html";
    }
</script>
</body>
</html>

MyHttpServletRequestWrapper

请求包装类,处理敏感词

java 复制代码
package com.qf.wrapper;

public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
    //有参构造
    public MyHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    //子类重写
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        //把尖括号替换成字符尖括号,替换后不会认为是html里的尖括号符号
        value = value.replaceAll("<", "&lt;");
        value = value.replaceAll(">", "&gt;");
        value = value.replaceAll("傻逼", "**");

        return value;

    }
}

SensitiveWordsFilter

java 复制代码
package com.qf.filter;

public class SensitiveWordsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //创建请求包装类对象(注意:对象中包含了请求对象)
        MyHttpServletRequestWrapper myHttpServletRequestWrapper = new MyHttpServletRequestWrapper(request);

        //放行的是请求包装类对象
        filterChain.doFilter(myHttpServletRequestWrapper,response);

    }

    @Override
    public void destroy() {

    }
}
xml 复制代码
    <filter>
        <filter-name>SensitiveWordsFilter</filter-name>
        <filter-class>com.qf.filter.SensitiveWordsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>SensitiveWordsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

运行结果:

总结

Filter

概念

理解:过滤器链

过滤器的生命周期

案例

相关推荐
懒大王爱吃狼28 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
秃头佛爷2 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
阿伟*rui2 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
待磨的钝刨2 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck3 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei3 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师4 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法