ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [12] Spring Web MVC : ViewResolver
    Spring/Spring boot 2020. 6. 21. 09:27
    반응형

    [ContentNegotiatingViewResolver]

    ContentNegotiatingViewResolver는 file명 또는 Accept header를 기반으로 view를 처리하는 ViewResolver의 구현체입니다.

     

    ContentNegotiatingViewResolver는 view 자체를 resolving하지 않는 대신 다른 view resolvers에게 resolving 하도록 위임합니다. 보통 application context에서 view resolving을 위임받을 view resolver들을  자동으로 선택 하지만 viewResolvers property를 사용하여 사용하고자 하는 view resolver를 명시적으로 설정할 수도 있습니다. 명시적으로 설정한 view resolver가 제대로 동작하려면 order property를 다른 property보다 높은 우선 순위로 설정해야 합니다. (기본값은 Ordered.HIGHEST_PRECEDENCE 입니다.)

    View resolver는 request에 걸맞은 View를 선택하기 위해 request된 media type을 사용합니다.

     

    1. request 경로는 file 확장자를 가지고 있고 setFavorPathExtension(boolean) property 값이 true이면 media type[각주:1]을 맞추기 위해mediaTypes property를 검사합니다.
    2. request가 확장자를 정의하는 parameter를 포함하고 setFavorPathExtension(boolean) property 값이 true이면  media type을 맞추기 위해 mediaTypes property를 검사합니다. 기본으로 설정되는 parameter의 이름은 format이고 parameterName property를 사용하여 paramter 이름을 설정할 수 있습니다.
    3. mediaTypes property 중에 일치하는 것이 없고 Java Active Framework(JAF)를 사용하도록 설정되어 있으며 class path에 존재하는 경우 FileTypeMap.getContentType(String)이 대신 사용됩니다. 
    4. 1~3 중에 media type을 맞추지 못하고 ignoreAcceptHeader가 false이면 reqeust Accept header를 사용하지 않습니다.

    일단 request media type이 결정되면 ContentNegotiatingViewResolver는 resolving을 위임받을 각 resolver들에게 View를 resolving하도록 요청하고 결정합니다. (reqeust media type이 view의 content type과 맞는 경우) 가장 잘 맞는 view를 반환합니다.

    또한 ContentNegotiatingViewResolverdefaultViews property를 표시하므로 view resolver가 제공 한 view를 재정의 할 수 있습니다. 기본적으로 제공되는 view는 candicate로써 제공되며 request content type(상기의 file 확장자, parameter 또는 Accept header)도 여전히 필요합니다. 기본 content type을 직접 설정할 수도 있으며 Accept header, file 확장자 또는 parameter 등과 일치하지 않는 경우 설정해 놓은 기본 content type을 반환합니다.

    예를 들어 request path가 /view.html인 경우 view resolver는 html file 확장자를 기반으로 text/html content type을 가진 view를 찾을 것입니다. text/html reqeust Accept header에 대한 request와 동일한 결과입니다.

     

    view resolver 중 하나로 들어오는 accept header에 따라 응답이 달라지는 view resolver

    accept header에 있는  정보는 browser가 원하는 server의 response type입니다. (client가 server에게 알려주는 정보)

    request가 있을 경우 응답을 만들어낼 수 있는 모든  viewer를 찾아냄  -> accept header와 비교해서 client가 필요로 하는 view를 반환합니다.

    사용자에게 필요한 view를 가장 간단하게 알 수 있는 것이 accept header이지만 경우에 따라서는 제공하지 않는 request도 존재합니다. 그런 경우에는 format이라는 parameter를 사용합니다. (e.g. "/path?format=pdf")

     

     

    ContentNegotiatingViewResolver는 이미 등록되어 있는 상태이므로 request는 JSON으로, response는 XML로 하도록 하는 예제를 통해 ContentNegotiatingViewResolver의 동작을 살펴보도록 합니다.

     

    먼저 test code를 다음과 같이 작성합니다.

    @RunWith(SpringRunner.class)
    @WebMvcTest(UserController.class)
    public class UserControllerTest {
    
        @Autowired
        MockMvc mockMvc;
    
        @Test
        public void createUser_XML() throws Exception {
            String userJson = "{\"username\":\"dave\", \"password\":\"123\"}";
            mockMvc.perform(post("/users/create")
                    .contentType(MediaType.APPLICATION_JSON)	//	①
                    .accept(MediaType.APPLICATION_XML)	//	②
                    .content(userJson))
                    .andExpect(status().isOk())
                    .andExpect(xpath("/User/username")	//	③
                            .string("dave"))
                    .andExpect(xpath("/User/password")
                            .string("123"));
    
        }
    }

    ① request media type은 application/json으로 지정합니다.

    ② response media type은 application/xml로 지정합니다.

    ③ application/xml response media type의 data에 접근하고자 할 때는 xpath() method를 사용합니다. 여기서는 "/User/username" path의 data가 "dave"일 것과 "/User/passworld" path의 data가 "123" 일 것을 기댓값으로 주고 test를 진행합니다.

     

    UserController, User class는 이전 게시글과 동일하게 두고 test를 진행합니다.

     

     test code의 acceptI() method에 parameter로 MediaType.APPLICATION_XML을 지정했지만 "application/xml" media type을 처리할 HttpMessageConverter가 없기 때문에 406 status(Not acceptable status)가 발생한 것입니다. HttpMessageConverter는 HttpMessageConvertersAutoConfiguration에 의해 적용됩니다. 

     

    HttpMessageConvertersAutoConfiguration -> JacksonHttpMessageConvertersConfiguration을 살펴보면 @ConditionalOnClass({XmlMapper.class})라는 annotation을 적용하여 XmlMapper.class가 class path에 존재해야만 application/xml media type을 처리할 수 있는 MappingJackson2XmlHttpMessageConverter bean을 등록하도록 되어 있습니다.

    XmlMapper.class를 class path에 넣기 위해 pom.xml에 다음과 같은 의존성을 추가해 줍니다.

    <dependency>
    	<groupId>com.fasterxml.jackson.dataformat</groupId>
    	<artifactId>jackson-dataformat-xml</artifactId>
    	<version>2.9.6</version>
    </dependency>

     

    다시 test code를 실행하면 pass 됨을 확인할 수 있습니다. JSON의 경우 Spring boot에서 특별히 의존성을 추가하지 않아도 response 가능하지만 XML로 response 할 경우에는 별도의 의존성이 추가되어야 함에 주의합니다.

     

    1. media type(이전의 MIME type)은 internet에서 전송되는 내용을 file 형식과 content의 두 부분으로 나눠 식별하기 위해 사전에 정의해 놓은 값들입니다. 

      media type의 예: application/json, text/css [본문으로]

    'Spring > Spring boot' 카테고리의 다른 글

    [14] Spring Web MVC : Web JAR  (0) 2020.06.23
    [13] Spring Web MVC : static resource 지원  (0) 2020.06.22
    [11] Spring Web MVC: HttpMessageConverters  (0) 2020.06.17
    [10] Spring Web MVC: Introduction  (0) 2020.06.15
    [09] Test  (0) 2020.06.10

    댓글

Designed by Tistory.