1. Argument Resolver란?
- 사용자가 임의의 값을 컨트롤러의 메소드 인자로 전달할 때 사용됨
- 예를 들어, 세션에 저장되어 있는 값 중 특정 이름의 값을 메소드 인자로 전달하는 경우
즉, 어떠한 요청이 컨트롤러에 들어왔을 때, 요청에 들어온 값으로부터 원하는 객체를 만들어내는 일을 Argument Resolver가 간접적으로 해줄 수 있음
예를 들어, 사용자가 로그인되어 있을 때, 올바른 사용자인지 확인해야 함. 사용자가 가진 토큰이 유효한 토큰인지 검증을 거친 후, 토큰에 저장된 id를 꺼내 LoginMember라는 객체로 만들어내는 과정이 필요 -> 이때 ArgurmentResolver를 사용할 수 있음
Argument Resolver와 Interceptor의 차이점
- Argument Resolver는 Interceptor 이후에 동작하며, 어떠한 요청이 컨트롤러에 들어왔을 때, 요청에 들어온 값으로부터 원하는 객체를 반환함
- Interceptor는 실제 컨트롤러가 실행되기 전에 요청을 가로채며, 특정 객체를 반환할 수 없음. 오직 boolean 혹은 void의 리턴 타입만 존재함
https://hudi.blog/spring-handler-interceptor/
Spring HandlerInterceptor를 활용하여 컨트롤러 중복 코드 제거하기
우아한테크코스 레벨2 마지막 미션인 장바구니 미션에서 인증과 인가를 구현하기 위해, Spring Interceptor 를 사용해야했다. 이를 위해 학습한 내용을 정리해보았다. 컨트롤러에서 발생한 중복 코드
hudi.blog
https://hudi.blog/spring-argument-resolver/
스프링에서 Argument Resolver 사용하기
컨트롤러에서 쿼리 스트링을 변수에 바인딩하려면 @RequestParam 을, 가변적인 경로를 변수에 바인딩하려면 @PathVariable 을, HTTP Body를 변수에 바인딩하려면 @RequestBody 를 사용해야한다. 하지만 HTTP Head
hudi.blog
Argument Resolver 작성 방법
- org.springframework.web.method.support.HandlerMethodArgumentResolver를 구현한 클래스를 작성함
- supportsParameter 메소드를 오버라이딩한 후, 원하는 타입의 인자가 있는지 검사한 후 있을 경우 true를 리턴하도록 함
- resolveArgument 메소드를 오버라이딩한 후, 메소드의 인자로 전달할 값을 리턴함
이렇게 작성한 후,
JavaConfig에 설정한다면, WebMvcConfigurerAdapter를 상속받은 Java Config 파일에서 addArgumentResolvers 메소드를 오버라이딩한 후 원하는 Argument Resolver 클래스 객체를 등록함
xml 파일에 설정한다면,
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="ArgumentResolver클래스명"></bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
2. Argument Resolver 적용하기
웹 애플리케이션에 Argument Resolver를 적용해 HTTP 요청 헤더 정보를 저장하고 있는 HeaderInfo 인자 타입이 메소드에 있는 경우, 자동으로 넘겨주기
- Map이나 Map을 상속받는 객체는 Spring에서 내부적으로 사용하고 있는 Argument Resolver가 선처리하기에 직접 사용할 수 없음
- 그러므로 Map을 필드로 가지고 있는 HeaderInfor라는 클래스를 작성하도록 함
#HeaderInfo.java
package com.example.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);
}
}
# HeaderMapArgumentResolver.java
- HandlerMethodArguementResolver를 상속받는 클래스
package com.example.guestbook.argumentresolver;
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;
import java.util.Iterator;
public class HeaderMapArgumentResolver implements HandlerMethodArgumentResolver {
// 인자의 정보를 parameter로 전달함. 해당 파라미터 정보에 원하는 정보가 있다면 true 리턴
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType() == HeaderInfo.class;
}
// supportsParameter()가 true를 리턴할 때만, 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;
}
}
# WebMvcContextConfiguration.java
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
System.out.println("argument resolver 등록");
argumentResolvers.add(new HeaderMapArgumentResolver());
}
ArgumentResolver를 생성하고 등록함
그럼 이제 Controller에서, ArgumentResolver는 해당 인자가 넘어왔을 때 사용됨. 그러므로 파라미터에 HeaderInfo를 추가함
# GuestbookController.java
@GetMapping("/list")
public String list(@RequestParam(name = "start", required = false, defaultValue = "0") int start,
ModelMap model, @CookieValue(value="count", defaultValue = "0", required = true) String value,
HttpServletResponse response, HeaderInfo headerInfo) {
System.out.println("----------------------------");
System.out.println(headerInfo.get("user-agent"));
System.out.println("----------------------------");
// 이하 기존 코드
}
'강의 노트 > 웹 프로그래밍(풀스택)' 카테고리의 다른 글
[boostcourse] 5.6. Interceptor - BE (0) | 2023.07.16 |
---|---|
[boostcourse] 5.5. Spring MVC에서의 Session 사용하기 - BE (0) | 2023.07.11 |
[boostcourse] 5.4. Cookie & Session - BE (0) | 2023.07.10 |
[boostcourse] 3.11. Controller - BE (0) | 2023.07.09 |
[boostcourse] 3.10. Layered Architecture - BE (2) (0) | 2023.06.27 |