[MVC1] 7. 스프링 MVC의 요청조회와 응답

kiwonkim·2021년 7월 15일
0
post-thumbnail

이전 포스팅

스프링 MVC의 구조에 대해 이해해 보았다. 클라이언트가 URI로 요청을 하면. 디스패쳐 서블릿은 매핑 방식에 따른 여러 핸들러 매핑에서 URI에 해당하는 핸들러를 찾고. 어댑터 목록에서 해당 핸들러의 구현방식을 처리할 수 있는 어댑터를 찾고. 처리하여 뷰에서 렌더링한다.

그러면 스프링 MVC는 요청 조회나 응답을 어떻게 처리할까? 서블릿과 동일하게 getParameter와 JackSon 라이브러리를 사용해 처리할까? 이번 포스팅은 스프링 MVC의 요청 조회와 응답에 대해 알아보자.



스프링의 요청 조회

클라이언트가 서버로 데이터를 전송하는 방식은

  1. GET - 쿼리 파라미터
  2. POST - HTML Form
  3. HTTP message Body에 저장

위의 세가지 방식이 있다고 하엿다.
1, 2는 파라미터의 범주에 속하므로 서블릿이 request.getParameter로 조회.
3은 서블릿이 request.getInputStream() 과 streamUtils.copyToString 으로 Body를 String으로 변환해 조회하였다.

스프링은 파라미터와 바디 조회를 어떻게 수행할까?

1 & 2. 요청 파라미터 조회

@RequestParam - 파라미터 변수화

//@RequestParam 사용. 변수로 지정.
public String requestParamV2(
            @RequestParam("username") String memberName,
            @RequestParam("age") int memberAge)

//파라미터 이름과 변수 이름 같으면 @RequestParam 내부 생략 가능
public String requestParamV3(
            @RequestParam String username,
            @RequestParam int age)

//필수 여부인 required 속성 추가. 
public String requestParamV4(
            @RequestParam(required = true) String username,
            @RequestParam(required = false) Integer age) 
            //int는 null 불가능하므로 Integer로 설정
            
//디폴트 값인 defaulValue 속성 추가.
public String requestParamDefault(
            @RequestParam(defaultValue = "guest") String username,
            @RequestParam(defaultValue = "-1") int age)

//모든 파라미터를 Map으로 조회
public String requestParamMap(
            @RequestParam Map<String, Object> paramMap)

파라미터를 단순 조회할 때 컨트롤러의 파라미터에 @RequestParam 을 사용한다.


@ModelAttribute - 파라미터 객체화

@Data //getter setter 생성자 만들어줌
public class HelloData {
    //필드명은 파라미터명과 같게
    private String username;
    private int age;
}


//@ModelAttribute 사용. 파라미터를 setter로 객체에 넣어줌
public String modelAttributeV1(@ModelAttribute HelloData helloData)

//@ModelAttribute 생략 가능. 파라미터에 객체만 넘겨줌
public String modelAttributeV2(HelloData helloData)

Setter를 생성해 놓은 객체를 @ModelAttribute와 함께 파라미터로 넘겨주면. 자동으로 setter를 호출해 조회한 파라미터를 넘겨준다. 파라미터 이름과 객체의 필드명을 같게해야 함에 유의한다.


3 - 1. 요청 바디 조회 - String

//HttpEntity 객체 사용
@PostMapping("/request-body-string-v1")
    public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) {

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

        return new HttpEntity<>("ok");
    }

//@RequestBody 사용
@ResponseBody
    @PostMapping("/request-body-string-v2")
    public String requestBodyStringV4(@RequestBody String messageBody) {

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

        return "ok";
    }

Body에 담긴 문자열을 조회할 때는
1. Http 자체를 객체화한 HttpEntity를 파라미터로 받거나.
2. @RequestBody 로 요청 바디 부분만 파라미터로 받으면 된다.


먼저 HttpEntity 객체는 Http 메시지를 header와 body 로 나눠 필드화한 객체이다. 제네릭 타입은 body의 타입이다. 요청 body가 String이므로 HttpEntity <String>으로 받은 것이다.
요청과 응답 모두에 사용할 수 있어 return new HttpEntity("ok") 를통해 바디에 "ok"를 담은 메시지를 응답에 사용한 것을 볼 수 있다.
HttpEntity를 상속받은 RequestEntity, ResponseEntity 객체도 존재한다.


헤더 정보가 필요없다면 @RequstBody로 요청 바디를 쉽게 조회할 수 있다.
스프링의 HTTP 메시지 컨버터는 요청 메시지의 content-type(text)과 사용한 변수 타입(String)을 확인해 Body를 String 자료형에 담아 파라미터로 넘겨준다.

3 - 2. 요청 바디 조회 - JSON


//@RequestBody 사용
public String requestBodyJsonV1(@RequestBody HelloData helloData) {

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

        return "ok";
    }

//HttpEntity 의 바디 제네릭을 객체로
public HelloData requestBodyJsonV2(HttpEntity<HelloData> httpEntity) {
        HelloData data = httpEntity.getBody();
        log.info("username={}, age={}", data.getUsername(), data.getAge());
        return data;
    }
    

요청 Body에 Json 이 담겨오는 경우 컨트롤러는 객체로 저장하여 사용한다. 이때 Body에 String 이 담겨오는 경우와 동일하게 @RequestBody나 HttpEntity를 사용하는데, 차이점은 변수 타입이 String 이 아니라 객체라는 점이다.

스프링의 HTTP 메시지 컨버터는 요청 메시지의 content-type(application/json)과 사용한 변수 타입(HelloData)을 확인해 HelloData의 setter로 객체화하여 파라미터로 넘겨준다.

파라미터 조회
조회 후 변수로 - @RequestParam
조회 후 객체로 - @ModelAttribute

바디 조회
바디만 필요 - @RequestBody
바디 + 헤더 필요 - @HttpEntity
-> 바디 내용(문자열, Json)을 알맞은 객체(문자열, 임의객체)로 변환해주는 것은 HTTP 메시지 컨버터가 담당.



스프링의 응답

서버가 클라이언트로 응답하는 방식은

  1. 정적 리소스 제공
  2. 동적 HTML 제공
  3. Http API - Body에 데이터 담아 제공

세가지 방식이 있다.

1. 정적 리소스 제공

src/main/resources/static 은 스프링 정적리소스 기본 경로이다.
기본 디렉토리에 파일을 리소스를 넣어두면 스프링 부트가 정적 리소스로 서비스를 제공한다.


2. 동적 HTML 제공

    @RequestMapping("/response-view-v1")
    public ModelAndView reponseViewV1() {
        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";
    }

스프링은 컨트롤러가 직접 ModelAndView 객체를 생성하고 이를 반환하는 V3 방식과
컨트롤러가 model을 매개변수로 사용하고 뷰 상대경로만 반환하는 V4 방식을 동시에 제공한다.

뷰 기본 경로는 src/main/resources/templates 이며 기본 자료형은 .html이다.


3 - 1. Http API - Body에 문자열 담아 제공

    //서블릿과 동일한 response.getWriter().writer 방식
    @GetMapping("/response-body-string-v1")
    public void responseBodyV1(HttpServletResponse response) throws IOException {
        response.getWriter().write("ok");
    }

    //HttpEntity 상속받은 ResponseEntity 객체 사용
    @GetMapping("/response-body-string-v2")
    public ResponseEntity<String> responseBodyV2() 
    				throws IOException {
        return new ResponseEntity<>("ok", HttpStatus.OK);
    }
	
    //메서드에 @ResponseBody. 또는 클래스에 @RestController 사용.
    @ResponseBody
    @GetMapping("/response-body-string-v3")
    public String responseBodyV3() {
        return "ok";
    }

3 - 2. Http API - Body에 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);
    }
    
    //@ReponseBody 후 객체 반환
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    @GetMapping("/response-body-json-v2")
    public HelloData responseBodyJsonV2() {
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);

        return helloData;
    }

서블릿 Body 응답은 HttpEntity를 상속받은 ResponseEntity 객체를 사용하거나. @ResponseBody 후 객체 자체를 반환할 수 있다.
객체를 반환하면 Http 메시지 컨버터가 Json으로 변환하여 클라이언트에게 전달해준다.

@ResponseBody가 가장 간단하나 Http 응답 코드를 설정하려면 ResponseEntity 객체를 사용하자. @ResponseBody를 사용하면서 Http 응답코드를 설정하려면 @ResponseStatus 를 이용하자

Body에 담아 응답
응답 코드 추가 - ResponseEntity 에 담아 리턴
Body 내용만 반환 - @ResponseBody 추가 후 문자열 or 객체 반환
-> 반환 객체(문자열, 임의객체)를 알맞은 바디 내용(문자열, Json)으로 변경해 주는 것은 Http 메시지 컨버터가 담당



정리

스프링 MVC의 요청처리와 응답을 정리해보자면..

  • 요청 파라미터는 @RequestParam 을 통해 변수로 받거나, @ModelAttribute 를 통해 객체로 받을 수 있다.
  • 요청 Body는 @RequestBody 사용. Body 타입의 문자열일 경우 파라미터 타입을 String으로. Json일 경우 파라미터 타입을 객체로한다.
  • HttpEntity를 파라미터로 사용할 경우 getBody로 바디를 가져올 수 있다.
  • 정적 리소스 응답은 정해진 디렉토리에 넣는다.
  • 동적 HTML 응답은 정해진 디렉토리에 넣은 후 반환형을 String 으로 하고 뷰 상대경로를 리턴하여 포워드 한다.
  • Body에 담아 응답은 @ResponseBody 사용. Body 타입이 문자열일 경우 반환 타입을 String으로. Json일 경우 반환 타입을 객체로 한다.
  • ResponseEntity 를 사용할 경우 바디에 직접 객체나 문자열을 넣어 return 하면 된다.

즉 요청은 컨트롤러의 파라미터로, 응답은 리턴값으로한다.



본 글은 김영한님의 "스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술" 강의내용 및 이해한 내용을 정리한 것입니다.

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

0개의 댓글

관련 채용 정보