I learned about interceptor in Spring, so I will write an article.
The Interceptor class in Spring is a class used when, for example, "I want to implement a class that performs some common processing before the controller is called". For example, it is used when you want to authenticate the accessing user before mapping the request.
I will briefly explain the implemented class.
TestInterceptor.java
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.example.annotation.NonAuth;
import com.example.models.TestUser;
import com.example.service.UserPermissionService;
public class TestInterceptor extends HandlerInterceptorAdapter{
@Autowired
UserPermissionService service;
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
//False if the request cannot be mapped
if( handler instanceof HandlerMethod ) {
// @Check if NonAuth is granted
HandlerMethod hm = (HandlerMethod) handler;
Method method = hm.getMethod();
NonAuth annotation = AnnotationUtils.findAnnotation(method, NonAuth.class);
if (annotation != null) {
return true;
}
//User authentication
HttpSession session = request.getSession(false);
try {
TestUser user = (TestUser)session.getAttribute("user");
if(!service.checkPermission(user)) {
response.sendRedirect("/error");
return false;
}
}catch(NullPointerException e){
response.sendRedirect("/error");
return false;
}
return true;
}
response.sendRedirect("/error");
return false;
}
}
-The Interceptor class must inherit from HandlerInterceptorAdaptor. -PreHandle () is a method that is called before the controller process is called. You can also override postHandle (), which is called after the controller has finished processing, and afterCompletion (), which is called after a series of request processing is finished. -Returns true if the request is made to a method with NonAuth annotation in the first place (described later). -In the above class, user authentication is performed with UserPermission.checkPermission (), and if the check is hit, the user is redirected to the error screen (described later). -If the passed Handler is not an instance of HandlerMethod, it will redirect to the error screen (described later).
BeanConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import com.example.interceptor.TestInterceptor;
import com.example.service.TestService;
@Configuration
public class BeanConfiguration {
@Bean
public HandlerInterceptor testInterceptor() throws Exception{
return new TestInterceptor();
}
}
-Define the Interceptor class as a bean.
WebMvcConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
HandlerInterceptor testInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor);
}
}
-Interceptor is a class that inherits WebMvcConfigurer, and it is necessary to make Spring recognize it by addInterceptors (). -Call the Interceptor class with Autowired.
TestInterceptorController.java
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.example.annotation.NonAuth;
import com.example.models.TestUser;
@Controller
@RequestMapping("/interceptor")
public class TestInterceptorController {
@RequestMapping(value="/index",method = RequestMethod.GET)
@NonAuth
public String index(Model model, HttpServletRequest request) {
TestUser user = new TestUser();
user.setName("Tanaka");
HttpSession session = request.getSession(false);
if (session == null){
session = request.getSession(true);
session.setAttribute("user", user);
}else {
session.setAttribute("user", user);
}
return "test/index";
}
@RequestMapping(value="/test", method=RequestMethod.GET)
public String test(Model model) {
model.addAttribute("msg", "HelloWorld!");
return "test/test";
}
}
-First, when you access index, the user is registered in the session. -Since the index has NonAuth annotation, it passes the authentication without any questions. -You must clear the authentication to access test.
That's all for the rough implementation class.
-As mentioned above, there is a method using annotations, for example. -Define the annotation yourself. -We are checking whether the method is annotated as defined in preHandle () of the Interceptor class. ・ If it is given, no questions are asked and true is returned. ・ I referred to the following site. https://qiita.com/dmnlk/items/cce551ce18973f013b36
-If you want to handle errors in Spring, define a class that inherits ErrorController (class prepared in Spring).
ErrorController
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.annotation.NonAuth;
@Controller
public class ErrController implements ErrorController {
private static final String PATH = "/error";
@RequestMapping("/404")
@NonAuth
String notFoundError() {
return "test/error";
}
@RequestMapping(PATH)
@NonAuth
String home() {
return "test/error";
}
@Override
@NonAuth
public String getErrorPath() {
return PATH;
}
}
-Since the defined method does not perform authentication processing, add NonAuth annotation. -It seems that return false must be done after dispatching the error screen in the Interceptor class. This is because if you do not write return false, the handler method (mapped controller method) will be started even if the transition to the error screen is performed. I referred to the following site. https://stackoverflow.com/questions/44740332/redirect-using-spring-boot-interceptor I will try to google translate what is written in the above site.
Returns: true if the execution chain should proceed with the next interceptor or the handler itself. Else, DispatcherServlet assumes that this interceptor has already dealt with the response itself. True if the execution chain needs to proceed to the next interceptor or the handler itself. Otherwise, DispatcherServlet assumes that this interceptor has already processed the response itself.
I'm not sure what I'm saying in "If not ...", but I think the DispatcherServlet probably considers that a response has already been returned when it is returned fales with preHandle (otherwise the controller does not return false). Since the method of is started, does "if not" mean "if false"?). Anyway, if you don't want to invoke the controller method, write return false.
-I am verifying whether the handler is a HandlerMethod in the Interceptor class, because the handler is not necessarily a HandlerMethod. -For example, if you try to send a request to an address that is not supposed to be mapped, ResourceHttpRequestHandler will be passed. ・ I referred to the following site. https://qiita.com/tukiyo320/items/d51ea698c848414b5874
reference: Set up interceptor with springboot Put processing before and after the controller method in Interceptor Pre-process the method of Controller with specific Annotation of Spring Boot WebMvcConfigurer Memorandum of Spring Boot 2.0 (Spring 5) Display error screen with Springboot I was addicted to using Spring Boot (about 1.2) [Updated from time to time] RedirectusingSpringbootinterceptor The method that comes to preHandle is not always HandlerMethod
Recommended Posts