요청 매핑
매핑 정보
@RequestMapping("/hello-basic")
/hello-basic URL 호출이 오면 이 메서드가 실행되도록 매핑한다.
대부분의 속성을 배열[] 로 제공하므로 다중 설정이 가능하다. {"/hello-basic", "/hello-go"}
둘 다 허용
다음 두가지 요청은 다른 URL이지만, 스프링은 다음 URL 요청들을 같은 요청으로 매핑한다.
매핑: /hello-basic
URL 요청: /hello-basic , /hello-basic
HTTP 메서드
@RequestMapping 에 method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출된다.
모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
HTTP 메서드와 다른 요청을 하면 스프링 MVC는 HTTP 405 상태코드(Method Not Allowed)를 반환한다.
PathVariable(경로 변수) 사용
최근 HTTP API는 다음과 같이 리소스 경로에 식별자를 넣는 스타일을 선호한다.
ex. /mapping/userA, /users/1
*쿼리 파라미터 방식은 ?userId=userA
@RequestMapping 은 URL 경로를 템플릿화({}) 할 수 있는데, 파라미터로 @PathVariable 을 사용하면 매칭 되는 부분을 편리하게 조회할 수 있다.
@PathVariable 의 이름과 파라미터 변수의 이름이 같으면 생략할 수 있다.
미디어 타입 조건 매핑
HTTP 요청 Content-Type, consume
클라이언트: Content-type, 서버: consume
HTTP 요청 헤더에 content-type 이 있긴 하지만 헤더 조건 매핑(headers)이 아닌 더 최적화된 consume을 쓰자.
클라이언트가 전송한 데이터의 content-type이 서버가 소비(consume)하는 타입과 맞아야 한다.
consumes = "text/plain"
consumes = {"text/plain", "application/*"}
consumes = MediaType.TEXT_PLAIN_VALUE
만약 맞지 않으면 HTTP 415 상태코드(Unsupported Media Type)을 반환한다.
HTTP 요청 Accept, produce
클라이언트: Accept, 서버: produce
HTTP 요청 헤더의 Accept 기반으로 미디어 타입을 매핑한다.
클라이언트가 Accept 타입만 수용한다는 뜻. 즉, 서버가 생산(produce)하는 타입과 맞아야 한다.
produces = "text/plain"
produces = {"text/plain", "application/*"}
produces = MediaType.TEXT_PLAIN_VALUE
produces = "text/plain;charset=UTF-8"
만약 맞지 않으면 HTTP 406 상태코드(Not Acceptable)을 반환한다.
요청 매핑 - API 예시
회원 관리를 HTTP API로 만든다 생각하고 매핑을 어떻게 하는지 알아보자.
(실제 데이터가 넘어가는 부분은 생략하고 URL 매핑만)
회원 관리 API
회원 목록 조회: GET /users
회원 등록: POST /users
회원 조회: GET /users/{userId}
회원 수정: PATCH /users/{userId}
회원 삭제: DELETE /users/{userId}
*URL이 같아도 HTTP method로 매핑 구분
HTTP 요청 - 기본, 헤더 조회
애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다.
메서드를 호출하거나 하는 과정 없이 파라미터로 받으면 된다.
MultiValueMap<key, value>
하나의 키에 여러 값을 받을 수 있다.
HTTP header, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용한다.
ex. keyA=value1&keyA=value2
List<String> values = multiValueMap.get("keyA"); //[value1, value2]
참고: @Conroller 의 사용 가능한 파라미터 목록
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-arguments
참고: @Conroller 의 사용 가능한 응답 값 목록
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-return-types
HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form
HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 3가지 방법
GET - 쿼리 파라미터
/url?username=hello&age=20
메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
예) 검색, 필터, 페이징등에서 많이 사용하는 방식
POST - HTML Form
content-type: application/x-www-form-urlencoded
메시지 바디에 쿼리 파리미터 형식으로 전달 username=hello&age=20
예) 회원 가입, 상품 주문, HTML Form 사용
HTTP message body에 데이터를 직접 담아서 요청
HTTP API에서 주로 사용, JSON, XML, TEXT
데이터 형식은 주로 JSON 사용
POST, PUT, PATCH
요청 파라미터 조회
서블릿에서는 GET(쿼리 파라미터), POST(HTML Form)의 요청 파라미터 조회 방식이 request.getParameter() 로 같았다.
스프링에서도 HttpServletRequest 객체를 파라미터로 받아 똑같이 적용 가능하다.
참고: 반환 타입이 없으면서(void) 응답(response)에 값을 직접 집어넣으면, view를 조회하지 않는다.
참고: Jar 를 사용하면 webapp 경로를 사용할 수 없다. 이제부터 정적 리소스도 클래스 경로에 함께 포함해야 한다.
@RequestParam
@RequestParam("username") String memberName
=> request.getParameter("username")
참고: @ResponseBody 애노테이션을 붙이면 RestController가 아니어도 String 반환 시 view를 조회하지 않고 Http 메세지 바디에 데이터를 직접 내린다.
HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="xx") 생략 가능
@RequestParam() String username
+String , int , Integer 등 단순 타입이면 @RequestParam 도 생략 가능 (물론 요청 파라미터 이름과 같아야)
Map으로 조회하기
@RequestParam Map paramMap
파라미터를 Map, MultiValueMap으로 조회할 수 있다. *파라미터 값은 보통 1개를 쓴다.
@RequestParam Map => Map(key=value)
@RequestParam MultiValueMap => MultiValueMap(key=[value1, value2, ...]
@RequestParam 의 옵션
required: 파라미터 필수 여부
@RequestParam(required = true)
디폴트는 true.
즉, 따로 설정 없이 값이 들어오지 않으면 에러 남
주의! 필수 파라미터라도 파라미터 이름만 있고 값이 없는 경우 빈문자("")라고 통과
/request-param?username=
주의! 파라미터가 들어오지 않으면 기본적으로 null이 입력되는데 null이 들어가지 못하는 기본형 타입(ex.int)은 에러가 난다. 필수 파라미터가 아닌 경우, defaultValue를 설정하거나 wrapper class를 사용하자.
defaultValue: 파라미터 기본 값
@RequestParam(required = false, defaultValue = "-1")
defaultValue를 설정하면 이미 기본 값이 있기 때문에 required 는 의미가 없다.
defaultValue 는 빈 문자의 경우에도 설정한 기본 값이 적용된다.
/request-param-default?username=
=> 빈 문자 무시. defaultValue로 초기화
@ModelAttribute
요청 파라미터 -> 객체로 자동 변환
바인딩에 필요한 객체 필요!
롬복의 @Data
: @Getter , @Setter , @ToString , @EqualsAndHashCode , @RequiredArgsConstructor 자동 세팅
작동 과정 by 스프링MVC
1. HelloData 객체를 생성한다.
2. 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다.
3. 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩) 한다.
바인딩 오류
int age=abc 처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException 이 발생한다.
이런 바인딩 오류를 처리하는 방법은 검증 부분에서 다룬다.
@ModelAttribute도 @RequestParam 처럼 생략 가능
스프링은 해당 생략시 다음과 같은 규칙을 적용한다.
String , int , Integer 같은 단순 타입 = @RequestParam
나머지 = @ModelAttribute (argument resolver 로 지정해둔 타입 외)
혼란을 야기할 수 있으니 @RequestParam도 @ModelAttribute도 괜히 생략하지 말자!
HTTP 요청 메세지 - 단순 텍스트
요청 파라미터와 다르게, HTTP 메시지 바디를 통해 데이터가 직접 넘어오는 경우는 @RequestParam , @ModelAttribute 를 사용할 수 없다. (물론 HTML Form 형식으로 전달되는 경우는 요청 파라미터로 인정)
단순 텍스트 조회
서블릿에서는 HTTP 메시지 바디의 데이터를 InputStream 을 사용해서 직접 읽을 수 있었다.
스프링에서도 HttpServletRequest 객체를 파라미터로 받아 똑같이 적용 가능하다.
스프링 MVC는 다음 파라미터를 지원한다.
InputStream(Reader): HTTP 요청 메시지 바디의 내용을 직접 조회
OutputStream(Writer): HTTP 응답 메시지의 바디에 직접 결과 출력
HttpEntity<T>
HTTP header, body 정보를 편리하게 조회할 수 있는 객체
메시지 바디 정보를 직접 조회하고, Http 메세지 컨버터에 의해 문자나 객체로 자동 변환
*요청 파라미터를 조회하는 기능과 관계가 없다. @RequestParam, @ModelAttribute 못 붙임
HttpEntity을 반환 타입으로 지정 가능 => 메세지 바디에 직접 데이터를 내림 (헤더 정보 포함, view 조회X)
HttpEntity 를 상속받은 객체들
RequestEntity: HttpMethod, url 정보가 추가
ResponseEntity: HTTP 상태 코드 설정 가능(HttpStatus)
return new ResponseEntity("Hello World", responseHeaders, HttpStatus.CREATED)
@RequetBody
@RequestBody 를 사용하면 HTTP 메시지 바디 정보를 편리하게 조회할 수 있다.
헤더 정보가 필요하다면 HttpEntity 를 사용하거나 @RequestHeader 를 사용
*메시지 바디를 직접 조회하는 기능은 요청 파라미터를 조회하는 @RequestParam, @ModelAttribute 와는 관련 X
참고: 요청 파라미터 vs HTTP 메시지 바디
요청 파라미터를 조회하는 기능: @RequestParam , @ModelAttribute
HTTP 메시지 바디를 직접 조회하는 기능: @RequestBody
@ResponseBody
@ResponseBody 를 사용하면 응답 결과를 HTTP 메시지 바디에 직접 담아서 전달할 수 있다.
물론 이 경우에도 view를 반환하지 않는다.
ex. return "ok" -> 응답 메세지 바디