숑숑이의 개발일기

기본, 헤더 조회

애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다. 고로 이전에 사용했던 HttpServletRequest, HttpServletResponse 등 다양한 객체를 사용할 수 있다.

@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";
    }
}
  • Locale : Locale 정보를 조회
  • @RequestHeader MultiValueMap<String, String>
    • 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.
    • Map과 유사한데, 하나의 키에 여러 값을 받을 수 있다.
    • HTTP header, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용한다.
  • @RequestHeader("host")
    • 특정 HTTP 헤더를 조회한다. 속성으로는 필수 값 여부인 required, 기본 값 속성인 defaultValue가 존재함
  • @CookieValue(value ="myCookie", required = false)
    • 특정 쿠키를 조회한다. 필수 값 여부인 required, 기본 값 속성인 defaultValue가 존재함

 

@Slf4j 어노테이션을 활용하면 아래의 코드를 자동으로 생성하여 로그를 선언해준다. 개발자는 log로 사용이 가능하다.

private static final org.slf4j.Logger log = 
org.slf4j.LoggerFactory.getLogger(RequestHeaderController.class);

 

 

쿼리 파라미터, HTML Form 방식

쿼리 파라미터의 Get방식, HTML Form에서 넘어오는 POST 방식의 경우에는 간단히 HttpServletRequest가 제공하는 getParameter() 메서드를 사용해 조회할 수 있다.

@Slf4j
@Controller
public class RequestParamController {
    @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"));
        log.info("username={}, age={}", username, age);

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

 

 

@RequestParam

스프링이 제공하는 @RequestParam을 사용하면, 요청 파라미터를 매우 편리하게 사용할 수 있다.

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

@RequestParam의 name(value) 속성이 파라미터 이름으로 사용된다.

즉, 이는 request.getParameter("username")과 같다.

 

해당 메서드에 @ResponseBody 어노테이션을 붙이면, 클래스 단위에서 @RestController를 붙인것 과 같이 HTTP message body에 직접 해당 내용을 입력한다.

 

참고로 아래와 같이 HTTP 파라미터 이름이 변수 이름과 같으면 생략이 가능하다.

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

 

더 나아가, @RequestParam 자체를 생략할 수도있는데, 이는 명확성이 떨어져 보이므로 팀과 협의가 된 상태에서 사용하는 것을 추천.

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

 

required, 필수값 설정

그리고 @RequestParam에는 필수값을 설정할 수도있다. 기본값(true) @RequestParam(required = true)

@RequestParam 어노테이션을 생략하는 경우 required=false를 적용한다.

 

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

위와같은 코드에서는

  • /request-param-required : username이 없으므로 400 예외
  • /request-param-required?username=: 빈문자로 통과

여기에서 age를 Integer로 설정한 이유는 int는 기본형이므로 null이 들어갈 수 없기 때문이다.

 

defaultValue

위의 상황은 @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";
}

이 경우에는 빈문자열이 들어와도, defaultValue인 guest로 설정된다. 그리고 age가 들어오지 않더라도 기본값이 -1로 설정되어 있기 때문에 500예외가 발생하지 않는다.

 

파라미터의 값이 1개가 확질하지 않은 경우, MultiValueMap을 통해 조회할 수 있다.

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

 

@ModelAttribute

실제 개발시에는 요청 파라미터를 받아 필요한 객체를 만들고 그 객체에 값을 넣어주어야한다. 

@ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV1(@RequestParam String username, @RequestParam int age) {
        HelloData helloData = new HelloData();
        helloData.setUsername(username);
        helloData.setAge(age);
        log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
        return "ok";
    }

 

하지만 @ModelAttribute를 사용하여 이를 간략하게 작성할 수 있다.

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

대신 해당 코드는 바인딩 받을 객체가 필요하다.

package hello.springmvc.basic;

import lombok.Data;

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

Lombok의 @Data 어노테이션은 @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor를 자동으로 적용해준다.

 

@ModelAttribute 어노테이션이 있는 경우 스프링 MVC가 아래의 과정을 거친다.

  1. 객체생성
  2. 요청 파라미터의 이름으로 객체의 프로퍼티를 찾음.
  3. 해당 프로퍼티의 setter를 호출하여 파라미터의 값을 바인딩

@ModelAttribute도 아래와 같이 생략이 가능하다

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

 

위 글은 김영한 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술의 일부 내용을 정리한 것입니다.
profile

숑숑이의 개발일기

@숑숑-

풀스택 개발자 준비중입니다