어떤 요청을 할 때, 응답 형태를 text/html 로 할 수도 있고, application/xml 로 할 수도 있고,
application/json 형태로 할 수도 있다.
이런 경우, 지금까지 난 ContentNegotiatingViewResolver 를 통해 ViewResolover와 View를
등록하고 요청 url 끝에 확장자를 붙여서 ContentNegotiatingViewResolver 가 적절한 ViewResolver 를 선택하여 원하는 형태의 View 로 출력하게끔 했었다.
헌데, Model 의 정보를 나타내야할 형태가 고작 html, xml이나 json 을 쓰는게 다 인 경우가 많고, 이런 경우
Model 오브젝트를 xml로 컨버트 해주는 MarshallingHttpMessageConverter 와
json 으로 컨버트 해주는 MappingJackson2HttpMessageConverter 를 등록 하여 사용하는 것이 훨씬 깔끔하다고 느껴졌다.
게다가 spring 3.2 에선 @RequestMapping 의 속성에 produces와 consume 이 생겨 요청에 대한 응답을 축소 할 수 있어서 더욱 ContentNegotiatingViewResolver 보단 @ResponseBody, @RequestBody 와 Convert 하여 처리해 주는 것이 깔끔하게 느껴졌다.
우선, 컨버터를 등록해줘야 모델 오브젝트를 적절한 형태로 컨버트 할 수 있다.
난 스프링 설정 파일로 그동안 쭉 xml 을 써왔지만 스프링 3.1 부턴 @Configuration 을 통한 자바 설정 파일로 바꿨다..
훨씬 강력하고, 이해하기 쉽고, 관리도 쉽기 때문이다.
@Configuration 자바 설정 파일에서 mvc 를 확장하기 위해선 서블릿 컨텍스트에 해당하는 설정파일에서,
WebMvcConfigurer를 구현하여야하는데, 일반적으로 모든 확장포인트를 일일히 구현하기가 매우 번거롭고, 귀찮다.
또한 mvc의 모든 기능을 확장 할 일은 사실상 거의 없다고 봐도 된다. 그렇기 때문에 스프링에서 이미 WebMvcConfigurer를 구현해서 제공하고 있는 WebMvcConfigurerAdapter 를 상속해서 필요한 부분만 확장 하면 편하다.
WebMvcConfigurerAdapter 는 추상 클래스기 때문에 단독으로 사용할 수는 없다.
@Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
jackson2HttpMessageConverter.setPrettyPrint(true);
logger.info("Creating Jackson converter: "+ jackson2HttpMessageConverter.getClass().getSimpleName());
converters.add(jackson2HttpMessageConverter);
converters.add(xmlConverter());
}
@Bean
public CastorMarshaller marshaller(){
CastorMarshaller castorMarshaller = new CastorMarshaller();
String[] targetPackages = {"me.anna.dommain"};
castorMarshaller.setTargetPackages(targetPackages);
return castorMarshaller;
}
@Bean
public MarshallingHttpMessageConverter xmlConverter(){
MarshallingHttpMessageConverter marshallingHttpMessageConverter = new MarshallingHttpMessageConverter(marshaller());
List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
supportedMediaTypes.add(MediaType.APPLICATION_XML);
marshallingHttpMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
return marshallingHttpMessageConverter;
}
위 와 같이 컨버터를 등록 해주고(자세한 설명은 생략- 궁금하신 분은 댓글 달아주시면 답글 드릴께요),
@Override
public void configureContentNegotiation(
ContentNegotiationConfigurer configurer) {
configurer.
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}
확장자에 따른 미디어 타입을 결정해주는 contentNegotiation 설정을 해준다..
이렇게 해주면 기본적으로 컨버터를 통한 Model Object 컨버트 하여 표현하는 기능을 사용할 준비가 다 된것이다..
간단한 예제를 살펴보자..
@RequestMapping(value = "/filelist", produces={"application/xml", "application/json"})
@ResponseStatus(HttpStatus.OK)
public @ResponseBody List<FileDomain> listWithMarshalling(){
return fileService.getFileList();
}
@RequestMapping(value = "/filelist")
public String fileList(Model model){
model.addAttribute("fileList", listWithMarshalling());
return "filelist";
}
위 와 같은 형태로 @ResponseBody 와 컨버터를 통한 Model Object 를 컨버트 하여 표현할 수 있다..
localhost/filelist 를 호출 하면 일반적인 html 형태의 파일리스트가 호출 된다.
localhost/filelist.xml 을 호출하면 MarshallingHttpMessageConverter 에 의해 xml 형태로,
localhost/filelist.json 을 호출하면 MappingJackson2HttpMessageConverter 에 의해 json 형태로 화면에 출력 된다.
ContentNegotiatingViewResolver 를 통해 적절한 ViewResolver 를 통해 화면에 표현할 지, @ResponseBody 와 Converter 를 통해 화면에 표시할 지는 상황에 따라 적절히 선택하면 될 것이다..
@ResponseBody 와 Converter 가 더 깔끔해보인다는건 다분히 내 개인적인 생각일 뿐이다..
단, 위 예제와 거의 동일한 예제가 2013년 5월 13일에 스프링 공식 블로그에 개제되었다..