관리자 글쓰기

 본 내용은 혼자 공부하기 위하여 다른 포스트를 보면서 저에게 필요한 부분과 궁금했던 부분을 추가하여 게시하는 곳입니다.


궁금한 것에 대한 것은 모르는 것이 많겠지만 함께 알아보도록 노력하겠습니다.


참조 게시 포스트 : http://addio3305.tistory.com/


-------------------------------------------------------------------------------------------------------------------------------------------


1. HandlerMethodArgumentResolver?


 스프링 사용 시 컨트롤러에서 파라미터의 값을 가져오거나 수정하는 경우가 있는데 그럴 경우가 있다.

그럴 경우에는 세션에 저장하고 세션에 있던 값을 사용하거나 한다. 하지만 HandlerMethodArgumentResolver를 사용하면 컨트롤러에 도달하기 전에 파라미터를 수정하거나 할 수 있게 해준다.


 1.1 CommandMap 생성

우리가 생성했던 SampleController의 메소드들을 살펴보면 파라미터들은 전부 Map 형식인 것을 알 수 있다. 이 형식의 파라미터들은 HandlerMethodArgumentResolver에서 처리하지 않고 스프링의 기본 설정인 ArgumentResolver에서 처리가 된다.

(action-servlet.xml에서 <mvc:annotation-driven />이 선언 되어 있지 않을 경우에 해당)

<mvc:annotation-driven>이 선언되면 map을 사용할 수 없고, 다른 형식을 사용하여야 한다. map을 대신할 commandMap을 만들 것이다.


1) com.mycompany.myapp.common.common 경로에 CommandMap 클래스 생성


2) 하단과 같은 코드를 작성

public class CommandMap {

	Map<String,Object> map = new HashMap<String,Object>();
	
	public void put(String key, Object value) {
		map.put(key, value);
	}
	
	public Object get(String key) {
		return map.get(key);
	}
	
	public boolean isEmpty() {
		return map.isEmpty();
	}
	
	public Map<String, Object> getMap(){
		return map;
	}
	
	public void clear() {
		map.clear();
	}
	
	public boolean containsKey(String key) {
		return map.containsKey(key);
	}
	
	public boolean containsValue(Object value) {
		return map.containsValue(value);
	}
	
	public Object remove(String key) {
		return map.remove(key);
	}
	
	public Set<Entry<String, Object>> entrySet(){
		return map.entrySet();
	}
	
	public Set<String> keySet(){
		return map.keySet();
	}
	
	public void putAll(Map<? extends String, ? extends Object> m) {
		map.putAll(m);
	}
}
  위 코드는 Map의 기능 일부분을 똑같이 사용하기 위하여 만든 클래스이다. Map을 상속 받지 않고 Map을 따로 클래스 안에서 만들어줘서 활용하여야 한다.(Map을 상속 받게 되면 스프링의 기본 설정 ArgumentResolver를 거치게 됨)

1.2 CustomMapArguementResolver 작성
     HandlerMethodArgumentResolver의 역할을 할 클래스를 만들 것이다.
1) com.mycompany.myapp.common.resovler 패키지 경로에 CustomMapArgumentResolver 클래스 생성

2) 하단과 같이 코드 작성

public class CustomMapArgumentResolver implements HandlerMethodArgumentResolver {

	Logger log = Logger.getLogger(this.getClass());
	
	@Override
	public Object resolveArgument(MethodParameter para, ModelAndViewContainer mvc, NativeWebRequest webReq,
			WebDataBinderFactory binderFactory) throws Exception {
		
		CommandMap commandMap = new CommandMap();
		
		HttpServletRequest req = (HttpServletRequest)webReq.getNativeRequest();
		Enumeration<?> enumeration = req.getParameterNames();
		
		String key = null;
		String[] values = null;
		while(enumeration.hasMoreElements()) {
			key = (String) enumeration.nextElement();
			values = req.getParameterValues(key);
			if(values!=null	) {
				commandMap.put(key, (values.length>1)? values : values[0]);
			}
		}
		
		return commandMap;
	}

	@Override
	public boolean supportsParameter(MethodParameter para) {
		return CommandMap.class.isAssignableFrom(para.getParameterType());
	}
}


위 클래스는 HandlerMethodArgumentResolver 인터페이스를 구현한 클래스로 2개의 메소드를 구현하였다.


- supportsParameter 메소드

해당 메소드는 바인딩할 클래스를 지정해주는 곳으로 여기서 지정한 클래스를 resolveArgument 메소드에서 처리를 할 수 있다.


- resolveArgument 메소드

해당 메소드는 바인딩된 클래스의 파라미터들을 수정하거나 값을 가져올 수 있는데 여기서 CommandMap 클래스를 새로 만들어 파라미터 안의 값들을 CommandMap에 할당하고 그 값을 리턴하여 준다.


1.3 CustomMapArgumentResolver 등록
위에서 만든 CustomMapArgumentResolver를 이제 DispatcherServlet 설정 파일에 등록 시켜줘야 한다.(action-servlet.xml)

action-servlet.xml 의 내용에 하단 내용을 추가하자.
    <mvc:annotation-driven>
    	<mvc:argument-resolvers>
    		<bean class="com.mycompany.myapp.common.resolver.CustomMapArgumentResolver" />
    	</mvc:argument-resolvers>
    </mvc:annotation-driven>

- mvc:annotation-driven 태그에 mvc:argument-resolvers에 빈 객체를 작성하여 확장 추가하였다.


1.4 테스트

1) 지금까지 만든 것들이 잘 작동하는지 테스트를 하기 위하여 컨트롤러에 다음 부분을 추가한다.

	@RequestMapping(value="/testCustomMapArgumentResolver.do")
	public ModelAndView testCommandMap(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()+ " , values:"+entry.getValue());
			}
		}
		return mv;
	}

위 코드를 살펴보면 다른 테스트와 게시판 목록을 만드는 형식처럼 만들었으며 안의 내용은 반복자를 사용하여 CommandMap의 Entry들을 로그를 이용하여 키 값과 밸류 값을 출력하도록 하였다.


2) 다음으로 주소에 localhost:8080/myapp/testCustomMapArgumentResolver.do?test1=value1&test2=value2 를 입력하였을 때 콘솔 창에 다음과 같은 화면이 뜨면 정상적으로 작동하는 것이다.