서론
스프링에서 비동기 처리를 하는 경우 @RequestBody 와 @ReponseBody 를 사용합니다. 여기서는 좀 더 자세하게, 위 어노테이션을 사용하여 어떻게 비동기 처리를 할 것인지에 대해서 배워보겠습니다.
클라이언트와 서버의 비동기 통신 처리
웹에서 이루어지는 데이터를 가져오고, 전송하는 이러한 동작들은 클라이언트(Client)와 서버(Server)간의 통신이 이루어지기 때문에 가능합니다.
예를들어 우리가 브라우저에서 검색 키워드를 입력하고 검색 버튼을 누르게 되면 검색 키워드가 클라이언트(ex. Js)를 통해 서버(ex. Java)로 전송이되며 서버에서 검색 키워드를 이용하여, 클라이언트에서 요청한 메시지를 처리하고, 응답을 만들어서 다시 클라이언트로 보내며 클라이언트는 화면에 뿌리는 역할을 하게 됩니다.
여기서 중요한 포인트가 바로 요청(request)과 응답(response)입니다. 즉, 클라이언트에서 서버로 통신하는 메시지를 요청 메시지라고 하며, 서버에서 클라이언트로 통신하는 메시지를 응답 메시지라고 합니다.
보통 웹에서 화면 전환(refresh, F5)이 없이 이루어지는 동작들은 대부분 비동기 통신으로 이루어집니다. 비동기 통신을 하기위해서 클라이언트가 서버로 요청 메시지의 본문에 데이터를 담아서 보내야하며, 서버도 클라이언트로 응답을 보내기 위해서는 응답 메시지의 본문에 데이터를 담아서 보내야 합니다.
여기서 중요한 포인트가 바로 본문(Body)입니다. 위에서 첫 번째로 강조한 포인트 요청과 응답, 그리고 두 번째로 강조한 포인트인 본문을 연결하여 단어를 만들면요청본문(ReqeustBody), 응답 본문(ResponseBody)라는 단어가 만들어 집니다.
그러면 본문에 담겨야 하는 데이터의 형식은 무엇일까요?…
여러가지가 있겠지만 대표적으로 사용되는 것은 바로 JSON(Javascript Object Notation)입니다.
즉, 비동기 클라이언트 서버 통신을 위해서 데이터를 전송하는데 JSON이라는 형식의 데이터를 서버와 클라이언트 서로서로에게 전송하는 것입니다.
요청 본문에 담긴 값을 자바 객체로 Conversion
@RequestBody 를 통해서 자바 객체로 Conversion 을 할때 그냥 변환되는것이 아니라 HttpMessageConverter 를 사용하는데 아래의 메서드에 각종의 메시지 컨버터가 설정되어있습니다.
WebMvcConfigurationSupport.addDefaultHttpMessageConverters
만약 요청이 JSON으로 들어온 경우 요청 헤더에(request header)에 컨텐츠 타입(Content-Type)을 알려줘야 합니다. 그러면 헤더에 있는 컨텐츠 타입을 보고 JSON을 컨버팅 할 수 있는 컨버터(Jackson2ObjectMapperBuilder)를 사용해야 겠다라고 JSON을 자바 객체로 변환하는 메시지 컨버터를 사용하여 요청 본문에 담긴 데이터를 자바 객체로 변환하게 되는 것입니다.
@RestController
@RequestMapping("/api")
public class HttpMessageController {
/**
* @RequestBody를 통해 자바 객체로 변환할 때 HttpMessageConverter를 사용하여
* 헤더에 담긴 컨텐츠 타입을 보고 어떤 메시지 컨버터를 사용할 것인지 판단하여
* 요청 본문에 담긴 값을 자바 객체로 변환
*/
@GetMapping
public String create(@ReqeustBody Event event) {
// 생략
return "redirect:/api/list";
}
}
Jackson2ObjectMapperBuilder 는 스프링부트에서 JacksonAutoConfiguration 클래스에서자동으로 설정하기 때문에 별다른 설정없이 JSON을 자바 객체로변환하는 ObjectMapper를 사용할 수 있습니다.
Jackson2ObjectMapperBuilder 내부를 보면 autoDetectGettersSetters() 라는 메서드를 사용합니다. 즉, JSON 타입으로 변환하기 위한 객체(DTO)에 getter 와 setter 메서드가 존재해야 하다는 뜻입니다.
public Jackson2ObjectMapperBuilder autoDetectGettersSetters(boolean autoDetectGettersSetters) {
this.features.put(MapperFeature.AUTO_DETECT_GETTERS, autoDetectGettersSetters);
this.features.put(MapperFeature.AUTO_DETECT_SETTERS, autoDetectGettersSetters);
this.features.put(MapperFeature.AUTO_DETECT_IS_GETTERS, autoDetectGettersSetters);
return this;
}
만약 getter/setter 가 존재하지 않으면 응답 메시지를 내보낼때 Jackson2ObjectMapperBuilder 를 제대로 사용하지 못해서 JSON 타입으로 변환이 제대로 되지않아 클라이언트(JS) 단에서 success() 함수로 결과값(res) 를 받아올 수 없습니다.
@RequriedArgsConstructor
@RequestMapping("/test")
@RestController
public class RequestBodyTestController {
private final TestService testService;
/**
* TestDto 에 getter, setter 메서드가 없으면
* JSON 타입 변환에 실패하여 JS 의 success 함수가 아닌 error 함수를 타게 된다.
*/
@RequestMapping("/search")
public TestDto search(TestVo testVo) {
TestVo result = testService.findTest(testVo);
return result.toDto();
}
}
스프링부트의 pom.xml 을 보면 spring-boot-starter-web 이 존재하는데 내부에 들어가보면 jackson-databind 의존성이 자동으로 잡혀있는 것을 볼 수 있습니다. 해당 의존성이 있어야 JSON 타입으로 제대로 변환이 됩니다.
정리
클라이언트에서 서버로 필요한 데이터를 전송하기 위해서 JSON이라는 데이터를 요청 본문에 담아서 서버로 보내면, 서버에서는 @RequestBody 어노테이션을 사용하여 HTTP 요청 본문에 담긴 값들을 자바 객체로 변환 시켜, 객체에 저장시킵니다.
서버에서 클라이언트로 응답 데이터를 전송하기 위해서 @ResponseBody 를 사용하여 자바 객체를 HTTP 응답 본문의 객체로 변환하여 클라이언트로 전송시키는 역할을 합니다.
'Programming > Spring' 카테고리의 다른 글
@Controller와 @RestController의 차이 (0) | 2021.01.31 |
---|---|
SpringMVC Controller 생성하기 (0) | 2021.01.31 |
@Transactional 이란? (0) | 2021.01.31 |
Lombok 어노테이션(Annotation) (0) | 2021.01.31 |
Spring과 Node.js의 차이 (0) | 2021.01.31 |