ArgumentResolver
컨트롤러의 메소드 인자로
사용자가 임의의 값을 전달하는 방법을 제공하고자 할 때 사용
서비스 운영 중에 받는 여러 종류의 데이터(파라미터)를 공통으로 처리할 수 있도록 구현된 인터페이스
예로, 세션에 저장된 값 중
특정 이름의 값을 메소드의 인자로 전달할 때
ArgumentResolver를 Controller 단에서 사용하면 중복 코드 (HttpSession의 세션 로드, HttpServletRequest의 요청 URL 및 ip 정보 로드 등)을 깜끌하게 처리할 수 있다
ArgumentResolver 작성 방법
- HandlerMethod ArgumentResolver 인터페이스를 구현한 클래스 작성
- supportsParameter 메소드를 오버라이딩한 후 원하는 타입의 인자가 있는지 검사
- 있을 경우 true 리턴
- resolveArgument 메소드를 오버라이딩한 후, 메소드의 인자로 전달할 값을 리턴
- 작성한 파일을
- Java Config에다가 설정하는 방법
- WebMvcConfigurerAdapter를 상속받은 Java Config 파일에서
- addArgumentResolvers 메소드를 오버라이딩 한 후
- 원하는 ArgumentResolver 클래스 객체를 등록합니다.
- web.xml 파일에 설정하는 방법
- bean class로 ArgumentResolver 클래스 설정
-
<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="아규먼트리졸버클래스"></bean> </mvc:argument-resolvers> </mvc:annotation-driven>
- Java Config에다가 설정하는 방법
Spring MVC의 기본 ArgumentResolver들
Controller 메소드에 HttpServletRequest나 HttpSession 등을 적으면 값이 전달되는 것을 볼 수 있음
이런 일이 가능한 이유가 Spring MVC가 기본을 제공하는 ArgumentResolver가 있기 때문
getDefaultArgumentResolvers() 메소드를 보면
기본으로 설정되는 ArgumentResolver에 어떤 것이 있는지 알 수 있음
알아야 할 것은
Map객체나 Map을 상속받은 객체는
Spring에서 이미 선언한 ArgumentResolver가 처리하기 때문에, 전달 할 수 없습니다.
Map객체를 전달하려면
Map을 필드로 가지고 있는 별도의 객체를 선언한 후 사용해야 합니다.
실습 - ArgumentResolver를 이용해 HTTP Header 정보를 Map 객체에 담아 Controller에 전달하기
Http 요청 헤더 정보를 저장하고 있는 HeaderInfo 인자 타입이
메소드에 있을 경우
자동으로 넘겨주는 예제 작성
참고로 Map 이나 Map을 상속받는 객체는
Spring에서 내부적으로 사용하는 ArgumentResolver가 선처리하기에
직접 사용할 수 없음
그래서 Map을 필드로 가진 HeaderInfo라는 클래스를 하나 작성
해당 클래스도 ArgumentResolver에서 사용할 것이기에
패키지를 하나 지정
헤더 정보를 담을 클래스 생성
guestbook 프로젝트 이용
kr.or.connect.guestbook.argumentresolver 패키지 생성
거기에 HeaderInfo 클래스 파일 생성
package kr.or.connect.guestbook.argumentresolver;
import java.util.HashMap;
import java.util.Map;
public class HeaderInfo {
// Map을 직접 사용할 수 없기 때문에 이렇게 필드로 Map을 하나 가지게 함
private Map<String, String> map;
// 생성자에 Map이 생성되게 함
public HeaderInfo() {
map = new HashMap<>();
}
// 값을 넣고 꺼낼 수 있는 put(), get() 메소드 정의
public void put(String name, String value) {
map.put(name, value);
}
public String get(String name) {
return map.get(name);
}
}
HandlerMethodArgumentResolver 인터페이스를 구현한 HeaderMapArugmentResolver 클래스 작성
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 {
// supportsParameterr가 true를 리턴한 경우에만 호출됨
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 요청으로 넘어온 모든 헤더 정보를 HeaderInfo 객체에 담아서 리턴
HeaderInfo headerInfo = new HeaderInfo();
//NativeWebRequest로부터 헤더의 name을 iterator 형태로 꺼내옴
Iterator<String> headerNames = webRequest.getHeaderNames();
while(headerNames.hasNext()) { // 꺼내온 헤더의 이름과 값을 headerinfo 객체에 put
String headerName = headerNames.next();
String headerValue = webRequest.getHeader(headerName);
System.out.println(headerName + " , " + headerValue);
headerInfo.put(headerName, headerValue);
}
return headerInfo; // 여기서 리턴한 값은 Controller 메소드의 인자로 전달
}
// Controller 메소드의 인자가 네 개일 경우 supportsParameter 메소드가 매번 호출됨
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 이 메소드는 인자의 정보를 파라미터로 전달하게 되는데
// 해당 파라미터 정보에 원하는 정보가 있다면 true를, 없다면 false를 반환
return parameter.getParameterType() == HeaderInfo.class;
// 파라미터 타입이 HeaderInfo 클래스 타입일 경우 true 리턴
}
}
ArgumentResolver 등록
WebMvcContextConfiguration에 아래 코드 추가
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
System.out.println("아규먼트 리졸버 등록..");
// 인자로 넘어온 argumentResolver 앞에
// 생성한 argumentResolver를 넘겨줌
argumentResolvers.add(new HeaderMapArgumentResolver());
}
Controller에 HeaderInfo를 메소드 인자 값으로 추가
@GetMapping(path="/list")
public String list(@RequestParam(name="start", required=false, defaultValue="0") int start,
ModelMap model,
@CookieValue(value="count", defaultValue="0") String value,
HttpServletRequest request,
HttpServletResponse response,
HeaderInfo headerInfo) { // 추가
System.out.println("-----------------------------------------------------");
System.out.println(headerInfo.get("user-agent"));
System.out.println("-----------------------------------------------------");
결과 - 헤더 정보와 user-agent 정보가 출력되는 것을 확인할 수 있다
public java.lang.String kr.or.connect.guestbook.controller.GuestbookController.list(int,org.springframework.ui.ModelMap,java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,kr.or.connect.guestbook.argumentresolver.HeaderInfo) 가 종료되었습니다. list을 view로 사용합니다.
public java.lang.String kr.or.connect.guestbook.controller.GuestbookController.list(int,org.springframework.ui.ModelMap,java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,kr.or.connect.guestbook.argumentresolver.HeaderInfo) 를 호출했습니다.
accept , image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, */*
accept-language , ko-KR
ua-cpu , AMD64
accept-encoding , gzip, deflate
user-agent , Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; rv:11.0) like Gecko
host , localhost:8082
connection , Keep-Alive
cookie , JSESSIONID=BC8571368E4ADC6904ACEE5FEDBA98DD; count=37
-----------------------------------------------------
Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; rv:11.0) like Gecko
-----------------------------------------------------
public java.lang.String kr.or.connect.guestbook.controller.GuestbookController.list(int,org.springframework.ui.ModelMap,java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,kr.or.connect.guestbook.argumentresolver.HeaderInfo) 가 종료되었습니다. list을 view로 사용합니다.
'Web > Java+Spring' 카테고리의 다른 글
Logging (0) | 2021.09.10 |
---|---|
Interceptor (0) | 2021.07.13 |
Spring MVC에서 Session 사용하기 (0) | 2021.07.08 |
RestController - Rest API by Spring MVC (0) | 2021.06.10 |
Layered Architecture 실습 - 방명록 (0) | 2021.06.09 |