Spring MVC interceptor

  • Interceptors are powerful controls in Spring MVC that can do things before entering the processor, after the processor has finished, or even after rendering the view.

Interceptor Overview

  • As with any good MVC framework, there are some common operations such as request data encapsulation, type conversion, data validation, parsing uploaded files, preventing multiple submission of forms, and so on. The early MVC framework wrote all these operations in the core controller, and these common operations are not all requests need to be implemented, which leads to the lack of flexibility and scalability of the framework
  • SpringMVC provides the Interceptor Interceptor mechanism, similar to the Filter Filter in servlets, which intercepts user requests and processes them accordingly. For example, interceptors can be used to authenticate user permissions, or to determine whether a user is logged in. The Spring MVC interceptor is a pluggable design that requires a functional interceptor that can be applied in a configuration file. If you don’t need the functional interceptor, simply unapply it in the configuration file.
  • There are two ways to define an interceptor in Spring MVC: implementing the HandlerInterceptor interface and implementing the WebRequestInterceptor interface.

Implement the HandlerInterceptor interface

First to see HandlerInterceor the source of the interface, the interface is located in the org. Springframework. Web. Servlet package, defines three methods, to realize the interface, are going to achieve its three methods:

PreHandle () method: This method is executed before the controller method. The return value is a Boolean. If it returns false, it intercepts the request and does not proceed further; if it returns true, it permits further execution. (If there are no other interceptors, the Controller method is executed.) So this method can judge the request, decide whether the program should continue to execute, or do some initialization and preprocess the request.

PostHandle () method: This method is executed after the controller method call and before returning to ModelAndView. Because this method is called before the Return view is rendered by the DispatcherServlet, this method is used to process the returned view and further changes can be made to the model and view in the request domain.

AfterCompletion () method: This method is executed after the execution of the Controller method. Since the method is executed after the execution of the Controller method, it is suitable for cleaning up resources and logging information.

After the HandlerInterceptor interface is implemented, you need to configure the interceptor implementation class in the Spring class loading configuration file to enable the interceptor to intercept. There are two ways to load the configuration:

Example code for HandlerMapping configuration is as follows:

Here for BeanNameUrlHandlerMapping processor configured with a chain of interceptors blocker, the interceptor chain contains myInterceptor1 and myInterceptor2 two interceptors, The specific implementations correspond to the following bean configurations with ID myInterceptor1 and myInterceptor2, respectively.

Advantage: The advantage of this configuration is that interception is specific to the processor mapper

Disadvantages: The disadvantages are that if you use multiple processor mappers, you have to add the interceptor configuration information in multiple places, which can be tedious

For global configuration, the sample code is as follows:

In the above configuration, you can configure multiple interceptors under the MVC: Interceptors tag. The child bean defines a global interceptor, which intercepts all requests. The MVC :interceptor element defines an interceptor for the specified element. It will take effect for requests in the specified path. Its child elements must be in the order MVC :mapping –> MVC: exall-mapping –> bean.

Implement the WebRequestInterceptor interface

The WebRequestInterceptor also defines three methods that are used for intercepting. All three of these methods pass the same parameter WebRequest, which is an interface defined by Spring, and the method definitions are basically the same as HttpServletRequest, All operations performed on WebRequest in the WebRequestInterceptor are synchronized to the HttpServletRequest and passed through the current request. The three methods are as follows:

(1) The WebRequestInterceptor returns void, not Boolean. Therefore, this method cannot be used for request blocking, but is generally used for resource preparation.

(2) postHandle(WebRequest Request, ModelMap Model) : Data prepared in preHandle can be accessed through parameter WebRequest. ModelMap is a Model object returned by the Controller after processing. You can change the Model object Model by changing its properties to change the rendering effect of the view.

(3) afterCompletion(WebRequest Request, Exception ex) : The Exception argument represents the Exception object being requested, or null if the Exception thrown by the Controller has already been handled.

The execution flow of a single interceptor

When running a program, interceptors are executed in a sequence that is related to the order in which they are intercepted as defined in the configuration file. If only one interceptor is defined in the program, the execution flow of that single interceptor in the program is shown.

The program first executes the preHandle() method in the interceptor class. If this method returns true, the program continues down the handler’s method, otherwise it does not. After the request is processed by the business Controller class Controller, the postHandle() method is executed and the corresponding response is returned to the client via DispatcherServlet. The afterCompletion() method is executed after the DispatcherServlet has processed the request.

The execution flow of a single interceptor

The following is an example of the execution flow of a single interceptor in a SpringMVC-6 project:

(1) Create a hello() method in the UserController class in the SRC com.springMVC.Controller package and use the @requestMapping annotation to map it.

package com.springmvc.controller; import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.i18n.CookieLocaleResolver; import org.springframework.web.servlet.i18n.SessionLocaleResolver; import org.springframework.web.servlet.support.RequestContext; import com.springmvc.entity.User; @Controller public class UserController { @RequestMapping("/hello") public String hello() { System.out.println("Hello! Controller The Controller class executes the hello method "); return "hello"; }}Copy the code

(2) under the SRC directory, create a new com. For springmvc. The interceptor package, create MyInterceptor interceptor class, realize HandlerInterceptor interface.

package com.springmvc.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class MyInterceptor implements HandlerInterceptor{ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {system.out.println ("MyInterceptor interceptor executes preHandle() method "); return true; } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {system.out.println ("MyInterceptor interceptor executes afterCompletion method "); } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object Handler,ModelAndView ModelAndView) throws Exception {system.out.println ("MyInterceptor interceptor executes postHandle() method "); }}Copy the code

(3) Add the interceptor configuration code to the springMVC. XML configuration file.

<? The XML version = "1.0" encoding = "utf-8"? > <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd "> <! <context:component-scan base-package="com.springmvc"/> <! Automatic registration of processor mapper and processor adapter --> < MVC :annotation-driven/> <! Configure the view resolver, Will return to the logical view controller method resolves to physical view - > < bean class = "org. Springframework. Web. Servlet. The InternalResourceViewResolver" > < property name="prefix" value="/ch11/"></property> <property name="suffix" value=".jsp"></property> </bean> <! If you don't want to go through the controller class and forward it directly to the page, < MVC :view-controller path="/success" view-name="success"/> < MVC :view-controller path="/index" view-name="index"/> <mvc:default-servlet-handler/> <mvc:interceptors> <! - use the bean directly defined in MVC: under the interceptors interceptor intercepts all requests - > < bean class = "com. For springmvc. Interceptor. MyInterceptor" / > </mvc:interceptors> </beans>Copy the code

(4) In the CH11 folder, create a hello. JSP page file and write “Interceptor execution complete!” in the main part. Info.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <! DOCTYPE HTML > < HTML > <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> </body> </html>Copy the code

(5) to restart Tomcat, visit http://localhost:8080/springmvc-6/hello, the browser will jump to the hello. The JSP page, the console output.

Execution flow of multiple interceptors

In a Web project, even in a single HandlerMapping processor adapter, you can configure multiple interceptors, each of which executes in a pre-configured order. Instead of executing internally like many normal Java classes, their design pattern is based on a “chain of responsibility” pattern.

The following example describes the execution process of multiple interceptors. Suppose there are two interceptors, MyInterceptor1 and MyInterceptor2, and configure MyInterceptor1 first, as shown in the figure.

When multiple interceptors work at the same time, their preHandle() methods are executed in the same order as the interceptors in the configuration file, and their postHandle() and afterCompletion() methods are executed in reverse order

Execution flow of multiple interceptors

Modify an example of a single interceptor execution flow to demonstrate the execution of multiple interceptors as follows:

(1) in the com) for springmvc) interceptor package, two new interceptor class MyInterceptor1 and MyInterceptor2, this both interceptor class implements HandlerInterceptor interface, The code is similar to MyInterceptor.

MyInterceptor1

package com.springmvc.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class MyInterceptor1 implements HandlerInterceptor{ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {system.out.println ("MyInterceptor1 interceptor executes the preHandle() method "); return true; } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {system.out.println ("MyInterceptor1 interceptor executes afterCompletion method "); } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView ModelAndView) throws Exception {system.out.println ("MyInterceptor1 interceptor postHandle() method "); }}Copy the code

MyInterceptor2

package com.springmvc.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class MyInterceptor2 implements HandlerInterceptor{ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {system.out.println ("MyInterceptor2 interceptor executes preHandle() "); return true; } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {system.out.println ("MyInterceptor2 interceptor executes afterCompletion method "); } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView ModelAndView) throws Exception {system.out.println ("MyInterceptor2 interceptor postHandle() method "); }}Copy the code

(2) In the springMVC. XML configuration file, first comment out the MyInterceptor interceptor configured previously, and then configure the two interceptors defined above in the MVC: Interceptors element.

<mvc:interceptors> <! < MVC :interceptor><! MVC: Mapping path="/**"/><! Configure the path used by interceptors --> <! - defined in the < MVC: interceptor > the interceptor said matching path below request to intercept - > < bean class = "com. For springmvc. Interceptor. MyInterceptor1" > < / bean > </mvc:interceptor> <mvc:interceptor><! - interceptor 2 - - > < MVC: mapping path = "/ hello" / > < bean class = "com. For springmvc. Interceptor. MyInterceptor2" > < / bean > </mvc:interceptor> </mvc:interceptors>Copy the code

(3) restart Tomcat, visit http://localhost:8080/springmvc-6/hello, after the program will then run correctly, the browser will jump to the hello. The JSP page, the console output as shown.

2.3 Authenticating user login permission using interceptors

The implementation of user login permission verification using interceptors was completed in the SpringMVC-6 project as follows:

(1) In the com.springMVC. Controller package, in the controller UserController class, annotate the previous method, and define in this class the methods to jump to the home page, jump to the login page, perform user login and other operations.

@requestMapping (value="/login",method= requestmethod.get) public String loginPage() {@requestmethod.get (value="/login",method= requestmethod.get) public String loginPage() { System.out.println(" user jumps login.jsp from login request to login "); return "login"; @requestMapping (value="/login",method= requestmethod. POST) public String login(User User,Model) @requestMapping (value="/login",method= requestmethod. POST) public String login(User User,Model model,HttpSession session) { String loginName=user.getLoginName(); String password=user.getPassword(); If (loginname.equals (" Mary ") && password.equals("123456")) {system.out.println (" login succeeded "); // Add the user to the session. Save session.setattribute ("current_user", user); Return "redirect:/index"; } model.addattribute ("message", "wrong account or password, please log in again "); Return "login"; @requestMapping (value="/index",method= requestmethod.get) public String indexPage() { System.out.println(" user from index request to home page to index.jsp page "); Return "index"; } @requestMapping (value="/logout",method= requestmethod.get) public String logout(HttpSession session) { // Clear session session.invalidate(); System.out.println(" Exit function implementation, clear session, redirect to login request "); return "redirect:/login"; // Redirect to the login page}Copy the code

(2) in com) for springmvc) interceptor package, new LoginInterceptor interceptor class.

package com.springmvc.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; Public class loginInterceptor implements HandlerInterceptor {public Boolean preHandle(HttpServletRequest) request, HttpServletResponse response, Object Handler) throws Exception {// Obtain the request URI. String URL = Request.getrequestURI (); if(! Url.tolowercase ().contains("login")) {if(request.getSession().getAttribute("current_user")! =null) {return true; }else {request. SetAttribute ("message", "You haven't logged in yet, please log in first "); request.getRequestDispatcher("/ch11/login.jsp").forward(request, response); } }else { return true; } return false; } @override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); }}Copy the code

(3) In the springMVC. XML configuration file, first annotate the previously configured interceptor, and then configure the LoginInterceptor interceptor defined above in the MVC: Interceptors element.

<! < MVC :interceptors> < MVC :interceptor> < MVC :mapping path="/**"/><! - configure interceptor role by the path - > < bean class = "com. For springmvc. Interceptor. LoginInterceptor" > < / bean > < / MVC: interceptor > </mvc:interceptors>Copy the code

(4) In the CH11 folder, create login page login. JSP and home page index.jsp.

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <! DOCTYPE HTML > < HTML > <head> <meta charset="UTF-8"> <title> Login page </title> </head> <body> <font Color = "red" > ${requestScope. Message} < / font > < br / > < br / > < h3 > login page < / h3 > < form action = "${contextPath pageContext. Request }/login" method="post"> Account: <input type="text" name="loginName"/><br/><br/> < input type = "password" name = "password" / > < br / > < br / > < input type = "submit" value = "login" / > < / form > < / body > < / HTML >Copy the code

Home page index. The JSP

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <! DOCTYPE HTML > < HTML > <head> <meta charset=" utF-8 "> <title> ${sessionScope. Current_user. LoginName} < a href = "${pageContext. Request. ContextPath} / logout" > out of < / a > < / body > < / HTML >Copy the code

(5) to restart Tomcat, visit http://localhost:8080/springmvc-6/index, run the interface as shown.

summary

The Spring MVC interceptor introduces how to define and configure interceptors in a Spring MVC project, explains the execution flow of a single interceptor and multiple interceptors, and finally explains the practical application of interceptors through an example of user login permission verification. The Spring MVC framework manages functionality in a pluggable manner.

The last

Thank you for reading here, the article has any shortcomings please correct, feel the article is helpful to you remember to give me a thumbs up, every day will share Java related technical articles or industry information, welcome to pay attention to and forward the article!