[Spring] ArgumentResolver

이준우·2024년 3월 14일
0

Arguement Resolver란?

  • 스프링의 디스패처 서블릿은 컨트롤러로 요청을 전달한다. 그때 컨트롤러에서 필요로 하는 객체를 만들고 값을 바인딩하여 전달하기 위해 사용된다.
  • 스프링에서 제공하는 ArgumentResolver 로 동작하는 어노테이션
    • @RequestParam : 쿼리 파라미터 값 바인딩
    • @ModelAttribute : 쿼리 파라미터 폼 및 데이터 바인딩
    • @CookieValue : 쿠키값 바인딩
    • @RequestHeader : 헤더값 바인딩
    • @RequestBody : 바디값 바인딩
  • 우리 프로젝트에서, 나는 사용자가 JWT를 이용해서 우리 서비스의 API에 접근할 때, JWT에서 사용자를 가져오는 작업을 ArgumentResolver로 구현하였다.
  • 즉 인증된 사용자의 객체를 주입받을 때, 중복되는 코드를 제거하기 위해 사용했다.

코드

ArgumentReslover코드 사용 예시

@PostMapping("/sign-up")
	public ResponseEntity<HttpStatus> register(@RequestBody MemberSignUpRequest memberSignUpRequest,
		@LoginMember Member member) {
		memberService.register(member, memberSignUpRequest);

		return ResponseEntity.status(HttpStatus.OK).build();
	}
  • 해당 코드는 MemberController 에 구현되어 있는 회원가입에 대한 코드이다.
  • register() 의 매개변수를 보면 @LoginMember Member member 를 볼 수 있을 것이다.
  • @LoginMember 의 역할은 헤더를 통해서 넘어온 JWT에서 사용자 정보를 가져와 Member member에 주입시켜주는 역할이다.
    • 즉, 인증된 사용자의 객체를 주입받기 위해 사용한다.

memberService.getLoginMember

  • 인증된 사용자의 객체를 불러오는 메서드
@Transactional(readOnly = true)
	public Member getLoginMember() {
		String accessToken = jwtService.extractAccessToken(request).orElseThrow(NotFoundTokenException::new);
		String email = jwtService.extractEmail(accessToken).orElseThrow(NotFoundEmailException::new);
		Member member = memberRepository.findByEmail(email).orElseThrow(NotFoundMemberException::new);

		return member;
	}
  1. 헤더에서 액세스 토큰을 추출한다.
  2. 추출한 액세스 토큰에서 사용자의 이메일을 추출한다.
  3. 추출한 이메일을 사용하여 DB에서 사용자를 가져온다.

만약 Resolver 를 구현하지 않았다면 Controller 에서 인증된 사용자 객체가 필요할 때마다, 위 메서드를 불러와야한다.
하지만 Resolver 를 구현함으로써, 반복되는 코드를 적는 것이 아닌 @LoginMember 를 통해서 인증된 사용자 객체를 주입받을 수 있게 되었다.

@LoginMember

  • Controller 에서 인증된 사용자 객체를 주입해주는 어노테이션.
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginMember {
}
  • @Target({ElementType.PARAMETER})
    • 어노테이션을 매개변수에 적용될 수 있음을 나타낸다.
  • @Retention(RetentionPolicy.RUNTIME)
    • 어노테이션 정보가 런타임동안 유지됨을 나타낸다
    • 어노테이션 정보를 프로그램이 동적으로 활용됨을 나타낸다.

LoginMemberArgumentResolver

  • Controller에서 @LoginMember 이 적용된 Member에 인증된 사용자 객체를 주입해주는 코드
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.example.memetory.domain.member.service.MemberService;
import com.example.memetory.global.annotation.LoginMember;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RequiredArgsConstructor
@Component
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {

	private final MemberService memberService;

	@Override
	public boolean supportsParameter(MethodParameter methodParameter) {
		return methodParameter.hasParameterAnnotation(LoginMember.class);
	}

	@Override
	public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
		NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
		return memberService.getLoginMember();
	}
}
  • HandlerMethoadArgumentResolver 는 컨트롤러 메서드의 매개변수를 해석하고 해당 매개변수에 값을 제공한다.
  • boolean supportsParameter()
    • 해당 Resolver가 주어진 매개변수를 처리할 수 있는지 여부를 결정한다.
    • @LoginMember 가 있는지 확인해주는 메서드이다.
  • Object resolveArgument()
    • 매개변수에 값을 제공해주는 로직이다. @LoginMember 가 적용된 변수에 인증된 사용자 객체(Member)를 주입해주는 Resolver의 메인 로직이다.
    • resolverArgument() 의 매개변수
      • MethodParameter methodParameter
        • 현재 처리중인 매개변수의 정보
      • ModelAndViewContainer modelAndViewContainer
        • 주로 뷰의 이름이나 모델 설정에 사용하는 객체
      • NativeWebRequest nativeWebRequest
        • 웹 요청과 관련된 정보를 얻을 수 있다.
      • WebDataBinderFactory webDataBinderFactory
        • 데이터 바인딩 및 유효성 검사에 사용

설정파일

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.example.memetory.global.resolver.LoginMemberArgumentResolver;

import lombok.RequiredArgsConstructor;

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

	private final LoginMemberArgumentResolver loginMemberArgumentResolver;

	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
		resolvers.add(loginMemberArgumentResolver);
	}
}
  • WebMvcConfigurer
    • 스프링 MVC에 대한 콜백을 제공하는 인터페이스이다.
    • 인터셉트 등의 다양한 기능을 추가할 수 있다.
  • addArgumentResolvers()
    • 컨트롤러 메서드의 매개변수를 처리하는 HandlerMethoadArgumentResolver 를 등록하는 역할을 한다.

Reference

profile
잘 살고 싶은 사람

0개의 댓글