[Spring] @RequestBody 어노테이션과 @ReponseBody 어노테이션의 사용

2020. 7. 6. 14:55 Spring Framework/Spring Core

@RequestBody 어노테이션과 @ReponseBody 어노테이션의 사용


웹 서비스와 REST 방식이 시스템을 구성하는 주요 요소로 자리 잡으면서 웹 시스템간에 XML이나 JSON 등의 형식으로 데이터를 주고 받는 경우가 증가하고 있다.

이에 따라 스프링 MVC도 클라이언트에서 전송한 XML 데이터나 JSON 또는 기타 데이터를 컨트롤러에서 DOM 객체나 자바 객체로 변환해서 받을 수있는 기능(수신)을 제공하고 있으며,

비슷하게 자바 객체를 XML이나 JSON 또는 기타 형식으로 변환해서 전송할 수 있는 기능(송신)을 제공하고 있다.


@RequestBody 어노테이션과 @ResponseBody 어노테이션은 각각 HTTP 요청 몸체를 자바 객체로 변환하고 자바 객체를 HTTP 응답 몸체로 변환하는 데 사용된다.

@RequestBody 어노테이션을 이용하면 HTTP 요청 몸체를 자바 객체로 전달받을 수 있다. 비슷하게 @ResponseBody 어노테이션을 이용하면 자바 객체를 HTTP 응답 몸체로 전송할 수 있다.


import org.springframework.stereotype.Controller;

import org.springframework.util.MultiValueMap;

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

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

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

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


@Controller

public class SimpleConverterController {


@RequestMapping(value = "/test/simpleTest.do", method = RequestMethod.GET)

public String simpleTestForm() {

return "test/simpleTestForm";

}


@RequestMapping(method = RequestMethod.POST)

// @RequestBody 어노테이션은 @RequestMapping에 의해 POST 방식으로 전송된 HTTP 요청 데이터를 String 타입의 body 파라미터로 전달된다.(수신)

// 그리고 @ResponseBody 어노테이션이 @RequestMapping 메서드에서 적용되면 해당 메서드의 리턴 값을 HTTP 응답 데이터로 사용한다.

// simpleTest() 메서드의 리턴 값이 String 타입이므로 String 데이터를 HTTP 응답 데이터로 전송한다.(송신)

@ResponseBody

public String simpleTest(@RequestBody String body) {

return body;

}

}


SimpleConverterController에 GET 방식으로 요청이 전달되면 simpleTestForm 뷰가 사용되는데, 이 뷰가 아래와 같은 폼을 생성한다고 해보자

<form method="POST">

이름: <input type="text" name="name" /> <br/>

나이: <input type="text" name="age" />

<input type="submit" />

</form>


이때 HTTP 몸체로 전송되는 데이터는 다음과 같은 형식을 취한다.

name=%C3%D6%B9%FC%B1%D5%$age=34


SimpleConverterController 컨트롤러는 POST 방식으로 요청이 들어오는 경우 @RequestBody 어노테이션이 적용되어 있으므로 그대로 결과 값으로 리턴한다.

그런데, @ResponseBody 어노테이션이 적용되어 있으므로 결과적으로 HTTP 요청 몸체 데이터가 HTTP 응답 몸체로 전송된다.


스프링 MVC는 HttpMessageConverter를 이용해서 자바 객체와 HTTP 요청/응답 몸체 사이의 변환을 처리하는데, @ResponseBody 어노테이션 적용 메서드의 리턴 타입이 String인 경우

HTTP 응답 데이터의 컨텐츠 타입은 "text/plain;charset=ISO-8859-1"이 된다.


1. HttpMessageConverter를 이용한 변환 처리

AnnotationMethodHandlerAdapter 클래스는 @RequestBody 어노테이션이 적용된 파라미터나 @ResponseBody 어노테이션이 적용된 메서드에 대해 HttpMessageConverter를 사용해서 변환을 처리한다. 주요 HttpMessageConverter 구현 클래스는 다음과 같다.


 구현 클래스

 설 명

 ByteArrayHttpMessageConverter(*)

 HTTP 메시지와 byte 배열 사이의 변환을 처리한다. 컨텐츠 타입은  application/octet-stream이다.

 StringHttpMessageConverter(*)

 HTTP 메시지와 String 사이의 변환을 처리한다. 컨텐츠 타입은  text/plain;charset=ISO-8859-1이다.

 FormHttpMessageConverter(*)

 HTML 폼 데이터를 MultiValueMap으로 전달받을 때 사용된다. 지원하는 컨텐  츠 타입은 application-x-www-form-urlencorded이다.

 SourceHttpMessageConverter(*)

 HTTP 메시지와 javax.xml.transform.Source 사이 변환을 처리한다. 컨텐츠 타  입은 application/xml 또는 text/xml이다.

 MarshallingHttpMessageConverter(*)

 스프링의 Marshaller와 unMarshaller를 이용해서 XML HTTP 메시지와 객체 사  이의 변환을 처리한다. 컨텐츠 타입은 application/xml 또는 text/xml이다.

 MappingJacksonHttpMessageConverter(*)

 Jackson 라이브러리를 이용해서 JSON HTTP 메시지와 객체 사이의 변환을 처  리한다. 컨텐츠 타입은 applicaion/json이다.


만약 기본 구현 클래스가 아닌 다른 구현 클래스를 사용하려면 다음과 같이 AnnotationMethodHandlerAdapter에 명시적으로 구현 클래스 목록을 지정해 주어야 한다.

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

<property name="cacheSeconds" value="0" />

<property name="alwaysUseFullPath" value="true" />

<property name="webBindingInitializer">

<bean class="madvirus.spring.chap06.binder.CustomWebBindingInitializer" />

</property>

<property name="messageConverters">

<list>

<ref bean="byteArrayHttpMessageConverter" />

<ref bean="marshallingHttpMessageConverter" />

<!--<ref bean="stringHttpMessageConverter" />-->

<!--<ref bean="formHttpMessageConverter" />-->

<!--<ref bean="sourceHttpMessageConverter" />-->

<!--<ref bean="jsonHttpMessageConverter" />-->

</list>

</property>

</bean>


<bean id="byteArrayHttpMessageConverter" class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />

<bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">

<property name="marshaller" ref="jaxb2Marshaller" />

<property name="unmarshaller" ref="jaxb2Marshaller" />

</bean>


예를 들어, 다음과 같이 JAXB 2의 어노테이션이 적용된 자바 객체가 있다고 하자

public class WriteArticleServiceImpl{@XmlAccessorType(XmlAccessType.FIELD)

@XmlRootElement(name="message-list")

public class GuestMessageList{

@XmlElement(name="message")

private List<GuestMessage> message;

...

}


@XmlAccessorType(XmlAccessType.FIELD)

@XmlType(name="", propOrder={"id", "message", "creationTime"})

public class GuestMessage{

private Integer id;

private String message;

private Date creationTime;

}


컨트롤러에서는 아래 코드와 같이 @ResponseBody 어노테이션을 이용해서 GuestMessageList를 리턴하도록 구현할 수 있을 것이다.

@Controller

public class GuestMessageController {


@RequestMapping(value = "/guestmessage/xml.do", method = RequestMethod.GET)

@ResponseBody

public GuestMessageList listXml() {

GuestMessageList list = ...;

return list;


}

...

}


JAXB2를 이용해서 자바 객체를 XML 응답으로 전송하려면 MarshallingHttpMessageConverter의 marshaller와 unmarshaller로 스프링 OXM 모듈의 Jaxb2Marshaller를 사용하면 된다.

<bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">

<property name="marshaller" ref="jaxb2Marshaller" />

<property name="unmarshaller" ref="jaxb2Marshaller" />

</bean>


<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">

<property name="classesToBeBound">

<list>

<value>madvirus.spring.chap06.model.GuestMessageList</value>

</list>

</property>

</bean>

이제 스프링 MVC는 MarshallingHttpMessageConverter를 이용해서 GuestMessageList 객체를 XML로 변환할 수 있게 된다.


2. Content-Type과 Accept 헤더 기반의 변환 처리

AnnotationMethodHandlerAdapter가 HttpMessageConverter를 이용해서 요청 몸체 데이터를 @RequestBody 어노테이션이 적용된 자바 객체로 변환할 때에는 HTTP 요청 헤더의 Content-Type 헤더에 명시된 미디어 타입(MIME)을 지원하는 HttpMessageConverter 구현체를 선택한다.

예를 들어, 요청 미디어 타입이 application/xml 이고 @RequestBody 어노테이션이 적용된 파라미터가 Source 타입인 경우 SourceHttpMessageConverter가 선택된다.

비슷하게 @ResponseBody 어노테이션을 이용해서 리턴한 객체를 HTTP 응답 객체로 변환할 때에는 HTTP 요청 헤더의 Accept 헤더에 명시된 미디어 타입을 지원하는 HttpMessageConveter 구현체를 선택한다.

예를 들어, Accept 헤더에 명시된 값이 application/json이고 @ResponseBody 어노테이션이 적용된 메서드의 리턴 타입이 자바 객체인 경우

MappingJacksonHttpMessageConverter가 선택된다. 예를 들어, 자바스크립트레서 아래와 같은 코드를 이용해서 Accept 헤더의 값으로 "application/json"을 지정했다고 하자.


<script type="text/javascript">

...

xmlhttp.open("GET","json.do",true);

xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xmlhttp.setRequestHeader("Accept", "application/json");

xmlhttp.send(null);

...

</script>


이 경우 다음과 같이 @ResponseBody 어노테이션이 적용된 메서드의 리턴 객체를 변환할 때 MappingJacksonHttpMessageConverter를 사용하게 된다.

@RequestMapping(value = "/guestmessage/json.do", method = RequestMethod.GET, headers = "accept=application/json")

@ResponseBody

public GuestMessageList listJson() {

...

}


3. MappingJacksonJsonView를 이용한 JSON 응답 생성

스프링3 버전은 자바 객체를 JSON으로 변환해서 보여주는 뷰 구현 클래스인 MappingJacksonView를 제공하고 있다. 


아래 코드는 MappingJacksonJsonView의 설정 예를 보여주고 있다.

<bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" />


<bean id="pageJsonReport" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />


컨트롤러에서는 다음과 같이 뷰 이름으로 MappingJacksonJsonView 타입의 빈을 설정해주면 된다.

@RequestMapping("/pageReport")

public ModelAndView pdfReport() {

List<PageRank> pageRanks = new ArrayList<PageRank>();

pageRanks.add(new PageRank(1, "/bbs/mir2/list"));

pageRanks.add(new PageRank(2, "/bbs/mir3/list"));

pageRanks.add(new PageRank(3, "/bbs/changchun2/list"));

return new ModelAndView("pageReport", "pageRanks", pageRanks);

}


MappingJacksonJsonView는 모델에 저장된 모든 객체를 JSON 형식으로 변환해준다.

{"report":{"pageRanks":["rank":1,"page"."/bbs/mir2/list"},{"rank":2,"page":"/bbs/mir3/list},{"rank":3,"page":"/bbs/changchun2/list"}]}}


예를 들어,  컨틀롤러에서 모델에 다음과 같이 값을 설정했다고 해보자

public String controllerMethod(Model model){

...

model.addAttribute("report", report);

model.addAttribute("summary", summary);

...

}


 컨트롤러에서 위와 같이 모델을 설정한 경우 MappingJacksonJsonView는 다음과 같은 형식의 JSON 응답 결과를 생성한다.

{"report":.... "summary":...}



출처: https://devbox.tistory.com/entry/Spring-RequestBody-어노테이션과-ReponseBody-어노테이션의-사용?category=574587 [장인개발자를 꿈꾸는 :: 기록하는 공간]

'Spring Framework > Spring Core' 카테고리의 다른 글

XML 스키마 기반의 POJO 클래스를 이용한 AOP 구현  (0) 2020.07.06
[Spring] AOP 개요  (0) 2020.07.06
[Spring] Locale 처리  (0) 2020.07.06
[Spring] ViewResolver 설정  (0) 2020.07.06
[Spring] 파일업로드 처리  (0) 2020.07.01
[Spring] 요청 URI 매칭  (0) 2020.07.01
[Spring] 모델 생성하기  (0) 2020.07.01
[Spring] 뷰 지정  (0) 2020.07.01