본문 바로가기

Spring

Spring WEB MVC와 HttpMessageConverters

MVC 패턴이란 말은 스프링부트를 공부하다보면 자연스럽게 많이 들을 수 밖에 없는 이야기 같습니다.

저 역시 스프링부트를 처음 공부하면서 MVC 패턴을 접했고 이해하기 위해 많은 자료들을 참고했습니다.

그만큼 많은 사람들이 스프링 또는 부트에서 MVC 패턴을 활용한 서비스를 제작하고 있는거라 생각하면 되겠습니다.

Spring WEB MVC

스프링부트 프레임워크에서는 이러한 MVC 패턴을 별도의 설정없이 바로 개발을 시작할 수 있도록 도와줍니다.

그 이유로는 AutoConfiguration을 통한 자동설정 지원에 있습니다.

spring-boot-autoconfigure -> META-INF -> spring.factories

 spring.factories ->  WebMvcAutoConfigutration

WebMvcAutoConfigutration를 통해 스프링부트에서는 web MVC를 아무설정없이 바로 사용할 수 있습니다.

HttpMessageConverters

스프링 프레임워크에서 제공하는 인터페이스로 HttpMessageConverters가 있습니다.

http 요청으로 들어오는 본문을 객체로 변환하거나 또는 객체를 http 응답 본문으로 변환 할 때 사용됩니다.

많이 사용하는 것은 @ResponseBody이며 어떤 데이터가 요청으로 들어올 때 요청의 본문에 있는 데이터를 내가 객체로

받기 위해서는 @RequestBody입니다.

흔히 http 요청을 할 때 Headers에 Key 값으로 Content-Type, value로 application/x-www-form-urlencoded을 작성!

만약 Headers에 Content-Type이 json이고 요청과 본문이 json으로 들어온다면 json-message-converter가 사용되어

json 메시지를 우리가 정의한 객체로 변환해줍니다.

그리고 객체를 리턴할 때 이 객체를 그대로 response로 보낼 수는 없겠죠??(http는 문자)

이 때 httpmessageconverters를 사용( 이 상황에서는 json-message-converter)! 

구조 

UserController (반환형 User 객체)

@ResponseBody, @RequestBody를 사용하게 되면  httpmessageconverter를 활용해 User라는 객체로 받을 수 있습니다

그리고 @RestController가 붙어있으면 @ResponseBody를 생략할 수 있으며 그냥 @Controller를 사용하게 될 경우

꼭 앞에 @ResponseBody를 명시해줘야 합니다. 그렇지 않으면 이 return값에 해당하는 뷰를 찾으려고 시도합니다!

UserController (반환형 String)

반환형을 User라는 객체가 아닌 String으로 주게 되면 String message converter가 사용됩니다. int형이라면? int 컨버터!

Test Code Example

폴더 구조

UserControllerTest

import org.hamcrest.Matchers;
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;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

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

    @Autowired
    MockMvc mockMvc; // webmvctest라는 어노테이션을 사용하면 자동으로 빈으로 만들어주기 때문에 우리가 그냥 빈에 있는걸 꺼내다가 막 사용 가능

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

}

UserController

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

@RestController
public class UserController {

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

User

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;
    }

}

User를 구현할 때 getter, setter는 무조건 존재해야 합니다. (자바빈 규약에 의해 getter, setter를 사용해서 바인딩을 해주므로)

출처 : https://docs.spring.io/spring/docs/5.0.7.RELEASE/spring-framework-reference/web.html#mvc-config-message-converters

 

Web on Servlet Stack

This part of the reference documentation covers support for Servlet stack, WebSocket messaging that includes raw WebSocket interactions, WebSocket emulation via SockJS, and pub-sub messaging via STOMP as a sub-protocol over WebSocket. 4.1. Introduction The

docs.spring.io

백기선님 강의