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

oyeon·2021년 3월 15일
0

인터셉터를 이용해 Controller 공통 로직 처리하기에서 이어짐

웹 어플리케이션에 아규먼트 리졸버를 적용해 HTTP요청 헤더 정보를 저장하고 있는 HeaderInfo 인자타입이 메소드에 있을 경우 자동으로 넘겨주는 예제를 작성해 보자

실습

HeaderInfo.java

  1. Argument Resolver 생성
    앞서 Map객체나 Map을 상속받은 객체는 Spring에서 내부적으로 사용하고 있는 아규먼트 리졸버가 선처리하기 때문에 직접 사용할 수 없다고 했다. 그러므로 Map을 필드로 가지고있는 HeaderInfo 클래스를 먼저 작성하자.
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);
	}
}

HeaderMapArgumentResolver.java

  1. HandlerMethodArgumentResolver를 상속받아 구현하고 있는 HeaderMapArgumentResolver 클래스 작성.
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 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;
	}

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

Controller에서 메서드의 인자가 4개일 경우에 supportsParameter 메서드가 4번 호출된다. supportsParameter는 인자의 정보를 parameter로 전달하게 되는데, 해당 파라미터 정보에 원하는 정보가 있다면 true를 반환하고 없으면 false를 반환한다.

Parameter 타입이 방금 만든 HeaderInfo.class 타입일 경우에 true를 리턴하도록 method를 오버라이드 하였다.

supportsParameter가 true를 리턴할 경우에만 resolveArgument 메서드가 호출된다. 이 resolveArgument가 리턴한 값은 Controller에서 메서드의 인자로 전달된다.

이를 구현하기 위해 코드에서는 요청으로 부터 넘어온 모든 Header 정보를 HeaderInfo 객체에 담아서 리턴하고 있다.

WebMvcContextConfiguration.java

package kr.or.connect.guestbook.config;

import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import kr.or.connect.guestbook.argumentresolver.HeaderMapArgumentResolver;
import kr.or.connect.guestbook.interceptor.LogInterceptor;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "kr.or.connect.guestbook.controller" })
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter{

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
        registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
        registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
    }
 
    // default servlet handler를 사용하게 합니다.
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
   
    @Override
    public void addViewControllers(final ViewControllerRegistry registry) {
    	System.out.println("addViewControllers가 호출됩니다. ");
        registry.addViewController("/").setViewName("index");
    }
    
    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry){
    	registry.addInterceptor(new LogInterceptor());
    }
    
    @Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    		System.out.println("아규먼트 리졸버 등록..");
		argumentResolvers.add(new HeaderMapArgumentResolver());
	}
}
  1. 생성한 Argument Resolver 등록

생성한 Argument Resolver를 적용하기 위해서는 WebMvcContextConfiguration.java에서 addArgumentResolvers 메서드를 오버라이딩 하고 인자로 넘어온 argumentResolver에 앞에서 생성한 argumentResolver를 추가한다.(add)

GuestbookController.java

package kr.or.connect.guestbook.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import kr.or.connect.guestbook.argumentresolver.HeaderInfo;
import kr.or.connect.guestbook.dto.Guestbook;
import kr.or.connect.guestbook.service.GuestbookService;

@Controller
public class GuestbookController {
	@Autowired
	GuestbookService guestbookService;
	
	@GetMapping(path="/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("-----------------------------------------------------");
		...
  1. 인자 넘기기

Argument Resolver는 해당 인자가 넘어왔을 때 사용된다고 했었다. 기존에 사용하던 Controller에 인자를 넘기도록 HeaderInfo headerInfo를 파라미터에 추가하자. headerInfo의 get메서드에 user-agent를 넘기면 값이 출력되는 것을 알 수 있다.

결과

컨트롤러 메소드에서 자주 사용되는 값이 있을 경우 아규먼트 리졸버를 만들어서 넘겨주도록 하면 편리하게 사용할 수 있다.

profile
Enjoy to study

0개의 댓글