본문 바로가기
Spring

[Spring] ArgumentResolver 추가 방법 (kotlin ver.)

by 노력남자 2022. 12. 18.
반응형

ArgumentResolver란?

 

@RestController
class UserController {
    
    @GetMapping("/user/{userId}")
    fun getUser(
        @PathVariable userId: Long << 여기
    ) {
        // ...
    }
}

 

controller에 @PathVariable을 붙이면 path에서 자동으로 파라미터에 맵핑을 해주는데 이걸 바로 ArgumentResolver가 해준다.

(@PathVariable는 PathVariableMethodArgumentResolver.java에서 처리)

 

@RequestParam, @RequestBody도 마찬가지다.

 

그럼 이걸 누가 호출할까?

 

 

바로 핸들러 어댑터가 호출한다.

 

핸들러 어댑터가 핸들러를 호출할 때 핸들러의 파라미터를 읽어 그에 해당하는 ArgumentResolver를 찾아서 호출한다.

 

ArgumentResolver 추가 방법

 

스프링에서 우리가 필요한 대부분을 추가해놔서 거의 추가할 일이 없지만 가끔 쓸일이 있다.

 

header에 token을 받아 UserInfoResponse를 만들어주는 ArgumentResolver를 추가하는 걸 예시로 설명하겠다.

 

@RestController
class UserController {
    
    @GetMapping("/user")
    fun getUser(
        user: UserInfoResponse << token 헤더를 읽어 UserInforResponse 생성
    ): UserInfoResponse {
        return user
    }
}

 

추가 방법은 다음과 같다.

 

ArugmentResolver 정의 -> WebMvcConfigurer에 추가

 

정말 간단하다.

 

1. ArgumentResolver 정의

 

HandlerMethodArgumentResolver를 구현한 클래스를 만들어야 한다.

 

public interface HandlerMethodArgumentResolver {

	boolean supportsParameter(MethodParameter parameter);

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

}

 

구현해야 할 메소드는 2개다.

 

supportsParameter : 어떤 파라미터를 처리할 건지

resolveArgument : 어떤 값을 만들 건지

 

header에 token 값을 읽어서 해당 유저 정보를 리턴해주는 UserInfoArgumentResolver를 만들어보자.

 

@Component
class UserInfoArgumentResolver(
    val userRepository: UserRepository
): HandlerMethodArgumentResolver {

    override fun supportsParameter(parameter: MethodParameter): Boolean {
        return parameter.parameterType == UserInfoResponse::class.java // 타입
                || parameter.hasMethodAnnotation(UserInfo::class.java) // 어노테이션
    }

    override fun resolveArgument(
        parameter: MethodParameter,
        mavContainer: ModelAndViewContainer?,
        webRequest: NativeWebRequest,
        binderFactory: WebDataBinderFactory?
    ): Any? {
        val token = webRequest.getHeader("token") as String
        val user = userRepository.findByToken(token)

        return UserInfoResponse(
            id = user.id,
            name = user.name
        )
    }
}

 

2. WebMvcConfigurer에 추가

 

WebMvcConfigurer를 구현한 클래스를 만들어야 한다.

 

위에서 만든 UserInfoArgumentResolver를 추가해보겠다.

 

@Component
class WebMvcConfig(
    val userInfoArgumentResolver: UserInfoArgumentResolver
): WebMvcConfigurer {

    override fun addArgumentResolvers(resolvers: MutableList<HandlerMethodArgumentResolver>) {
        resolvers.add(userInfoArgumentResolver)
    }
}

 

※ 결과

 

위에서 정의한 ArgumentResolver가 정상적으로 동작하는지 보자.

 

- request

curl --location --request GET 'http://localhost:8080/user' \
--header 'token: ASDA1321DKDL'

 

- response

{
    "id": 1,
    "name": "유저명"
}

 

잘 동작한다.

반응형

댓글