Detailed explanation of JavaWeb filter (Filter), it's time to understand the filter thoroughly

        Note: This article is very long. After learning it, it will solve all your doubts about the filter (Filter). The following will explain the demonstration through the combination of theory and code..... 


 content

basic introduction

filter principle

Filter interface

Use filter (Filter)

Create a filter (Fliter)

Use filter (Filter)

Configure filter (Filter) interception path 

Annotation method

xml method 

Filter life cycle

Theoretical Description 

code demo

Description of FilterConfig and FilterChain

FilterConfig

Example use of FilterConfig

FilterChain 

FilterChain application example

Execution order of multiple filters

Perform sequential verification

Filter application example (implementing sensitive vocabulary filtering) 

Code

code verification

Summarize 


basic introduction

        Filter, as the name implies, is to filter things. The filter in the Web is of course to filter the request. We can use the filter to intercept the request, and then do the corresponding processing to realize many special functions. Such as login control, permission management, filtering sensitive words, etc.

filter principle

        When we use the filter, the filter will filter the request of the browser. The filter can be dynamically divided into 3 parts, 1. The code before release, 2. Release, 3. The code after release , these 3 parts Parts will play a different role.

  • The first part of the code will filter the browser request for the first time, and then continue to execute
  • The second part of the code is to release the browser request. If there is still a filter, then continue to the next filter
  • The third part of the code is to filter the returned web resources again

We use filters, that is, not only do requests go through filters, but our responses also go through filters.


Filter interface

        When we learn filters, we must first look at the filter interface provided by the official. Below we use Idea to view Filter.

         We can see that the filter (Filter) is relatively simple to use through the official filter, let's learn how to use the filter (Filter)


Use filter (Filter)

        We must import the corresponding jar package to use the filter. Filter is in servlet-api.jar. We put the jar package in the lib directory under WEB-INF, and then add the project.

Create a filter (Fliter)

        To create a Filter, we only need to inherit the Filter interface.

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

public class MyFilter implements Filter {

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

    }
}

         The Filter interface has 3 methods, but only one method is not implemented, we only need to implement this method. We can find that we have implemented a doFilter method, which is where we write the filtering code. The specific logic is the same as the filter principle described above.


Use filter (Filter)

        Let's first feel how to use filters, and we will explain the details later. We write the following code in the class created above and add a WebFIlter annotation

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

@WebFilter("/*")
public class MyFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("对request进行过滤");
        //下面这行代码就是放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("对response进行过滤");
    }
}

        Let me briefly introduce the above code, WebFilter("/*") means to filter all requests, and the release code in doFilter is filterChain.doFilter(servletRequest, servletResponse); this line of code is to release the interception, We'll talk about the details later, just understand how to understand it now.

        Start the server, and then we enter http://localhost:8080/filter/abc in the browser . Note that the filter is the web project path configured by ourselves, and the abc that follows is entered casually. Let's take a look at the console output after the browser.

browser output 

console output 

        Now, we can already draw two conclusions, the filter does not care whether the resource exists, but only intercepts the configured interception path. Interception not only intercepts the request, but also intercepts the response.


Configure filter (Filter) interception path 

        There are two ways to configure the interception path of Filter, one is annotation, the other is xml method, we will explain them separately.

Annotation method

        If we use annotations for configuration, then we need to use @WebFilter, we don't talk nonsense, just look at the source code of the annotation.

        There are still a lot of configuration items in it, and I will explain the common configuration items below:

  • filterName: the name of the filter
  • initParams: initialization parameters
  • displayName: filter display name
  • servletNames: Specify which servlets to filter
  •  asyncSupported: Whether to support asynchronous mode
  • urlPatterns: Specify the interception path
  • value: specifies the interception path

        Note: urlPatterns and value are the same. Only one of urlPatterns and value can be configured, not both, and an error will be reported if both are configured.

        For the use of @WebFilter , the multiple parameters in it are separated by . 

        Note: If we only need to configure an interception path, then we can directly abbreviate @WebLister("intercept path"), such as @WebFilter("/*") to intercept all requests. 


xml method 

        The xml method can be said to be the same as the servlet's xml configuration method, so there is no nonsense here, just configure one directly.

    <filter>
        <filter-name>myFilter</filter-name>
        <filter-class>com.clucky.filter.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>myFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

        This is the xml configuration method, except that the annotations are replaced by xml tags to configure, and the attributes are the same. This is basically the same as the Servlet configuration method, so I won't go into details here.


Filter life cycle

        We all know that Servlet has a life cycle. Of course, Filter also has a life cycle. Let's discuss the life cycle of Filter.

        The life cycle of Filter is also very similar to that of Servlet. If you are not familiar with the life cycle of Servlet, you can read this article on the life cycle of Servlet .

        We create a class that implements all the methods of Filter.

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

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

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

    @Override
    public void destroy() {
    }
}

Theoretical Description 

          Filter has 3 stages, namely initialization, interception and filtering, and destruction.

  1. Initialization phase: When the server starts, our server (Tomcat) will read the configuration file, scan the annotation, and then create our Filter.
  2. Interception and filtering phase: As long as the path of the requested resource is the same as the intercepted path, the filter will filter the request, and this phase will keep looping during the server running process.
  3. Destruction phase: When the server (Tomcat) is shut down, the Filter created by the server will also be destroyed.

code demo

        The three stages of Filter correspond to the three methods of Filter. The init method will be called when the Filter is created, the doFilter method will be called when the request and interception match, and the destroy method will be called when the Filter is destroyed . Let's write validation for these methods.

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

@WebFilter("/*")
public class LifeCycleFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //这个方法就是初始化方法,在Filter创建时调用
        System.out.println("调用了init()方法");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //这个方法就是过滤和拦截的方法,当请求和拦截匹配时调用
        System.out.println("调用了doFilter()方法");
    }

    @Override
    public void destroy() {
        //这个方法就是销毁方法,在Filter销毁前调用
        System.out.println("调用了destroy()方法");
    }
}

start server console output

Console output when intercepting 

Turn off server console output 

        As we expected, at this point, we have successfully verified the life cycle of Filter. 


 Description of FilterConfig and FilterChain

        The two objects, FilterConfig and FilterConfig, are passed in by the server (Tomcat) when creating and calling the Filter object. These two objects are very useful. The FilterConfig object can read the initial parameters of our configuration, and the FilterChain can implement multiple Filters. connection between.


FilterConfig

        The old rule, we want to learn an object, first look at the class diagram and source code

        There are only 4 methods in it, and we will explain them separately below.

  • getFilterName(): Get the name of the filter
  • getServletContext():获取ServletContext
  • getInitparamter(String var1): Get the value of the initial parameter of the configuration
  • getInitParamterNames(): Get all parameter names of the configuration

Example use of FilterConfig

        We use FilterConfig in the init method to read the information of the configured database and output it.

java code

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

public class MyFilterConfig implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("-----------获取全部key:value------------");
        //得到所有配置参数的名字
        Enumeration<String> names = filterConfig.getInitParameterNames();
        while (names.hasMoreElements()) {
            //得到每一个名字
            String name = names.nextElement();
            System.out.println(name+" = "+filterConfig.getInitParameter(name));
        }
        System.out.println("-----------end.....------------");
    }

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

    @Override
    public void destroy() {
    }
}

xml placement 

<filter>
        <filter-name>myFilterConfig</filter-name>
        <filter-class>com.clucky.filter.MyFilterConfig</filter-class>
        <init-param>
            <param-name>driver</param-name>
            <param-value>com.mysql.jdbc.Driver</param-value>
        </init-param>
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/equip_employ_manage?serverTimezone=GMT</param-value>
        </init-param>
        <init-param>
            <param-name>username</param-name>
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>root</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>myFilterConfig</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Start the server, console output

         We successfully implemented the function using the method provided by FilterConfig, which is used to read the configuration file.


FilterChain 

        In the same way, let's look at the source code and class diagram first.

         Looking at the class diagram, we can find that there is only one method in FilterChain. In fact, this method is used to release the interception. If there are multiple interceptors, then the next Filter will continue to be called for interception. The doFilter method needs to pass in a parameter, one is the ServletRequest and the other is the ServletResponse parameter, which is directly passed in.

        When Tomcat calls the filter, it will pass in Request and Response by default. This parameter encapsulates the request and response, and we can use it directly. ServletResquest and ServletResponse can be directly converted into HttpServletRequest and HttpServletResponse, and then use the corresponding method.

 将ServletRequest转成HttpServletRequest


FilterChain application example

        We have always been a Filter in front of us. Now let's configure 2 Filters and perform multiple filtering through FilterChain.

The first Filter

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

@WebFilter("/*")
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("调用过滤器01对请求进行过滤~~~~");
        //放行,如果还有过滤器,那么就执行下一个过滤器
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("调用过滤器01对响应进行过滤~~~~");
    }

    @Override
    public void destroy() {
    }
}

second filter

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

@WebFilter("/*")
public class Filter02 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("调用过滤器02对请求进行过滤~~~~");
        //放行,如果还有过滤器,那么就执行下一个过滤器
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("调用过滤器02对响应进行过滤~~~~");
    }

    @Override
    public void destroy() {
    }
}

        Start the server, and then enter http://localhost:8080/filter/abc in our browser (filter is the web project path I configured) to access and view the console output.

         We can see that Filter01 filters first, then passes it to Filter02, then accesses the resource, then Filter02 filters the response, and then Filter01 filters the response. The diagram is as follows:

        We first use Filter01 to filter the request, so naturally, we use Filter02 to filter the response first. 


 Execution order of multiple filters

        We have configured 2 filters above, so how do we know which filter to execute first? In fact, you can directly use the code to verify and cultivate the habit of independent thinking. Here I will give the answer directly.

  • If we configure the filter in web.xml, then the execution order of the filter is the order in which the <filter-mapping> is configured in the web, and if it is configured above, it will be executed first.
  • If we use @WebFilter for configuration, the execution order is the character comparison order. For example, if there are 2 filters, one is AFilter and the other is BFilter, then AFilter will be executed first.
  • If annotations and xml are mixed, the ones configured in web.xml will be executed first.

Perform sequential verification

        I will verify the first item here, that is, the order of configuration in web.xml is the same as the order of <filter-mapping>, and everyone else is interested in verifying by themselves.

xml configuration order 3->1->2

    <filter>
        <filter-name>filter03</filter-name>
        <filter-class>com.clucky.filter.Filter03</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter03</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>filter01</filter-name>
        <filter-class>com.clucky.filter.Filter01</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter01</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>filter02</filter-name>
        <filter-class>com.clucky.filter.Filter02</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter02</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Filter01

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

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("调用过滤器01对请求进行过滤~~~~");
        //放行,如果还有过滤器,那么就执行下一个过滤器
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("调用过滤器01对响应进行过滤~~~~");
    }

    @Override
    public void destroy() {
    }
}

Filter02

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

public class Filter02 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("调用过滤器02对请求进行过滤~~~~");
        //放行,如果还有过滤器,那么就执行下一个过滤器
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("调用过滤器02对响应进行过滤~~~~");
    }

    @Override
    public void destroy() {
    }
}

Filter03

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

public class Filter03 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("调用过滤器03对请求进行过滤~~~~");
        //放行,如果还有过滤器,那么就执行下一个过滤器
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("调用过滤器03对响应进行过滤~~~~");
    }

    @Override
    public void destroy() {
    }
}

        We start the server, access the browser, and then check whether the console output is in the order of 3->1->2 we configured

         It is found that the execution order is really like this. If you are interested in the verification of the other two, you can verify it yourself. I will not verify it here. If it is troublesome, just remember it.


Filter application example (implementing sensitive vocabulary filtering) 

        We have learned so much, now let's do an example, we write a comment page, we can comment, if the comment contains the sensitive words we define, then we will filter and use ** instead.

Code

jsp page

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>评论</title>
</head>
<body>
<h1>输入评论内容</h1>
<form action="${pageContext.request.contextPath}/comment" method="post">
    <textarea name="message" cols="30" rows="10"></textarea>
    <input type="submit" value="提交">
</form>
<p >${requestScope.get("name")}<span style="color: red">${requestScope.get("comment")}</span></p>
</body>
</html>

Filter code

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@WebFilter(servletNames = {"comment"},initParams = {@WebInitParam(name = "sensitiveWord", value = "zz")})
public class CommentFilter implements Filter {

    private List<String> sensitiveWords = new ArrayList<>();
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //得到敏感词汇
        String word = filterConfig.getInitParameter("sensitiveWord");
        //加入集合
        sensitiveWords.add(word);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //设置编码
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=utf-8");
        //得到评论
        String message = servletRequest.getParameter("message");
        for (String sensitiveWord : sensitiveWords) {
            //对所有敏感词汇进行过滤
            if (message.contains(sensitiveWord)){
                //替换敏感词汇
                message = message.replace(sensitiveWord, "**");
            }
        }
        //存入request域
        servletRequest.setAttribute("comment",message);
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
    }
}

Servlet code

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.HashSet;

@WebServlet(name = "comment",value = "/comment")
public class CommentServlet extends HttpServlet {

    //记录评论敏感词汇的ip
    private HashSet<String> hashSet = new HashSet<>();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String message = request.getParameter("message");
        String comment = (String) request.getAttribute("comment");
        if (message.equals(comment)){
            System.out.println("没有敏感词汇.....");
            //设置名字
            request.setAttribute("name","good boy:");
        }else {
            //有敏感词汇,记录IP
            String localAddr = request.getLocalAddr();
            System.out.println(localAddr);
            hashSet.add(localAddr);
            //设置名字
            request.setAttribute("name","bad boy:");
        }
        //转发到comment.jsp页面
        request.getRequestDispatcher("/comment.jsp").forward(request,response);
    }

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

code verification

        We enter http://localhost:8080/filter/comment.jsp to visit the jsp page.

         Enter comment content: Hello! ! !

         Our comments are shown below, let's type again: you're such a zz

         Show that you are a real **, and our comment filtering succeeded.


Summarize 

        Through the above study, I believe that everyone's mastery of Filter must have reached a new level, but the mastery of theoretical knowledge does not mean that everyone has really learned the code. Open the compiler and start practicing. The technology is piled up by lines of code. ! ! !

        If you think it's good, then give it a like and comment. 

Guess you like

Origin blog.csdn.net/m0_51545690/article/details/123677340