Spring 7기 프로젝트/일정관리 프로젝트

Spring 컨트롤러 메서드의 파라미터에 자동으로 바인딩해주는 기능

JuNo_12 2025. 5. 21. 19:16

과제를 진행하던 중에 코드 리펙토링을 하려고 쭉 돌아보는데

컨트롤러 레이어에서 로그인 여부에 대한 로직이 각 메핑마다 반복되는 걸 보았다.

이에 불편함을 느껴서 이를 해결할 방법을 찾아보다가,  Spring ArgumentResolver라는 개념을 알게 되었다.

 

Spring ArgumentResolver란?

스프링 MVC에서는 컨트롤러 메서드의 파라미터에 값을 자동으로 바인딩해주는 기능이 있다.

예를 들어, @RequestParam, @PathVariable, @RequestBody 등은 모두 내부적으로 ArgumentResolver에 의해 처리된다.

 

HandlerMethodArgumentResolve

는 스프링에서 컨트롤러 메서드의 파라미터를 어떻게 처리할지를 결정하고, 필요한 값을 주입해주는 인터페이스다.

public interface HandlerMethodArgumentResolver {
    boolean supportsParameter(MethodParameter parameter); // 지원 여부 판단
    Object resolveArgument(...); // 실제 파라미터 주입
}

 

커스텀 ArgumentResolver 만들기 예시

컨트롤러에서 로그인한 유저 정보를 편리하게 받기 위해, 다음과 같이 사용하고 싶다고 가정:

@GetMapping("/profile")
public String profile(@LoginUser User user) {
    // 로그인 유저 정보 사용
}

 

1. 어노테이션 만들기

어노테이션 패키지를 따로 생성해주어서 이 인터페이스를 만들어주면 된다.

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

 

2. ArgumentResolver 구현

@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
    //  ArgumentResolver가 어떤 파라미터를 처리할 수 있는지 판단하는 메서드
    
        return parameter.hasParameterAnnotation(LoginUser.class)
               && parameter.getParameterType().equals(User.class);
               // 해당 파라미터에 @LoginUser 어노테이션이 붙어 있고
               // 파라미터의 타입이 User.class일 경우에만 이 resolver가 동작하도록 조건을 지정
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) {
              // supportsParameter()가 true를 반환했을 때, 
              // 스프링이 이 메서드를 호출해서 해당 파라미터에 어떤 값을 넣을지 결정
                
        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
        // 세션에 접근해주고
        return request.getSession().getAttribute("loginUser");
        // 로그인 시 세션에 저장된 "loginUser"라는 이름의 속성을 꺼내주어서
        // User 객체를 컨트롤러 메서드의 파라미터에 자동으로 주입해준다.
    }
}

 

3. WebMvcConfigurer에 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final LoginUserArgumentResolver loginUserArgumentResolver;

    public WebConfig(LoginUserArgumentResolver loginUserArgumentResolver) {
        this.loginUserArgumentResolver = loginUserArgumentResolver;
    }

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

 

4. 컨트롤러에서 사용

@GetMapping("/profile")
public String profile(@LoginUser User user) {
// @LoginUser 어노테이션이 붙은 User user 파라미터는,
// 앞서 만든 LoginUserArgumentResolver 덕분에 세션에서 자동으로 
// 로그인 사용자 정보를 꺼내서 주입받는 것

    System.out.println("로그인 유저: " + user.getName());
    return "profile";
}

 

 

 

실제 프로젝트에서 유저 인증, 세션 정보, 커스텀 객체 바인딩 등을 자동화할 때 매우 유용하다고 생각한다.