深度好文之Servlet技术详解(十一)Filter过滤器

目录

一.过滤器作用

二.Filter对象的创建

三.在Filter中设置请求编码

四.FilterConfig对象的使用

五.FilterChain(过滤器链)

六.基于注解式开发Filter

 七.Filter的生命周期  


一.过滤器作用

Filter 过滤器是 Servlet2.3 中所提供的一个过滤请求与响应的对象。
Filter 过滤器既可以对客户端向服务器端发送的请求进行过滤,也可以对服务器端向客户端产生的响应进行过滤处理。

二.Filter对象的创建

创建一个 Class 实现 Filter 接口,并实现接口中三个抽象方法。
  • init()方法:初始化方法,在创建Filter后立即调用。可用于完成初始化动作。
  • doFilter()方法:拦截请求与响应方法,可用于对请求和响应实现预处理。
  • destroy()方法:销毁方法,在销毁Filter之前自动调用。可用于完成资源释放等动作。

容器启动时,就会创建Filter对象,Filter对象被实例化后会立即调用init函数,容器关闭时,才会销毁Filter对象。

FirstFilter.java:
package com.first.filter;

import javax.servlet.*;
import java.io.IOException;

public class FirstFilter implements Filter {
    /*
    当Filter对象被实例化后,会立即调用的一个方法
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Init......");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //对请求进行处理
        System.out.println("请求被过滤");
        //对请求做放行处理
        filterChain.doFilter(servletRequest,servletResponse);
        //对响应进行处理
        System.out.println("响应被过滤");
    }

    /*
    当Filter对象在销毁之前会调用一次该方法
     */
    @Override
    public void destroy() {

    }
}

配置web.xml:

配置和servlet的配置差不多,放在<web-app>标签内

路径配置为/test/*,和上节的AnnotationServlet.java路径一样,给此servlet过滤

    <filter>
        <filter-name>firstFilter</filter-name>
        <filter-class>com.first.filter.FirstFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>firstFilter</filter-name>
        <url-pattern>/test/*</url-pattern>
    </filter-mapping>

输出:

控制台输出:

请求被过滤
响应被过滤

三.Filter中设置请求编码

需求:在 Filter 中实现对请求的编码的设置。
实际应用原因:因为当有多个servlet接受客户端请求时,而此时客户端的数据都包含了中文,如果一个个servlet去单独设置编码的话效率太低,所以可以直接在过滤器中设置编码!

控制台如果乱码的话那就是请求编码没设置。

以之前添加用户的例子(戳这里)稍加修改做演示:

getRequestDataServlet.java:

package com.first.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/*
获取请求数据
 */
public class getRequestDataServlet extends HttpServlet {
    @Override
    //客户端是以post方式传递的数据,所以这里要用doPost函数
    //Tomcat拿到请求后会对请求做解析,解析出的数据会放到req对象当中
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求编码,这个必须放在获取请求数据之前,否则无效
        //将请求编码注释掉,检测Filter的作用
        //req.setCharacterEncoding("utf-8");

        //获取用户名
        String username=req.getParameter("username");
        //获取用户密码
        String password=req.getParameter("password");

        //获取复选框中被选中的数据
        String[] hobbies=req.getParameterValues("hobbies");
        //转化为列表
        List<String> list= Arrays.asList(hobbies);

        //获取表单中的所有的key
        Enumeration<String> parameterNames=req.getParameterNames();
        List<String> paraList=new ArrayList<>();
        while(parameterNames.hasMoreElements()){
            paraList.add(parameterNames.nextElement());
        }

        //使用Map结构获取提交数据
        Map<String,String[]> parameterMap=req.getParameterMap();
        Iterator<Map.Entry<String,String[]>> iterator=parameterMap.entrySet().iterator();

        resp.setContentType("text/plain;charset=utf-8");
        PrintWriter pw=resp.getWriter();
        pw.println("username:"+username);
        //在控制台输出username,看是否乱码
        //System.out.println(username);

        pw.println("password:"+password);
        pw.println("hobbies:"+list);
        pw.println("all_key:"+paraList);
        while(iterator.hasNext()){
            Map.Entry<String,String[]> entry=iterator.next();
            String key=entry.getKey();
            String[] value=entry.getValue();
            //要转化成列表再输出,直接输出value输出的是数组的地址
            pw.println(key+" = "+Arrays.asList(value));
        }
        pw.flush();
        pw.close();
    }
}

addUser.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--action加个../是为了从test目录里跳出,最前面加个/是因为Context Path用了绝对路径/,
所以在最前面才可以加/,也可以不加/-->
<form action="getRequestData.do" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>

    爱好:<input type="checkbox" name="hobbies" value="sports">体育
    <input type="checkbox" name="hobbies" value="music">音乐
    <input type="checkbox" name="hobbies" value="art">艺术<br>
    <input type="submit" value="OK">
</form>
</body>
</html>

配置web.xml:

路径配置为/*,即匹配所有路径

    <filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>com.first.filter.EncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

EncodingFilter.java:

package com.first.filter;

import javax.servlet.*;
import java.io.IOException;

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

    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //设置请求编码
        servletRequest.setCharacterEncoding("utf-8");
        //对请求做放行处理
        filterChain.doFilter(servletRequest,servletResponse);
    }
}

输出:

控制台输出的username也没乱码,可见配置成功!

四.FilterConfig对象的使用

FilterConfig对象是用来读取<filter> <init-param> 初始化参数的对象。该对象通过参数传递到init方法中,用于读取初始化参数。
filterConfig.getInitParameter("name")
通过 name 获取对应的 value
filterConfig.getInitParameterNames()
返回该 Filter中所有<param-name> 中的值。

 

对上一个编码的例子进行改造

    <filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>com.first.filter.EncodingFilter</filter-class>
<!--        通过修改<param-value>达到灵活设置请求编码的功能-->
        <init-param>
            <param-name>code</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

EncodingFilter.java:

package com.first.filter;

import javax.servlet.*;
import java.io.IOException;

public class EncodingFilter implements Filter {

    //设置默认编码
    private String defaultCode = "utf-8";
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String code=filterConfig.getInitParameter("code");
//        如果web.xml中没有配置编码,那么就使用默认编码
        if (code!=null && code.length()>0){
            this.defaultCode = code;
        }
    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //设置请求编码
        servletRequest.setCharacterEncoding(this.defaultCode);
        //对请求做放行处理
        filterChain.doFilter(servletRequest,servletResponse);
    }
}

可以再运行addUser.html测试一下。

五.FilterChain(过滤器链)

Filter 技术的特点是在对请求或响应做预处理时,可实现 插拔式 的程序设计。我们可以根据自己需求添加多个 Filter ,也可以根据需求 去掉某个 Filter ,通过修改 web.xml 文件即可实现。那么如果有多个 过滤器对某个请求及响应进行过滤,那么这组过滤器就称为过滤器 链。

Filter 执行顺序
则按照在 web.xml 文件中配置的上下顺序来决定先后。在上的先执行,在下的后执行。

 

六.基于注解式开发Filter

Filter 支持注解式开发,通过 @WebFilter 注解替代 web.xml Filter的配置。

使用注解式开发 Filter 时,执行顺序会根据 Filter 名称 进行排序的结果决定调用的顺序,即按字典序的是顺序排序。
当web.xml文件和注解都配置了Filter时,web.xml文件里面的配置优先级更高。
配置示例:
和servlet注解配置大同小异

 

 七.Filter的生命周期  

Filter 的生命周期是由容器管理的。当容器启动时会实例化 Filter 并调用 init 方法完成初始化动作。当客户端浏览器发送请求时,容器会 启动一个新的线程来处理请求,如果请求的 URL 能够被过滤器所匹 配,那么则先调用过滤器中 的 doFilter 方法,再根据是否有 chain.doFilter 的指令,决定是否继续请求目标资源。当容器关闭时 会销毁 Filter 对象,在销毁之前会调用 destroy 方法。

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

深海鱼肝油ya

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

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

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

打赏作者

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

抵扣说明:

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

余额充值