Introduction to the SpringMVC interceptor

What is an interceptor

The Interceptor in Spring MVC is similar to the Filter in servlets. It is mainly used to intercept user requests and process them accordingly. For example, the interceptor can verify permissions, log request information, and determine whether users log in.

Interceptor quick start

1. Create an interceptor to implement the HandlerInterceptor interface 2. Configure interceptors. 3. Test the interception effect of interceptors

1. Create an interceptor implementing the HandlerInterceptor interface

package com.pjh.HandleInterceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; Public class MyInterceptor implements HandlerInterceptor {/* Implements HandlerInterceptor {/* implements HandlerInterceptor; Public Boolean preHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler) throws Exception {system.out.println (" first: preHandle"); return false; } /* After the target method is executed, Public void postHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler, ModelAndView ModelAndView) throws Exception {system.out.println (" first: postHandle"); } public void afterCompletion(HttpServletRequest Request, HttpServletResponse Response, Object handler, Exception ex) throws Exception {system.out.println (" first: afterCompletion"); }}Copy the code

Methods to introduce

  • PreHandle () method: This method is executed before the controller method and its return value indicates whether subsequent operations are interrupted. If the return value is true, the execution continues.

When the return value is false, all subsequent operations (including invocation of the next interceptor and method execution in the controller class) are interrupted.

  • PostHandle () method: This method is executed after the controller method is called and before the view is parsed. You can use this method to make further changes to the model and view in the request domain.

  • AfterCompletion () method: This method is executed after the entire request is complete, that is, after rendering the view. You can use this method to clear resources and record log information.

2. Configure interceptors

Interceptors, like servlets or filters, need to be configured in a configuration file. The configuration code is as follows:

<mvc:interceptors> <mvc:interceptor> <! MVC: Mapping path="/**"/> <! < MVC :interceptor> < MVC :interceptor> Only intercepts requests that match the specified path. - this is for all the target method to intercept - > < bean class = "com. PJH. HandleInterceptor. MyInterceptor" / > < / MVC interceptor > < / MVC: interceptors >Copy the code

In the code above, the MVC: Interceptors element is used to configure a set of interceptors. The base child element defines a global interceptor, which intercepts all requests. The MVC: Interceptor element defines an interceptor for the specified path, which takes effect for requests in the specified path. The child of the MVC: Interceptor element MVC: Mapping is used to configure the path used by the interceptor, as defined in its property PATH. For example, the path attribute value “/**” in the preceding code means to intercept all paths, and “/hello” means to intercept all paths ending in “/hello”. If you include something in the request path that you don’t need to intercept, you can also configure it using the MVC :exclude-mapping element. Note: The child elements in the MVC: Interceptor must be written in the configuration order described above, that is, MVC :mapping MVC: excide-mapping. Otherwise, an error will be reported in the file.

The execution flow of interceptors

Single interceptor

When running a program, interceptors are executed in a sequence that is related to the order in which interceptors are defined in the configuration file. The execution flow of a single interceptor in the program is shown below:

1. The program executes the preHandle() method first. If this method returns true, the program continues down the handler’s method, otherwise it does not.

2. After the request is processed by the business processor (i.e. the Controller class), the postHandle() method is executed and the response is returned to the client via the DispatcherServlet.

3. AfterCompletion () is executed after the DispatcherServlet processes the request.

The test case

Define an interceptor that accesses the resource and watches the console output

package com.pjh.HandleInterceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; Public class MyInterceptor implements HandlerInterceptor {/* Implements HandlerInterceptor {/* implements HandlerInterceptor; Public Boolean preHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler) throws Exception {system.out.println (" first: preHandle"); return false; } /* After the target method is executed, Public void postHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler, ModelAndView ModelAndView) throws Exception {system.out.println (" first: postHandle"); } public void afterCompletion(HttpServletRequest Request, HttpServletResponse Response, Object handler, Exception ex) throws Exception {system.out.println (" first: afterCompletion"); }}Copy the code

Configure the execution flow of multiple interceptors

Multiple interceptors (assuming that there are two interceptors Interceptor1 and Interceptor2, and that Interceptor1 comes first in the configuration file). The execution flow of the program is as follows:

As you can see from the figure, when there are multiple interceptors working at the same time, their preHandle() methods are executed in the configuration order of the interceptors in the configuration file, while their postHandle() and afterCompletion() methods are executed in reverse order.

The test case

Data in the MVC configuration file

<! < MVC :interceptors> <! < MVC :interceptor> <! MVC: Mapping path="/**"/> <! < MVC :interceptor> < MVC :interceptor> Only intercepts requests that match the specified path. - this is for all the target method to intercept - > < bean class = "com. PJH. HandleInterceptor. MyInterceptor" / > < / MVC interceptor > <! - the second interceptors - > < MVC: interceptor > < MVC: mapping path = "/ * *" / > < bean class = "com. PJH. HandleInterceptor. MyInterceptor2" / > </mvc:interceptor> </mvc:interceptors>Copy the code

The code in the first interceptor

/* Execute before the target method is executed. Public Boolean preHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler) throws Exception {system.out.println (" first: preHandle"); return true; } /* After the target method is executed, Public void postHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler, ModelAndView ModelAndView) throws Exception {system.out.println (" first: postHandle"); } public void afterCompletion(HttpServletRequest Request, HttpServletResponse Response, Object handler, Exception ex) throws Exception {system.out.println (" first: afterCompletion"); }Copy the code

Code in the second interceptor

package com.pjh.HandleInterceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; Public class MyInterceptor2 implements HandlerInterceptor {/* Implements HandlerInterceptor; Public Boolean preHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler) throws Exception {system.out.println (" second: preHandle"); return true; } /* After the target method is executed, Public void postHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler, ModelAndView ModelAndView) throws Exception {system.out.println (" second: postHandle"); } public void afterCompletion(HttpServletRequest Request, HttpServletResponse Response, Object handler, Exception ex) throws Exception {system.out.println (" second: afterCompletion"); }}Copy the code

Console output after accessing a resource

Interceptor Case 1

The interceptor determines whether to jump to the page case by judging the parameters in the GET method

Interceptor code configuration

package com.pjh.HandleInterceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; Public class MyInterceptor implements HandlerInterceptor {/* Implements HandlerInterceptor {/* implements HandlerInterceptor; Public Boolean preHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler) throws Exception {system.out.println (" first: preHandle"); String param = request.getParameter("param"); /* If ("yes".equals(param)){return true; }else { request.getRequestDispatcher("error.jsp").forward(request,response); return false; }} /* After the target method is executed, Public void postHandle(HttpServletRequest Request, HttpServletResponse Response, Object Handler, ModelAndView ModelAndView) throws Exception {system.out.println (" first: postHandle"); } public void afterCompletion(HttpServletRequest Request, HttpServletResponse Response, Object handler, Exception ex) throws Exception {system.out.println (" first: afterCompletion"); }}Copy the code

When the get method takes the argument yes

When the get method takes an argument other than yes

Interceptor case 2 determines whether the user is logged in

Project Background:

Take accessing a background management system as an example, if the user logged in, let it access the background management system, if the user did not log in, when the user clicks any menu will jump to the login page

Click any of the buttons in the sidebar to jump to the login page

Configuration of interceptors

<! < MVC :interceptors> < MVC :interceptor> <! -- configured interceptor paths, in which methods to intercept operations - > < MVC: mapping path = "/ * *" / > <! < MVC :exclude-mapping path="/user/login"/> <! - configure Interceptor class location - > < bean class = "com. PJH. Interceptor. PrivilegeInterceptor" / > < / MVC: Interceptor > < / MVC: interceptors >Copy the code

Interceptor code implementation

package com.pjh.Interceptor; import com.pjh.domain.User; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.print.DocFlavor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class PrivilegeInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object Handler) throws Exception {/* If the user Object in the session field is empty, the login page is displayed, indicating that the user does not log in or fails to log in. */ HttpSession Session = request.getSession(); User user = (User) session.getAttribute("user"); System.out.println(" interceptor: "+user); if (user==null){ response.sendRedirect(request.getContextPath()+"/login.jsp"); return false; } /* The user is allowed */ return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); }}Copy the code

Controller layer /login code

Call the Service layer function to determine whether the user exists

 @Autowired
    private UserService userService;
   @RequestMapping("/login")
   public String login(String username, String password, HttpSession session){
       System.out.println(username);
       System.out.println(password);
     User user =userService.login(username,password);
     if (user!=null){
         session.setAttribute("user",user);
         System.out.println(user);
         return "redirect:/index.jsp";
     }else {
         return "redirect:/login.jsp";
     }
   }
Copy the code

Service layer login function code

public User login(String username, String password) {
        User user=userDao.findPasswordAndUsername(username,password);
       return user;
    }
Copy the code

The Dao layer queries the user for the presence of code

Note that exceptions must be caught here otherwise an exception will be thrown when the user is empty

 public User findPasswordAndUsername(String username, String password) {
       try{
       User user = jdbcTemplate.queryForObject("select * from sys_user where username=? and password=?", new BeanPropertyRowMapper<User>(User.class), username, password);
       System.out.println(user);
       return user;
   }catch (EmptyResultDataAccessException e){
       return null;
    }
}
Copy the code

After the above Settings, users can enter the background management page only after entering the correct user name and password

Introduction and use of filters

What is a filter?

As the name implies, it filters out things, for example, the college entrance examination we go through is a filter, it filters out some people who are not very good at study, and those who are good at study go to high school, college.

But a filter in Java works much like a filter in real life, controlling objects according to a set of rules

What Filer does:

A filter is a filter between a client and a server, through which requests are modified and judged before accessing resources. Intercepts or modifies requests that do not comply with the rules in mid-stream, and intercepts or modifies responses

Application scenarios

Automatic login Unified setting encoding format Access permission control Sensitive character filtering

Filter Quick Start

Coordinates of the JARS that need to be imported

< the dependency > < groupId > org, apache tomcat < / groupId > < artifactId > servlet - API < / artifactId > < version > 6.0.29 < / version > < / dependency > < the dependency > < groupId > org. Mortbay. Jetty < / groupId > < artifactId > servlet API - 2.5 < / artifactId > The < version > 6.1.7 < / version > < / dependency >Copy the code

1. The steps:

  1. Define a class that implements the interface Filter
  2. Copying method

3.1 Annotation Configuration 3.2 Web.xml configuration

3.1 Annotation Configuration

The code for the Filter class is as follows

package com.pjh; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; /* This Filter is implemented before all resources are executed */ @webFilter ("/*") public class MyFilter1 implements Filter {/* After the server is started, a Filter object is created and init is called. Perform this operation only once. */ Public void init(FilterConfig FilterConfig) throws ServletException {system.out.println (" initialize "); } /*: is executed each time a request is made for an intercepted resource. Public void doFilter(ServletRequest ServletRequest, ServletResponse ServletResponse, FilterChain FilterChain) throws IOException, ServletException {system.out. println(" Perform filter operation "); /* Filterchain.dofilter (servletRequest, servletResponse); } /* The Filter object is destroyed after the server is shut down. If the server is properly shut down, the destroy method is executed. Perform this operation only once. */ public void destroy() {system.out.println (" filter destroy "); }}Copy the code

3.2 web. XML configuration

<filter> <filter-name>MyFilter1</filter-name> <! <filter-class>com.pjh.MyFilter1</filter-class> </filter> <filter-mapping> <! -- Intercepting path configuration --> <filter-name>MyFilter1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>Copy the code

1. Filter execution process

  1. Executive filter
  2. Resources after being released
  3. Come back and execute the code below the filter release code

2. Filter life cycle approach

1. init:

After the server starts, the Filter object is created and the init method is called. Perform this operation only once. Used to load resources **

2. doFilter:

Is executed each time a request is made for an intercepted resource. Many times

3. destroy:

After the server is shut down, the Filter object is destroyed. If the server is properly shut down, the destroy method is executed. Perform this operation only once. Used to release resources

4. Filter configuration details

* Intercepting path configuration:

The filter will be executed only if the index. JSP resource is accessed

2. Blocking directory: /user/* Filters will be executed when all resources under /user are accessed

3. Suffix name interception: *.jsp accesses all resources with the suffix JSP, the filter is executed

4. Block all resources: /* Filters are executed when all resources are accessed

* Interception mode configuration: How resources are accessed

*** Notes Configuration: *** Sets the dispatcherTypes attribute. 1. REQUEST: default. Browser requests resources directly 2. FORWARD: forwards resources 3. INCLUDE: includes resources 4Copy the code

case

package com.pjh; import javax.print.DocFlavor; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @webFilter (value = "/*",dispatcherTypes = dispatcherType.request) public class */ @webfilter (value = "/*",dispatcherTypes = dispatcherType.request) public class MyFilter1 implements Filter {/* After the server starts, a Filter object is created and the init method is called. Perform this operation only once. */ Public void init(FilterConfig FilterConfig) throws ServletException {system.out.println (" initialize "); } /*: is executed each time a request is made for an intercepted resource. Public void doFilter(ServletRequest ServletRequest, ServletResponse ServletResponse, FilterChain FilterChain) throws IOException, ServletException {system.out. println(" Perform filter operation "); /* Filterchain.dofilter (servletRequest, servletResponse); } /* The Filter object is destroyed after the server is shut down. If the server is properly shut down, the destroy method is executed. Perform this operation only once. */ public void destroy() {system.out.println (" filter destroy "); }}Copy the code

* web. XML configuration

* Set the <dispatcher></dispatcher> tagCopy the code

case

<filter> <filter-name>MyFilter1</filter-name> <! <filter-class>com.pjh.MyFilter1</filter-class> </filter> <filter-mapping> <! </filter-name> MyFilter1</filter-name> <url-pattern> </filter-mapping>Copy the code

5. Filter chain (configure multiple filters)

* Order of execution: If there are two filters: filter 1 and filter 2

Just look at the picture. It makes sense

1. Filter 1 2. Filter 2 3. Resource Execution 4. Filter 1Copy the code

* Filter sequencing problem:

  1. Annotation configuration: Class names are compared according to string comparison rules, with smaller values executed first
For example, AFilter and BFilter, AFilter is executed firstCopy the code
  1. Web. XML configuration: Who defines above, who executes first

Case 1: Filter – User login case

Project Background:

To visit a background management system as an example, if the user logged in to let it access the background management system, if the user did not log in can not access any of the website page, and automatically jump to the login page, after logging in can access other pages

Click any of the buttons in the sidebar to jump to the login page

Filter code implementation

package com.pjh.Filter; import com.pjh.domain.User; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.io.IOException; public class LoginFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { System.out.println(" filter start "); } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain FilterChain) throws IOException, ServletException {system.out. println(" filter execution "); System.out.println(servletRequest); /* cast */ HttpServletRequest request= (HttpServletRequest)servletRequest; /* The path to the requested resource */ String uri = request.getrequesturi (); / * determine whether contains login resources related path should pay attention to rule out CSS/js/picture/verification code and other resource * / if (uri. The contains ("/login ") | | uri. The contains ("/login JSP ") | | uri.contains("/loginServlet") || uri.contains("/css/") || uri.contains("/js/") || uri.contains("/fonts/") || Uri. The contains ("/checkCodeServlet ") | | uri. The contains ("/img/")) {/ * is access login relative path. Release. * / filterChain doFilter (servletRequest, servletResponse); */ HttpSession session = request.getSession(); / / HttpSession = request.getSession(); */ user user = (user)session.getAttribute("user"); System.out.println(user); If (user = = null) {/ * * / request not login to jump to login page. GetRequestDispatcher ("/login JSP "). The forward (servletRequest, servletResponse); }else{/* filterchain.dofilter (servletRequest, servletResponse); }}} public void destroy() {system.out.println (" filter destroy "); }}Copy the code

Configuration of filters in web.xml

<filter> <filter-name>filter1</filter-name> <! - where filters - > < filter - class > com. PJH. Filter. The LoginFilter < / filter - class > < / filter > < filter - mapping > <filter-name>filter1</filter-name> <! <url-pattern>/*</url-pattern> </filter-mapping>Copy the code

After the above configuration users can only be logged in to access the resources

Case 2: Filter sensitive words

Application Scenarios:

For example, in the king of Glory, there are often low-quality people in the inside to spray others, full of filthy words, this time in order to create a good atmosphere of the game, it is necessary to use the sensitive words filter technology, the abusive words into “****”

Basic Principles:

At this point we need to use the filter, in the filter for these sensitive words and so on

For example, our sensitive words are “bad guys”. If we input “you are bad guys”, the filtered content will be “you are **”. Since the reqest object does not have setParemeter operation in the filter, So we can only enhance the getParameter method of the Request object and create a new Parameter object, adding filtered terms to the new Request object for other methods to call

Filter uses dynamic proxy to Filter sensitive terms

The following sensitive terms need to be filtered and replaced with “*” **

A fool foolCopy the code

Analysis: 1. Enhance the request object, and enhance the related method of obtaining parameters 2. Release, passing the proxy object

The Filter function code is as follows

package com.pjh.Filter; import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; import javax.servlet.*; import java.io.*; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; Public class SensitiveWordFilter implements Filter {private List<String> List = new ArrayList<String>(); Public void init(FilterConfig FilterConfig) throws ServletException {/* Reads sensitive vocabulary files and stores them in the corresponding collection */ try{/* Obtains the real path of the file */ ServletContext servletContext = filterConfig.getServletContext(); InputStream path = this.getClass().getResourceAsStream("/SensitiveWord.txt"); BufferedReader = new InputStreamReader(path," utF-8 "); /* Add each line of file to list */ String line=null; while ((line=bufferedReader.readLine())! =null){ list.add(line); } bufferedReader.close(); // System.out.println(list); }catch (Exception e){ System.out.println(e); } } public void doFilter(final ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("Filter1:"+servletRequest); ServletRequest proxy_req= (ServletRequest) Proxy.newProxyInstance(servletRequest.getClass().getClassLoader(), servletRequest.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /*1. 2. Enhance getParameter */ if (method.getName().equals("getParameter")){/* Enhance return value */ /* obtain return value */ String value= (String)method.invoke(servletRequest,args); /* If (value! =null){ for (String s : list) { if (value.contains(value)){ value=value.replace(s,"***"); } } } return value; } return method.invoke(servletRequest,args); }}); System.out.println("list set data: "+list); System.out.println("filter2proxy_req:"+proxy_req); /* / filterchain.dofilter (proxy_req,servletResponse); } public void destroy() {system.out.println (" destroy "); }}Copy the code

Set the interception path in web.xml

<! -- Set sensitive term filter --> <filter> <filter-name>filter2</filter-name> <filter-class>com.pjh.Filter.SensitiveWordFilter</filter-class> </filter> <filter-mapping> <filter-name>filter2</filter-name> <url-pattern>/filter/*</url-pattern> </filter-mapping>Copy the code

The Controller class code

package com.pjh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.UnsupportedEncodingException;
/*设置编码格式*/
@Controller
@RequestMapping(value = "/filter",produces = "text/html;charset=utf-8")
public class TestFilterController {
    @RequestMapping("/test1")
    @ResponseBody
    public String test1(ServletRequest request, ServletResponse response) throws UnsupportedEncodingException {
        System.out.println("test1:"+request);
        String id = request.getParameter("id");
        System.out.println("test1ID:"+id);
        return "你的id是"+id;
    }
}

Copy the code

Before the filter is configured

After setting the filter

The difference between filters and interceptors and the basics of filters:

Differences between filters and interceptors

1. Filter:

Depends on the servlet container. The implementation is based on function callbacks and can filter almost any request, but the disadvantage is that a filter instance can only be called once when the container is initialized. The purpose of using the filter is to do some filtering operations to obtain the data we want to obtain, such as: modify the character encoding in the filter; Modify some parameters of HttpServletRequest in the filter, including filtering vulgar text, dangerous characters, and so on

2. Interceptor:

It depends on the Web framework, and in the case of SpringMVC it depends on the SpringMVC framework. The reflection mechanism based on Java is an application of AOP. Because interceptors are web framework based invocations, you can use Spring’s dependency injection (DI) for business operations, and an interceptor instance can be invoked multiple times within the lifetime of a Controller. The disadvantage is that only controller requests can be intercepted, and other requests, such as direct access to static resources, cannot be intercepted. Interceptors are based on Java’s reflection mechanism, while filters are based on function callbacks. ② The interceptor does not depend on the servlet container, and the filter depends on the servlet container. ③ Interceptors work only on action requests, while filters work on almost all requests. (4) The interceptor can access the action context and objects in the value stack, but the filter cannot. The interceptor can be called multiple times during the life of the action, while the filter can only be called once during container initialization. (6) Interceptors can fetch individual beans from the IOC container, while filters cannot. This is important. Inject a service into the interceptor to invoke business logic.

The filter

@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException { System.out.println("before..." ); chain.doFilter(request, response); System.out.println("after..." ); }Copy the code

chain.doFilter(request, response); This method is called as a watershed. The Servlet’s doService() method is actually called in chain.dofilter (Request, response); It’s done in this method.