티스토리 뷰

ICT Eng/Spring

[Spring Boot] ViewResolver

nroo 2019. 1. 11. 15:06

백기선 - 스프링 부트 개념과 활용

ViewResolver

스프링부트에 등록 되어있는 스프링 웹 MVC의 ContentNegotiatingViewResolver 가 어떤 contentType일 때 어떤 응답을 보내고, accept header 요청에 의해서 해당 요청에 맞는 응답을 보내는 작업을 알아서 해준다.

그래서 Accept header를 XML 타입으로 설정하고 xpath를 이용해서 XML로 받는 응답을 검증하는 테스트코드를 작성하고 실행시켜보면 406 HttpMediaTypeNotAcceptableException이 떨어진다.

package io.namjune.springbootconceptandutilization.user;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class UserControllerTest {

   @Autowired
   MockMvc mockMvc;

   @Test
   public void createUser_JSON() throws Exception {
       String userJson = "{\"username\":\"namjune\", \"password\":\"123\"}";
       mockMvc.perform(post("/users/create")
          .contentType(MediaType.APPLICATION_JSON_UTF8)
          .accept(MediaType.APPLICATION_XML)
          .content(userJson)
      )
          .andExpect(status().isOk())
          .andExpect(xpath("/User/username").string("namjune"))
          .andExpect(xpath("/User/password").string("123"));
  }
}

스프링 부트의 HttpMessageConverters는 HttpMessageConvertersAutoConfiguration 클래스로 인해서 적용이 된다. 해당 클래스를 찾아보면 spring-boot-autoconfigure의존성 아래에 http/ 안에 존재한다. 이 클래스에 @Import 로 선언되어있는 JacksonHttpMessageConvertersConfiguration 클래스를 보면 MappingJackson2XmlHttpMessageConverterConfiguration 클래스가 정의 되어있고, MappingJackson2XmlHttpMessageConverterConfiguration 클래스에는 @ConditionalOnClass(XmlMapper.class)으로 XmlMapper클래스가 classpath에 존재해야만 등록되도록 정의되어 있다. 406 에러가 떨어진 이유는 xml로 변환할 수 있는 컨버터가 등록되어있지 않기 때문이다.

@Configuration
class JacksonHttpMessageConvertersConfiguration {
 
...
   
 @Configuration
@ConditionalOnClass(XmlMapper.class)
@ConditionalOnBean(Jackson2ObjectMapperBuilder.class)
protected static class MappingJackson2XmlHttpMessageConverterConfiguration {

@Bean
@ConditionalOnMissingBean
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter(
Jackson2ObjectMapperBuilder builder) {
return new MappingJackson2XmlHttpMessageConverter(
builder.createXmlMapper(true).build());
}

}

...
   
}

XML 메시지 컨버터를 classpath에 추가해주면 문제를 해결할 수 있다. 의존성을 추가해주면 된다. 이제 위에서 작성한 XML 검증 테스트를 통과시킬 수 있다.

보통 JSON을 많이 사용하기 때문에 추가설정을 아무것도 하지 않아도 되지만, XML로 내보내고 싶은 경우 의존성을 추가해서 필요한 메세지 컨버터를 테스트 할 수 있다.

dependencies {
  ...
     
   implementation('com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.6')
 
  ...
}



댓글