본문 바로가기

프로그래밍/Spring

전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 2

지난번 글에서는 Java Config 방식으로 Spring MVC 환경 설정하는 방법 중 RequestMappingHandlerAdapter 클래스 설정의 커스터마이징 방법과 사용자 정의 Interceptor를 추가하는 방법에 대해 설명했다. 이번글에서는 Java Config 방식으로 HandlerExceptionResolver를 설정하는 방법에 대해 설명하도록 하겠다

 

다음의 XML은 예외가 던져졌을때 이를 처리하는 HandlerExceptionResolver 인터페이스를 구현한 클래스를 등록하는 <bean> 태그이다. 여기서는 HandlerExceptionResolver 인터페이스를 구현한 클래스인 SimpleMappingExceptionResolver 클래스를 Spring bean으로 등록하고 있다.

 

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="defaultErrorView" value="cmmn/egovError"/>
	<property name="exceptionMappings">
		<props>
			<prop key="org.springframework.dao.DataAccessException">cmmn/dataAccessFailure</prop>
			<prop key="org.springframework.transaction.TransactionException">cmmn/transactionFailure</prop>
			<prop key="egovframework.rte.fdl.cmmn.exception.EgovBizException">cmmn/egovError</prop>
			<prop key="org.springframework.security.AccessDeniedException">cmmn/egovError</prop>
		</props>
	</property>
</bean>

 

위의 설정으로 SimpleMappingExceptionResolver 클래스를 Spring bean으로 등록하게 되는데 그러면 이런 예외처리 하는 HandlerExceptionResolver 인터페이스를 구현한 클래스를 Java Config 방식에서는 어떻게 Spring bean으로 등록할까? WebMvcConfigurationSupport 클래스는 예외처리를 하는 HandlerExceptionResolver 인터페이스를 구현한 클래스로 HandlerExceptionResolverComposite 클래스를 Spring bean으로 등록하고 있다. WebMvcConfigurationSupport 클래스에서 방금 설명한 부분의 소스는 다음과 같다.

 

@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
	List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<HandlerExceptionResolver>();
	configureHandlerExceptionResolvers(exceptionResolvers);

	if (exceptionResolvers.isEmpty()) {
		addDefaultHandlerExceptionResolvers(exceptionResolvers);
	}

	HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
	composite.setOrder(0);
	composite.setExceptionResolvers(exceptionResolvers);
	return composite;
}

 

위의 소스를 보면 HandlerExceptionResolverComposite 클래스를 bean으로 등록하기 전에 몇가지 작업을 하는 것이 있다. 첫번째는 HandlerExceptionResolver 인터페이스를 구현한 클래스들이 들어갈 ArrayList 클래스 객체를 만든뒤 이를 configureHandlerExceptionResolver 메소드의 파라미터로 넣고 있다. 그리고 두번째는 파라미터로 넣은 ArrayList 객체가 비어있으면 addDefaultHandlerExceptionResolvers 메소드의 파라미터로 ArrayList 객체를 다시 넣고 있다. 그리고 이렇게 사용된 ArrayList 객체를 HandlerExceptionResolverComposite 클래스 객체를 생성한 뒤에 넣고 있다. 이러한 일련의 과정을 설명하기 전에 한가지 알아둬야 할 것이 있어서 이를 먼저 설명하고 진행하고자 한다. 바로 HandlerExceptionResolverComposite 클래스이다. 이 클래스는 HandlerExceptionResolver 인터페이스를 구현한 클래스들을 여러개 넣어서 이 클래스들을 이용해 예외처리를 하는 클래스이다. 그러면 왜 이렇게 여러개의 HandlerExceptionResolver 인터페이스를 구현한 클래스를 넣어서 종합적으로 사용하는 클래스가 필요한 것일까? 

 

우리는 프로젝트에서 다양한 예외를 처리해야 한다. 또한 이러한 예외에 대한 처리 방법이 여러개가 존재할 수 있다. 예를 들어 위에서 설정한 SimpleMappingExceptionResolver 클래스의 경우는 지정된 4개의 예외에 따라 그에 맞는 화면을 보여주고 그 예외를 제외한 나머지 예외는 디폴트로 지정된 화면을 보여주고 있다. 그러나 이러한 처리방법이 아닌 다른 방법 즉 특정 예외가 발생하면 Json으로 에러메시지를 출력해야 한다거나, 또는 XML로 보여줘야 한다면? 또 예외를 처리하면서 별도 로그를 기록해야 한다면 등등..이렇게 여러 상황에 따라 다양하게 대응해야 하기 때문에 여러개의 HandlerExceptionResolver 인터페이스를 구현한 클래스를 사용해야 하고 이를 종합적으로 관리하는 HandlerExceptionResolverComposite 클래스에 넣어서 사용하는 것이다. 비단 HandlerExceptionResolverComposite 클래스 뿐만 아니라 실제로 Spring에서 제공하는 클래스 중에는 이와 같이 같은 성격의 클래스나 또는 같은 인터페이스를 구현한 클래스를 하나로 모아 통합적으로 관리하는 같은 타입의 클래스 또는 인터페이스를 구현한 클래스가 있다.

 

그럼 HandlerExceptionResolverComposite 클래스를 사용하는 이유에 대해서는 설명이 되었으리라 생각하고 다음으로 넘어가겠다. 방금 설명한 HandlerExceptionResolverComposite 클래스의 설명에서 보면 여러개의 HandlerExceptionResolver 인터페이스를 구현한 클래스들을 사용한다고 했다. 그럼 이 클래스들을 어떤 방법으로 등록할까? Spring Bean을 생성하는 handlerExceptionResolver 메소드를 보면 HandlerExceptionResolver 인터페이스를 구현한 클래스를 넣는 ArrayList 객체를 만들고 이를 configureHandlerExceptionResolvers 메소드의 파라미터로 넣고 있다. 그리고 이렇게 사용했던 ArrayList 객체를 HandlerExceptionResolverComposite 클래스의 setExceptionResolvers 메소드를 이용해서 이 ArrayList 객체를 설정하고 있다. 위의 설명과 짜맞춰보면 configureHandlerExceptionResolvers 메소드가 파라미터로 넘겨진 ArrayList 객체에 HandlerExceptionResolverComposite 클래스에서 사용하게 될 HandlerExceptionResolver 인터페이스를 구현한 클래스를 넣어주고 이러한 객체를 HandlerExceptionResolverComposite 클래스의 setExceptionResolver 메소드에 ArrayList 객체를 넣어줌으로써 HandlerExceptionResolverComposite 클래스에서 이 ArrayList 객체 안에 있는 클래스들을 사용하는 것이라 볼 수 있다. 즉 우리가 사용해야 할 SimpleMappingExceptionResolver 클래스를 configureHandlerExceptionResolvers 메소드를 이용해서 넣어주면 SimpleMappingExceptionResolver 클래스를 사용할 수 있게 된다.

 

@Override
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
	// TODO Auto-generated method stub
	SimpleMappingExceptionResolver smer = new SimpleMappingExceptionResolver();
	smer.setDefaultErrorView("cmmn/egovError");
	Properties mappings = new Properties();
	mappings.setProperty("org.springframework.dao.DataAccessException", "cmmn/dataAccessFailure");
	mappings.setProperty("org.springframework.transaction.TransactionException", "cmmn/transactionFailure");
	mappings.setProperty("egovframework.rte.fdl.cmmn.exception.EgovBizException", "cmmn/egovError");
	mappings.setProperty("org.springframework.security.AccessDeniedException", "cmmn/egovError");
	smer.setExceptionMappings(mappings);
	exceptionResolvers.add(smer);
}

 

방금 설명을 보고 configureHandlerExcptionResolvers 메소드 코드를 보자. SimpleMappingExceptionResolver 클래스 객체를 생성한뒤 관련된 값을 설정하고 이렇게 설정한 SimpleMappingExceptionResolver 클래스 객체를 파라미터에서 받아들인 List<HandlerExceptionResolver> 인터페이스를 구현한 클래스 객체에 넣어주고 있다. 파라미터로 사용한 List 객체에 우리가 만든 SimpleMappingExceptionResolver 클래스를 넣었기 때문에 configureHandlerExceptionResolver 메소드를 호출한 곳에서는 이 List 객체를 이용해서 관련 작업을 할 수가 있는 것이다. 이런 방법으로 Java Config 방식에서 HandlerExceptionResolver 인터페이스를 구현한 클래스를 등록하는 것으로 이해하면 되겠다.

 

나머지 <bean> 태그들을 Java Config 방식으로 바꾸는 것에 대해서는 그리 설명해야 할 부분이 없어서 이것은 마지막에 올라갈 최종 소스에서 참고들 하시기 바라고 마지막 <mvc:view-controller> 태그를 사용하는 태그를 Java Config 방식으로 하는 방법에 대해 설명하겠다. 먼저 XML 태그를 보자

 

<mvc:view-controller path="/cmmn/validator.do" view-name="cmmn/validator"/>

 

이 태그가 하는 기능은 url로 path 파라미터에 입력된 내용이 들어오면 view-name 파라미터에 설정된 값을 화면으로 보여준다. 단 view-name에서 설정된 값이 사용되는 근거는 Servlet Context에 등록되는 View Resolver에 설정된 내용을 가지고 화면을 보여주게 된다. 이 글에서는 설명하고 있지 않지만 Servlet Context에는 UrlBasedViewResolver 클래스 객체가 Spring bean으로 등록되기 때문에 UrlBasedViewResolver 클래스 객체 설정 값과 view-name 파라미터에 설정된 값을 이용해서 보여주는 화면을 결정하게 된다. UrlBasedViewResolver bean에서는  /WEB-INF/jsp/egovframework/example/ 디렉토리를 기준으로해서 확장자가 jsp인 화면을 보여주기 때문에 웹브라우저에서 <mvc:view-controller> 태그에 설정된 /cmmn/validator.do 로 URL이 오면 /WEB-INF/jsp/egovframework/example/cmmn/validator.jsp를 보여주는 것이 된다. 이렇게 <mvc:view-controller> 태그가 하는 기능에 대해 이해하고 이제 이런 <mvc:view-controller> 태그를 어떻게 Java Config 방식으로 설정하는지 보도록 하자.

 

Java Config 방식으로 바꿀때는 WebMvcConfigurationSupport 클래스에서 <mvc:view-controller> 태그에 설정한 값을 이용해서 이러한 기능을 하는 bean이 등록되어서 이용되는지를 알아봐야 한다. WebMvcConfigurationSupport 클래스에서는 viewControllerHandlerMapping 메소드를 이용해서 이러한 기능을 하는 bean을 등록한다. 엄밀하게 얘기하면 ViewControllerRegistry 클래스 객체가 설정된 AbstractHandlerMapping 클래스 객체를 bean으로 등록한다고 보면 된다.

 

@Bean
public HandlerMapping viewControllerHandlerMapping() {
	ViewControllerRegistry registry = new ViewControllerRegistry();
	addViewControllers(registry);

	AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
	handlerMapping = (handlerMapping != null ? handlerMapping : new EmptyHandlerMapping());
	handlerMapping.setInterceptors(getInterceptors());
	return handlerMapping;
}

 

위의 코드를 보면 많이 보는 스타일이다. 위에서 설명했던 HandlerExceptionResolverComposite 클래스를 Spring bean으로 등록하는 코드와 비슷한 스타일이다. 다만 차이가 있다면 위에서는 ArrayList 객체를 생성한뒤 이를 configureHandlerExceptionResolvers 메소드의 파라미터로 사용한 것에 반해 여기서는 ViewControllerRegistry 클래스 객체를 생성하고 이를 addViewControllers 메소드의 파라미터로 사용하고 있다. 위에서 설명했던 configureHandlerExceptionResolvers 메소드와 같이 설정해야 할 정보를 addViewControllers 메소드를 통해서 설정하는 것이다. 그러면 우리가 여기서 설정해야 하는 정보란 것은 무엇인가? 바로 <mvc:view-controller> 태그에서 설정한 path 파라미터 값과 이 path 파라미터 값에 대한 view-name 파라미터 값이다. 그래서 우리는 addViewControllers 메소드를 override 해서 이 파라미터 값들을 설정하면 되는 것이다.

 

@Override
protected void addViewControllers(ViewControllerRegistry registry) {
	// TODO Auto-generated method stub
	registry.addViewController("/cmmn/validator.do").setViewName("cmmn/validator");
}

 

addViewControllers 메소드의 파라미터로 넘어오는 ViewControllerRegistry 클래스 객체에 addViewController 메소드와 setViewName 메소드를 이용해서 설정해주면 된다. 만약 이러한 설정이 여러개가 있다면 addViewController 메소드와 그에 매핑되는 setViewName 메소드를 해당 갯수만큼 호출해주면 된다. 덧붙여서 말하자면 현재 전자정부 프레임워크 3.5의 경우는 Spring Framework 4.0.9 버전 기반으로 만들어져 있다. 그러나 4.1 버전으로 올라가면 ViewControllerRegistry 클래스에 addRedirectViewController(String urlPath, String redirectUrl) 메소드가 추가되어 기존의 addViewController 메소드와 setViewName 메소드 이렇게 2번 호출하는 것을 1번으로 줄여서 작업할 수 있게 된다.

 

이번 글에서는 Java Config 방식으로 Spring MVC 환경 설정하는 방법 중 HandlerExceptionResolver를 등록하는 방법과 view-controller 설정 방법에 대해. 다음에는 이렇게 만들어진 Java Config 방식의 클래스를 어떻게 사용하는지에 대해 설명하도록 하겠다.

 

 

목     차

 1. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(환경구축)

 2. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(기초)

 3. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-aspect.xml 변환)

 4. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-common.xml 변환)

 5. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-datasource.xml 변환)

 6. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-sqlMap.xml, context-mapper.xml 변환)

 7. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-transaction.xml 변환)

 8. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-idgen.xml, context-properties.xml, context-validator.xml 변환)

 9. 작성된 Java Config 클래스 파일들을 실제 등록해보자(RootContext 클래스 제작)

 10. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 1

 11. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 2

 12. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 3