【Servlet09】过滤器filter

过滤器是数据源和目标程序之间的一个servlet组件,可以起到起到过滤的作用。

使用过滤器需要实现Filter接口,Filter接口在API中的描述;

A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static content), or on the response from a resource, or both.

Filters perform filtering in the doFilter method. Every Filter has access to a FilterConfig object from which it can obtain its initialization parameters, and a reference to the ServletContext which it can use, for example, to load resources needed for filtering tasks.

Filters are configured in the deployment descriptor of a web application.

Examples that have been identified for this design are:

  1. Authentication Filters

  2. Logging and Auditing Filters

  3. Image conversion Filters

  4. Data compression Filters

  5. Encryption Filters

  6. Tokenizing Filters

  7. Filters that trigger resource access events

  8. XSL/T filters

  9. Mime-type chain Filter

1 编写过滤器

1.1 实现接口

编写过滤器需要implements Filter接口:

实现其中的三个方法:

public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init in TestFilter......");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter in TestFilter [Before filterChain.doFilter]......");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("doFilter in TestFilter [After filterChain.doFilter]......");
    }

    @Override
    public void destroy() {
        System.out.println("destroy in TestFilter......");
    }
}
  • public void init(FilterConfig filterConfig):初始化方法,服务器启动时会实例化过滤器类,实例化完毕后会自动调用该方法;

  • public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain):过滤器的核心方法,验证请求是否合法,控制请求的运行;

  • public void destroy():销毁对象方法,服务器关闭时会自动调用该方法;

实现了这三个方法以后需要对过滤器进行配置,配置方法分为两种:xml方式注解方式

1.2 xml配置过滤器

和Servlet类似,过滤器的xml配置方式再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>test1</filter-name>
        <filter-class>com.jackqiang.filter.TestFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>test1</filter-name>
        <url-pattern>/testFilter</url-pattern>
    </filter-mapping>
</web-app>
  • <url-pattern>/testFilter</url-pattern>:配置过滤器需要过滤的请求url,可以使用/*表示所有请求,此处的testFilter如下:
@WebServlet("/testFilter")
public class TestFilterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("doGet in TestFilterServlet.......");
    }
}

重启服务器查看测试结果:

1.3 注解配置过滤器

使用注解的方式配置过滤器需要用到@WebFilter注解,查看其源码:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebFilter {
    String description() default "";

    String displayName() default "";

    WebInitParam[] initParams() default {};

    String filterName() default "";

    String smallIcon() default "";

    String largeIcon() default "";

    String[] servletNames() default {};

    String[] value() default {};

    String[] urlPatterns() default {};

    DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};

    boolean asyncSupported() default false;
}

可以发现其结构和@WebServlet注解十分相似,一般在括号内填入需要过滤的请求名称即可,例如有以下Servlet:

@WebServlet("/testAnnoFilter")
public class TestAnnoFilterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("doGet in TestAnnoFilterServlet.......");
    }
}

编写以下过滤器:

@WebFilter("/testAnnoFilter")
public class TestAnnoFilter 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("doFilter in TestAnnoFilter [Before filterChain.doFilter]......");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("doFilter in TestAnnoFilter [After filterChain.doFilter]......");
    }

    @Override
    public void destroy() {

    }
}

重启服务器查看执行结果:

2 过滤器的执行结构

2.1 单个过滤器

单个过滤器通过过滤器的核心方法:public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)来验证请求是否合法,控制请求的运行:

  • 如果判断请求合法,请求会继续向后执行;

  • 如果不合法,停止运行,直接向浏览器响应

请求否合法性的判断则是通过方法中的FilterChain filterChain参数来执行:

  • 如果在方法体内执行了filterChain.doFilter,则判定该请求合法;

  • 如果在方法体内没有执行filterChain.doFilter,则判定该请求不合法;

此外filterChain.doFilter还可以作为程序运行的分界线:方法之上请求时执行,方法之下响应时执行

演示和执行结果可以参考 1;

2.2 多个过滤器

再编写一个过滤器做演示:

xml配置文件方式配置的过滤器:

public class TestFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init in TestFilter2......");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter in TestFilter2 [Before filterChain.doFilter]......");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("doFilter in TestFilter2 [After filterChain.doFilter]......");
    }

    @Override
    public void destroy() {
        System.out.println("destroy in TestFilter2......");
    }
}

注解方式配置的过滤器:

@WebFilter("/testAnnoFilter")
public class TestAnnoFilter2 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("doFilter in TestAnnoFilter2 [Before filterChain.doFilter]......");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("doFilter in TestAnnoFilter2 [After filterChain.doFilter]......");
    }

    @Override
    public void destroy() {

    }
}

多个过滤器的控制执行的方式是通过配置来进行的;

如果是使用xml配置的方式配置的过滤器,会按照web.xml文件的从上到下顺序执行,例如以下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>test1</filter-name>
        <filter-class>com.jackqiang.filter.TestFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>test1</filter-name>
        <url-pattern>/testFilter</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>test2</filter-name>
        <filter-class>com.jackqiang.filter.TestFilter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>test2</filter-name>
        <url-pattern>/testFilter</url-pattern>
    </filter-mapping>
</web-app>

测试结果:

如果改变了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>test2</filter-name>
        <filter-class>com.jackqiang.filter.TestFilter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>test2</filter-name>
        <url-pattern>/testFilter</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>test1</filter-name>
        <filter-class>com.jackqiang.filter.TestFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>test1</filter-name>
        <url-pattern>/testFilter</url-pattern>
    </filter-mapping>
</web-app>

执行结果:

如果是使用注解的方式配置的过滤器,则会按照过滤器类名的字典顺序执行;对于两个用注解方式配置的过滤器TestAnnoFilterTestAnnoFilter2,显然是TestAnnoFilter先于TestAnnoFilter2执行:

如果对于一个请求同时使用了xml配置和注解配置两种配置方式,则会优先执行所有的xml文件配置的过滤器,再执行所有的注解配置的过滤器,例如将两个注解配置的过滤器也配置到/testFilter上:

3 过滤器的应用

3.1 字符编码过滤器

以前编写Servlet的时候,如果涉及到数据交互,为了防止中文乱码,需要再请求中添加以下两行代码:

request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");

如果Servlet很多,为每一个Servlet都添加就会造成代码冗余,因此可以使用字符编码过滤器,这样整个模块下所有的Servlet都不需要再配置字符编码了,由过滤器统一完成:

@WebFilter("/*")
public class EncodingFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

3.2 登录校验过滤器

登录页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="login" method="post">
    <label>账号:</label>
    <input type="text"  placeholder="请输入账号" name="username" /><br />
    <label>密码:</label>
    <input type="password" placeholder="请求输入密码"  name="password" /><br />

    <input type="submit" value="登录" />
    <input type="reset"  value="重置" />
</form>

</body>
</html>

登录成功的欢迎页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  登录成功,欢迎${user}
  </body>
</html>

Servlet:

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("张三".equals(username) && "123456".equals(password)){
            HttpSession session = request.getSession();
            session.setAttribute("user",username);
            response.sendRedirect("index.jsp");
        }else {
            response.sendRedirect("login.jsp");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

过滤器:

@WebFilter("/*")
public class LoginFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        Object user = request.getSession().getAttribute("user");
        if (user != null || request.getRequestURI().contains("login")) {
            chain.doFilter(req, resp);
        } else {
            response.sendRedirect("login.jsp");
        }
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

 

版权声明:
作者:jackqiang
链接:http://www.jackqiang.com/javaweb/server/servlet/2157/filter/
来源:JackQiang's
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录