본문 바로가기

더 나은 엔지니어가 되기 위해/지금은 안쓰는 자바

[부스트코스 웹 프로그래밍] 인터셉터와 아규먼트 리졸버

부스트코스 웹 프로그래밍 BE 영상을 보며 공부한 것을 간단히 정리한다.

1. 인터셉터

인터셉터 (Interceptor)

인터셉터는 다음의 상황에서 뭔가를 제어해야할 때 동작하는 객체다.

  • Dispatcher servlet -> Handler(Controller) 요청을 보낼 때
  • Handler -> Dispathcer servlet 응답을 보낼 때

예를 들어, 요청이 오고 로그를 기록해야 할 때 인터셉터를 활용할 수 있다.

출처 : https://www.edwith.org/boostcourse-web/lecture/16804/

구현

1) 커스텀 HandlerInterceptor 구현

HandlerInterceptorAdapter 를 상속받아 기존의 HandlerInterceptor 의 메쏘드를 오버라이드 하면 된다.

public class LogInterceptor extends HandlerInterceptorAdapter{

  // Handler 에 들어가기 전
  @Override
  public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
    System.out.println(handler.toString() + " 를 호출했습니다.");
    return true;
  }

  // Handler 가 끝난 후
  @Override
  public void postHandle(HttpServletRequest request, 
                         HttpServletResponse response, 
                         Object handler,
                         ModelAndView modelAndView) throws Exception {
    System.out.println(handler.toString() + " 가 종료되었습니다.  " + modelAndView.getViewName() + "을 view로 사용합니다.");
  }
}

2) WebMvcContextConfiguration 에 등록

이후, WebMvcContextConfiguration 이렇게 내가 만든 인터셉터를 등록하면 된다.

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"org.example.guestbook.controller"})
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {

  ...

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LogInterceptor());
  }

  ...
}

3) 결과

org.example.guestbook.controller.FileController.uploadform() 를 호출했습니다.
org.example.guestbook.controller.FileController.uploadform() 가 종료되었습니다.
list 을 view로 사용합니다.

2. 아규먼트 리졸버

아규먼트 리졸버 (Argument Resolver)

컨트롤러 메소드에서 자주 사용되는 값이 있을 경우, 아규먼트 리졸버를 만들어서 넘겨주도록 하면 편리하게 사용할 수 있다.
예를 들어 다음과 같이 사용자가 정의한 HeaderInfo 에 세션에 대한 데이터를 담고, 이 클래스를 요청 파라미터에 추가하여, 컨트롤러에서 활용할 수 있다.

@GetMapping(path="/list")
public String list(...,
                   HeaderInfo headerInfo) {
  ...
  System.out.println(headerInfo.get("user-agent"));
  ...
}

구현

아규먼트 리졸버에 관련해 새로 생성하는 파일들은 config, controller 등의 패키지와 동일한 디렉토리에서 argumentresolver 패키지를 새로 생성해 여기에 담는다.

1) 데이터를 담을 클래스 정의

public class HeaderInfo {
    private Map<String, String> map;

    public HeaderInfo() {
        map = new HashMap<>();
    }

    public void put(String name, String value) {
        map.put(name, value);
    }

    public String get(String name) {
        return map.get(name);
    }
}

2) 커스텀 ArgumentResolver 구현

HandlerMethodArgumentResolver 를 상속받아 메쏘드 오버라이딩을 통해 구현한다.
여기서는 세션의 헤더정보를 담아본다.

public class HeaderMapArgumentResolver implements HandlerMethodArgumentResolver {

  @Override
  public boolean supportsParameter(MethodParameter methodParameter) {
    return methodParameter.getParameterType() == HeaderInfo.class;
  }

  @Override
  public Object resolveArgument(MethodParameter methodParameter, 
                                ModelAndViewContainer modelAndViewContainer, 
                                NativeWebRequest nativeWebRequest, 
                                WebDataBinderFactory webDataBinderFactory) throws Exception {

    // 우리가 정의한 클래스 객체 생성
    HeaderInfo headerInfo = new HeaderInfo(); 

    // 세션의 헤더 정보를 headerInfo 에 담는다.
    Iterator<String> headerNames = nativeWebRequest.getHeaderNames();
    while (headerNames.hasNext()) {
      String headerName = headerNames.next();
      String headerValue = nativeWebRequest.getHeader(headerName);
      headerInfo.put(headerName, headerValue);
    }

  return headerInfo;
  }
}

3) WebMvcContextConfiguration 에 등록

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"org.example.guestbook.controller"})
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {

  ...

  @Override
  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(new HeaderMapArgumentResolver());
  }

  ...
}

4) 사용

다음과 같이 파라미터로 입력받아 사용 가능하다.

@GetMapping(path="/list")
public String list(...,
                   HeaderInfo headerInfo) {
  ...
  System.out.println(headerInfo.get("user-agent"));
  ...
}