스프링 웹 MVC-10.HTTP 메시지 컨버터(개요, JSON, XML)


HTTP 메시지 컨버터 1부: 개요

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.html#configureMessageConverters-java.util.List-
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.html#extendMessageConverters-java.util.List-

HTTP 메시지 컨버터

  • 요청 본문에서 메시지를 읽어들이거나(@RequestBody), 응답 본문에 메시지를 작성할 때(@ResponseBody) 사용한다.

기본 HTTP 메시지 컨버터

  • 바이트 배열 컨버터
  • 문자열 컨버터
  • Resource 컨버터
  • Form 컨버터 (폼 데이터 to/from MultiValueMap<String, String>)
    () 괄호는 의존성이 있는 경우만.
  • (JAXB2 컨버터)
  • (Jackson2 컨버터)
  • (Jackson 컨버터)
  • (Gson 컨버터)
  • (Atom 컨버터)
  • (RSS 컨버터) …

설정 방법

  • 기본으로 등록해주는 컨버터에 새로운 컨버터 추가하기: extendMessageConverters
  • 기본으로 등록해주는 컨버터는 다 무시하고 새로 컨버터 설정하기: configureMessageConverters
  • 의존성 추가로 컨버터 등록하기 (추천)
    • 메이븐 또는 그래들 설정에 의존성을 추가하면 그에 따른 컨버터가 자동으로 등록 된다.
    • WebMvcConfigurationSupport
    • (이 기능 자체는 스프링 프레임워크의 기능임, 스프링 부트 아님.)

참고

  • https://www.baeldung.com/spring-httpmessageconverter-rest

HTTP 메시지 컨버터 2부: JSON

스프링 부트를 사용하지 않는 경우

  • 사용하고 싶은 JSON 라이브러리를 의존성으로 추가
  • GSON
  • JacksonJSON
  • JacksonJSON 2

스프링 부트를 사용하는 경우

  • 기본적으로 JacksonJSON 2가 의존성에 들어있다.
  • 즉, JSON용 HTTP 메시지 컨버터가 기본으로 등록되어 있다.

참고

  • JSON path 문법
  • https://github.com/json-path/JsonPath
  • http://jsonpath.com/
@RestController // Rest 붙이면 이 클래스의 모든 메서드에 @ResponseBody 붙인것과 동일
public class SampleController {

    @GetMapping("/message")
    public String message(@RequestBody String body) { // @RequestBody 요청시 본문에 들어있는 메세지를 HTTP 메세지 컨버터를 사용해서 컨버전을 한다.
        System.out.println("message");
        return body;
    }

    @GetMapping("/jsonMessage")
    public Person jsonMessage(@RequestBody Person person){ // 부트는 기본적으로 jackson2가 제공하는 objectMapper 사용해서 컨버전
        return person;
    }
}
@AutoConfigureMockMvc
class SampleControllerTest {

    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    @Test
    public void jsonMessage() throws Exception {
        Person person = new Person();
        person.setId(1l);
        person.setName("jaeuk");
        String jsonString = objectMapper.writeValueAsString(person);
        System.out.println(jsonString);

        this.mockMvc.perform(get("/jsonMessage")
                .contentType(MediaType.APPLICATION_JSON) // 제이슨으로 컨텐츠를 보낼거고
                .accept(MediaType.APPLICATION_JSON) // 제이슨으로 응답이 오길 바란다.
                .content(jsonString))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(1))
                .andExpect(jsonPath("$.name").value("jaeuk"));;
    }

테스트 성공

{"id":1,"name":"jaeuk"}

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /jsonMessage
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"23"]
             Body = {"id":1,"name":"jaeuk"}
    Session Attrs = {}

Handler:
             Type = me.jaeuk.webmvc.SampleController
           Method = me.jaeuk.webmvc.SampleController#jsonMessage(Person)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"application/json"]
     Content type = application/json
             Body = {"id":1,"name":"jaeuk"}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

HTTP 메시지 컨버터 3부: XML

OXM(Object-XML Mapper) 라이브러리 중에 스프링이 지원하는 의존성 추가

  • JacksonXML
  • JAXB

스프링 부트를 사용하는 경우

  • 기본으로 XML 의존성 추가해주지 않음.

JAXB 의존성 추가

		<!-- jaxb 인터페이스 -->
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
		</dependency>
		<!-- jaxb 구현체 -->
		<dependency>
			<groupId>org.glassfish.jaxb</groupId>
			<artifactId>jaxb-runtime</artifactId>
		</dependency>
		<!-- xml->객체, 객체->xml 변환 (마샬러)-->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

Marshaller 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();

        String name = Person.class.getPackage().toString(); // getPackageName 8에는 없음.
        System.out.println(name); // 이게 package me.jaeuk.webmvc 이렇게 출력됨..
        name = name.replace("package ", "");
        System.out.println(name);

        jaxb2Marshaller.setPackagesToScan(name);
        return jaxb2Marshaller;
    }

도메인 클래스에 @XmlRootElement 애노테이션 추가

import org.springframework.oxm.Marshaller; // 잘못 받지 않도록 주의
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
class SampleControllerTest {

    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    @Autowired
    Marshaller marshaller;

    @Test
    public void xmlMessage() throws Exception {
        Person person = new Person();
        person.setId(1l);
        person.setName("jaeuk");

        StringWriter stringWriter = new StringWriter();
        Result result = new StreamResult(stringWriter);
        marshaller.marshal(person, result);
        String xmlString = stringWriter.toString();

        //System.out.println(xmlString);

        this.mockMvc.perform(get("/jsonMessage")
                .contentType(MediaType.APPLICATION_XML) // xml으로 컨텐츠를 보낼거고
                .accept(MediaType.APPLICATION_XML) // xml으로 응답이 오길 바란다.
                .content(xmlString))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(xpath("person/name").string("jaeuk"))
                .andExpect(xpath("person/id").string("1"));
    }
..

참고

  • Xpath 문법
  • https://www.w3schools.com/xml/xpath_syntax.asp
  • https://www.freeformatter.com/xpath-tester.html





© 2019. by jaeuk