HandlerInterceptorμ μΈμ μ¬μ©νλμ?
μλ νμΈμ Mamboμ λλ€. μ€λμ μ€νλ§ MVC λͺ¨λμ ν¬ν¨λμ΄μλ HandlerInterceptor μΈν°νμ΄μ€λ₯Ό μΈμ μ¬μ©νλκ°μ λν΄μ μμλ³΄κ² μ΅λλ€.
HandlerInterceptor
A HandlerInterceptor gets called before the appropriate HandlerAdapter triggers the execution of the handler itself. This mechanism can be used for a large field of preprocessing aspects, e.g. for authorization checks, or common handler behavior like locale or theme changes. Its main purpose is to allow for factoring out repetitive handler code.
HandlerInterceptorλ 컨νΈλ‘€λ¬ νΈλ€λ¬ ν¨μμ λν μ μ²λ¦¬ λμμ μνν μ μλ λ°©λ²μ μ 곡ν©λλ€. νν°λ μ μ²λ¦¬ λμμ μνν μ μμ§λ§ web.xmlμ μ μλλ νν°μ λ€λ₯΄κ² HandlerInterceptorλ μ ν리μΌμ΄μ 컨ν μ€νΈμμ κ΄λ¦¬νλ―λ‘ μμ² μ 보λ₯Ό λΆμνμ¬ μ¬μ©μλ₯Ό μΈμ¦νκ±°λ μλ΅ λ·°λ₯Ό λ λλ§νκΈ° μ μ λΆκ° λ°μ΄ν°λ₯Ό μ£Όμ νλ λμμ μνν μ μμ΅λλ€.
μλ₯Ό λ€μ΄, κΈ°λ³ΈμΌλ‘ μ 곡λλ HandlerInterceptor ꡬνμ²΄μΈ LocaleChangeInterceptorλ λ‘μΌμΌ νλΌλ―Έν°μ λ°λΌ νμ¬ λ‘μΌμΌμ λ³κ²½νλ λμμ μννμ£ .
μ μ 리μμ€ ν¨ν΄ μ μΈ
ResourceHandlerRegistryλ μ μ 리μμ€λ₯Ό λ°°ν¬νκΈ° μν νΈλ€λ¬λ₯Ό λ±λ‘νλ κ²μ μ§μνλ ν΄λμ€μ λλ€. μ΄λ, 리μμ€ νΈλ€λ¬κ° μ²λ¦¬ν κ²½λ‘λ₯Ό 맀μΉνκΈ° μνμ¬ AntPathMatcher λλ PathPatternμ μ¬μ©νκ² λλλ° Ant μ€νμΌμ ν¨ν΄ 맀μΉμ μ¬μ©νλ―λ‘ νΉμ ν¨ν΄μ μ μΈνκΈ° μν Regex κ°μ λ°©μμ μ¬μ©ν μ μμ΅λλ€.
리μμ€ νΈλ€λ¬κ° μ²λ¦¬νλ κ²½λ‘μ λν΄μ νΉμ ν¨ν΄μ μ μΈνκΈ° μν΄μλ ν΄λΉ ν¨ν΄μ μ²λ¦¬νμ§ μλλ‘ ν¨ν΄λ³λ‘ λ±λ‘νμ¬μΌν©λλ€. νμ§λ§, μ΄λ κ² μ¬λ°λ₯Έ ν¨ν΄λ§λ€ 리μμ€ νΈλ€λ¬λ₯Ό λ±λ‘νλ κ²μ λΆνΈν©λλ€.
@Configuration(proxyBeanMethods = false)
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/");
}
}
μ μμλ /images/** ν¨ν΄μ κ²½λ‘μ λν΄μ ν΄λμ€ν¨μ€μ static/images ν΄λμ μλ μ μ 리μμ€λ‘ μ²λ¦¬νκΈ° μν νΈλ€λ¬λ₯Ό λ±λ‘ν©λλ€. images ν΄λμλ μ΄λ―Έμ§ νμΌλ§ μλ€κ³ κ°μ νμΌλ κ°λ°μμ μ€μλ‘ images ν΄λμ μ΄λ―Έμ§κ° μλ λμμ νμΌμ΄λ μ€λμ€ νμΌμ΄ λ€μ΄μλ€λ©΄ ν΄λΉ 리μμ€λ μ²λ¦¬νκ² λ©λλ€.
μ΄λ κ² νΉμ ν¨ν΄μ λ°©μ§ν΄μΌνλ κ²½μ°μ HandlerInterceptorλ₯Ό λ±λ‘νμ¬ μμ²μ λΆμνμ¬ λ¦¬μμ€λ₯Ό μλ΅νμ§ μλλ‘ μ μ²λ¦¬ λμμ ꡬνν μ μμ΅λλ€.
λ€μκ³Ό κ°μ΄ μ΄λ―Έμ§ νμΌ ν¨ν΄μ΄ μλλΌλ©΄ μμ²μ 404 Not Foundλ‘ μ²λ¦¬νλ λμμ μνν μ μμ΅λλ€.
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(onlyServeImagesHandlerInterceptor()).addPathPatterns("/images/**");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/");
}
@Bean
OnlyServeImagesHandlerInterceptor onlyServeImagesHandlerInterceptor() {
return new OnlyServeImagesHandlerInterceptor();
}
public static class OnlyServeImagesHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
if(!requestURI.matches(".*\\/.*\\.(jpg|jpeg|png|gif)")) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return false;
}
return true;
}
}
}
μ μΈν°μ ν°κ° μ λ§λ‘ μ΄λ―Έμ§ νμΌμ λν΄μλ§ μ²λ¦¬ν μ μκ² μ¬μ μ²λ¦¬λ₯Ό μννλμ§ νμΈν΄λ³΄κ² μ΅λλ€.
μ κ²°κ³Όλ₯Ό 보면 μ΄λ―Έμ§ νμΌμ μ μ 리μμ€λ‘ λ°°ν¬λλλ‘ μ²λ¦¬λμμ§λ§ λμμ νμΌμ μ²λ¦¬λμ§ μκ² λκ±Έ νμΈν μ μμ΅λλ€.
λ·° μλ΅ μ λΆκ° μ 보 μ£Όμ
λλ²μ§Έλ‘λ λ·°λ₯Ό μλ΅νλ νΈλ€λ¬ ν¨μμ λνμ¬ λΆκ° μ 보λ₯Ό μ£Όμ νλλ°μ μ¬μ©ν μ μμ΅λλ€.
λ€μμ μ½λλ λ·°λ₯Ό μλ΅νκ²λλ νΈλ€λ¬ ν¨μμ μ¬μ© κ°λ₯ν μΈμ΄μ ν¨κ» νμ¬ λ‘μΌμΌμ λν λ©μμ§ μ½λ λͺ©λ‘μ μ£Όμ νλ μΈν°μ ν° μμμ λλ€.
public static class InjectionLocalesInterceptor extends HandlerInterceptorAdapter {
private MessagePool messagePool = null;
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if(modelAndView != null && messagePool != null) {
Locale locale = messagePool.getLocale();
if(locale == null) {
locale = Locale.getDefault();
}
modelAndView.addObject("lang", locale.getLanguage());
modelAndView.addObject("locale", locale.toString());
if(handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Class<?> beanType = handlerMethod.getBeanType();
Controller controller = beanType.getAnnotation(Controller.class);
if(controller != null) {
modelAndView.addObject("locales", messagePool.getLocales());
modelAndView.addObject("messages", messagePool.getMessagesInJson().toString());
}
}
}
super.postHandle(request, response, handler, modelAndView);
}
}
μ΄μ ν νλ¦Ώ μμ§μμ μ£Όμ λ λΆκ° μ 보λ₯Ό μ¬μ©νμ¬ λ λλ§μ ν μ μκ² λ©λλ€.
μΈμ¦μ μν μΈν°μ ν°
λ λ€λ₯Έ μΈν°μ ν°μ νμ© λ°©μμ μΈμ¦ μ²λ¦¬μ λλ€. μ¬μ©μμκ² μ΄λ©μΌ λλ μΉ΄μΉ΄μ€ν‘ λ©μμ§λ±μ λ°μ‘νμ¬ μ΄λ€ νλμ ν μ μλ λ§ν¬λ₯Ό μ£Όκ² λλ€κ³ κ°μ ν΄λ³΄λ©΄ ν΄λΉ λ§ν¬λ₯Ό ν΅ν΄ λ€μ΄μ€λ μ¬μ©μμ μΈμ¦μ μννκΈ° μ μΌ μ μμ΅λλ€. μ΄λ μ£Όμ΄μ§λ λ§ν¬μ μμμ μΌλ‘ μΈμ¦μ μ¬μ©ν μ μλ λ§λ£μ± ν ν° νλΌλ―Έν°λ₯Ό ν¬ν¨μν΄μΌλ‘μ¨ μ¬μ©μλ₯Ό μΈμ¦νλ λ‘μ§μ μΆκ°ν μ μμ΅λλ€.
μ μμ μ΄λ―Έμ§μ μ΄λ©μΌ μΈμ¦νκΈ° λ²νΌμ λν λ§ν¬μλ μ½μΈμμμ λΆμν μ μλ μ΄λ ν νλΌλ―Έν°μ μΈμ¦μ μν μλ³ μ λ³΄κ° μμκ±°λΌ μΆμΈ‘ν©λλ€.
λ€μμ ν ν° νλΌλ―Έν° μ 무λ₯Ό νμΈνκ³ ν ν° νλΌλ―Έν°λ₯Ό λΆμνμ¬ μΈμ¦μ μννλ μΈν°μ ν° κ΅¬νμ μμμ λλ€.
public static class TokenBasedAuthenticationInterceptor implements HandlerInterceptor {
private static final String TOKEN_PARAMETER_NAME = "token";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String parameter = request.getParameter(TOKEN_PARAMETER_NAME);
if(parameter != null && !parameter.equals("")) {
// NOTE: ν ν° νλΌλ―Έν° λΆμ λ° κ²μ¦
String token = analyticsToken(parameter);
boolean valid = validateToken(token);
if(valid) {
// NOTE: ν ν° κΈ°λ° μΈμ¦ μ²λ¦¬
authenticationByToken(token);
}
return valid;
}
return false;
}
}
μΌμ μκ°μ΄ λ§λ£λλ©΄ ν΄λΉ ν ν°μΌλ‘λ μΈμ¦ν μ μκ³ μ΄λ―Έ μΈμ¦μ μννμ¬ μ¬μ©μ΄ μλ£λ ν ν°μΌλ‘ νμΈνλ κ²μ ν ν° νλΌλ―Έν° λΆμ λ° κ²μ¦ λ‘μ§μ ν¬ν¨λ κ²λλ€.
κ°λ¨νκ² HandlerInterceptorμ νμ© λ°©μ 3κ°μ§λ₯Ό νμΈν΄λ³΄μμ΅λλ€. μ ν리μΌμ΄μ λ§λ€ μꡬμ¬νμ΄ λ€λ₯΄κ³ 무κΆλ¬΄μ§ νκΈ° λλ¬Έμ HandlerInterceptorλ λ λ€μν λ°©μμΌλ‘ νμ©ν μ μμ κ²λλ€. μ΄μμΌλ‘ HandlerInterceptorμ μΈμ μ¬μ©νλμ?λ₯Ό λ§μΉκ² μ΅λλ€. κ°μ¬ν©λλ€.