스프링 MVC: RequestMapping & RequestParameter(몰랐던것 중심)

RisingJade의 개발기록·2022년 3월 3일
1

SPRING MVC

목록 보기
3/6

요청 매핑

@RequestMapping

  • 기본적으로 어떤 HTTP메소드도 받을 수 있다.
  • 예시: @RequestMapping("/hello")
  • 매개변수로 method를 받을 시 특정 HTTP만을 받는다.
    • GET, HEAD, POST, PUT, PATCH, DELETE
  • 예시: @RequestMapping(value="/hello", method="RequestMethod.GET")

@Get,Post,Put,Delete,PatchMapping

  • 편리한 축약 에노테이션

파라미터로 추가 매핑

  • params의 값이 쿼리파라미터로 오지 않으면 400 bad_request를 반환한다.
    • params="mode",
    • params="!mode"
    • params="mode=debug"
    • params="mode!=debug" (! = )
    • params = {"mode=debug","data=good"}
@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
log.info("mappingParam");
return "ok";
}

특정 헤더 조건 매핑

  • 파라미터랑 비슷한데 HTTP header를 사용한다는 점이 다르다.
@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
log.info("mappingHeader");
return "ok";
}

미디어 타입 조건 매핑 - HTTP 요청 Content-Type, consume

  • Content-Type 헤더 기반 추가 매핑 Media Type
    만약 맞지 않으면 415 Unsupported Media Type 에러를 반환한다. (무엇을 서버(정확힌 컨트롤러)가 받을 수 있는지 적어둠)
//consumes 뒤에 오는 타입을 받겠다는 약속
//consumes를 통해 여러 타입의 데이터를 다른 방식으로 가공가능
@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
log.info("mappingConsumes");
return "ok";
}
//____타입 명명
consumes = "text/plain"
consumes = {"text/plain", "application/*"}
consumes = MediaType.TEXT_PLAIN_VALUE
  • consumes 쓸때 되도록이면 MediaType에 정해진 걸 쓰자

미디어 타입 조건 매핑 - HTTP 요청 Accept, produce

  • HTTP 요청의 Accept 헤더를 기반으로 미디어 타입으로 매핑한다.(서버가 생성해서 넘겨주는 것이 무엇인지 produce에서 확인)
    만약 맞지 않으면 HTTP 406 상태코드(Not Acceptable)을 반환한다
@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
log.info("mappingProduces");
return "ok";
}
//----타입
produces = "text/plain"
produces = {"text/plain", "application/*"}
produces = MediaType.TEXT_PLAIN_VALUE
produces = "text/plain;charset=UTF-8"

요청 헤더

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

HttpServletRequest: request를 받는다.

HttpServletResponse: response를 받는다.

HttpMethod : HTTP 메서드를 조회한다.

  • org.springframework.http.HttpMethod

Locale : Locale 정보를 조회한다.

@RequestHeader MultiValueMap<String, String> headerMap

: 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.

@RequestHeader("host") String host

  • 특정 HTTP 헤더를 조회한다.
  • 속성
    • 필수 값 여부: required
    • 기본 값 속성: defaultValue
  • 특정 쿠키를 조회한다.
  • 속성
    • 필수 값 여부: required
    • 기본 값: defaultValue

MultiValueMap

MAP과 유사한데, 하나의 키에 여러 값을 받을 수 있다.
HTTP header, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용한다.

  • keyA=value1&keyA=value2

요청 파라미터 1

  • @RequestParamname(value) 속성이 파라미터 이름으로 사용
  • @RequestParam("username") String memberName -> request.getParameter("username")
    • RequestParam과 매개변수 명이 같으면 ("username") 생략가능!
    • RequestParam과 매개변수 명이 같고, 기본 자료형(int, long, string)일 경우 @RequestParam("username")생략가능!

기본값 적용

  • 파라미터에 값이 없는 경우 defaultValue를 사용하면 기본 값을 적용할 수 있다.
    • @RequestParam(required = false, defaultValue = "-1") int age)

파라미터를 Map으로 조회하기 - requestParamMap

  • 파라미터를 Map, MultiValueMap으로 조회할 수 있다.
  • @RequestParam Map
    • Map(key=value)
  • @RequestParam MultiValueMap
    • MultiValueMap(key=[value1, value2, ...]
    • ex)
  /?userIds=id1&userIds=id2 -> (key=userIds, value=[id1, id2])

파라미터의 값이 1개가 확실하다면 Map 을 사용해도 되지만, 그렇지 않다면 MultiValueMap 을 사용하자.
(보통 파라미터값은 1개가 맞긴하다... 애매하게 2개이상 주는 경우는 적다)

/**
* @RequestParam Map, MultiValueMap
* Map(key=value)
* MultiValueMap(key=[value1, value2, ...] ex) (key=userIds, value=[id1, id2])
*/
@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";
}

주의!
1. JAVA에서 int와 같은 기본형(primitive)에는 null이 들어갈 수 없다!. 따라서 외부에서 값을 받는 매개변수가 int로 되어있는데 null 값을 받을 것 같다 싶으면, Integer를 써서 급한 불을 끄거나 defaultValue등을 사용할 수 있다.(Integer는 객체라 null을 받을 수 있다.)
제일 좋은건 저런 케이스를 안 만드는거지만...

2. 파라미터 이름만 사용
/request-param?username=
파라미터 이름만 있고 값이 없는 경우 빈문자로 통과 (""null은 다르다! 빈문자열은 null이 아니다.)


요청 파라미터 2

@ModelAttribute

  • 스프링MVC는 @ModelAttribute 가 있으면 다음을 실행한다.
  1. HelloData 객체를 생성한다.
  2. 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter
  3. 호출해서 파라미터의 값을 입력(바인딩) 한다.
    예) 파라미터 이름이 username 이면 setUsername() 메서드를 찾아서 호출하면서 값을 입력한다.

바인딩 오류

  • age=abc 처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException이 발생한다. 이런 바인딩 오류를
    처리하는 방법은 검증 부분에서 다룬다.

@ModelAttribute 생략

  • @ModelAttribute 는 생략할 수 있다.
    그런데 @RequestParam 도 생략할 수 있으니 혼란이 발생할 수 있다.
    스프링은 해당 생략시 다음과 같은 규칙을 적용한다.
    String , int , Integer 같은 단순 타입은 @RequestParam으로
    나머지는 @ModelAttribute (argument resolver 로 지정해둔 타입 외) -> argument resolver는 나중에 다룬다.
 @ResponseBody
    @RequestMapping("/model-attribute-v1")//
    public String modelAttributeV1(@ModelAttribute HelloData helloData) {
        log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
        return "ok";
    }

profile
언제나 감사하며 살자!

0개의 댓글