Spring MVC Core

DeadWhale·2022년 11월 16일
0

Spring-MVC-Core

목록 보기
6/6
post-thumbnail

요청 메시지 - Text

요청 파라미터의 경우

  • @RequestParam
  • @ModelAttribute

두개를 활용해 요청 파라미터를 가져올 수 있지만

HTTP 메시지 바디에 직접 데이터가 넘어오는 경우에는 사용 할 수 없다.

  • HTML FORM 형식인 경우에는 요청파라미터로 인식된다.

  • InputStream을 이용해 읽을 수 있다.

  • 내보낼때에는 response Writer을 활용해야 한다.

@PostMapping("/request-body-string-v1")
public void requestBodyString(HttpServletRequest request, HttpServletResponse response)throws Exception{
    ServletInputStream inputStream = request.getInputStream();
    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    log.info("messageBody = {}",messageBody);
    response.getWriter().write("ok");
}
  • HttpServletRequest 객체를 받아 InputStreamd() 을 추출해낸다.
  • StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
    • 문자열로 변환한다 이 때 파라미터로 스트림 + 변환할 타입을 전달한다.

HttpServletRequest.getInputStream()

HttpEntity<String> httpEntity
@RequestBody String messageBody

Request에서 하나하나 추출하지 않고

  • HttpEntity라는 객체를 활용해 편하게 변환할 수 있다.

HttpEntity

  • HTTP Header , Body의 정보를 편하게 조회
    • 메시지 바디 정보를 직접 조회할 수 있다.
    • 요청 파라미터를 조회하는 기능과 관련이 없다.(모델,파람)
  • 응답에서도 사용 가능하다.
    • 메시지 바디 정보를 직접 변환한다.
    • 헤더 정보 포함 가능하다
    • view를 조회하지 않고 바로 반환한다.

return new RequestEntity<String>( 메세지 ,상 태코드 );

  • 스프링에서 작성해준 상태코드를 참조해 전달 할 수 있다.
  • HttpStatus.CREATED :: 201

결론

@RequestBody String messageBody 으로 가장 편하게 처리할 수 있디.

반환의 경우 메서드에 @ResponseBody 를 추가해 입출력을 모두 편하게 구현 할 수 있다.

  • Header가 필요할 경우 @RequestHeader 를 받아 처리하면 된다.
  • @RequestParam , @ModelAttribute 와는 상관 없다.

요청 파라미터를 조회하는 기능

  • @RequestParam , @ModelAttribute

HTTP 메시지 바디를 직접 조회하는 기능

  • @RequestBody

@ResponseBody

  • 응답 결과를 HTTP 메시지 바디에 직접 담아 전달하는 것,
  • View를 조회,사용하지 않는다.

JSON

  • HTTP API 에서 주로 사용하는 전달 방식
  • @RequestBody 어노테이션 생략시 ModelAttribute으로 인식된다.
    • JSON은 HTTP 메시지 바디에 담겨와 쿼리파라미터용인 모델은 사용할 수 없다.
  • ContentType/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);

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

    response.getWriter().write("ok");
}
  • request 객체에서 Input Stream을 읽어 문자열을 ObjectMapper으로 객체 자료형에 맞게 재 구성한다.

  • objectMapper가 있어야 객체를 매핑할 수 있다.

  • 객체를 HTTP 메시지 바디에 직접 넣어줄 수도 있다.

@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData helloData) throws IOException {
    log.info("username:{} , age :{} ", helloData.getUsername(), helloData.getAge());
    return helloData;
}

@RequestBody 를 명시하며 객체 자료형을 선언해도 자동으로 매팽해준다.

  • 만약 @RequestBody 를 생략할 경우에는 @ModelAttribute으로 인식해 매핑되지 않는다.
  • 반환 시에도 객체 자료형을 보내도 자동으로 JSON 형태로 반환해준다.
    • @ResponseBody

HTTP 응답

응답 데이터의 3 종류

  • 정적 리소스
    • HTML ,CSS , JS
  • 뷰 탬플릿
    • 사용자마다 맞는 화면을 구성 ⇒ 뷰 탬플릿
  • HTTP 메시지 사용
    • HTTP API는 화면이 아니라 데이터를 HTTP 메시지 바디에 JSON같은 자료형을 전달한다

정적 리소스 , 뷰 탬플릿

스프링 부트는 ClassPath에서 아래 디렉토리들에 있는 정적 리소스를 제공한다.

src/main/resources/ 하위의 경로들

  • /static
  • /public
  • /resources
  • /META-INF/resources

localhost:8080/basic/hello.html

View Template

src/main/resources/ 하위의 경로 중

/templates는 뷰탬플릿의 경로로 제공된다

@RequestMapping("/response-view-v2")
public String responseViewV2(Model model){
    model.addAttribute("data","hello");
    return "response/hello";
}
  • 반환되는 접두사 , 후미를 붙여 자동으로 경로를 생성해준다. src/main/resources/templates/response/hell.html
  • 매핑된 주소와 반환값이 void일 경우 주소의 경로와 일치하는 경로로 자동으로 찾아간다( 비추 )

Spring Thymeleaf 설정

  • dependencies 추가
    • implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
  • Application.properties
    • Prefix : classpath:/templates/
    • suffix : .html

HTTP API - Message Body

HTML이나 뷰 탬플릿을 사용해도 HTTP 응답 메시지 바디에 HTML 데이터가 전달된다
그러한 방식이 아니라 HTML파일, 뷰탬플릿을 거치지 않고 직접 HTTP 응답 메시지를 전달하는 경우

@GetMapping("response-body-string-v1")
public ResponseEntity<String> responseBody(){
    return new ResponseEntity<>("ok", HttpStatus.OK);
}

@ResponseBody
@GetMapping("response-body-string-v3")
	public String responseBodyV3(){
	    return "ok";
}

@ResponseStatus(HttpStatus.OK) 
@ResponseBody
@GetMapping("response-body-json-v1")
public HelloData responseBodyJsonV1(){
    return new HelloData("KHG",50);
}
  • 어노테이션으로 상태코드를 전달하고 싶을 경우에는 @ResponseStatus(상태코드)를 사용한다
    • 다만 어노테이션으로 작성 시 동적으로 응답코드를 변경 할 수 없다
    • 동적으로 보내할 경우에는 ResponseEntity<T>을 사용한다

HTTP Message Converter

HTTP API 처럼 JSON 데이터를 HTTP 메시지 바디에 직접 읽거나 쓰는 경우 HTTP 메시지 컨버터를 사용하면 편하다.

@ResponseBody ( @RestController )

  • view Resolver 으로 View를 찾는것이 아니라 HttpMessageConverter 가 동작한다.
  • 기본 문자 처리 : StringHttpMessageConverter 가 동작
  • 기본 객체 처리 : MappingJackson2HttpMessageConverter 가 동작
  • 외에도 여러 자료형에 맞는 컨버터가 존재한다.

응답의 경우 HTTP Accept Header 와 서버 컨트롤러의 반환 정보를 조합해 컨버터가 선택된다.

스프링 MVC는 이럴 경우 HTTP Message Converter 가 동작한다

  • HTTP Request. ⇒ @RequestBody , HttpEntity(RequestEntity)
  • HTTP Response ⇒ @RequestBody , HttpEntity(ResponseEntity)

모든 자료형의 컨버터는 <Inteface> HttpMessageConverter 를 상속받는다.

요청과 응답 모두에서 사용된다.

  • CanRead() , CanWrite()
    • 메시지 컨버터가 해당 클래스 , 미디어 타입을 지원하는 체크
      • 미디어 타입 : 요청시 Header 에 포함되 있는 해당 객체의 자료형
  • read() , write()
    • Can을 통과 시 동작
    • 메시지 컨버터를 통해 메시지를 일고 쓰는 기능

스프링 부트는 기본적으로 메시지 컨버터를 컨테이너에 올려둔다

  • 바이트 배열
    • 바이트 배열일 경우 처리
    • 반환시 미디어 타입 : application/octet-stream
  • 문자열
    • String 타입일 경우 처리
    • 바이트로 데이터가 전달해도 문자열로 컨버팅
    • 반환시 미디어 타입 : text/plain
  • JSON
    • Application/JSON 일 경우 동작
    • 클래스 타입이 객체 , HashMap일 경우 동작한다.
    • 반환시 미디어 타입 : application/JSON

요청 흐름

Http요청 ⇒ 컨트롤러에 @RequestBody,HttpEntity가 있을 경우

⇒ 메시지 컨버터가 동작

⇒ 클래스 타입을 지원하는가

⇒ 요청의 Content-Type 미디어 타입을 지원하는가

⇒ canRead()를 통과 시 read()를 호출

응답 흐름

컨트롤러에서 @ResponseBody , HttpEntity 값 반환

⇒ 메시지 컨버터가 메시지를 처리할 수 있는지 canWriter를 호출

⇒ 클래스 타입을 지원하는가

⇒ 요청의 Accept 미디어 타입 제한을 지원하는가 ( @RequestMapping의 produces )

⇒canWrite() 통과 시 write() 호출

  • 불가능한 경우
    • Content-type : text/plane

    • @RequestBody HelloData data

      ⇒ 불가능


요청 매핑 핸들러 어뎁터 구조

RequestMapping

모든 기능은 RequestMappingHandller에 담겨있다.

ArgumentResolver

❕ 모든 어노테이션은 누군가가 읽어서 처리해줘야한다

어노테이션 기반의 컨트롤러를 처리하는 RequestMappingHandlerAdaptor

ArgumentResolver를 호출 후 컨트롤러가 필요로 하는 모든 파라미터 값(객체)를 생성한다.

이러한 준비가 모두 끈나면 컨트롤러를 호출해 값을 넘겨준다.

  • Argument Resolver ( 매개변수 처리 )
    • 모든 어노테이션을 처리해줄수 있게 해주는 것

ReturnValueResolver

  • 컨트롤러의 반환 값을 처리해주는 Resolver
  • ArgumentResolver와 유사하게 동작

ModelAndView, @ResponseBody , String등 여러 종류가 있다.

HTTP Message Converter

  • 데이터 생성 , 반환할떄 사용한다.
  • ArgumentResolver , ReturnValueResolver
    객체를 생성할 일이 있으면 메시지 컨버터를 사용해 생성한다.

WebMvcConfigurer 등을 활용해 기능 확장을 구현 할 수 있다.


출처

  • 영한님의 Spring MVC 핵심 강의를 기반으로 학습한 내용을 정리한 것입니다.

0개의 댓글