본문 바로가기
JAVA

아규먼트 리졸버(Argument Resolver)

by enai 2019. 8. 26.

아규먼트 리졸버(Argument Resolver)는 사용자가 컨트롤러의 메서드 인자값으로 임의의 값을 전달하려할 때 사용된다.

예를 들어, 세션에 저장되어 있는 값 중, 특정 이름의 값을 메서드 인자로 전달한다.

 

아규먼트 리졸버 작성 방법

  1. org.springframework.web.method.support.HandlerMethodArgumentResolver를 구현한 클래스 작성
  2. supportsParameter 메서드를 오버라이딩 한 후, 원하는 타입의 인자가 있는지 검사하여 있으면 true를 리턴하도록 한다.
  3. resolveArgument 메서드를 오버라이딩한 후, 메서드의 인자로 전달할 값을 리턴한다.

 

  • Java Config에 설정하는 방법
    • WebMvcConfigurerAdapter를 상속받은 Java Config 파일에서 addArgumentResolvers 메서드를 오버라이딩한 후, 원하는 아규먼트 리졸버 클래스 객체를 등록한다.
  • xml 파일에 설정하는 방법
    • xml 파일에 다음과 같은 내용을 추가한다.
  <mvc:annotation-driven>
    <mvc:argument-resolvers>
    <bean class="아규먼트리졸버클래스"></bean>      
    </mvc:argument-resolvers>
  </mvc:annotation-driven>

 

 

Spring MVC가 제공하는 기본 Argument Resolver들이 아주 많다.

Controller 메서드에 HttpServletRequest나 HttpSession 등을 적으면 값이 전달된다. 이런 일이 가능한 것이 기본 Argument Resolver가 있기 때문이었다.

소스 코드의 getDefaultArgumentResolvers() 메서드에서 resolvers.add로 기본으로 설정되는 Argument Resolver들을 확인할 수 있다.

 

 

참고로 Map 객체나 Map을 상속받은 객체는 스프링에서 이미 선언한 아규먼트 리졸버가 처리하기 때문에 전달할 수 없다.

그래서 Map 객체를 전달하려면 Map 객체를 필드로 가지고 있는 별도의 객체를 선언한 후에 사용해야 된다.

 

Map 객체를 전달하는 아규먼트 리졸버 만들기 예제:

헤더 정보를 Map으로 가져오는 아규먼트 리졸버를 만들어 보겠다.

 

1) Map 객체를 필드로 가지는 별도의 객체를 먼저 만든다.

HeaderInfo.java

package kr.or.connect.guestbook.argumentresolver;

import java.util.HashMap;
import java.util.Map;

public class HeaderInfo {
  private Map<String, String> map;

  public HeaderInfo() {
  map = new HashMap<>();
  }

  public void put(String name, String value) {
  map.put(name, value);
  }

  public String get(String name) {
  return map.get(name);
  }
}

 

2) HandlerMethodArgumentResolver를 구현하는 클래스를 만든다.

HeaderMapArgumentResolver.java

package kr.or.connect.guestbook.argumentresolver;

import org.springframework.web.method.support.HandlerMethodArgumentResolver;

public class HeaderMapArgumentResolver implements HandlerMethodArgumentResolver {


}

 

3) 2번에서 생성한 클래스에 supportsParameter 메서드를 오버라이딩 한 후, 원하는 타입의 인자가 있는지 검사하여 있으면 true를 리턴하도록 한다.

@Override
public boolean supportsParameter(MethodParameter parameter) {
  return parameter.getParameterType() == HeaderInfo.class;
}

이 아규먼트 리졸버에선 supportsParameter 메서드가 제일 먼저 실행된다.

supportsParameter 메서드는 컨트롤러 메서드 인자에 헤더 정보를 가져오는 HeaderInfo가 있는지 검사한다. 있으면 true, 없으면 false를 반환한다.

 

4) 2번 클래스에 resolveArgument 메서드를 오버라이딩한 후, 메서드의 인자로 전달할 값을 리턴한다.

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

  HeaderInfo headerInfo = new HeaderInfo();

  Iterator<String> headerNames = webRequest.getHeaderNames();
  while(headerNames.hasNext()) {
  String headerName = headerNames.next();
  String headerValue = webRequest.getHeader(headerName);
  //System.out.println(headerName + " , " + headerValue);
  headerInfo.put(headerName, headerValue);
  }

  return headerInfo;

}

supportsParameter가 true를 반환하면 이 resolveArgument 메서드가 실행된다.

NativeWebRequest로 헤더의 name들을 가져와 Iterator 형태로 담았고, while문으로 헤더의 이름과 헤더의 값들을 얻어와, headerInfo에 담았다.

주석처리된 System.out.println()으로 해당 헤더 이름과 값을 콘솔 창에 출력해 볼 수 있다.

마지막으로, 헤더 정보를 담은 headerInfo 객체를 반환한다.

 

-> HeaderMapArgumentResolver.java

package kr.or.connect.guestbook.argumentresolver;

import java.util.Iterator;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

public class HeaderMapArgumentResolver implements HandlerMethodArgumentResolver {
  @Override
  public boolean supportsParameter(MethodParameter parameter) {
    return parameter.getParameterType() == HeaderInfo.class;
  }

  @Override
  public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

    HeaderInfo headerInfo = new HeaderInfo();

    Iterator<String> headerNames = webRequest.getHeaderNames();
    while(headerNames.hasNext()) {
      String headerName = headerNames.next();
      String headerValue = webRequest.getHeader(headerName);
      //System.out.println(headerName + " , " + headerValue);
      headerInfo.put(headerName, headerValue);
    }

    return headerInfo;

  }
}

이렇게 구현이 된다.

 

 

5) Java Config로 설정하기 위해 WebMvcConfiguration 클래스에 addArgumentResolver라는 메서드를 오버라이딩한다.

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
  System.out.println("아규먼트 리졸버 등록..");
  argumentResolvers.add(new HeaderMapArgumentResolver());
}

위에서 생성한 HeaderMapArgumentResolver를 넘겨준다.

 

 

이제 컨트롤러에서 이렇게 생성한 아규먼트 리졸버를 인자로 넘겨 사용할 수 있다.

@GetMapping(path="/list")
  public String list(HeaderInfo headerInfo) {
    
    System.out.println("-----------------------------------------------------");
    System.out.println(headerInfo.get("user-agent"));
    System.out.println("-----------------------------------------------------");
    
  }

컨트롤러 메서드 list에 인자로 HeaderInfo를 받고 있다.

headerInfo의 get 메서드로 user-agent라는 이름의 헤더 값을 가져오고, 콘솔에 출력해볼 수 있다.

 

이렇게 아규먼트 리졸버 사용 방법에 대해 알아보았다.

 

 

 

 

출처)

edwith 부스트코스 웹 프로그래밍

- 아규먼트 리졸버란?

아규먼트 리졸버를 이용해 HTTP Header정보를 Map객체에 담아서 Controller에게 전달하기

 

'JAVA' 카테고리의 다른 글

로깅에 대하여  (0) 2019.09.12
enum으로 코드 줄이기  (0) 2019.09.04
인터셉터(Interceptor) - Cotroller 공통 로직 처리하기  (0) 2019.08.26
세션(Session) 이용하는 방법  (5) 2019.08.26
쿠키(Cookie) 이용하는 방법  (0) 2019.08.23

댓글