Altiora Petamus

다양한 HTTP Mapping 2 본문

Java/Spring Framework

다양한 HTTP Mapping 2

Haril Song 2021. 7. 31. 21:30

Intro

REST API 의 다양한 사용법에 대해 알아봅니다.

모든 테스트는 Postman 을 활용해 진행했습니다.

HTTP Request

기본 사용법

@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {

    @GetMapping
    public String user() {
        return "get users";
    }

    @PostMapping
    public String addUser() {
        return "post user";
    }

    @GetMapping("/{userId}")
    public String findUser(@PathVariable String userId) {
        return "get userId=" + userId;
    }

    @PatchMapping("/{userId}")
    public String updateUser(@PathVariable String userId) {
        return "update userId=" + userId;
    }

    @DeleteMapping("/{userId}")
    public String deleteUser(@PathVariable String userId) {
        return "delete userId=" + userId;
    }

}

@RequestMapping 을 클래스 레벨에 매핑 정보를 작성하면 모든 메서드에 해당 경로가 조합되어 적용됩니다. url 경로의 중복을 제거하는 방법으로 사용할 수 있습니다.

header 조회

@Slf4j
@RestController
public class RequestHeaderController {

    @RequestMapping(value = "/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("host = {}", host);
        log.info("cookie = {}", cookie);

        return "ok";

    }

}

HttpServletRequest

HttpServletResponse

HttpMethod : Http method 를 조회합니다.

Locale : Locale 정보를 조회합니다.

@RequestHeader MultiValueMap<String, String> : 모든 헤더를 MultiValueMap 형식으로 조회합니다.

@RequestHeader("host") String host : 특정 HTTP 헤더를 조회합니다.

@CookieValue(value = "myCookie", required = false) String cookie : 특정 쿠키를 조회합니다.

필수 값 여부 : require

기본 값 : defaultValue

Parameter 조회

파라미터를 조회할 땐 다음 3가지 방식으로 조회할 수 있습니다.

  1. GET - 쿼리 파라미터
    • /url?username=hello&age=20
    • 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
    • 예) 검색, 필터, 페이징등에서 많이 사용하는 방식
  2. POST - HTML Form
    • content-type: application/x-www-form-urlencoded
    • 메시지 바디에 쿼리 파리미터 형식으로 전달 username=hello&age=20
    • 예) 회원 가입, 상품 주문, HTML Form 사용
  3. HTTP message body에 데이터를 직접 담아서 요청
    • HTTP API에서 주로 사용, JSON, XML, TEXT
    • 데이터 형식은 주로 JSON 사용
    • POST, PUT, PATCH

이 중 GET, POST 는 전송 형식이 같으므로 구분없이 조회할 수 있습니다.

하나씩 알아봅니다.

Request parameter 조회

HttpServletRequest - V1

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

}

request.getParameter() 를 사용하여 요청으로 들어오는 파라미터 값을 조회할 수 있습니다.

 

@RequestParam - V2

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

    log.info("memberName = {}, age = {}", memberName, memberAge);
    return "ok";
}

@RequestParam : 파라미터값을 아주 편리하게 조회할 수 있습니다.

@ResponseBody : view 조회를 무시하고 값을 직접 HTTP message body 에 입력합니다. 추후에 나오는 @RestController 와 관련이 있습니다.

 

@RequestParam - V3

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

    log.info("username = {}, age = {}", username, age);
    return "ok";
}

@RequestParam 의 이름이 변수명과 같다면 생략 가능합니다.

 

@RequestParam 의 생략 - V4

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

    log.info("username = {}, age = {}", username, age);
    return "ok";
}

만약 변수의 타입이 String, int, Integer 등의 단순 타입이면 @RequestParam 도 생략 가능합니다!

 

@RequestParam 을 생략하면 스프링 내부적으로 required = false 를 적용합니다.

⚠️너무 과한 생략은 가독성을 해칠 수 있으므로 충분한 합의가 있을 경우에 사용합시다!

 

파라미터의 필수 여부

@ResponseBody
@RequestMapping("/request-param-v5")
public String requestParamRequired(
        @RequestParam(required = true) String username,
        @RequestParam(required = false) Integer age) {

    log.info("username = {}, age = {}", username, age);
    return "ok";
}

required = true 가 기본값으로 설정되어 있으며 요청시 파라미터가 넘어오지 않는다면 400 예외를 발생시킵니다. false 로 설정하게 될 경우, 값이 넘어오지 않으면 null 값이 세팅되는데 int 타입은 null 일 수 없으므로 Integer 로 바꿔줍니다.

⚠️빈 문자("")는 null 이 아님을 주의합니다!

 

파라미터의 기본값 설정

@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(
        @RequestParam(defaultValue = "guest") String username,
        @RequestParam(defaultValue = "-1") int age) {

    log.info("username = {}, age = {}", username, age);
    return "ok";
}

파라미터가 없을 때 설정한 값을 넣어줍니다. 이 때 파라미터에는 무조건 값이 설정되므로 required = false 로 세팅해도 동작하지 않습니다."" 의 경우에도 기본값을 넣어줍니다.

 

파라미터를 맵으로 조회

@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 을 사용해도 되지만, 그렇지 않다면 MultiValueMap 을 사용하면 됩니다. 하지만 대부분 파라미터는 1개이므로 필요할 때 사용합시다.

@ModelAttribute 의 사용

실제 개발을 할 때면 파라미터를 받아서 객체를 생성해야할 경우가 있습니다. 다음과 같이 말이죠.

@RequestParam String username;
@RequestParam int age;

HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);

스프링은 이 과정을 완전히 자동화 해주는 @ModelAttribute 기능을 제공합니다.

먼저 요청 파라미터를 바인딩 받을 객체를 만듭니다.

package hello.springmvc.basic;
import lombok.Data;

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

 

@ModelAttribute 적용

@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
    log.info("helloData = {}", helloData);
    return "ok";
}

Spring MVC 는 @ModelAttribute 가 있으면 다음을 실행합니다.

  1. HelloData 객체를 생성
  2. 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter 를 호출해서 파라미터의 값을 입력(바인딩).

 

@ModelAttribute 의 생략

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

@ModelAttribute 는 생략할 수 있습니다. 그런데 위에서 살펴본 바와 같이 @RequestParam 도 생략할 수 있으니 뭐가 적용될 지 혼란이 발생할 수 있습니다. 스프링은 해당 생략시 다음과 같은 규칙을 적용합니다.

  • String, int, Integer 등 단순 타입 ⇒ @RequestParam
  • 그 외 Reference Type ⇒ @ModelAttribute (argument resolver 로 지정해둔 타입 제외)

'Java > Spring Framework' 카테고리의 다른 글

@JsonNaming 사용 (springboot 2.5.3 ~)  (0) 2021.08.04
다양한 HTTP Mapping 1  (0) 2021.07.28
in-memory DB 구현  (0) 2021.06.30
Spring Security 사용하기 1  (0) 2021.06.26
Spring Security란?  (0) 2021.06.19