Spring MVC Interceptor Tutorial
In this tutorial, we are going to discuss about SpringMVC Interceptor. First, we discuss about Spring MVC architecture and where an interceptor is invoked in this architecture, then we have a look at the implementation of interceptor in more details.
1. Overview of Spring MVC Architecture
Spring’s web MVC framework is request-driven and designed based on a central Servlet that dispatches requests to controllers and invokes other functionality that facilitates the development of web applications.
The request processing workflow of the Spring MVC DispatcherServlet
is illustrated in the following diagram.
The DispatcherServlet
is an actual Servlet
and inherits from the HttpServlet
base class. When a request is sent to the web application, the workflow of handling a request is as below:
- When
DispatcherServlet
receives the request, it dispatches the task of selecting an appropriate controller toHandlerMapping
. Then,HandlerMapping
selects the controller which is mapped to the incoming request URL and returns the (selected Handler) and Controller toDispatcherServlet
.
DispatcherServlet
dispatches the task of executing the business logic byController
toHandlerAdapter
.HandlerAdapter
calls the business logic process ofController
. When theHandlerAdapter
calls the controller,Interceptor
is invoked to intercept the request.- Then,
Controller
executes the business logic and sets the processing result inModel
. Then, if there is anyInterceptor
to intercept the response, is invoked as a post process. ThenController
returns the logical name of view toHandlerAdapter
. DispatcherServlet
dispatches the task of resolving theView
corresponding to the View name toViewResolver
.ViewResolver
returns theView
mapped to View name.DispatcherServlet
dispatches the rendering process to returnedView
.View
rendersModel
data and returns the response.
2. Intercepting the request
Spring’s handler mapping mechanism includes handler interceptors, which are useful when you want to apply specific functionality to certain requests, for example, checking for a principal. Interceptors must implement HandlerInterceptor
from the org.springframework.web.servlet
package. This interface defines three methods:
preHandle
is called before the actual handler is executed.postHandle
is called after the handler is executed.afterCompletion
is called after the complete request has finished.
These three methods should provide enough flexibility to do all kinds of pre-processing and post-processing.
The preHandle
method returns a boolean value. You can use this method to break or continue the processing of the execution chain. When this method returnstrue
, the handler execution chain will continue; when it returns false, the DispatcherServlet
assumes the interceptor itself has taken care of requests (and, for example, rendered an appropriate view) and does not continue executing the other interceptors and the actual handler in the execution chain.
Question: What is the difference between Spring MVC Interceptor and Servlet Filter?
HandlerInterceptor
is basically similar to a Servlet 2.5 Filter
, but it just allows custom pre-processing with the option of prohibiting the execution of the Handler itself, and custom post-processing. Filters allow for exchanging the request and response objects that are passed to the chain. It means Filters work more in the request/response domain while HandlerInterceptors are spring bean and can access other beans in the application. Note that a Filter gets configured in web.xml
, a HandlerInterceptor
in the application context.
3. A Simple Interceptor tutorial
Now, lets have a look at this example to see how interceptor works in a web application. In the following example, I created a springMVC project in Spring Tool Suite 3.7.1 and used tomcat 8 as a web app server. The project is implemented based on java 1.7 and springMVC 4.1.1.
3.1. Create an interceptor
The AuthInterceptor
implements HandlerInterceptor
interface to handle the request before and after the controller. So, it implements all three methods of HandlerInterceptor
. If there is no requirement for implementing the all three methods, it is recommended to extends HandlerInterceptorAdapter
class instead.
In the following code, in the preHandle
method, when the request method is GET
, the request will be passed to the controller otherwise it won’t.
AuthInterceptor.java
package com.springapp.mvc; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.logging.Logger; public class AuthInterceptor implements HandlerInterceptor { private static final Logger logger = Logger.getLogger("AuthInterceptor"); @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { logger.info(" Pre handle "); if(httpServletRequest.getMethod().equals("GET")) return true; else return false; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { logger.info(" Post handle "); if(modelAndView.getModelMap().containsKey("status")){ String status = (String) modelAndView.getModelMap().get("status"); if(status.equals("SUCCESS!")){ status = "Authentication " + status; modelAndView.getModelMap().put("status",status); } } } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { logger.info(" After Completion "); } }
In the postHandle
method, status
is checked and updated in ModelMap
. Also, a message will be logged in the console when each method is executed.
Note that the postHandle
method of HandlerInterceptor
is not always ideally suited for use with @ResponseBody
and ResponseEntity
methods. In such cases an HttpMessageConverter
writes to and commits the response before postHandle
is called which makes it impossible to change the response, for example to add a header. Instead an application can implement ResponseBodyAdvice
and either declare it as an @ControllerAdvice
bean or configure it
directly onRequestMappingHandlerAdapter
.
3.2. Spring MVC Interceptor Configuration
The interceptor must be configured in the mvc-dispatcher-servlet.xml
. We can use mvc:interceptors
element to wire all the interceptors. We can also provide URI pattern to match before including the interceptor for the request through mapping
element.
The final spring bean configuration file looks like below.
mvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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-3.1.xsd"> <context:component-scan base-package="com.springapp.mvc"/> <mvc:interceptors> <bean class="com.springapp.mvc.AuthInterceptor" /> </mvc:interceptors> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
3.2.1. Java Configuration of Interceptor
Interceptors can be also configured in java. See the below example of java configuration of interceptors (The following code is not available in the downloaded source code):
WebConfig.java
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**"); registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*"); } }
3.3. Spring MVC Controller
The AuthController
handle the request to the uri ‘/’, set the status and render the response to auth.jsp
. The controller code is as below:
AuthController.java
package com.springapp.mvc; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import java.util.logging.Logger; @Controller @RequestMapping("/") public class AuthController { private static final Logger logger = Logger.getLogger("AuthController"); @RequestMapping(method = RequestMethod.GET) public String printStatus(ModelMap model) { logger.info("AuthController -> printStatus"); model.addAttribute("status", "SUCCESS!"); return "auth"; } }
3.4. Dependency configuration
The main dependency for Spring MVC is the spring-webmvc package. There are also other dependencies for log4j and servlet-api in the pom.xml file which you can find them in the source code of this tutorial.
pom.xml
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency>
3.5 Running the web application on Tomcat
After deploying the application to tomcat server, hit the http://localhost:8080/ and you can see the following message in the log and the result page is as below:
The log:
The result page:
4. Download the code project
This was an example of SpringMVC Interceptor in eclipse.
You can download the full source code of this example here: Spring MVC Interceptor Tutorial