Back-End/Spring

[Spring MVC][HTTP 요청] - 3. 요청 메시지 - 단순 텍스트, JSON

얄루몬 2022. 3. 29. 20:50

💻본 포스팅은 '스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 김영한'님의 강의를 듣고 작성되었습니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com


[요청 메시지] 

HTTP message body에 데이터를 직접 담아서 요청한다.

  • HTTP API에서 주로 사용하면서 JSON, XML, TEXT가 대표 데이터 형식이다.
    • 데이터 형식은 주로 JSON을 사용한다.
  • POST, PUT, PATCH
  • 요청 파라미터와 다르게 HTTP 메시지 바디를 통해 데이터가 직접 넘어오는 경우엔 @RequestParam, @ModelAttribute를 사용할 수 없다
    • 그러나 HTML Form이면서 POST인 경우라면 요청 파라미터로 인정되어 사용가능하다.

[HTTP 요청 메시지 - 단순 텍스트 메시지]

  • 가장 단순한 텍스트 메시지를 HTTP 메시지 바디에 담아 전송할 때 사용한다.
  • HTTP 메시지 바디의 데이터를 InputStream을 사용해서 직접 읽을 수 있다.
package hello.springmvc.basic.request;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.nio.charset.StandardCharsets;

@Slf4j
@Controller
public class RequestBodyStringController {
	
    
    //기본
    @PostMapping("/request-body-string-v1")
    public void requestBodyStringV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        log.info("messageBody = {}", messageBody);

        response.getWriter().write("ok");
    }

	//Input, Output 스트림
    @PostMapping("/request-body-string-v2")
    public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException {
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        log.info("messageBody = {}", messageBody);

        responseWriter.write("ok");
    }
	
    //HTTP 컨버터라는 기능을 스프링이 제공
    //HttpEntity
    @PostMapping("/request-body-string-v3")
    public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) throws IOException {

        String messageBody = httpEntity.getBody();
        log.info("messageBody = {}", messageBody);

        return new HttpEntity<>("ok");

    }

    //@RequestBody로 HTTP컨버터 기능 애노테이션으로 제공
    @ResponseBody
    @PostMapping("/request-body-string-v4")
    public String requestBodyStringV4(@RequestBody String messageBody) {
        log.info("messageBody = {}", messageBody);
        return "ok";
    }
}

[단순 텍스트 메시지를 HTTP 메시지 바디에 담아 전송할 때 스프링MVC가 지원하는 파라미터]

  • HttpEntity
    • HTTP header, body 정보를 편리하게 조회할 수 있다.
    • 요청 파라미터를 조회하는 기능과는 관계 없다.(@RequestParam & @ModelAttribute)
    • HttpEntity는 응답서도 사용한다.
      • 메시지 바디 정보를 직접 반환한다
      • 헤더 정보를 포함 가능하다
      • view 조회는 불가하다.
  • HttpEntity를 상속받은 다음 객체들
    • RequestEntity
      • HttpMethod, url 정보가 추가, 요청에서 사용
    • ResponseEntity
      • HTTP 상태코드 설정 가능, 응답에서 사용한다.

[@RequestBody와 @ResponseBody]

  • @RequestBody
    • HTTP 메시지 바디 정보를 편리하게 조회할 수 있게 해준다.
    • 헤더 정보가 필요하다면 HttpEntity를 사용하거나 @RequestHeader을 사용하면 된다.
    • 이때 메시지 바디를 직접 조회하는 기능은 요청 파라미터를 조회하는 @RequestParam과 @ModelAttribute와는 전혀 관계가 없다.
  • @ResponseBody
    • 응답 결과를 HTTP 메시지 바디에 직접 담아 전달할 수 있다. 
    • 이 경우에도 view는 사용하지 않는다.

[요청 파라미터 VS HTTP 메시지 바디]

요청 파라미터 HTTP message Body
  • 요청파라미터는 고객이 뷰페이지에서 입력,선택한 자료들을 넘겨받아 작업하기 위해 먼저 서버로 전송하기 위한 데이터 이다. 
  • 요청 파라미터를 조회하는 기능 : @RequestParam, @ModelAttribute 
  • HTTP 메시지 바디는 실제로 전송할 데이터 즉, HTML 문서, 이미지, 영상, JSON 등등 byte로 표현할 수 있는 모든 데이터가 HTTP Message Body 안에 있다.
  • HTTP Message Body를 직접 조회하는 기능 : @RequestBody

[HTTP 요청 메시지 - JSON]

많은 HTTP API 중에서 가장 많이 사용하는 JSON 데이터 형식을 조회해보자.

package hello.springmvc.basic.request;


import com.fasterxml.jackson.databind.ObjectMapper;
import hello.springmvc.basic.HelloData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Slf4j
@Controller
public class RequestBodyJsonController {
    private ObjectMapper objectMapper = new ObjectMapper();


    //기존 방법을 사용한 Json
    @PostMapping("/request-body-json-v1")
    public void requestBodyJsonV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

        log.info("messageBody = {}", messageBody);
        HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
        log.info("username = {}, age = {}", helloData.getUsername(), helloData.getAge());

        response.getWriter().write("ok");
    }

    @ResponseBody
    @PostMapping("/request-body-json-v2")
    public String requestBodyJsonV2(@RequestBody String messageBody) throws IOException {
        log.info("messageBody = {}", messageBody);
        HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
        log.info("username = {}, age = {}", helloData.getUsername(), helloData.getAge());

        return "ok";
    }

    //@RequestBody에 객체를 넣어 줄 수 있다.
    @ResponseBody
    @PostMapping("/request-body-json-v3")
    public String requestBodyJsonV3(@RequestBody HelloData helloData) {

        log.info("username = {}, age = {}", helloData.getUsername(), helloData.getAge());
        return "ok";
    }

    //HttpEntity도 사용가능하다.
    @ResponseBody
    @PostMapping("/request-body-json-v4")
    public String requestBodyJsonV4(HttpEntity<HelloData> httpEntity) {
        HelloData data = httpEntity.getBody();
        log.info("username = {}, age = {}", data.getUsername(), data.getAge());
        return "ok";
    }

    @ResponseBody
    @PostMapping("/request-body-json-v5")
    public HelloData requestBodyJsonV5(@RequestBody HelloData data) {
        log.info("username = {}, age = {}", data.getUsername(), data.getAge());
        return data;
    }

}
  • @RequestBody는 생략이 불가능하다 이를 생략하게 될 땐 @ModelAttribute가 들어가게 된다.

[@RequestBody와 @ResponseBody]

@RequestBody 요청

JSON 요청 -> HTTP 메시지 컨버터 -> 객체로 변환해서 요청

@ResponseBody

객체로 응답 -> HTTP 메시지 컨버터 -> JSON으로 변환해서 응답