1. Overview
Interceptors are often used to insert custom logic at different stages of request processing.
Spring MVC's interceptor function is to arrive at the requestControllerIntercepting before or afterwards can perform some specific processing on requests and responses.
like:
- Login verification: For URLs that require login to access, use the interceptor to determine whether the user is logged in. If it is not logged in, it will jump to the login page.
- Permission verification: Access control is performed on some URLs based on user permissions, and unauthorized users are denied access.
- Request log: Record request information, such as request address, request parameters, request time, etc., for troubleshooting problems and performance optimization.
- Change the response: You can modify the content of the response, such as adding header information, adjusting the format of the response content, etc.
2. The difference between interceptor and filter
For filters, please read my previous articleIntroduction and use of filter filter。
It is easy to find that interceptors and filters are very similar. They both intercept the front and back of a certain stage and perform some processing. So what are the differences between them?
Filters are defined in servlets, while interceptors are provided by Spring MVC framework
The two have different scopes of function
- Filters focus more on processing in the process of ** request and response (i.e. before Servlet), and can modify the content of the request and response, such as setting encoding and character sets, request headers, status codes, etc.
- Interceptors focus more onControllerPerform pre- or post-processing, performing specific operations before or after the request reaches the controller, such as printing logs, permission verification, etc.
3. Customize the interceptor
Spring MVC providesHandlerInterceptor
Interface, developers can create custom interceptors by implementing this interface.
There are three default methods defined for intercepting different stages:
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):
- Called before the controller method is executed.
- return
true
Indicates that the subsequent interceptor and controller methods continue to be executed; returnfalse
Indicates interruption of execution and no subsequent interceptor and controller methods will be called. - Can be used for permission verification, logging, etc.
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):
- After the controller method is executed, but called before the view rendering.
- Can be used to modify
ModelAndView
Object, add extra data, etc.
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):
- Called after the entire request is processed, regardless of whether an exception occurs.
- Can be used for resource cleaning, logging, etc.
Create a custom interceptor:
import ; import ; import ; import ; public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // Call before the controller method is executed ("preHandle..." ); // Here we directly return true return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // After the controller method is executed, but before the view rendering is called ("postHandle..."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // Called after the entire request is processed ("AfterCompletion"); } }
In order for the interceptor to take effect at this time, we also need to configure it in the spring mvc configuration file (by default, all controllers are intercepted)
<mvc:interceptors> <mvc:interceptor> <!--Set the path to block--> <mvc:mapping path="/**"/> <!--Specify a path that does not intercept--> <mvc:exclude-mapping path="/test"/> <!--Configure the classpath of the custom interceptor--> <bean class=""/> </mvc:interceptor> </mvc:interceptors>
You can also add the @component annotation to the custom interceptor class, and the configuration file at this time is
<mvc:interceptors> <mvc:interceptor> <!--Set the path to block--> <mvc:mapping path="/**"/> <!--Specify a path that does not intercept--> <mvc:exclude-mapping path="/test"/> <!--The default name is lowercase in class name--> <ref bean="myInterceptor"></ref> </mvc:interceptor> </mvc:interceptors>
4. The execution order of multiple interceptors
In Spring MVC, multiple interceptors can form an interceptor chain and execute in sequence in order of registration (configuration).
Suppose now registers three interceptors Interceptor1, Interceptor2, Interceptor3 in order.
When all interceptors' preHandle methods return true:
- preHandle execution order: Interceptor1->Interceptor2->Interceptor3 (sequential execution)
- PostHandle execution order: Interceptor3->Interceptor2->Interceptor1 (reverse execution)
- AfterCompletion execution order: Interceptor3->Interceptor2->Interceptor1 (reverse execution)
When the preHandle method of a certain interceptor returns false, here is assumed to be Interceptor3
- preHandle execution order: Interceptor1->Interceptor2->Interceptor3 (execute in sequence until a certain interceptor returns false)
- The postHandle is not executed, and the controller method is not executed
- AfterCompletion execution order: Interceptor2->Interceptor1 (Return false's interceptor execution in reverse order)
Why is this order? We can observe the source code and find:
- preHandle source code analysis
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { //interceptorList is an ArrayList collection that stores all interceptors in order //The subscript starts from 0, from here we can know why it is executed sequentially. // = i++, note this code. If false is returned, its value represents the subscript of the interceptor that currently returns false for(int i = 0; i < (); = i++) { HandlerInterceptor interceptor = (HandlerInterceptor)(i); //If false is returned if (!(request, response, )) { //Execute AfterCompletion, here we know why not execute postHandle, but execute AfterCompletion (request, response, (Exception)null); return false; } } return true; }
- PostHandle source code analysis
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { // You can see that this is the reverse order traversal from the last interceptor for(int i = () - 1; i >= 0; --i) { HandlerInterceptor interceptor = (HandlerInterceptor)(i); (request, response, , mv); } }
- AfterCompletion source code analysis
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { //() - 1 indicates the subscript of the previous interceptor that currently returns false //Note that here is --i //This explains why the interceptor before returning false is executed in reverse order for(int i = () - 1; i >= 0; --i) { HandlerInterceptor interceptor = (HandlerInterceptor)(i); (request, response, , mv); } }
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.