[Spring] HandlerInterceptor
1. HandlerInterceptor
-
컨트롤러의 요청핸들러 메소드 실행 전처리/후처리를 구현하는 객체다. 실행은 interceptor -> argumentResolver -> 요청핸들러 메소드 실행 순이다. 로그인을 예시로 들면 interceptor가 제일 먼저 실행되어 세션에 로그인된 사용자가 있는지 확인하고, 없으면 에러페이지로 redirect 한다. 있으면 argumentResolver가 실행되어 세션 사용자 정보를 조회하고, 그 이후 요청 핸들러 메소드가 실행된다.
-
주요 API
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- 컨트롤러의 요청핸들러 메소드 실행 전 실행되는 메소드다.
- 이 메소드가 true를 반환하면 요청핸들러 메소드를 실행하고, false를 반환하면 요청핸들러 메소드를 실행하지 않는다.
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
- 컨트롤러의 요청핸들러 메소드 실행 후 실행되는 메소드다.
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- 클라이언트의 요청을 처리하고, DispatcherServlet에서 응답을 보낸 후 실행되는 메소드다.
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
2. Interceptor의 예시
- 응답 요청에 따라서 일반적인 interceptor와 restInterceptor가 존재한다.
public class LoginCheckInterceptor implements HandlerInterceptor {
private static Logger logger = LogManager.getLogger(LoginCheckInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
boolean hasLogineUser = false;
for (MethodParameter methodParameter : methodParameters) {
if (methodParameter.hasParameterAnnotation(LoginedUser.class)) {
hasLogineUser = true;
break;
}
}
logger.info("로그인 체크 여부: " + hasLogineUser);
if (!hasLogineUser) {
return true;
}
User user = (User) SessionUtils.getAttribute("LOGIN_USER");
if (user == null) {
response.sendRedirect("/error/login/form.do");
return false;
}
// rest 응답인 경우
User user = (User) SessionUtils.getAttribute("LOGIN_USER");
if (user == null) {
response.sendRedirect("/error/login/rest.do");
return false;
}
return true;
}
}
3. ErrorController
@Controller
@RequestMapping("/error")
public class ErrorController {
@RequestMapping("/login/form.do")
public String loginform() {
throw new LoginErrorException("로그인 후 사용가능한 서비스 입니다.");
// 아래의 예외처리 핸들러 메소드가 실행되도록 예외를 강제로 발생시켰다.
}
/*
@ExceptionHandler(LoginErrorException.class)
public String handleLoginErrorException(LoginErrorException e, Model model){
model.addAttribute("error", e.getMessage());
return "loginform.jsp";
}
*/
@RequestMapping("/login/rest.do")
public ResponseDto<?> rest() {
throw new RestLoginErrorException("로그인 후 사용가능한 서비스입니다.");
// 아래의 예외처리 핸들러 메소드가 실행된다.
}
/*
@ExceptionHandler(RestLoginErrorException.class)
public @ResponseBody ResponseDto<?> handleCartErrorException(RestLoginErrorException e) {
ResponseDto<?> response = new ResponseDto<>();
response.setStatus("FAIL");
response.setError(e.getMessage());
return response;
}
*/
}
4. context-web.xml 설정
<mvc:interceptors>
<!--
사용자정의 MethodInterceptor를 빈으로 등록한다.
-->
<!--
웹페이지 요청에 대한 로그인 체크를 담당하는 인터셉터
-->
<mvc:interceptor>
<mvc:mapping path="/**/*.do"/>
<mvc:exclude-mapping path="/rest/**/*.do"/> <!-- 이 요청은 제외됨 -->
<bean class="com.sample.interceptor.LoginCheckInterceptor"></bean>
</mvc:interceptor>
<!--
ajax 요청에 대한 로그인 체크를 담당하는 인터셉터
-->
<mvc:interceptor>
<mvc:mapping path="/rest/**/*.do"/>
<bean class="com.sample.interceptor.RestLoginCheckInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>