지난 포스팅에 이어, 이번 포스팅에서는 5) ~ 10)
까지의 내용을 정리한다.
👉 목차는 다음과 같다.
1) 프로젝트 생성
2) 로깅 간단히 알아보기
3) 요청 매핑
4) 요청 매핑 - API 예시
5) HTTP 요청 - 기본, 헤더 조회
6) HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form
7) HTTP 요청 파라미터 - @RequestParam
8) HTTP 요청 파라미터 - @ModelAttribute
9) HTTP 요청 메시지 - 단순 텍스트
10) HTTP 요청 메시지 - JSON
11) 응답 - 정적 리소스, 뷰 템플릿
12) HTTP 응답 - HTTP API, 메시지 바디에 직접 입력
13) HTTP 메시지 컨버터
14) 요청 매핑 헨들러 어뎁터 구조
15) 정리
지난 포스팅을 통해서 매핑 방법을 이해했으니, 이제부터 HTTP 요청이 보내는 데이터들을 스프링 MVC로 어떻게 조회하는지 알아보자.
이전에 서블릿 강의에서 HTTP 요청 메시지 헤더 정보등을 어떻게 조회하는지 알아보았었다. (서블릿이 여러 기능을 제공해줬었다.)
이번에는 스프링 MVC가 그것들을 더 편리하게 조회할 수 있는 여러가지 기능들을 제공한다. 따라서 그 중에서 먼저 기본, 헤더 조회에 대해서 알아볼 것이다.
👉 애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다. 이번 내용에서는 HTTP 헤더 정보를 조회하는 방법을 알아보자.
RequestHeaderController
: src > main > java > hello > springmvc > basic > request 패키지를 생성하고, 내부에 RequestHeaderController 클래스를 생성하자. (생성 후 postman으로 실행해보자.)HttpMethod
: HTTP 메서드를 조회한다. ( org.springframework.http.HttpMethod
)Locale
: (가장 우선 순위가 높은) Locale 정보를 조회한다.@RequestHeader MultiValueMap<String, String> headerMap
: 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.@RequestHeader("host") String host
required
defaultValue
@CookieValue(value = "myCookie", required = false) String cookie
required
defaultValue
✔️ 참고
keyA=value1&keyA=value2
)log
라고 사용하면 된다.private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RequestHeaderController.class);
@Conroller
의 사용 가능한 파라미터 목록은 다음 공식 메뉴얼에서 확인할 수 있다.@Conroller
의 사용 가능한 응답 값 목록은 다음 공식 메뉴얼에서 확인할 수 있다.다음에는 본격적으로 요청 파라미터를 어떻게 받는지 알아보자.
서블릿에서 학습했던 HTTP 요청 데이터를 조회하는 방법을 다시 떠올려보자.
그리고 서블릿으로 학습했던 내용을 스프링이 얼마나 깔끔하고 효율적으로 바꾸어주는지 알아보자.
HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법을 알아보자.
클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 다음 3가지 방법을 사용한다.
👉 하나씩 알아보자.
요청 파라미터 - 쿼리 파라미터, HTML Form
HttpServletRequest의 request.getParameter()를 사용하면 다음 두가지 요청 파라미터를 조회할 수 있다.
http://localhost:8080/request-param?username=hello&age=20
GET 쿼리 파리미터 전송 방식이든, POST HTML Form 전송 방식이든 둘다 형식이 같으므로 구분없이 조회할 수 있다. 이것을 간단히 요청 파라미터(request parameter) 조회라 한다.
지금부터 스프링으로 요청 파라미터를 조회하는 방법을 단계적으로 알아보자.
RequestParamController
: src > main > java > hello > springmvc > basic > request 패키지 내부에 RequestParamController 클래스를 생성하자.
Post Form 페이지 생성
먼저 테스트용 HTML Form을 만들어야 한다.
리소스는 /resources/static
아래에 두면 스프링 부트가 자동으로 인식한다. (/resources/static
은 외부에 공개되는 경로이다.)
webapp
경로를 사용할 수 없다. 이제부터 정적 리소스도 클래스 경로에 함께 포함해야 한다.스프링이 제공하는 @RequestParam
을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다.
👉 코드로 확인해보자.
requestParamV2
: 좀 전에 생성한 RequestParamController 클래스에 다음 코드를 추가하자.@RequestParam
: 파라미터 이름으로 바인딩.name(value)
속성이 파라미터 이름으로 사용@ResponseBody
: View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력.requestParamV3
: RequestParamController 클래스에 다음 코드를 적용해보자.@RequestParam(name="xx")
생략 가능requestParamV4
: RequestParamController 클래스에 다음 코드를 적용해보자.String
, int
, Integer
등의 단순 타입이면 @RequestParam
도 생략 가능.@RequestParam
애노테이션을 생략하면 스프링 MVC는 내부에서 required=false
를 적용한다. required
옵션은 바로 다음에 설명한다.@RequestParam
이 있으면 명확하게 요청 파리미터에서 데이터를 읽는다는 것을 알 수 있다.)
파라미터 필수 여부 - requestParamRequired
requestParamRequired
: RequestParamController 클래스에 다음 코드를 적용해보자.@RequestParam.required
/request-param
으로 요청username
이 없으므로 400 예외가 발생한다./request-param?username=
: 파라미터 이름만 있고 값이 없는 경우, 빈문자로 통과 (null이 아니고 빈 문자열임.)/request-param
요청null
을 int
에 입력하는 것은 불가능(500 예외 발생)null
을 받을 수 있는 Integer
로 변경하거나, 또는 다음에 나오는 defaultValue
사용
기본 값 적용 - requestParamDefault
requestParamDefault
: RequestParamController 클래스에 다음 코드를 적용해보자.defaultValue
를 사용하면 기본 값을 적용할 수 있다. 이미 기본 값이 있기 때문에 required
는 의미가 없다.defaultValue
는 빈 문자의 경우에도 설정한 기본 값이 적용된다. ( ex. /request-param-default?username=
)
파라미터를 Map으로 조회하기 - requestParamMap
requestParamMap
: RequestParamController 클래스에 다음 코드를 적용해보자.@RequestParam Map
Map(key=value)
@RequestParam MultiValueMap
MultiValueMap(key=[value1, value2, ...]
ex) (key=userIds, value=[id1, id2])Map
을 사용해도 되지만, 그렇지 않다면 MultiValueMap
을 사용하자.실제 개발을 하면 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어주어야 한다.
보통 다음과 같이 코드를 작성할 것이다.
@RequestParam String username;
@RequestParam String int age;
HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);
스프링은 이 과정을 완전히 자동화해주는 @ModelAttribute 기능을 제공한다.
👉 코드로 확인해보자. (먼저 요청 파라미터를 바인딩 받을 객체를 만들고, @ModelAttribute를 적용해보자.)
HelloData
: src > main > java > hello > springmvc > basic 패키지 내부에 HelloData 클래스를 생성하자.@Data
= @Getter
, @Setter
, @ToString
, @EqualsAndHashCode
, @RequiredArgsConstructor
를 자동으로 적용해준다.modelAttributeV1
: RequestParamController 클래스 내부에 아래 코드를 적용해보자.HelloData
객체가 생성되고, 요청 파라미터의 값도 모두 들어가 있다.HelloData
객체를 생성한다.HelloData
객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter
를 호출해서 파라미터의 값을 입력(바인딩) 한다.getUsername()
, setUsername()
메서드가 있으면, 이 객체는 username
이라는 이름의 프로퍼티를 가지고 있다고 말한다. username 프로퍼티의 값을 변경하면 setUsername()
이 호출되고, 조회하면 getUsername()
이 호출된다. class HelloData {
getUsername();
setUsername();
}
age=abc
처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException
이 발생한다. 이런 바인딩 오류를 처리하는 방법은 검증 부분에서 다룬다.modelAttributeV2
: RequestParamController 클래스 내부에 아래 코드를 적용해보자.@ModelAttribute
는 생략할 수 있다. 그런데 @RequestParam
도 생략할 수 있으니 혼란이 발생할 수 있다.@ModelAttribute
생략시 다음과 같은 규칙을 적용한다.String
, int
, Integer
같은 단순 타입인 경우 = @RequestParam
적용@ModelAttribute
적용 (argument resolver 로 지정해둔 타입 외)지금까지 우리는 클라이언트에서 서버로 요청 데이터를 전달할 때 사용하는 아래 3가지 방법 중, 요청 파라미터(①, ②)를 조회하는 것에 대해서 알아보았다.
다음부터는 ③ HTTP message body에 데이터가 직접 넘어오는 경우에 대해서 알아보자.
이전에 서블릿에서 학습한 내용을 떠올려보자.
HTTP message body에 데이터를 직접 담아서 요청하는 경우
요청 파라미터와 다르게, HTTP 메시지 바디를 통해 데이터가 직접 넘어오는 경우는 @RequestParam
, @ModelAttribute
를 사용할 수 없다. (물론 HTML Form 형식으로 전달되는 경우는 요청 파라미터로 인정된다.)
👉 먼저 가장 단순한 텍스트 메시지를 HTTP 메시지 바디에 담아서 전송하고, 읽어보자.
( HTTP 메시지 바디의 데이터를 InputStream
을 사용해서 직접 읽을 수 있다. )
RequestBodyStringController
: src > main > java > hello > springmvc > basic > request 패키지 내부에 RequestBodyStringController 클래스를 생성하자. (생성 후 Postman으로 실행해보자.)👉 좀 더 개선해보자.
RequestBodyStringController - requestBodyStringV2
: 클래스 내 아래 코드를 추가해보자. (추가 후 Postman을 사용해서 테스트 해보자.)👉 이렇게 Stream으로 받고 하는것도 그닥 효율적이진 않아보인다. 좀 더 개선해보자.
RequestBodyStringController - requestBodyStringV3
: 클래스 내 아래 코드를 추가해보자. (추가 후 Postman을 사용해서 테스트 해보자.)@RequestParam(X)
, @ModelAttribute(X)
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED)
RequestBodyStringController - requestBodyStringV4
: 클래스 내 아래 코드를 추가해보자. (추가 후 Postman을 사용해서 테스트 해보자.)@RequestBody
@RequestBody
를 사용하면 HTTP 메시지 바디 정보를 편리하게 조회할 수 있다.HttpEntity
를 사용하거나 @RequestHeader
를 사용하면 된다.@RequestParam
, @ModelAttribute
와는 전혀 관계가 없다. (HttpMessageConverter라는 매커니즘이 동작한다.)요청 파라미터 조회 vs HTTP 메시지 바디 조회
@RequestParam
, @ModelAttribute
@RequestBody
@ResponseBody
@ResponseBody
를 사용하면 응답 결과를 HTTP 메시지 바디에 직접 담아서 전달할 수 있다.✔️ 참고
이번에는 HTTP API에서 주로 사용하는 JSON 데이터 형식을 조회해보자.
기존 서블릿에서 사용했던 방식과 비슷하게 시작해보자.
RequestBodyJsonController
: src > main > java > hello > springmvc > basic > request 패키지 아래 RequestBodyJsonController 클래스를 생성하자. (생성 후 Postman을 사용해서 테스트 해보자.)objectMapper
를 사용해서 자바 객체로 변환한다.RequestBodyJsonController - requestBodyJsonV2 (@RequestBody 문자 변환)
: RequestBodyJsonController 클래스에 아래 코드를 추가해보자.@RequestBody
를 사용해서 HTTP 메시지에서 데이터를 꺼내고 messageBody에 저장한다.objectMapper
를 통해서 자바 객체로 변환한다.🤔 문자로 변환하고 다시 json으로 변환하는 과정이 불편하다. @ModelAttribute처럼 한번에 객체로 변환할 수는 없을까?
RequestBodyJsonController - requestBodyJsonV3 (@RequestBody 객체 변환)
: RequestBodyJsonController 클래스 내 아래 코드를 추가해보자.@RequestBody 객체 파라미터
(ex. @RequestBody HelloData data
)@RequestBody
에 직접 만든 객체를 지정할 수 있다.HttpEntity
, @RequestBody
를 사용하면 HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 우리가 원하는 문자나 객체 등으로 변환해준다. HTTP 메시지 컨버터는 문자 뿐만 아니라 JSON도 객체로 변환해주는데, 우리가 방금 V2에서 했던 작업을 대신 처리해준다. 자세한 내용은 뒤에 HTTP 메시지 컨버터에서 다룬다.@ModelAttribute
에서 학습한 내용을 떠올려보자. 스프링은 @ModelAttribute
, @RequestParam
과 같은 해당 애노테이션을 생략시 다음과 같은 규칙을 적용한다.String
, int
, Integer
같은 단순 타입 = @RequestParam
@ModelAttribute
(argument resolver 로 지정해둔 타입 외)👉 물론 앞서 배운 것과 같이 HttpEntity를 사용해도 된다.
RequestBodyJsonController - requestBodyJsonV4
: RequestBodyJsonController 클래스 내 아래 코드를 추가해보자.👉 응답의 경우에도 @ResponseBody 를 사용하면 해당 객체를 HTTP 메시지 바디에 직접 넣어줄 수 있다.
RequestBodyJsonController - requestBodyJsonV5
: RequestBodyJsonController 클래스 내 아래 코드를 추가해보자.@ResponseBody
@ResponseBody
를 사용하면 해당 객체를 HTTP 메시지 바디에 직접 넣어줄 수 있다.HttpEntity
를 사용해도 된다.✔️ 정리
@RequestBody
요청@ResponseBody
응답강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 김영한 강사님께 있습니다.