当前位置: 首页 > article >正文

板块一 Servlet编程:第九节 过滤器全解 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程:第九节 过滤器全解

  • 一、什么是过滤器
  • 二、过滤器的实现
      • 一个过滤器拦截一个目录
      • 多个过滤器(Filter链)拦截一个目录
  • 三、过滤器处理中文乱码问题
  • 四、使用XML配置过滤器

程序员始终在为代码的可复用性努力着,过滤器也是一个典型的提高可复用性的工具,它让我们在一些逻辑上可以实现一劳永逸的效果

一、什么是过滤器

Filter 即为过滤,用于在Servlet之外对Request或者Response进行修改。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理
使用Filter的完整流程:Filter 对用户请求进行预处理,接着将请求交给Servlet 进行处理并生成响应,最后Filter再对服务器响应进行后处理。 举个栗子,在 板块一 Servlet编程:第三节Request 中,请求响应进入Servlet的时候,每个文件都要对请求响应作中文乱码的处理,非常难受,如果在数据流入每个Servlet文件前面都经过一个过滤器,就能在过滤器里一劳永逸解决中文乱码问题了
在这里插入图片描述
在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链
在这里插入图片描述

请求时先配置先执行;响应时以相反的顺序执行。
在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
在HttpServletResponse到达客户端之前,拦截HttpServletResponse。根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

二、过滤器的实现

在当前包下新建一个Fileter目录,作过滤器层
在这里插入图片描述
在Filter目录下新建filter1.java,现在的目录结构为
在这里插入图片描述

一个过滤器拦截一个目录

在filter1.java中实现一个过滤器需要以下步骤
实例

  • 实现接口
    在这里插入图片描述
  • 重写实现生命周期的三个方法
    在这里插入图片描述
    其中init()destroy()显然是我们耳熟能详的过滤器的生命周期的两个方法。而doFilter()就是过滤器的核心:过滤方法
    重写方法后,要在其中添加filterChain.doFilter(servletRequest,servletResponse);表示过滤后能放行的资源,也就是放行了来时的请求以及去时的响应,否则请求响应无法到达资源
    因此总体的doFliter()方法代码为
	@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {
        System.out.println("正在经过过滤器");
        filterChain.doFilter(servletRequest,servletResponse);
    }
  • 最后加上过滤器的访问注解@WebFilter("/start")
    注解中的目录就是过滤器将会过滤的目录,当然通常情况下是很多个项目一起过滤,此处只过滤start.java

最终filter.java的代码为

package www.caijiyuan.Filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter("/start")
public class filter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化成功");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {
        System.out.println("正在经过过滤器");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}

它将过滤的start.java文件内容为

package www.caijiyuan.Servlt;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@WebServlet("/start")
public class start extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {
        System.out.println("访问到Start");
    }
}

启动服务器,在浏览器中访问start,即可得到
在这里插入图片描述
可以看出服务器访问start.java文件之前是先经过lfilter1.java过滤器的

多个过滤器(Filter链)拦截一个目录

就如一、什么是过滤器中图示的,当有多个过滤器时,对于同一个文件请求的拦截顺序和响应的拦截顺序刚好相反,我们用实例来验证
在过滤器层中新添一个filter2
在这里插入图片描述
除了文件名内容与filter1完全一致

package www.caijiyuan.Filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter("/start")
public class filter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化成功");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {
        System.out.println("filter2正在拦截");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("filter2处理响应");
    }

    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}

此时再启动服务器,在浏览器中访问start.java即可在控制台打印
在这里插入图片描述
这就是filter链的演示效果,此外,如果filter1和filter2二者有一没有对请求响应进行filterChain.doFilter放行就会导致最终无法到达资源

三、过滤器处理中文乱码问题

早在Servlet的request和response两大对象小节我们就已经总结过中文乱码问题,现在我们就假设Tomcat8及以上POST请求时,使用Fliter处理中文乱码问题
在这里插入图片描述
实例:通过EncoderFliter.java过滤hello.jsp向after.java传递的中文参数

  • 实现生命周期:新建一个EncoderFliter.java的过滤器,implements自父类是Servlet包的Filter,并且在类中重写三个生命周期方法init\doFilter\destroy注意
  • 请求响应类型转换:doFilter中的request和response对象来自Servlet的实体,而我们之前用的request和response是来自HttpServlet的实体,因此需要在doFilter方法中类型转换
  • 处理乱码request.setCharacterEncoding("UTF-8");
  • 放行资源filterChain.doFilter(request,response);
  • Filter注释标识过滤范围,"*"为全部

最终EncoderFliter.java代码为

package www.caijiyuan.Filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/*")
public class EncodeFliter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {
        // 基于HTTP
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 处理POST请求乱码
        request.setCharacterEncoding("UTF-8");
        //放行资源
        filterChain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

此时的项目结构为
在这里插入图片描述

在hello.jsp中写一个POST表单用于传递请求参数

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>hello</title>
    <h1>Tomcat with IDEA</h1>
</head>
<body>
<form action="after" method="post">
    输入参数<input type="text" name="name">
    <button>提交</button>
</form>
</body>
</html>

after.java用于接收参数

package www.caijiyuan.Servlt;


import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@WebServlet("/after")
public class after extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {
        String name = req.getParameter("name");
        System.out.println(name);
    }
}

启动服务器在浏览器中访问hello.jsp,并传中文参
在这里插入图片描述
在没有使用过滤器之前,after.java在控制台打印
在这里插入图片描述

使用了过滤器之后,after.java在控制台打印
在这里插入图片描述
说明参数在被after接受之前确实先经过EncoderFliter.java过滤器,并且成功执行了doFilter里的设置。
这在我们有大量文件需要处理相同的设置时尤为方便,可以达到一劳永逸的效果,例如在访问一个购物网站时有些资源是登录以后才能查看的,例如在未登录状态下访问购物车就是一个非法访问,应该跳转到登录界面。这个非法访问拦截操作就可以用过滤器来实现

四、使用XML配置过滤器

除了用Servlet配置一个过滤器,其实我们还可以使用web.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_3_1.xsd"
         version="3.1">

    <filter>
        <filter-name>FilterName</filter-name>
        <filter-class>包的路径</filter-class>
        <!-- Optional: Filter initialization parameters -->
        <init-param>
            <param-name>参数名</param-name>
            <param-value>参数值</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>FilterName</filter-name>
        <url-pattern>/urlPattern</url-pattern>
        <!-- Optional: Specify dispatcher types -->
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ERROR</dispatcher>
    </filter-mapping>

</web-app>

例如,我们上面的处理中文乱码的过滤器就可以这样写
EncodeFilter.java

package www.caijiyuan.Filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class EncodeFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletExceptionIOException {
        // 基于HTTP
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 处理POST请求乱码
        request.setCharacterEncoding("UTF-8");
        //放行资源
        filterChain.doFilter(request,response);
    }
}

可以看出少了注解,此时过滤器覆盖的路径可以在web.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">

    <filter>
        <filter-name>EncodeFilter</filter-name>
        <filter-class>www.caijiyuan.Filter.EncodeFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>EncodeFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

此时实现的效果与使用Servlet配置过滤器一致
注意,XML的配置必须写在中,若配置XML文件请保证语法配置正确,否则Tomcat无法正常启动
可以看到XML中过滤器还有初始参数这一项

<init-param>
    <param-name>参数名</param-name>
    <param-value>参数值</param-value>
</init-param>

举个栗子可以这样使用:过滤器中使用初始化参数

<filter>
    <filter-name>CustomFilter</filter-name>
    <filter-class>com.example.CustomFilter</filter-class>
    <init-param>
        <param-name>apiKey</param-name>
        <param-value>YOUR_API_KEY</param-value>
    </init-param>
</filter>

我们定义了一个名为CustomFilter的过滤器,并为它指定了一个名为apiKey的初始化参数,其值为YOUR_API_KEY
在过滤器的init()方法中,可以通过FilterConfig对象来获取这个初始化参数

public class CustomFilter implements Filter {
    private String apiKey;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        apiKey = filterConfig.getInitParameter("apiKey");
    }
    ...
}

如此或取了初始化参数的值,并将其存储在apiKey变量中供过滤器的其他方法使用,初始化参数是可选的,可以根据需要在过滤器的配置中添加或删除它们

以上就是此小节的所用内容了,我们学习了过滤器最基础的使用方法,下一节中我们将学习过滤器的兄弟:监听器


http://www.kler.cn/a/550639.html

相关文章:

  • Dify - 创建 RAG Workflow 及 Restful HTTP 请求
  • 华大MCU HC32F005端口GPIO控制失效问题
  • Github 2025-02-17 开源项目周报Top15
  • 教育小程序+AI出题:如何通过自然语言处理技术提升题目质量
  • Python学习心得Pycharm的程序调试
  • 基于海思soc的智能产品开发(图像处理的几种需求)
  • 如何预防DDOS攻击
  • Qt QGroupBox 组件总结
  • 宠物企业宣传网站静态模板 – 前端静态页面开发实例
  • TCP开发
  • ubuntu22.04安装kvm、virt-manage并配置SR-IOV操作
  • CV -- 基于GPU版显卡CUDA环境+Pycharm YOLOv8 检测
  • 如何保证工业相机工作的精准与稳定?
  • 【深度学习】计算机视觉(CV)-目标检测-Faster R-CNN —— 高精度目标检测算法
  • Ubuntu 下 nginx-1.24.0 源码分析 - ngx_memalign函数
  • 王炸 用AI+飞书 分解 一键生成 项目计划表模版
  • R 语言科研绘图第 25 期 --- 直方图-山脊线
  • Linux 固定 IP 地址和网关
  • 【工具变量】上市公司网络安全治理数据(2007-2023年)
  • 【系统设计】跨域问题以及解决方法