오늘은 이것저것 하다가 늦게 집에 들어 왔지만 짧은 글이라 금방 할거 같다. 못하면 내일 해야지
오늘은 HandlerMethodArgumentResolver 인터페이스에 대해 알아보자. 나도 오늘 회사에서 일하다 알게 된 것이다. 왜 이제까지 이걸 몰랐지.. 아무튼 알아보자.
기준은 Spring boot이다. 마침 오늘 스프링부트 책이 왔는데 대충 넘겨보니 아는내용이 많지만 그래도 모르는 내용이나 잘못알고 있는 내용이 있을거 같아서 (영어도 못하는데
영문 문서로 힘들게 봐서…) 정독해서 읽어야 겠다.
서론이 너무 길었다.
HandlerMethodArgumentResolver 인터페이스의 역할은 간단하다. 컨트롤러에서 파라미터를 바인딩 해주는 역할을한다. 예를들어 특정클래스나 특정 어노테이션등의 요청 파라미터를 수정해야한다거나 또는 클래스의 파라미터를 조작, 혹은 공통적으로 써야하는 파라미터들을 바인딩 해주는 그런 역할이다. 말은 역시나 와닿지 않는다.
소스를 보면서 하자. 일단 필자는 로그인정보를 갖고 있는 그런 클래스 만들었다..

@Getter
@RequiredArgsConstructor
public class LoginUser {
  private final String username;
  private final String name;
}

위의 클래스는 바인딩 대상의 클래스이다. username과 name이 존재한다.

public class UserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
  @Override
  public boolean supportsParameter(MethodParameter parameter) {
    return LoginUser.class.isAssignableFrom(parameter.getParameterType());
  }

  @Override
  public LoginUser resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    return new LoginUser("leeww", "wonwoo");
  }
}

실질적으로 HandlerMethodArgumentResolver 인터페이스 구현한 클래스이다. 두개의 추상 메서드가 있는데 supportsParameter 메서드는 바인딩할 클래스를 지정해주면 된다. 여기서는 LoginUser 클래스를 지정하였다. resolveArgument메서드는 바인딩할 객체를 조작할 수 있는 그런 메서드다. 이 예제에서는 그냥 아무 로직없이 넣어주었는데 유저 정보를 가져오는 그런 로직이 들어 가면 되겠다.

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

대충 이런코드가 들어가면 맞지 않나 싶다. webRequest 에서도 뺄수 있을거 같은데..

마지막으로 설정을 해줘야하는데 WebMvcConfigurerAdapter 클래스를 보면 addArgumentResolvers 메서드가 있다. 그걸 오버라이딩 해서 넣어주면 된다. xml 설정은 다 까먹었다. 별로 xml 설정은 하고 싶지 않아서..

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
  @Override
  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(new UserHandlerMethodArgumentResolver());

  }
}

설정 까지 되었다면 테스트를 해보자.

@RestController
public class UserController {

  @GetMapping("userTest")
  public LoginUser loginUser(LoginUser loginUser){
    return loginUser;
  }
}

LoginUser라는 클래스에는 아무 파라미터를 넣지 않아도 테스트를 해보면 위에서 넣어둔 (new LoginUser(“leeww”, “wonwoo”)) username은 leeww name은 wonwoo가 출력 될 것이다.

이렇게 공통적으로나 다른 어떤 클래스를 바인딩 시킬때나 조작할 때 사용하면 될 것이다. 이외에도 우리가 흔히 쓰던 @RequestParam, @RequestBody, @ModelAttribute, Model 등등 기타 컨트롤러에서 받을수 있는 어노테이션과 클래스 여러개가 위의 인터페이스를 사용해서 구현되어 있다. 구현체들은 많으니 참고해서 개발하면 되겠다.
오늘은 늦었으니 짧게만 써야겠다. 글은 딱히 읽지 않아도 소스만 보면 거의 다 알지 않나 싶다.