Notice
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
01-10 04:46
Today
Total
관리 메뉴

그날그날 공부기록

ArgumentResolver 본문

Spring 공부

ArgumentResolver

given_dragon 2023. 12. 19. 13:50

231218 ArgumentResolver

argument resolver는 요청의 메서드 파라미터를 인자값으로 변환하기 위한 전략 인터페이스이다.

인터페이스에는 아래와 같이 2개의 메서드가 있다.

public interface HandlerMethodArgumentResolver {

    boolean supportsParameter(MethodParameter parameter);

    @Nullable
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}
  • supportsParameter()
    • 주어진 메서드 파라미터가 해당 Resolver를 지원하는지 확인하는 로직 구현
  • resolveArgument()
    • supportsParameter()에서 true값이 반환될 경우 실행되는 메서드
    • 메서드 파라미터를 인자값으로 변환하여 반환.
    • ModelAndViewContainer
      • 현재 요청의 모델 컨테이너
    • NativeWebRequest
      • 현재 요청(request)
    • WebDataBinderFactory
      • 데이터 바인딩에 사용하는 WebDataBinder 인스턴스 생성

 

다음은 ArgumetResolver를 통해 개선할 코드인 홈페이지의 home컨트롤러의 메서드이다.

@SessionAttribute를 통해 세션에 저장되어 있는 Member객체를 바인딩하고, 유무를 통해 사용자의 로그인 여부를 확인한다.

이 메서드에서 @SessionAttribute 대신, 커스텀 어노테이션과 Argument Resolver를 통해 깔끔하게 처리할 수 있다.

@GetMapping("/")
public String homeLogin(@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model model) {
    if (loginMember == null) {
        return "home";
    }
    model.addAttribute("member", loginMember);
    return "loginHome";
}

-->

@GetMapping("/")
    public String homeLogin(@Login Member loginMember, Model model) {

        if (loginMember == null) {
            return "home";
        }
        model.addAttribute("member", loginMember);
        return "loginHome";
    }

 

 

이제 커스텀 어노테이션 @Login 만들어보자.

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Login {
}
  • @Target
    • 해당 어노테이션이 적용될 수 있는 종류를 지정한다.
  • @Retention
    • 어노테이션의 보유 정책을 지정
    • 런타임에도 유지되도록 설정하고, 리플렉션을 통해 해당 어노테이션을 조최하고 처리 가능.

 

 

HandlerMethodArgumentResolver를 구현한다.

@Slf4j
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        log.info("supportsParameter 설정");

        boolean hasLoginAnnotation = parameter.hasParameterAnnotation(Login.class);
        boolean assignableType = Member.class.isAssignableFrom(parameter.getParameterType());

        return hasLoginAnnotation && assignableType;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        log.info("resolveArgument 실행");
        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
        HttpSession session = request.getSession(false);
        if (session == null) {
            return null;
        }

        return session.getAttribute(SessionConst.LOGIN_MEMBER);
    }
}
  • supportsParameter()
    • 해당 인자에 @Login이 있는지 확인한다.
    • 해당 인자가 Member 타입인지 확인한다.
  • resolveArgument()
    • request에서 세션을 가져온다.
    • 가져온 세션에서 Member 객체를 반환하여 파라미터에 전달한다.

 

 

LoginMemberArgumentResolver를 Config파일에 등록하면 작동한다.

@Configuration
public class WebConfig implements WebMvcConfigurer {

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

WebMvcConfigurer의 addArgumentResolvers를 오버라이드 하고, 추가한다.

@SessionAttribute를 사용했을 때와 실행 결과는 동일하지만 가독성이 좋고, 재사용도 편리하다.

 
Comments