WebArgumentResolver

이동훈·2023년 8월 2일
2

서론

(Spring 3.0- : WebArgumentResolver) - Deprecated
(Spring 3.1+ : HandlerMethodArgumentResolver)

숨쉬듯 사용해온 @RequestParam, @RequestBody, @AuthenticationPrincipal 등등.
우리에게 편리함을 안겨주는, 파라미터로 받는 이 Annotation들은 어째서 사용이 가능한걸까?

Spring Boot에는 HandlerMethodArgumentResolver를 implements한 많은 구현체가 존재하기 때문이다.

@RequestParam:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.html
@RequestBody:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/result/method/annotation/RequestBodyMethodArgumentResolver.html

http 요청 파라미터나, form 데이터 등을 간편하게 받아쓸 수 있게 해주는 interface, WebArgumentResolver와 HandlerMethodArgumentResolver를 알아보자.


효과

사용자 요청이 Controller에 도달하기 전에 그 요청의 파라미터들을 수정할 수 있도록 해준다.

왜? HttpServletRequest에서 뽑아쓰면 될텐데?

  • 매번 뽑아쓰는건 비효율적이고, 코드도 지저분해진다.

사용자 정의 구현체

예시 코드)

public class CustomWebArgumentResolver implements WebArgumentResolver {
    @Override
    public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception {
        if (methodParameter.getParameterType().equals(Map.class)) {
            Map<String, String> paramMap = new HashMap<>();
            Enumeration<String> parameterNames = webRequest.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                String paramName = parameterNames.nextElement();
                String paramValue = webRequest.getParameter(paramName);
                paramMap.put(paramName, paramValue);
            }
            return paramMap;
        }
        return UNRESOLVED;
    }
}

MethodParameter는 컨트롤러 메서드의 파라미터 정보와 관련된 데이터를 담고 있으며,
NativeWebRequest는 웹 요청과 관련된 데이터를 추상화하여 제공한다.

Controller에서 parameter로 사용하기 위해
반환할 Map을 선언해준 뒤,

parameterType과 (HttpServletRequest) webRequest.getNativeRequest()을 가지고 iterator를 돌려 Map을 채우자.

세션 등에 넣을 공통처리 코드가 있으면 이 클래스에서 미리 처리 해주는 것도 가능하다.


Controller

예시 코드)

@RequestMapping("/processForm")
public String processForm(@RequestParam Map<String, String> commandMap) {
    // 컨트롤러 로직
}

Controller 단에서는 위와 같이 parameter로 받으면 된다.
단, 구현체에서 정의했던 타입과 이름이 일치해야 한다.


등록

구현체 생성은 끝났다. 그런데 아직은 Dispatcher Servlet이 클래스를 알지 못한다.
이 클래스를 인식시키기 위해선 bean을 등록해야 한다.

1. XML

dispatcher-servlet.xml에 등록을 시키자.

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <!-- 여기에 필요한 프로퍼티들 설정 -->
    </bean>
    
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <!-- 여기에 필요한 프로퍼티들 설정 -->
    </bean>

등록시킬 bean 타깃은

AnnotationMethodHandlerAdapter(Spring 3.0 이전), Requestmappinghandleradapter(Spring 3.1 이후) 이다.
여기에 property로서 추가시키면 된다. 여러 클래스를 등록하는 것이 가능하다.

2. WebMvcConfigurer

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

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

위와 같이 등록하면 된다.


Deprecated

Spring 3.1 이상에서, WebArgumentResolver가 Deprecated되고 HandlerMethodArgumentResolver로 대체, 확장되었다.

작성일(2023.08.02) 기준 최신 Spring 버전이 무려 6.0.11이다.
3.1 버전의 릴리즈가 2011.12.13이니 강산이 바뀌도록 넘은 셈이다.

하지만 오래도록 유지보수 되어온 프로젝트의 경우, 여전히 WebArgumentResolver를 사용하는 것들이 존재하니 공부가 필요하다.


다음 포스팅은 WebArgumentResolver에서 HandlerMethodArgumentResolver로 넘어가면서,
무엇이 달라졌고 어떤 기능이 추가되었고 응용할 수 있는 것들은 무엇인지에 대해 다루어 보고자 합니다.

profile
Fool Snack Developer

2개의 댓글

comment-user-thumbnail
2023년 8월 2일

많은 도움이 되었습니다, 감사합니다.

답글 달기
comment-user-thumbnail
2023년 8월 2일

기본형 반환 Object로 다양한 타입별 대응이 가능하군요 :) 유익해요

답글 달기