ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring MVC (6) - 스프링 MVC 기본 기능
    Web/Spring 2023. 10. 9. 21:19

    1. 들어가기 전에 

     

    - 프로젝트 생성 주의점

    Packaging War가 아닌, Jar를 선택 -> JSP를 사용하지 않기 때문에 

    (스프링 부트를 사용하면 주로 위 방식을 사용하게 된다) 

    Jar+내장 톰캣+ webapp경로x

    War+ 주로 외부 웹 서버 + webapp경로 o

     

    - Welcome페이지 만들기 

    스프링 부트에 Jar를 사용하면, /resoureces/static 위치에 파일을 두면, Welcome페이지로 처리해준다.

    정적컨텐츠는 주로 저 위치에 두면된다. 

     

    1.2 로깅 알아보기 

     

    - 운영시스템에서는 System.out.println()같은 시스템 콘솔을 사용해서 필요한 정보 출력x

       > 별도의 로깅 라이브러리를 사용해서 로그를 출력한다.

    - 로깅 라이브러리 : 스프링 부트 라이브러리를 사용하면 스프링 부트 로깅 라이브러리가 함께 포함된다. 

                                    스프링 부트 로깅 라이브러리는 기본으로 다음 로깅 라이브러리를 사용한다.

                                    SLF4J, Logback

    - SLF4J: 많은 로그 라이브러리를 통합해서 인터페이스 제공 Logback는 구현체임 (이런 구현체 선택하면됨)

    private Logger log = LoggerFactory.getLogger(getClass());
    private static final Logger log = LoggerFactory.getLogger(Xxx.class)
    //@Slf4j : 롬복 사용 가능
    @RestController
    public class LogTestController {
     private final Logger log = LoggerFactory.getLogger(getClass());
     @RequestMapping("/log-test")
     public String logTest() {
     String name = "Spring";
     
     log.trace("trace log={}", name);
     log.debug("debug log={}", name);
     log.info(" info log={}", name);
     log.warn(" warn log={}", name);
     log.error("error log={}", name);
     //로그를 사용하지 않아도 a+b 계산 로직이 먼저 실행됨, 이런 방식으로 사용하면 X
     log.debug("String concat log=" + name);
     return "ok";
     }
    }

    - @RestController는 메서드 String 반환 값을 HTTP 메시지 바디에 바로 입력함 

          *@ResponseBody와 연관이 있다.

     

    - 로그 레벨을 설정하여 출력을 하면 

      시간,로그레벨,프로세스 ID, 스레드명, 클래스명, 로그 메시지 쭉 나온다

      TRACE,DEBUG,INFO,WARN,ERROR순서 

      개발 서버는 주로 DEBUG사용, 운영서버는 INFO 사용 

     

    *로그 레벨 설정 

    application.properties
    
    전체 로그 레벨 설정(기본 info)
    logging.level.root=info
    #hello.springmvc 패키지와 그 하위 로그 레벨 설정
    logging.level.hello.springmvc=debug

    - 로그를 찍을 때 +연산말고, {}와 같은 format을 사용하자 -> 의미없는 연산이 발생하지 않음 

    - 로그를 사용하면, 쓰레드 정보 클래스 이름 같은 부가 정보 함께 볼 수 있고, 출력 모양 조정 가능 

      로그 레벨에 따라 개발 서버에서는 모든 로그 출력, 운영서버에서는 출력하지 않는 등 상황에 맞게 조절 

      콘솔 뿐 아니라 파일이나 네트워크 등 로그를 별도의 위치에 남길 수 있다. (파일로 남길 시 일별, 용량별 로그 분할 가능) 

     

     

    2. 요청 매핑 

     

    - 서버는 받을 수 있는 요청들을 미리 지정해두고, 클라이언트는 이에 맞춰서 요청을 날리는 것

      아무 요청이나 날릴 수 있고, 이를 해석해서 서버가 작동하는게 아님! ->

      서버에서 원하는 방향대로만 애초에 요청하도록 만들어야함 -> 

      서버에서 애초에 요청을 날리는 방식을 정해두고, 클라이언트는 이 중 선택

     

    2.1 기본 매핑 

    @RequestMapping("/hello-basic") // {"/hello-basic", "/hello-go"} 배열 가능
    @RequestMapping(value = "/mapping-get-v1", method = RequestMethod.GET)

    - 기본 요청 매핑임 HTTP 메서드 모두 허용하는 특징이 있음 

       (GET,HEAD,POST,PUT,PATCH,DELETE)

    - 물론 method를 지정할 수 있다.

    /**
     * 편리한 축약 애노테이션 (코드보기)
     * @GetMapping
     * @PostMapping
     * @PutMapping
     * @DeleteMapping
     * @PatchMapping
     */
    @GetMapping(value = "/mapping-get-v2")

    - 특정 HTTP 메서드만 받을 수 있도록 축약형 어노테이션도 제공한다

      어노테이션 내부에보면 @RequestMapping에 method를 지정해서 사용한 것을 볼 수 있다.

     

    2.2 PathVariabel(경로 변수) 사용

     

    /**
     * PathVariable 사용
     * 변수명이 같으면 생략 가능
     * @PathVariable("userId") String userId -> @PathVariable userId
     */
    @GetMapping("/mapping/{userId}")
    public String mappingPath(@PathVariable("userId") String data) {
     log.info("mappingPath userId={}", data);
     return "ok";
    }

    - 최근 HTTP API에서 다음과 같이 리소스 경로에 식별자 넣는 스타일 선호함 

      /mapping/userA, /users/1 등

    - @RequestMapping은 URL경로를 템플릿({} <- 포맷 )화 할 수 있는데 @PathVaridable을 사용하면,

    매칭 되는 부분을 편리하게 조회할 수 있다. 

    @GetMapping("/mapping/users/{userId}/orders/{orderId}")
    public String mappingPath(@PathVariable String userId, @PathVariable Long orderId){
    
    		// PathVariable 다중 사용

    * 쿼리 스트링 날리는 거랑 동일한 효과 다른 방식임!

     

    2.3 기본 요청 + 추가 매핑 (파라미터, 헤더 등) 

     

    - 특정 파라미터 조건 매핑 

    /**
     * 파라미터로 추가 매핑
     * params="mode",
     * params="!mode"
     * params="mode=debug"
     * params="mode!=debug" (! = )
     * params = {"mode=debug","data=good"}
     */
    @GetMapping(value = "/mapping-param", params = "mode=debug")

    > 특정 파라미터가 있거나 없는 조건을 추가하여 매핑할 수 있음 (잘 사용하지 않음)

     

    - 특정 헤더 조건 매핑 

    /**
     * 특정 헤더로 추가 매핑
     * headers="mode",
     * headers="!mode"
     * headers="mode=debug"
     * headers="mode!=debug" (! = )
     */
    @GetMapping(value = "/mapping-header", headers = "mode=debug")
    public String mappingHeader() {
     log.info("mappingHeader");
     return "ok";
    }

    > 파라미터 매핑과 비슷 요청 헤더에 특정 값이 있는지 확인 

     

    - 미디어 타입 조건 매핑 (Content-Type 헤더 기반 추가 매핑)

    /**
     * Content-Type 헤더 기반 추가 매핑 Media Type
     * consumes="application/json"
     * consumes="!application/json"
     * consumes="application/*"
     * consumes="*\/*"
     * MediaType.APPLICATION_JSON_VALUE
     */
    @PostMapping(value = "/mapping-consume", consumes = "application/json")
    public String mappingConsumes() {
     log.info("mappingConsumes");
     return "ok";
    }

    * consumes = {"text/plain","application/*"}

    consumes = "text/plain"
    consumes = {"text/plain", "application/*"}
    consumes = MediaType.TEXT_PLAIN_VALUE

    - 미디어 타입 조건 매핑 (HTTP 요청 Accept 기반 추가 매핑)

    /**
     * Accept 헤더 기반 Media Type
     * produces = "text/html"
     * produces = "!text/html"
     * produces = "text/*"
     * produces = "*\/*"
     */
    @PostMapping(value = "/mapping-produce", produces = "text/html")
    public String mappingProduces() {
     log.info("mappingProduces");
     return "ok";
    }
    produces = "text/plain"
    produces = {"text/plain", "application/*"}
    produces = MediaType.TEXT_PLAIN_VALUE
    produces = "text/plain;charset=UTF-8"

     

    - Consume : 클라이언트 요청 메시지 타입 중 이것만 받는다  (content-type과 consume 매핑)

    - Produce : 서버 응답 결과는 이런 타입이다 (요청 메시지에 클라이언트 accept와 produce 매핑) 

     

    2.4 요청 매핑 - API 예시 

    @RestController
    @RequestMapping("/mapping/users")
    public class MappingClassController {
     /**
     * GET /mapping/users
     */
     @GetMapping
     public String users() {
     return "get users";
     }
     /**
     * POST /mapping/users
     */
     @PostMapping
     public String addUser() {
     return "post user";
     }
     /**
     * GET /mapping/users/{userId}
     */
     @GetMapping("/{userId}")
     public String findUser(@PathVariable String userId) {
     return "get userId=" + userId;
     }
     /**
     * PATCH /mapping/users/{userId}
     */
     @PatchMapping("/{userId}")
     public String updateUser(@PathVariable String userId) {
     return "update userId=" + userId;
     }
     /**
     * DELETE /mapping/users/{userId}
     */
     @DeleteMapping("/{userId}")
     public String deleteUser(@PathVariable String userId) {
     return "delete userId=" + userId;
     }
    }
    회원 관리 API
    회원 목록 조회: GET /users
    회원 등록: POST /users
    회원 조회: GET /users/{userId}
    회원 수정: PATCH /users/{userId}
    회원 삭제: DELETE /users/{userId}

     

    3. HTTP 요청 파라미터 (데이터 조회) 

     

    3.1 기본/헤더  

     

    > 애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원함 

    > 헤더정보를 조회하는 방법을 알아보자 

     

    @Slf4j
    @RestController
    public class RequestHeaderController {
     @RequestMapping("/headers")
     public String headers(HttpServletRequest request,
     HttpServletResponse response,
     HttpMethod httpMethod,
     Locale locale,
     @RequestHeader MultiValueMap<String, String>
    headerMap,
     @RequestHeader("host") String host,
     @CookieValue(value = "myCookie", required = false)
    String cookie
     ) {
     log.info("request={}", request);
     log.info("response={}", response);
     log.info("httpMethod={}", httpMethod);
     log.info("locale={}", locale);
     log.info("headerMap={}", headerMap);
     log.info("header host={}", host);
     log.info("myCookie={}", cookie);
     return "ok";
     }
    }

     - Request,Response

     - HttpMethod : HTTP 메서드 조회 , Locale : Locale 정보 조회 

     - @RequestHeader MultiValueMap<String,String> headerMap : 모든 헤더 조회

    - @RequestHeader("host") String host : 특정 헤더 값 조회 

          required와 defaultValue 설정 가능 

    - @CookieValue: 특정 쿠기 조회 기능 

     

    * 지원가능한 파라미터 적으면, 핸들러 어답터가 처리해줌! (기본은 HTTP 요청메시지)

    * MultiValueMap : MAP과 유사한데, 하나의 키에 여러 값을 받을 수 있다.

      HTTP header, HTTP 쿼리 파라미터 같이 하나의 키에 여러 값을 받을 때 사용

      keyA=value1&keyA=value2 

    *Controller에 사용 가능한 파라미터 + 응답 가능한 값은 공식 메뉴얼에서 확인 가능 

     

     3.2 쿼리 파라미터, HTML Form 

     

    GET 쿼리 파라미터 전송 방식/ POST(HTML Form) 방식은 둘다 형식이 같아서 구분 없이 조회 가능 

    -> 간단히 요청 파라미터 조회라고 함 

     

    - request.getParameter()

    /**
     * 반환 타입이 없으면서 이렇게 응답에 값을 직접 집어넣으면, view 조회X
     */
     @RequestMapping("/request-param-v1")
     public void requestParamV1(HttpServletRequest request, HttpServletResponse 
    response) throws IOException {
     String username = request.getParameter("username");
     int age = Integer.parseInt(request.getParameter("age"));
     //
     }

    -> 서블릿 방식 request.getParameter()사용해서 조회 가능 

     

    - @RequestParam

    /**
     * @RequestParam 사용
     * - 파라미터 이름으로 바인딩
     * @ResponseBody 추가
     * - View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
     */
    @ResponseBody
    @RequestMapping("/request-param-v2")
    public String requestParamV2(
     @RequestParam("username") String memberName,
     @RequestParam("age") int memberAge) {
     //
     }
     
     /**
     * @RequestParam 사용
     * HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="xx") 생략 가능
     */
    @ResponseBody
    @RequestMapping("/request-param-v3")
    public String requestParamV3(
     @RequestParam String username,
     @RequestParam int age)
     
     /**
     * @RequestParam 사용
     * String, int 등의 단순 타입이면 @RequestParam 도 생략 가능
     */
    @ResponseBody
    @RequestMapping("/request-param-v4")
    public String requestParamV4(String username, int age)

    > @RequestParam : 파라미터 이름 바인딩 (request.getParameter와 같음)

    > @ResponseBody : String return값 message body에 바로 넣기

     

    *@RequestParam을 생략하면, 스프링 MVC 내부에서 required=false를 적용함 

      기본형일 경우 애노테이션 완전 생략 가능한데 그냥 적어주는게 나음 

     

    - 파라미터 필수 여부 및 기본값 

    /**
     * @RequestParam.required
     * /request-param-required -> username이 없으므로 예외
     *
     * 주의!
     * /request-param-required?username= -> 빈문자로 통과
     *
     * 주의!
     * /request-param-required
     * int age -> null을 int에 입력하는 것은 불가능, 따라서 Integer 변경해야 함(또는 다음에 나오는
    defaultValue 사용)
     */
    @ResponseBody
    @RequestMapping("/request-param-required")
    public String requestParamRequired(
     @RequestParam(required = true) String username,
     @RequestParam(required = false) Integer age)
     
     
     /**
     * @RequestParam
     * - defaultValue 사용
     *
     * 참고: defaultValue는 빈 문자의 경우에도 적용
     * /request-param-default?username=
     */
    @ResponseBody
    @RequestMapping("/request-param-default")
    public String requestParamDefault(
     @RequestParam(required = true, defaultValue = "guest") String username,
     @RequestParam(required = false, defaultValue = "-1") int age)

     > 파라미터 필수 여부 지정 가능 (기본값은 true)

     > 필수 파라미터를 지정하지 않으면, 400예외 발생 

     > 파라미터 이름만 사용 (/param?username=) 

        - 이럴 경우 빈 문자로 통과함 

     > 기본형에 null 입력 (@RequestParam(required=false) int age)

         - int형에 null 입력 불가능 (500예외)

        - Integer로 타입 변경 혹은 defaultValue사용하자 

     > 기본 값이 있는 경우 사실 required는 딱히 의미가 없긴함!

     

    - 파라미터 Map으로 조회하기 (requestParam Map<>)

    /**
     * @RequestParam Map, MultiValueMap
     * Map(key=value)
     * MultiValueMap(key=[value1, value2, ...]) ex) (key=userIds, value=[id1, id2])
     */
    @ResponseBody
    @RequestMapping("/request-param-map")
    public String requestParamMap(@RequestParam Map<String, Object> paramMap) {
     log.info("username={}, age={}", paramMap.get("username"),
    paramMap.get("age"));
     return "ok";
    }

    >  모든 파라미터 키와 값을 map으로 반환 받는다.

     

    3.3 요청 파라미터 to 객체

     

    - 실제 개발을 하면 요청 파라미터들을 통해 필요한 객체를 만들고 값을 넣어줌 

    - 이를 쉽게 만들어주는 어노테이션이 있음 

     

    @Data
    public class HelloData {
     private String username;
     private int age;
    }

    > 요청파라미터 값 담을 객체 (@Data하면 롬복이 Getter,Setter,ToString 등등 다해줌)

    /**
     * @ModelAttribute 사용
     * 참고: model.addAttribute(helloData) 코드도 함께 자동 적용됨, 뒤에 model을 설명할 때
    자세히 설명
     */
    @ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV1(@ModelAttribute HelloData helloData)

    - 스프링 MVC는 @ModelAttribute가 있으면 요청 파라미터 이름과 객체의 프로퍼티 찾음

    - 해당 프로퍼티의 setter를 호출해서 파라미터 값을 바인딩한다.

     

    * 프로퍼티 

      - 객체에 getUsername(),setUsername()메서드가 있으면, 객체는 username이라는 프로퍼티 가짐 

    * 바인딩 오류 

       age=abc처럼 숫자 들어가야할 자리에 문자 넣으면 BindException이 발생 (처리 방법은 검증에서 다룸)

     

    * @ModelAttribute 생략 가능
     * String, int 같은 단순 타입 = @RequestParam
     * argument resolver 로 지정해둔 타입 외 = @ModelAttribute
     */
    @ResponseBody
    @RequestMapping("/model-attribute-v2")
    public String modelAttributeV2(HelloData helloData)

    - @ModelAttribute 생략 가능 (@RequestParam도 생략 가능)

       > 단순타입은 RequestParam적용, 나머지는 ModelAttribute적용 

      

    *argument resolver는 뒤에서 학습 

     

    *여기까지 get과 html form데이터 조회 방법 알아봄 

      크게 @RequestParam(데이터 조회)

              @ModelAttribute(데이터 to 객체) 

      필수 값이나 기본 값 설정 등을 다룸

     

     

     4. HTTP 요청 메시지 - HTTP API

     

    - HTTP message body에 데이터 직접 담아서 요청 

      > HTTP API에서 주로 사용 JSON,XML,TEXT (주로 JSON)

     

    * 요청 파라미터와 다르게, HTTP 메시지 바디를 통해 데이터가 직접 넘어오는 경우

    @RequestParam, @ModelAttribute 사용 못함! 

     

    4.1 단순 텍스트 

     

    - 기존 서블릿 방식 

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

     

      > request를 통해 InputStream을 열고, StreamUtils를 통해 String으로 만듦

     

    - Input/OutputStream 파라미터

    /**
     * InputStream(Reader): HTTP 요청 메시지 바디의 내용을 직접 조회
     * OutputStream(Writer): HTTP 응답 메시지의 바디에 직접 결과 출력
     */
    @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");
    }

    > 파라미터로 inputStream과 Writer 등도 쓸 수 있음! (요청 파라미터 말고, body 읽기 용도)

      InputStream(Reader) : HTTP 요청 메시지 바디의 내용 직접 조회

      OutputStream(Writer) : HTTP 응답 메시지의 바디에 직접 결과 출력

     

    - HttpEntity 방식 

    /**
     * HttpEntity: HTTP header, body 정보를 편리하게 조회
     * - 메시지 바디 정보를 직접 조회(@RequestParam X, @ModelAttribute X)
     * - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
     *
     * 응답에서도 HttpEntity 사용 가능
     * - 메시지 바디 정보 직접 반환(view 조회X)
     * - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
     */
    @PostMapping("/request-body-string-v3")
    public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) {
     String messageBody = httpEntity.getBody();
     log.info("messageBody={}", messageBody);
     return new HttpEntity<>("ok");
    }

    > HttpEntity: HTTP header, body내용 편리하게 조회하는 기능함 

                            - 메시지 바디 직접 조회

                            - 요청 파라미터 조회 기능과는 관계 없다.

                            - request에서 헤더 조회기능과, InputStream얻어서 바디 조회 기능만 가짐 

                            - 응답(return값)으로 사용할 수도 있다. 

                            - 이때 헤더 정보 포함 가능하고, view조회 안하고 응답 메시지 대신 HttpEntity를 준다.

     

    > RequestEntity: HttpMehod,url정보 추가 (요청에서 사용)

    > ResponseEntity : HTTP 상태코드 설정 가능, 응답서 사용

    return new ResponseEntity<String>("Hello World", responseHeaders, 
    HttpStatus.CREATED)

    * 스프링 내부에서 HTTP 메시지 바디를 읽어서 문자나 객체로 변환해서 전달해 줌 

      이때 HTTP 메시지 컨버터라는 기능을 사용

     

    - @RequestBody 방식 

    /**
     * @RequestBody
     * - 메시지 바디 정보를 직접 조회(@RequestParam X, @ModelAttribute X)
     * - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
     *
     * @ResponseBody
     * - 메시지 바디 정보 직접 반환(view 조회X)
     * - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
     */
    @ResponseBody
    @PostMapping("/request-body-string-v4")
    public String requestBodyStringV4(@RequestBody String messageBody) {
     log.info("messageBody={}", messageBody);
     return "ok";
    }

    - @RequestBody를 사용하면, HTTP 바디 정보 편리하게 조회 가능하다 

       헤더 정보가 필요하면 HttpEntity를 사용하거나, @RequestHeader를 사용하자 

     

    4.2 JSON

     

    - HTTP API에서 주로 사용되는 JSON 형식을 조회해보자 

     

    - 기존 방식 

    public class RequestBodyJsonController {
     private ObjectMapper objectMapper = new ObjectMapper();
     @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 data = objectMapper.readValue(messageBody, HelloData.class);
     log.info("username={}, age={}", data.getUsername(), data.getAge());
     response.getWriter().write("ok");
     }
    }

    > 읽는 방식 동일, ObjectMapper로 Body의 내용을 특정 클래스로 변경 (readValue)

     

    - @RequestBody사용 

    /**
     * @RequestBody
     * HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
     *
     * @ResponseBody
     * - 모든 메서드에 @ResponseBody 적용
     * - 메시지 바디 정보 직접 반환(view 조회X)
     * - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
     */
    @ResponseBody
    @PostMapping("/request-body-json-v2")
    public String requestBodyJsonV2(@RequestBody String messageBody) throws
    IOException {
     HelloData data = objectMapper.readValue(messageBody, HelloData.class);
     log.info("username={}, age={}", data.getUsername(), data.getAge());
     return "ok";
    }

    > HTTP 바디 내용을 읽는 부분을 줄일 수 있음! 

    > 여전히 objectMapper를 사용해서 자바 객체로 변환 

    > 문자 to json 변환 과정에서 @ModelAttribute와 같이 한번에 객체로 변환 안되나?

     

    - @RequestBody + 객체 

    /**
     * @RequestBody 생략 불가능(@ModelAttribute 가 적용되어 버림)
     * HttpMessageConverter 사용 -> MappingJackson2HttpMessageConverter (contenttype: application/json)
     *
     */
    @ResponseBody
    @PostMapping("/request-body-json-v3")
    public String requestBodyJsonV3(@RequestBody HelloData data)

    > @RequestBody생략 없이 String이 아닌, 객체를 넣으면 변환해준다.

    > HttpEntity<특정클래스>, @RequestBody를 사용하면, HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 

    우리가 원하는 문자나 객체로 변환해 준다.

    > @RequestBody는 생략 불가능이다. -> 생략하면 요청 파라미터로 처리함

     

    * HTTP 요청시에 content-type이 application/json인지 꼭 확인해야함 그래야 json으로 처리해주는 메시지 컨버터가 실행된다.

     

    - ResponseBody

    /**
     * @RequestBody 생략 불가능(@ModelAttribute 가 적용되어 버림)
     * HttpMessageConverter 사용 -> MappingJackson2HttpMessageConverter (contenttype: application/json)
     *
     * @ResponseBody 적용
     * - 메시지 바디 정보 직접 반환(view 조회X)
     * - HttpMessageConverter 사용 -> MappingJackson2HttpMessageConverter 적용
    (Accept: application/json)
     */
    @ResponseBody
    @PostMapping("/request-body-json-v5")
    public HelloData requestBodyJsonV5(@RequestBody HelloData data) {
     log.info("username={}, age={}", data.getUsername(), data.getAge());
     return data;
    }

    > 응답에도 객체를 집어 넣을 수 있다! (HttpEntity도 사용가능)

    >  메시지 컨버터가 객체를 JSON으로 바꿔서 응답해준다. 

Designed by Tistory.