본문 바로가기
Java & 스프링/스프링부트 톺아보기

[스프링 부트] 스프링 MVC - 스프링 부트의 Message Converter

by hjhello423 2019. 10. 23.

스프링 mvc를 설정하지 않아도 부트에서 기본적으로 사용할 수 있는 이유는 기본적인 설정을 자동으로 해주기 때문이다. dependency에 'spring-boot-starter-web'이나 'mvc'를 추가하면 기본적인 설정을 해준다. 아래 경로에서 해당 내용을 찾아보자.

spring-boot-autoconfigure-2.1.5.RELEASE.jar -> spring.factories-> WebMvcAutoConfiguration

 


스프링이 request에 대한 응답을 response 할 때 json, xml과 같은 다양한 타입을 자동으로 변환하는 역할은 누가 하는 걸까?

바로 HttpMessageConverter 스프링에서 제공하는 interface에서 이 역할을 수행한다.

 

Spring MVC는 HttpMessageConverter 인터페이스를 사용하여 HTTP 요청 및 응답을 변환하는데 http요청 본문을(request body) 객체로 변환하거나 객체를 http응답 본문(response body)으로 변환한다.

그리고 Content-type을 참고해서 json converter나 string converter 등을 자동으로 선택해 사용한다

 

converter의 역할을 확인해 보기 위해 테스트 코드를 작성해 보자.

지금부터 작성할 소스는 글 가장 아래의 git에서 확인하면 된다. ( git의 User, UserController 클래스 참고 )

 

우선 json으로 응답을 받기를 원하는 상황을 가정해 보자.

우리는 json응답을 받기 위해 request의 요청 헤더에 content-type을 json으로 요청할 것이다.

아래의 코드는 '/users/create' 경로로 요청했을 때 response의 id와 pwd가 일치하는지 확인하는 하는 코드이다.

응답은 json형식으로 확인하게 된다.

 

이 코드가 테스트를 통과하면 우린 응답을 json형식으로 받은 게 증명되는 것이다.

// <UserControllerTest.java>

@Test
public void createUser_JSON() throws Exception {
    String userJson = "{\"username\":\"hongjun\",\"password\":\"1234\"}";
    mockMvc.perform(post("/users/create")
            .contentType(MediaType.APPLICATION_JSON_UTF8)
            .accept(MediaType.APPLICATION_JSON_UTF8)
            .content(userJson))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.username", is(equalTo("hongjun"))))
            .andExpect(jsonPath("$.password", is(equalTo("1234"))));
}

 

 


위에서 작성한 테스트 코드가 정상 동작하도록 하기 위해 간단한 controller와 User 클래스를 작성해 보자.

 

// <User.java>

public class User {

    private Long id;
    private String username;
    private String password;

   getter/setter() 생략....
}

 

// <UserController.java>

import org.springframework.web.bind.annotation.*;

@RestController
public class UserController {

    @GetMapping("/hello")
    public @ResponseBody
    String hello() {
        return "hello";
    }

    @PostMapping("/users/create")
    public User create(@RequestBody User user) {
        return user;
    }
}

@RestController 사용하면 @ResponseBody를 생략 가능하다. @RestController 선언으로 인해 converter를 자동으로 사용하기 때문이다.

@RestController를 생략하면 controller는 viewresolver를 사용해서 해당하는 이름의 view를 찾게 된다. 이때 return type은 String이어야 한다.

 

스프링 부트에서 converter는 기본적으로 감지 가능한 기본값이 포함되어 있다. 예를 들어 Jackson (Jackson 라이브러리를 사용하여) 또는 XML (사용 가능한 경우 Jackson XML 확장명을 사용하거나 Jackson XML 확장을 사용할 수 없는 경우 JAXB를 사용하여)로 객체를 자동으로 변환할 수 있다.

기본적으로 문자열은 UTF-8로 인코딩 된다.

 

Message Converter

 


xml형식으로 응답하는 테스트도 만들어 보자.

스프링 부트의 MessageConverter는 자동으로 응답 형식을 변환해줄 수 있다.

request의 header에서 content-type의 값을 보고 판단한다.

content-type을 xml로 요청하는 테스트 코드를 추가해 보자.

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

응답 데이터의 타입은 HttpMessageConvertersAutoConfiguration에서 자동으로 content-type 값을 참조하여 결정해준다.

HttpMessageConvertersAutoConfiguration 내에서 xml 형식으로 컨버팅 해주는 부분은  MappingJackson2XmlHttpMessageConverterConfiguration 클래스를 참고해 보자. 해당 클래스에서 xml형식으로 컨버팅 해주는 역할을 수행한다.

 

위의 테스트 코드는 실행되지 않는다. 

MappingJackson2XmlHttpMessageConverterConfiguration 클래스에 선언된 어노테이션을 참고해 보면 '@ConditionalOnClass(XmlMapper.class)'에서 XmlMapper.class가 참조 불가능으로 표시될 것이다.

@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형식으로 응답을 할 수 있도록 XmlMapper.class 추가를 위해 외무 라이브러리를 추가 해 주자.

pom.xml에 maven repo에서 xml 관련 모듈을 추가해주면 된다.

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

 

테스트 코드를 실행해 보면 정상 동작하는 것을 확인해 볼 수 있다.

 


링크

 

해당 포스팅은 백기선 님의 인프런 강좌를 참고하여 작성하였습니다.
반응형

댓글