티스토리 뷰

Framework/Spring

Spring Framework(7)

beecomci 2017. 3. 4. 17:29

[HandlerMethodArgumentResolver]


1. HandlerMethodArgumentResolver란?


스프링 3.1에서 추가된 인터페이스다. 그 이전에는 WebArgumentResolver 라는 인터페이스였는데, 그 이후에는 이름이 바뀌었다. 


역할은 다음과 같다.

스프링 사용 시, Controller에 들어오는 파라미터를 수정하거나 공통적으로 추가 해줘야 하는 경우에 리턴타입을 나에게 맞게 가공해서 사용하고 싶을 때 사용한다. 


예를 들어서, 로그인을 한 사용자의 아이디나 닉네임을 추가할 때, 이런 정보들을 보통 Session에 담아놓고 사용하는데 db에 그런 정보를 입력할 때는 결국 세션에서 값을 꺼내와서 파라미터로 추가 해야 한다. 

이런 경우가 많아지만 번거로우므로, HandlerMethodArgumentResolver는 사용자 요청이 Controller에 도달하기 전에 그 요청의 파라미터들을 그 요청의 파라미터들을 수정할 수 있도록 해준다. 


2. CommandMap 클래스 생성


rquest에 담겨있는 파라미터를 Map에 담아주는 역할을 하는 클래스이다. SampleController 클래스의 openSampleBoardList 메소드에서 파라미터로 map<String, Object> commandMap이라는 사용자가 넘겨준 인자가 있다. 


그런데 여기서 HandlerMethodArgumentResolver는 컨트롤러의 파라미터가 Map 형식이면 동작되지 않아 문제가 된다. 그래서 설정한 클래스가 아닌, 스프링에서 기본적으로 설정된 ArgumentResolver를 거치게 된다. 

-> 스프링의 <mvc:annotaion-driven/>을 선언하게 되면 이렇게 동작한다. 


그래서 Map을 그대로 사용할 수 없으므로 Map을 대신해서 CommandMap을 작성한다. 


/main/java/first/common 패키지 밑에 common 폴더를 생성하고 CommandMap.java 파일을 생성하고 작성한다. 


package first.common.common;
 
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
 
//절대 Map을 상속받지 않는다!!!
////상속받게 되면 작성할 ArgumentResolver를 거치지 않게 되므로...
public class CommandMap {
	//이 Map에 모든 데이터를 담는 역할을 한다. 
    Map<String,Object> map = new HashMap<String,Object>();
     
    //기본 Map과 똑같이 사용할 수 있도록 기존 Map의 메소드와 똑같이 작성한다. 
    public Object get(String key){
        return map.get(key);
    }
     
    public void put(String key, Object value){
        map.put(key, value);
    }
     
    public Object remove(String key){
        return map.remove(key);
    }
     
    public boolean containsKey(String key){
        return map.containsKey(key);
    }
     
    public boolean containsValue(Object value){
        return map.containsValue(value);
    }
     
    public void clear(){
        map.clear();
    }
     
    public Set<Entry<String, Object>> entrySet(){
        return map.entrySet();
    }
     
    public Set<String> keySet(){
        return map.keySet();
    }
     
    public boolean isEmpty(){
        return map.isEmpty();
    }
     
    public void putAll(Map<? extends String, ?extends Object> m){
        map.putAll(m);
    }
     
    public Map<String,Object> getMap(){
        return map;
    }
}


3. HandlerMethodArgumentResolver 작성


/main/java/first/common 패키지 밑에 resolver 폴더를 생성하고 CustomMapArgument.java 클래스를 생성하고 작성한다. 


package first.common.resolver;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

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 first.common.common.CommandMap;

public class CustomMapArgumentResolver implements HandlerMethodArgumentResolver{
   
	//Controller의 파라미터가 CommandMap 클래스인지 검사
	@Override
   public boolean supportsParameter(MethodParameter parameter) {
       return CommandMap.class.isAssignableFrom(parameter.getParameterType());
   }

   @Override
   public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
       CommandMap commandMap = new CommandMap();
        
       HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
       Enumeration<?> enumeration = request.getParameterNames();
        
       String key = null;
       String[] values = null;
       while(enumeration.hasMoreElements()){
    	   //request에 담긴 모든 키와 값을 commandMap에 저장
           key = (String) enumeration.nextElement();
           values = request.getParameterValues(key);
           if(values != null){
               commandMap.put(key, (values.length > 1) ? values:values[0] );
           }
       }
       return commandMap; //모든 파라미터가 담긴 commandMap에 반환
   }
}


4. CustomMapArgumentResolver 등록


CustomMapArgumentResolver는 root context 영역에 등록되어야 한다. 그래서 acition-servlet.xml에 등록해야 한다. 


<mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="first.common.resolver.CustomMapArgumentResolver"></bean>      
        </mvc:argument-resolvers>
</mvc:annotation-driven>


<mve:argument-resolvers>태그를 사용해서 만든 CustomMapArgumentResolver의 빈을 수동으로 등록한다. 


5. Controller의 수정 및 테스트


//만들어진 Map을 commandMap으로 바뀌고 담겨진 모든 파라미터를 iterator를 이용해서 출력
    @RequestMapping(value="/sample/testMapArgumentResolver.do")
    public ModelAndView testMapArgumentResolver(CommandMap commandMap) throws Exception{
        ModelAndView mv = new ModelAndView("");
         
        if(commandMap.isEmpty() == false){
            Iterator<Entry<String,Object>> iterator = commandMap.getMap().entrySet().iterator();
            Entry<String,Object> entry = null;
            while(iterator.hasNext()){
                entry = iterator.next();
                log.debug("key : "+entry.getKey()+", value : "+entry.getValue());
            }
        }
        return mv;
}


그리고 실행시킨 뒤, 주소창에 

localhost:8080/first/sample/testMapArgumentResolver.do?aaa=temp 

를 입력하면 콘솔에


2017-03-04 17:26:12,190 DEBUG [first.common.logger.LoggerInterceptor] ======================================          START         ======================================

2017-03-04 17:26:12,191 DEBUG [first.common.logger.LoggerInterceptor]  Request URI :  /first/sample/testMapArgumentResolver.do

2017-03-04 17:26:12,215 DEBUG [first.sample.controller.SampleController] key : aaa, value : temp

2017-03-04 17:26:12,215 DEBUG [first.common.logger.LoggerInterceptor] ======================================           END          ======================================


이 보여지면, get 방식으로 aaa라는 키와 temp라는 값이 정상적으로 CustomMapArgumentResolver에 등록된 것을 볼 수 있다. 


2개의 키와 값을 등록하려면

http://localhost:8080/first/sample/testMapArgumentResolver.do?aaa=value1&bbb=value2

를 입력한다.



'Framework > Spring' 카테고리의 다른 글

Spring Framework(8)  (0) 2017.03.27
Spring Framework(6)  (0) 2017.02.05
Spring Framework(5)  (0) 2017.02.05
Spring Framework(4)  (0) 2017.02.05
Spring Framework(3)  (0) 2017.02.05
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함