스프링 MVC: 응답 & HTTP메시지 컨버터 (몰랐던것 중심)

RisingJade의 개발기록·2022년 3월 4일
0

SPRING MVC

목록 보기
5/6

응답 - 정적 리소스, 뷰 템플릿

정적 리소스

정적 리소스는 해당 파일 변경없이 그대로 서비스 하는것으로써
웹 브라우저에서는 정적인 HTML, css, js을 제공할 때 정적 리소스를 사용한다.

  • 스프링 부트는 클래스패스의 다음 디렉토리에 있는 정적 리소스를 제공한다.
    • /static , /public , /resources , /META-INF/resources
    • src/main/resources 는 리소스를 보관하는 곳이고, 또 클래스패스의 시작 경로이다.
    • 따라서 다음 디렉토리에 리소스를 넣어두면 스프링 부트가 정적 리소스로 서비스를 제공한다.
      • 정적 리소스 경로: src/main/resources/static
      • ex) src/main/resources/static/basic/hello-form.html에 있는 파일을 접근할땐
        웹 브라우저에서 다음과 같이 실행하면 된다. http://localhost:8080/basic/hello-form.html

뷰 템플릿

뷰 템플릿을 거쳐서 HTML이 생성되고, 뷰가 응답을 만들어서 전달한다.
일반적으로 HTML을 동적으로 생성하는 용도로 사용하지만, 다른 것들도 가능하다. 뷰 템플릿이 만들 수 있는 것이라면 뭐든지 가능하다.

  • 뷰 템플릿 기본 경로
    • src/main/resources/templates
  • 뷰 템플릿을 호출하는 2가지 방법
	@RequestMapping("/response-view-v1")
    public ModelAndView responseViewV1(){
        ModelAndView mav = new ModelAndView("response/hello")
                .addObject("data", "hello!");
        return mav;
    }
    @RequestMapping("/response-view-v2")
    public String responseViewV2(Model model){
        model.addAttribute("data", "hello!");
        return "response/hello";
    }

보통 2번째 것을 자주 쓴다. 1번째 것은 너무 손이 많이가서..


HTTP 응답 - HTTP API, 메시지 바디에 직접입력

HTML이나 뷰 템플릿을 사용해도 HTTP 응답 메시지 바디에 HTML 데이터가 담겨서 전달된다.
여기서 설명하는 내용은 정적 리소스나 뷰 템플릿을 거치지 않고 직접! HTTP 응답 메시지를 전달하는 것을 뜻한다.

일반 타입을 보낼 때

  • HttpServletResponse 객체를 통해서 HTTP 메시지 바디에 직접 ok 응답 메시지를 전달한다.
    response.getWriter().write("ok")
  • ResponseEnitity 사용
    return new ResponseEntity<>("ok", HttpStatus.OK);
  • ResponseBody 사용
@ResponseBody
    @GetMapping("/response-body-string-v3")
    public String responseBodyV3(){
        return "ok";
    }

JSON 타입을 보낼 때

  • ResponseEntity<> + 제네릭에 클래스 타입
	@GetMapping("/response-body-json-v1")
    public ResponseEntity<HelloData> responseBodyJsonV1() {
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);

        return new ResponseEntity<>(helloData, HttpStatus.OK);
    }

위의 방법은 Http status도 상황에 따라 변경 가능하다는 장점이 있다.

  • 만약 간단하게 JSON을 보내고 싶다면
	@ResponseStatus(HttpStatus.OK)
    @ResponseBody
    @GetMapping("/response-body-json-v2")
    public HelloData responseBodyJsonV2() {
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);

        return helloData;
    }

사용이 편리하고 첫 번째 방법과 결과는 동일하지만 HTTP status가 애노테이션에 고정된다는 점이 단점이다.

TIP!
만약 @ResponseBody를 함수마다 붙이기엔 너무 많고 함수가 속해있는 함수 전부 HTTP 메시지 바디에 직접 응답하고 싶다면 @RestController를 클래스 단에 붙여주면 된다.


HTTP 메시지 컨버터

HTTP 메시지 컨버터가 적용되는 경우

  • @ResponseBody orHttpEntity(ResponseEntity) 사용시 -> HTTP 응답
    • HTTP의 Body에 문자 대신 내용을 직접 반환
    • viewResolver대신에 HttpMessageConverter가 동작
    • 기본 문자처리는 StringHttpMessageConverter가 작동하고
    • 기본 객체처리는 MappingJackson2HttpMessageConverter가 동작한다.
    • byte 처리 등등 기타 여러 Http 메시지 컨버터가 기본으로 등록되있음
  • @RequestBody or HttpEntity(RequestEntity) 사용시 -> HTTP 요청
    • 위와 거의 동일(역순일 뿐)

HTTP 메시지 컨버터 우선순위

당연히 여러종류의 HTTP메시지 컨버터가 있으니 어떤걸 먼저 쓸지 우선 순위가 있다.
우선순위는 다음과 같다.(이게 전부는 아님)
0 = ByteArrayHttpMessageConverter
1 = StringHttpMessageConverter
2 = MappingJackson2HttpMessageConverter

위의 컨버터가 대표적인 HTTP메시지 컨버터다.

  • ByteArrayHttpMessageConverter : byte[] 데이터를 처리한다.
    • 클래스 타입: byte[] , 미디어타입: */*
      요청 예) @RequestBody byte[] data
      응답 예) @ResponseBody return byte[] 쓰기 미디어타입 application/octet-stream
  • StringHttpMessageConverter : String 문자로 데이터를 처리한다.
    • 클래스 타입: String , 미디어타입: */*
      요청 예) @RequestBody String data
      응답 예) @ResponseBody return "ok" 쓰기 미디어타입 text/plain
  • MappingJackson2HttpMessageConverter : application/json
    • 클래스 타입: 객체 또는 HashMap , 미디어타입 application/json 관련
      요청 예) @RequestBody HelloData data
      응답 예) @ResponseBody return helloData 쓰기 미디어타입 application/json 관련

HTTP 요청 데이터 읽기

  1. HTTP 요청이 오고, 컨트롤러에서 @RequestBody , HttpEntity 파라미터를 사용한다.
  2. 메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead() 를 호출한다.
  3. 대상 클래스 타입을 지원하는지 체크
    예) @RequestBody 의 대상 클래스 ( byte[] , String , HelloData )
  4. HTTP 요청의 Content-Type 미디어 타입을 지원하는가.
    예) text/plain , application/json , */*
  5. canRead() 조건을 만족하면 read() 를 호출해서 객체 생성하고, 반환한다.

HTTP 응답 데이터 생성

  1. 컨트롤러에서 @ResponseBody , HttpEntity 로 값이 반환된다.
  2. 메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite() 를 호출한다.
  3. 대상 클래스 타입을 지원하는지 체크
    예) return의 대상 클래스 ( byte[] , String , HelloData )
  4. HTTP 요청의 Accept 미디어 타입을 지원하는가.(더 정확히는 @RequestMapping 의 produces )
    예) text/plain , application/json , */*
  5. canWrite() 조건을 만족하면 write() 를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성한다.

요약: HTTP 메시지 컨버터가 canWrite나 canRead를 통해 자동으로 해석하여 걸맞는 값을 읽기or 생성을 해준다고 생각하자

profile
언제나 감사하며 살자!

0개의 댓글