교육 및 인강/스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술

스프링 MVC 기본 기능, HTTP 요청 - 기본, 헤더 조회, 파라미터

loop-study 2021. 7. 20. 14:18

인프런 김영한 님의 스프링 강의이며, 섹션 6 - 스프링 MVC 기본 기능을 정리하는 시간이다.

자세한 설명이 궁금하면 수강을 권장한다.

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 원

www.inflearn.com


HTTP 요청 - 기본, 헤더 조회

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

 

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

HttpMethod : HTTP 메서드를 조회
Locale
: locale 정보를 조회
@RequestHeader
MultiValueMap<String, String> headerMap : 모든 HTTP 헤더를 MultiValueMap 형식으로 조회

@RequestHeader(key) : 특정 HTTP 헤더를 조회
@CookieValue(key)
: 특정 쿠키를 조회

 

참고 : MultiValueMap는 하나의 키에 여러 값을 받을 수 있는 Map이다.

 

스프링 컨트롤러의 다양한 파라미터와 응답 목록은 가이드를 참고하자.

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-arguments

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-return-types


HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form

HTTP 요청 데이터 조회 - 개요

이전 서블릿에서 HTTP 요청 데이터를 조회 방법을 스프링이 얼마나 깔끔하게 해 주는지 알아보자.

// 서블릿 방식
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String username = req.getParameter("username");
    System.out.println("username = " + username);
    ...
}

 

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

1. GET - 쿼리 파라미터

- /url?username=hello&age=20

- 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달

- 예) 검색, 필터, 페이징 등에서 많이 사용하는 방식 (URL에 노출돼도 상관없는 정보)

 

2. POST - HTML Form

- content-type : application/x-www-form-urlencoded

- 메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20

- 예) 회원 가입, 상품 주문, HTML Form 사용 (노출되면 안 되는 정보)  

<form action="/request-param-v1" method="post">
    username: <input type="text" name="username" />
    age: <input type="text" name="age" />
    <button type="submit">전송</button>
</form>

 

3. HTTP message body

- HTTP API에서 주로 사용 JSON, XML, TEXT

- 데이터 형식은 주로 JSON 사용

- POST, PUT, PATCH


HTTP 요청 파라미터 - @RequestParam

스프링이 제공하는 @RequestParam을 이용하면 편안하게 요청 데이터를 사용할 수 있다.

 

    @ResponseBody
    @RequestMapping("/request-param-v2")
    public String requestParamV2(
            @RequestParam("username") String username,
            @RequestParam("age") int age
    ) {
        log.info("username={}, age={}", username, age);
        return "ok";
    }

 

더 나아가 @RequestParam(key)에서 key와 변수명이 동일한 경우 key를 생략할 수 있다.

    @ResponseBody
    @RequestMapping("/request-param-v3")
    public String requestParamV3(
            @RequestParam String username,
            @RequestParam int age
    ) {
        log.info("username={}, age={}", username, age);
        return "ok";
    }

 

String, int, Integer 같은 단순 타입이면 @RequestParam 생략도 가능하다. 

    @ResponseBody
    @RequestMapping("/request-param-v4")
    public String requestParamV4(
            String username,
            int age
    ) {
        log.info("username={}, age={}", username, age);
        return "ok";
    }

 

필수 파라미터 여부

@RequestParam 속성엔 required가 있다. default=true이며, 필수인 값이 없으면 400 에러가 반환된다. 

    @ResponseBody
    @RequestMapping("/request-param-required")
    public String requestParaRequired(
            @RequestParam(required = true) String username,
            @RequestParam(required = false) int age
    ) {
        log.info("username={}, age={}", username, age);
        return "ok";
    }

필수값 username 없어서 에러 반환

만약에 null 값이 올 경우 변수 타입에 신경을 써야 한다.

int 타입은 null을 받을 수 없어서 에러가 발생.

username= 으로 보내면 빈문자로 인식하여 통과될 수도 있다. 

 

@RequestParam은 defaultValue 속성이 존재한다.

    @ResponseBody
    @RequestMapping("/request-param-default")
    public String requestParamDefault(
            @RequestParam(required = true, defaultValue = "guest") String username,
            @RequestParam(required = false, defaultValue = "-1") int age
    ) {
        log.info("username={}, age={}", username, age);
        return "ok";
    }

필수 데이터가 없어도 디폴트 값을 지정해서 400 에러가 발생하지 않는다.

 

Map 타입으로 요청 데이터를 담을 수 있다.

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

만약에 데이터가 배열로 넘어온다면 MultiValueMap을 사용하자.

 


HTTP 요청 파라미터 - @ModelAttribute

보통 데이터를 받으면 객체를 생성하고 그 객체에 값을 세팅하는데,

스프링은 이 과정을 자동화시켜주는 @ModelAttribute 기능을 제공한다.

 

@Data
public class HelloData {
    private String username;
    private int age;
}
    @ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV1(@ModelAttribute HelloData helloData) {
        log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
        log.info("helloData={}", helloData.getUsername());
        return "ok";
    }

롬복의 @Data를 사용하면 

@Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor를 적용해준다.

 

정상적으로 작동하는지 확인해보자

편하게 객체가 생성되고 값이 세팅되었다.

 

스프링의 @ModelAttribute 실행 순서

- HelloData 객체 생성

- 요청 파라미터의 이름으로 HelloData 객체 프로퍼티를 찾고, setter 호출해서 값을 바인딩한다.

- 예) 파라미터 이름이 username 이면 setUsername() 을 메서드를 찾아 호출하면서 값을 입력. (요청 데이터와 객체의 프로퍼티 명이 일치해야 한다) 

- 만약 타입에 어긋나는 데이터가 들어오면 에러가 발생한다.

 

@ModelAttribute도 생략이 가능하다.

    // @ModelAttribute 생략이 가능
    @ResponseBody
    @RequestMapping("/model-attribute-v2")
    public String modelAttributeV2(HelloData helloData) {
        log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
        log.info("helloData={}", helloData.getUsername());
        return "ok";
    }

 

스프링은 @RequestParam, @ModelAttribute 생략하면 다음의 규칙을 따른다.

- String, int, Integer 같은 단순 타입이면 @RequestParam을 자동 적용

- 나머지는 @ModelAttribute 를 적용한다. 단, argument resolver로 지정해둔 타입은 제외. (이 내용은 나중에 언급됨)