스프링 부트에서 API controller를 생성할 때 가끔 정보를 가져오기 위해 httpservletrequest에서 정보를 받아와 사용하였다. 하지만 Service에 httpservletreqeust를 바로 전달하는 것은 3 Layer Architecture에 위반한다고 들어 Argument Resolver를 사용하는 방법을 이번 프로젝트에 응용해 보았다.
🚀 ArgumentResolver
ArgumentResolver는 Spring MVC에서 컨트롤러 메서드의 매개변수를 해석하고 주입하는 기능을 확장하기 위해 사용된다. 일반적으로, Spring MVC는 기본적인 매개변수 유형에 대해 자동으로 매핑을 해주지만, 복잡한 객체나 특수한 상황에서는 이 기능을 확장해야 할 때가 있다. 이때 ArgumentResolver를 사용한다.
주요 역할:
컨트롤러 메서드의 매개변수에 대해 특정한 로직을 적용하여 값을 주입하는 기능을 제공한다. 예를 들어, 사용자 정의 객체를 매개변수로 받을 때, 해당 객체를 생성하거나 특정한 방식으로 초기화하고 싶을 때 사용할 수 있다.
구현 방법:
- HandlerMethodArgumentResolver 인터페이스 구현
- supportsParameter(MethodParameter parameter): 이 메서드는 현재 매개변수가 ArgumentResolver에서 지원하는 타입인지 여부를 반환합니다. 이 메서드가 true를 반환하면, 해당 매개변수에 대해 resolveArgument 메서드가 호출된다.
- resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory): 이 메서드는 실제로 매개변수를 해석하고, 주입할 값을 반환한다.
- 사용 시나리오:
- 사용자 정의 객체를 컨트롤러 메서드에서 직접 받으려는 경우
- 요청에 따라 특정 객체를 동적으로 생성하고 싶은 경우
- 특정한 전처리나 후처리가 필요한 경우
이를 통해 코드의 재사용성과 유연성을 높일 수 있으며, Spring MVC가 제공하는 기본적인 매개변수 주입 기능을 확장할 수 있다.
🔡 예시
public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver {
// @Auth 어노테이션이 있는지 확인
@Override
public boolean supportsParameter(MethodParameter parameter) {
boolean hasAuthAnnotation = parameter.getParameterAnnotation(Auth.class) != null;
boolean isAuthUserType = parameter.getParameterType().equals(AuthUser.class);
if(hasAuthAnnotation != isAuthUserType) {
throw new IllegalArgumentException("@Auth Annotation 와 AuthUser Type 은 함꺠 사용되어야 합니다.");
}
return hasAuthAnnotation;
}
// AuthUser 객체를 생성하여 반환
@Override
public Object resolveArgument(
@Nullable MethodParameter parameter,
@Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
@Nullable WebDataBinderFactory binderFactory
) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
// JwtFilter 에서 set 한 userId, email 값을 가져옴
Long userId = (Long) request.getAttribute("userId");
String userName = (String) request.getAttribute("userName");
String email = (String) request.getAttribute("email");
return new AuthUser(userId, userName, email);
}
}
위코드를 사용하면 먼저 컨트롤러에 @Auth annotation과 클래스 타입이 AuthUser 인지 확인해 준다. 그 뒤 JWT 토큰에서 request에 담아주었던 값들 (이경우에는 userId, userName, email)등을 받아와 알맞은 데이터 타입으로 저장한 뒤 AuthUser 생성자에 대입하여 객체를 생성한 뒤 반환해 준다.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
}
@Getter
public class AuthUser {
private final Long id;
private final String userName;
private final String email;
public AuthUser(Long id,String userName,String email){
this. id = id;
this.userName = userName;
this.email = email;
}
}
Auth annotation과 AuthUser 파일 내 코드는 위와 같다. @Target,@Retention을 사용한 뒤 @Inteface로 Auth annotation을 커스텀으로 생성하여 사용할 수 있다. AuthUser클래스내부에는 원하는 필드명과 타입을 지정해 준 뒤 생성자를 만들어주면 된다.
Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
// ArgumentResolver 등록
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new AuthUserArgumentResolver());
}
}
그 뒤 Webconfig 클래스를 사용하여 Argument resolver를 등록하여 사용하면 된다. WebConfig는 WebMvcConfiguerer 인터페이스를 implement 받아 Spring MVC configuration을 커스텀할 수 있게 한다.

이를 사용하여 위에 등록한 AuthUserArgumentResolver를 Spring MVC에 등록하여 @Auth 어노테이션 밑 AuthUser를 사용하여 원하는 데이터를 위와 같이받아올 수 있게 해 준다.
'Spring' 카테고리의 다른 글
[SpringBoot]MyBatis (2) | 2024.10.01 |
---|---|
[SpringBoot]Api Response (0) | 2024.09.06 |
[SpringBoot]Entity 연관관계 방향성 (0) | 2024.08.29 |
[SpringBoot] NaverOpen API 사용 (0) | 2024.08.29 |
[SpringBoot]환경변수 application.properties (0) | 2024.08.28 |