Spring MVC 활용기2

hoyong.eom·2023년 7월 18일
0

스프링

목록 보기
15/59
post-thumbnail

Spring

@Controller

@Controller 애노테이션을 이용해서 RequestMappingHandler를 만들게 되면 자동으로 컴포넌트스캔에 의해서 자동으로 스프링빈에 등록되어서 RequestMappingHandler와 RequestMappingHandlerAdapter에 의해서 컨트롤러가 호출될 수 있다고 했다.

그밖에도 @Controller 애노테이션을 활용한 컨트롤러는 다양한 인자를 제공할 수 있으며, 자세한 내용은 아래의 가이드 페이지에서 확인할 수 있다.

@Controller에서 사용할수 있는 인자들

이전 공부했었던 내용으로 몇가지 예시를 들면 아래와 같다.

   @RequestMapping("/headers")
    public String headers(HttpServletRequest request,
                          HttpServletRequest 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";
    }

위 코드를 postman으로 아래와같이 요청했을때의 수행결과는 다음과 같다.

2023-07-18 21:52:13.802  INFO 23492 --- [nio-8080-exec-9] h.s.b.request.RequestHeaderController    : request=org.apache.catalina.connector.RequestFacade@7ea44152
2023-07-18 21:52:13.803  INFO 23492 --- [nio-8080-exec-9] h.s.b.request.RequestHeaderController    : response=org.apache.catalina.connector.RequestFacade@7ea44152
2023-07-18 21:52:13.803  INFO 23492 --- [nio-8080-exec-9] h.s.b.request.RequestHeaderController    : httpMethod=POST
2023-07-18 21:52:13.803  INFO 23492 --- [nio-8080-exec-9] h.s.b.request.RequestHeaderController    : locale=ko_KR
2023-07-18 21:52:13.803  INFO 23492 --- [nio-8080-exec-9] h.s.b.request.RequestHeaderController    : headerMap={content-type=[application/json], cookie=[myCookie=1], user-agent=[PostmanRuntime/7.32.3], accept=[*/*], postman-token=[be571024-3fe3-48e8-8966-742b920f1d5e], host=[localhost:8080], accept-encoding=[gzip, deflate, br], connection=[keep-alive], content-length=[37]}
2023-07-18 21:52:13.803  INFO 23492 --- [nio-8080-exec-9] h.s.b.request.RequestHeaderController    : header host=localhost:8080
2023-07-18 21:52:13.803  INFO 23492 --- [nio-8080-exec-9] h.s.b.request.RequestHeaderController    : myCookie=1

HttpServletRequest : @Controoler에서도 Servlet에서 사용하던 HttpServletRequest값을 사용할 수 있다.

HttpServletResponse : @Controoler에서도 Servlet에서 사용하던 HttpServletResponse 값을 사용할 수 있다.

Local : locale 값 확인 가능
@RequestHeader("host)" : HttpRequestHeader중에서 host 정보를 가져온다.
@CookieValue(value = "myCookie", required=false) : 저장된 쿠키값을 조회한다.

Http 요청 파라미터

클라이언트에서 서버로 요청 데이터를 전달할때는 주로 3가지 방법을 사용한다고 한다.

GET - 쿼리파라미터 방식

  • /header?username=hoyo&age=20
  • 메시지 바디 없이 URL의 쿼리 파라미터에 데이터를 포함해서 전달

POST - Html Form 방식

  • 메시지 바디에 쿼리 파라미터 형식으로 전달
  • content-type:application/x-www-form-urlencoded

Http Message Body에 데이터를 직점 담는 방식

  • Http API에 주로 사용하며 JSON, XML, TEXT등 다양한 형식을 사용

Get방식과 HtmlForm 방식은 Spring에서 @RequestParam 애노테이션으로 모두 조회가 가능하다.

@RequestParam은 HttpServletRequest에서의 getParameter를 이용한 조회방식과 동일하다.

@RequestParam

Get방식과 Html Form 방식은 SpringMVC에서 @RequestParam 애노테이션을 이용해서 손쉽게 조회가 가능하다. 그러나, 좀 더 편리하게 사용하기 위해서 몇가지 알아야할 점이 있다.

  • @RequestParam(name) 속성으로 파리미터를 조회
  • Http파라미터 이름이 변수이름과 같다면 name 생략 가능
  • String, int, Integer 등의 단순 타입이라면 RequestParam 생략 가능
    @ResponseBody
    @RequestMapping("/request-param-v1")
    public String requestParamV1(
            @RequestParam("username") String username, @RequestParam("age") int age) {

        log.info("username : {}", username);
        log.info("age : {}", age);

        return "success";
    }

    @ResponseBody
    @RequestMapping("/request-param-v2")
    public String requestParamV2(
            @RequestParam String username, @RequestParam int age) {

        log.info("username : {}", username);
        log.info("age : {}", age);

        return "success";
    }

    @ResponseBody
    @RequestMapping("/request-param-v3")
    public String requestParamV3(
            String username, int age) {

        log.info("username : {}", username);
        log.info("age : {}", age);

        return "success";
    }
    
    @ResponseBody
    @RequestMapping("/request-param-map")
    public String requestParamMap(@RequestParam Map<String, Object> paramMap) {
        log.info("username={}, age={}", paramMap.get("username"), paramMap.get("age"));
        return "success";
    }

따라서, 위 3가지 코드는 모두 같은 기능을 수행한다.
참고) RequestBody는 return값을 그대로 Http 메시지 Body에 되돌려주도록 명시합니다.

그뿐만 아니라 RequestParam은 Map 컬렉션으로 조회도 가능합니다.

@ModelAttribute

@RequestParam이 단순한 데이터의 쿼리 파라미터를 조회하는 애노테이션이었다면 일반적인 객체들을 조회할 수 있도록 지원하는 애노테이션도 존재합니다.

일반적으로는 @RequestParam으로 쿼리 파라미터를 조회하고 나서 객체를 만들어주지만, Spring에서는 이 과정을 자동화해주는 @ModelAttribute라는 애노테이션이 존재합니다.

    @ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV1(@ModelAttribute Member member) {
        log.info("username={}, age={}", member.getUsername(), member.getAge());
        return "success";
    }

    @ResponseBody
    @RequestMapping("/model-attribute-v2")
    public String modelAttributeV2(Member member) {
        log.info("username={}, age={}", member.getUsername(), member.getAge());
        return "success";
    }

위 코드는 아래와 같이 실행됩니다.

  • Member객체를 생성
  • 요청 파라미터 이름으로 Member 객체의 프로퍼티를 찾고 Setter를 호출해서 프로퍼티 값을 바인딩
    (따라서 객체의 프로퍼티는 요청 파라미터와 같아야함)
  • ModelAttribute는 생략 가능함
  • RequestParam과 같이 생략이 가능하기 떄문에 생략된 경우 단순타입은 RequestParam, 나머지는 ModelAttribute가 사용됨.

Http Message Body

요청 파라미터가 아닌 Http Body에 Message가 담겨 전달되는 경우는 RequestParam과 ModelAttribute로 조회가 불가능하다.

따라서 SpringMVC에서는 아래와 같은 파라미터를 지원합니다.
HttpEntity를 사용하면 메시지 바디에 직접 정보를 추가해서 반환도 가능합니다.
(ResponseEntity도 물론 가능)

HttpEntity

  • 메시지 바디 정보를 직접 조회
  • Http Header와 Body 정보를 편리하게 조회

RequestEntity

  • HttpEntity를 상속 받은 객체
  • HttpEntity 기능에다가 HttpMethod, url 정보가 추가되어 요청에서 사용됨

ResponseEntity

  • HttpEntity를 상속 받은 객체
  • HttpEntty 기능에다가 Http 상태코드 설정이 가능, 응답에서 사용됨

@RequestBody

  • 매번 HttpEntity를 작성하기가 귀찮음
  • @RequestBody 애노테이션으로 편리하게 Body 메시지 조회 가능

@ResponseBody

  • 매번 HttpEntity를 작성하기가 귀찮음
  • @ResponseBody 애노테이션으로 편리하게 Body 메시지에 쓰기 가능

정리하자면
요청 파라미터 : @ReuqestParam, @ModelAttribute
Http 메시지 바디 : @RequestBody @ResponseParam

    @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);

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

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

    @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("success");
    }

    @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<>("success");
    }

    @ResponseBody
    @PostMapping("/request-body-string-v4")
    public String requestBodyStringV4(@RequestBody String messageBody) {
        log.info("messageBody={}", messageBody);
        return "success";
    }

그리고 @RequestBody는 ModelAttribute처럼 일반 객체로 한번에 변환도 가능하다.

  @ResponseBody
    @PostMapping("/request-body-json-v3")
    public String requestBodyJsonV3(@RequestBody Member member) {
        log.info("username={}, age={}", member.getUsername(), member.getAge());
        return "success";
    }

참고

해당 포스팅은 아래의 강의를 공부 후 개인적으로 정리한 내용입니다.
김영한님의 SpringMVC1편-요청매핑 API

김영한님의 SpringMVC1편-기본,헤더조회

김영한님의 SpringMVC1편-쿼리파라미터,HtmlForm

김영한님의 SpringMVC1편-@RequestParam

김영한님의 SpringMVC1편-@ModelAttribute

김영한님의 SpringMVC1편-단순텍스트

김영한님의 SpringMVC1편-JSON

1개의 댓글

comment-user-thumbnail
2023년 7월 18일

정보가 많아서 도움이 많이 됐습니다.

답글 달기