[Spring/Springboot]HandlerMethodArgumentResolver를 통해 Controller의 파라미터 자동처리하기

Juseong Han·2022년 9월 13일
1

궁금증

컨트롤러에서 특정한 데이터를 자주 받아들여야 하는 경우에 공통된 서비스 로직을 거치지 않고 파라미터에 annotation을 붙이는 것으로 데이터 바인딩이 가능할까?

해결법

HandlerMethodArgumentResolver를 사용하여 해결가능하다. 아래 방법은 JpaRepository를 이용한다. 해결에 쓰이는 것은 DB상의 모든 User를 가져오는 것으로 예시를 위함이니 User 보안상 실제로는 똑같이 따라하지는 않길바란다.

HandlerMethodArgumentResolver란

이러한 상황에 대처가 가능한 Spring Framework 3.1부터 지원하는 인터페이스이다. 공식문서는 여기 참고
크게 두 가지의 메소드가 있다.

boolean supportsParameter(MethodParameter parameter)

위 메소드는 파라미터의 지원 여부를 결정한다 true를 리턴하는 경우 argument resolve가 시작된다.

Object resolveArgument(...)

위 메소드는 실제로 해당 인자를 풀어주는 역할을 한다.

1. 모든 User를 반환하는 CustomAnnotation 만들기

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserList {
}

2. HandlerMethodArgumentResolver 구현체 만들기

@RequiredArgsConstructor
@Component
public class CustomArgumentResolver implements HandlerMethodArgumentResolver {
	// Autowired By Constructor
	private final UserRepository userRepository;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
    	// 파라미터에 붙은 어노테이션이 @UserList 인지
        boolean isUserListAnnotation = parameter.getParameterAnnotation(UserList.class) != null;
        // 파라미터의 타입이 java.util.List 인지
        boolean isList = parameter.getParameterType().equals(List.class);
        // 파라미터의 제네릭 타입이 User인지
        boolean isUserGeneric = parameter.getGenericParameterType().equals(User.class);
        // 세가지를 모두 충족한다면 true를 반환
        return isUserListAnnotation && isList && isUserGeneric;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        // 해당 파라미터에 다음 값 바인딩
        return userRepository.findAll();
    }
}

3. WebMvcConfigurer에 ArgumentResolver 등록

@RequiredArgsConstructor
@SpringBootConfiguration
public class MvcWebConfig implements WebMvcConfigurer {

    private final CustomArgumentResolver customArgumentResolver;

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

}

4. Controller에서 활용

@RestController
public class MyController {

	@RequestMapping("/example")
	public ResponseEntity<?> someReq(@UserList List<User> userList) {
    	// something to do..
    }
}

마무리

공통으로 처리되는 데이터를 Annotation을 통해 메소드 파라미터로 호출하면 자동으로 바인딩 되는 기술이라 로그인 여부를 확인하거나 공용 데이터를 다룰 때 유용하게 쓰일 수 있는 기능이다.

profile
개발이 하고 싶어요💻 개발이 너무 재밌는 Juseong입니다.🖐

0개의 댓글