티스토리 툴바


기존 Spring MVC 3.0.x의 <mvc:annotation-driven/> 태그의 전략은 

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

클래스를 사용하여 맵핑 및 여러 클래스를 추가하여 구성이 되었다.


하지만 이번 3.1 버전이 나오며 이야기가 달라졌다.

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

이 두개의 클래스가 주축이 되면서 기능 및 구성이 달라지고 

기존과는 거의 호환이 되게 만들졌다.


기존의 전략은 박성철님 블로그 ( http://gyumee.egloos.com/3056225 ) 여기에서 보는 것과 같이 구성되어 있었다.

하지만 3.1은 조금 달라졌다.

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">

<property name="order" value="0" />

</bean>


<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

<bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />


<!-- <mvc:message-converters> 태그의 messageConverter와 통합 -->

<util:list id="messageConverters">

<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />

<bean class="org.springframework.http.converter.StringHttpMessageConverter">

<property name="writeAcceptCharset" value="false" />

</bean>

<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />

<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />

<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" />

<!-- jaxb2라이브러리 존재시 -->

<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />

<!--  -->

<!-- jackson 라이브러리 존재시 -->

<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>

<!--  -->

<!-- rome 라이브러리 존재시 -->

<bean class="org.springframework.http.converter.feed.AtomFeedHttpMessageConverter" />

<bean class="org.springframework.http.converter.feed.RssChannelHttpMessageConverter" />

<!--  -->

</util:list>


<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

<property name="webBindingInitializer">

<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">

<property name="validator" ref="validator" />

<property name="conversionService" ref="conversion-service" />

</bean>

</property>

<property name="messageConverters" ref="messageConverters"/>

<!-- <mvc:argument-resolvers> 태그 존재시 -->

<!--

<property name="customArgumentResolvers">

</property>

-->

<!-- <mvc:return-value-handlers> 태그 존재시 -->

<!--

<property name="customReturnValueHandlers">

</property>

-->

</bean>


<bean class="org.springframework.web.servlet.handler.MappedInterceptor">

<constructor-arg index="0">

<null />

</constructor-arg>

<constructor-arg index="1">

<bean class="org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor">

<constructor-arg index="0" ref="conversion-service" />

</bean>

</constructor-arg>

</bean>


<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">

<property name="messageConverters" ref="messageConverters"/>

<property name="order" value="0"/>

</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver">

<property name="order" value="1"/>

</bean>

<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver">

<property name="order" value="2"/>

</bean>

이렇게 변경이 되었다 

먼저 변경된  부분만 이야기하면 

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

이 두 부분이 바뀐것이 가장 큰 변화이고 

그다음은 customArgumentResolvers 이 속성의 인터페이스가 변경 되었다.

기존에는 WebArgumentResolver인터페이스를 상속 받았으나 3.1부터는 HandlerMethodArgumentResolver 인터페이스를 상속 받아 구현을 해야한다. 

하지만 <mvc:annotation-driven/> 여기서 등록시에는 기존 WebArgumentResolver 이부분을 구현한 클래스가 사용은 가능하다. 내부적으로 ServletWebArgumentResolverAdapter 클래스를 사용하여 호환 가능하게 변경을 해준다. 

하지만 생각지 못한 버그가 발생할 수 있으니 변경된 인터페이스를 적용하는 것을 추천한다.


그리고 customModelAndViewResolvers 이 속성 또한 변경되었다. 

기존에는 ModelAndViewResolver인터페이스를 상속 받았으나 3.1부터는 HandlerMethodReturnValueHandler 인터페이스를 상속받아 구현해야한다.

이름은 customReturnValueHandlers 속성의 이름으로 변경되었으며 WebArgumentResolver와 같이 인터페이스도 변경되었다. 


추가로 로딩되는 Bean으로는 

<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">

<property name="messageConverters" ref="messageConverters"/>

<property name="order" value="0"/>

</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver">

<property name="order" value="1"/>

</bean>

<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver">

<property name="order" value="2"/>

</bean>

이렇게 3개의 Bean이 로딩이 된다 

첫번째 로딩되는 Bean인 ExceptionHandlerExceptionResolver 클래스는 RequestMappingHandlerAdapter 에서 참조 하는 messageConverters를 똑같이 참조하고 있다. 

용도를 정확히는 확인해보지는 않았지만 대략 @RequestBody의 @Valid 어노테이션을 사용할 수 있는 것과 관계 있는 것으로 보인다. 
이부분은 추후로 보완할 예정이다.





Posted by 코바

보통 DB에서 칼럼값을 가져 오게 되면 언더바(_)가 붙어 있는 문자열을 가져 오게 된다.

xxx_name, yyy_code 이런식으로 가져오게되는 경우가 많이 생긴다.

이것을 camel case 즉 낙타등 표기법으로 변경해서 가져오면 java에서 사용하기 적절한 문자열이 된다.


xxx_name -> xxxName 

yyy_code -> yyyCode 


만들어 쓸까 고민했지만 혹시나 해서 찾아보니 역시나  Spring에서는 이렇게 변경해주는 함수가 존재한다. 

org.springframework.jdbc.support 이 패키지에서 JdbcUtils 클래스안에 이 함수가 존재한다.

JdbcUtils.convertUnderscoreNameToPropertyName(String name) 

이렇게 호출을 하며 반환된 값은 camel case로 가져온다.


직접 구현 해도 되나 이 함수를 이용해도 되겠다.



Posted by 코바

MappingJacksonJsonView 를 사용해 JSON 결과를 보이도록 하다 보면 결과 값에 ModelKey 혹은 속성명이 같이 결과 같에 나오게 된다.


위 의 그림처럼 저런 result( 직접 지정해둔 modelKey명 )라고 값이 붙어서 json 결과 값이 나오게 된다.
이부분을 제외 시키는 방법을 찾아보니

MappingJacksonJsonView 설정 하는 부분에서
    <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" >
     <property name="objectMapper" ref="objectMapper" />
     <property name="modelKey" value="result" />
     <property name="extractValueFromSingleKeyModel" value="true" />
    </bean>

extractValueFromSingleKeyModel 속성 부분을 true 라고 해주면 앞에 modelKey값 또는 속성 나오는 부분을 제외 하고 json 데이터로 나온다.


이렇게 깔끔하게 나오게 된다. 

참고1. modelKey를 정해주는 이유는 model에 다른 값이 들어 있을 경우 그것 까지 json 값으로 바꿔 줄 수 있으니 직접 json 값으로 바꿔줄 부분을 선택 하기 위해 modelKey 속성을 지정하여 하게 된다.

참고2. Model 안에 값이 2개 이상인 상태에서 modelKey를 사용 하지 않고 전체 json으로 변경할 경우에는 이 속성은 먹히지 않는다.

참고3. Spring 3.1이상에서 사용 가능합니다.



Posted by 코바