글 작성자: 자바니또

이번 포스팅에서는 HandlerMethodArgumentResolver를 이용하여 메서드 파라미터에서 사용할 어노테이션을 만들어 본다.
Spring Boot에서 세션의 값을 가져오는 여러 방법이 있지만 가장 간단한 방법은 다음과 같다.

SessionUser user = (SessionUser)httpSession.getAttribute("user");    // "user"로 저장 되어있는 세션객체 SessionUser를 꺼내온다.

이 방법은 여러 컨트롤러에서 세션 값이 필요 할 때마다 직접 세션에서 값을 가져와야 하는 코드 중복이 발생한다. 메서드 인자로 세션 값을 바로 받을 수 있도록 변경해 보자.

목차

  • 어노테이션 기반으로 개선하기
    • @LoginUser 생성하기
    • HandlerMethodArgumentResolver 구현 클래스 생성하기
    • WebMvcConfigurer 구현 클래스 생성하기

어노테이션 만들기

해야 할 것은 다음과 같다.

  1. 사용할 어노테이션 클래스 생성하기
  2. 어노테이션 클래스를 사용하기 위한 환경을 구성하는 HandlerMethodArgumentResolver구현 클래스를 생성하여 유효성 체크메서드(supportParameter)와 객체를 주입시켜주는 메서드(resolveArgument)를 오버라이드하고, 빈으로 만든다.
  3. Resolver가 스프링에서 인식될 수 있도록 WebMvcConfigurer 구현 클래스를 생성하여 HandlerMethodArgumentResolver리스트에 2번에서 만든 Resolver추가하기.

1. @LoginUser 생성하기

가장 먼저 애노테이션 클래스를 생성해보자.

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser{
}
  • @Target(ElementType.PARAMETER)
    : 이 어노테이션이 생성될 수 있는 위치를 지정한다. PARAMETER로 지정했으니 메서드의 파라미터로 선언된 객체에서만 사용할 수 있다.
  • @Retention(RetentionPolicy.RUNTIME)
    : 어노테이션을 런타임 시 까지 사용하겠다는 의미이다. JVM이 런타임 환경을 구성하고 종료할 때 까지 메모리가 살아있다. 그 밖의 SOURCE, CLASS가 있다. SOURCE는 사실상 주석처럼 사용하는 것이고, CLASS는 런타임 시 메모리가 사라진다. 그렇기 때문에 리플렉션으로 선언된 애노테이션 데이터를 가져올 수 없다.

2. HandlerMethodArgumentResolver 구현 클래스 생성하기

@LoginUser를 사용하기 위한 환경을 구성하기 위해 LoginUserArgumentResolver 를 만들어보자.
이때 WebMvcConfigurer가 가져올 수 있도록 @Component를 붙인다.

@RequiredArgsConstructor
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {
    private final HttpSession httpSession;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        boolean isLoginUserAnnotation 
                = parameter.getParameterAnnotation(LoginUser.class) != null;
        boolean isUserClass = SessionUser.class.equals(parameter.getParameterType());

        return isLoginUserAnnotation && isUserClass;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter
                                ,ModelAndViewContainer mavContainer
                                ,NativeWebRequest webRequest
                                ,WebDataBinderFactory binderFactory) throws Exception {
        return httpSession.getAttribute("user");
    }
}
  • supportsParameter()
    : 컨트롤러 메서드의 특정 파라미터를 지원하는지 판단한다. 여기서는 @LoginUser 가 붙어 있고, 파라미터 클래스 타입이 SessionUser.class인 경우 true를 반환 한다.

  • resolveArgument()
    : 파라미터에 전달할 객체를 생성한다. 여기서는 세션에서 객체를 가져온다.

3. WebMvcConfigurer 구현 클래스 생성하기

LoginUserArgumentResolver가 스프링에서 인식될 수 있도록 WebMvcConfigurer를 추가하자. 이때 스프링부트에서 설정클래스로 인식할 수 있도록 @Configuration을 붙여야 한다.

@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
    private final LoginUserArgumentResolver loginUserArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArguementResolver> argumentResolvers) {
        argumentResolvers.add(loginUserArgumentResolver);
    }
}

참고