HttpMessageConverters

HttpMessageConverters는 스프링에서 제공하는 인터페이스로 스프링 MVC의 일부분이다. HTTP 요청 본문을 객체로 변환하거나, 객체를 HTTP 응답 본문으로 변환할 때 사용한다.

@RestController
public class UserController {

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

    @PostMapping("")
    public @ResponseBody User craate(@RequestBody User user) {
        return null;
    }
}

HttpMessageConverters는 보통 @RequestBody, @ResponseBody와 같이 사용된다.

@RequestBody

@RequestBody는 컨트롤러가 요청을 받을 때 본문에 들어있는 데이터를 객체로 받을 수 있으며, 스프링이 객체로 변환해준다. HttpMessageConverters는 여러가지가 있다. 어떤 요청을 받았는지, 어떤 응답을 보내야 하는지에 따라 사용해야하는 컨터버가 달라진다. 요청에는 content-type 이라는 헤더가 있는데, 이 헤더값에 따라 다른 컨버터를 사용하게 된다.

@RequestBody

컨트롤러에서는 객체 자체를 응답할 수 없다. 그 이유는 HTTP 응답은 문자열이기 때문이다. @RequestBody를 사용하면 객체를 문자열로 변환할 수 있다. 리턴 타입이 Composition 타입인 경우에는 기본적으로는 JSON 메시지 컨버터가 사용된다. 리턴 타입이 String인 경우 String 메시지 컨버터가 사용된다.

컨트롤러에 @RestController가 붙어있으면 @ResponseBody를 생략해도 된다. 반면 @Controller인 경우에는 @ResponseBody가 아니라면 ViewNameResolver가 사용된다. 컨버터를 이용하기 위해서는 @ResponseBody를 붙여야 한다.

실습

우선 사용자 생성에 대한 컨트롤러 테스트를 작성해보자.

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

    @Autowired
    MockMvc movckMvc;

    @Test
    public void createUser_JSON() throws Exception {
        String userJson = "";

        movckMvc.perform(post("/users/create")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .content(userJson))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.username", is(equalTo("jch"))))
            .andExpect(jsonPath("$.password", is(equalTo("123"))));

    }
}

/users/create를 매핑한 컨트롤러가 없기 떄문에 404응답을 받으면서 테스트가 실패한다. 컨트롤러를 작성해보자.

@RestController
public class UserController {

    @PostMapping("/users/create")
    public User craate() {
        return null;
    }
}

이번에는 200응답을 받지만, jsonPath에 지정한대로 본문이 응답되지 않았기 때문에 테스트가 실패한다. 도메인을 만들고 컨트롤러 코드와 테스트 코드를 약간 수정해보자.

// 도메인
public class User {
    
    private Long id;

    private String username;
    
    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

// 컨트롤러
@PostMapping("/users/create")
public User craate(@RequestBody User user) {
    return user;
}

// 테스트
@Test
public void createUser_JSON() throws Exception {
    String userJson = "{\"username\":\"jch\", \"password\":\"123\"}";

    movckMvc.perform(post("/users/create")
                     .contentType(MediaType.APPLICATION_JSON_UTF8)
                     .accept(MediaType.APPLICATION_JSON_UTF8)
                     .content(userJson))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.username", is(equalTo("jch"))))
        .andExpect(jsonPath("$.password", is(equalTo("123"))));
}

간단하게 테스트하기 위해 컨트롤러에서는 메시지컨버터로 변환된 요청 도메인 객체를 그대로 반환한다. 테스트는 요청 본문을 응답본문에 알맞는 json 문자열로 변경했다. 이제 테스트가 통과한다.

해당 포스팅은 스프링 부트 개념과 활용 강의 내용을 토대로 작성하였습니다.