스프링 MVC - 기본 기능1
1. 요청 매핑
MappingController
package hello.springmvc.basic.requestmapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
@RestController
public class MappingController {
private Logger log = LoggerFactory.getLogger(getClass());
/**
* 기본 요청
* 둘다 허용 /hello-basic, /hello-basic/
* HTTP 메서드 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
*/
@RequestMapping("/hello-basic")
public String helloBasic() {
log.info("helloBasic");
return "ok";
}
}매핑 정보
@RestController@Controller는 반환 값이String이면 뷰 이름으로 인식된다. 그래서 뷰를 찾고 뷰가 랜더링 된다.@RestController는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다. 따라서실행 결과로 ok 메세지를 받을 수 있다.
@ResponseBody와 관련이 있는데, 뒤에서 더 자세히 설명한다.
@RequestMapping("/hello-basic")/hello-basicURL 호출이 오면 이 메서드가 실행되도록 매핑한다.대부분의 속성을
배열[]로 제공하므로 다중 설정이 가능하다.{"/hello-basic", "/hello-go"}
HTTP 메서드
@RequestMapping 에 method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출된다.
모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
HTTP 메서드 매핑
HTTP 메서드 매핑 축약
PathVariable(경로 변수) 사용
최근 HTTP API 는 다음과 같이 리소스 경로에 식별자를 넣는 스타일을 선호한다.
/mapping/userA/users/1@PathVariable의 이름과 파라미터 이름이 같으면 생략할 수 있다.
특정 파라미터 조건 매핑
특정 헤더 조건 매핑
미디어 타입 조건 매핑 - HTTP 요청 Content-Type, consume
미디어 타입 조건 매핑 - HTTP 요청 Accept, produce
2. 요청 매핑 - API 예시
회원 관리를 HTTP API 로 만든다 생각하고 매핑을 어떻게 하는지 알아보자.
회원 관리 API
회원 목록 조회: GET
/users회원 등록: POST
/users회원 조회: GET
/users/{userId}회원 수정: PATCH
/users/{userId}회원 삭제: DELETE
/users/{userId}
MappingClassController
다른 예제와 HTTP API 경로가 겹칠 수 있기에 앞에 /mapping 을 붙였다.
매핑 방법을 이해했으니, 이제부터 HTTP 요청을 보내는 데이터들을 스프링 MVC 로 어떻게 조회하는지 알아보자.
3. HTTP 요청 - 기본, 헤더 조회
애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다.
RequestHeaderController
HttpServletRequestHttpServletResponseHttpMethod: HTTP 메서드를 조회한다.org.springframework.http.HttpMethodLocale: Locale 정보를 조회한다.@RequestHeader MultiValueMap<String, String> headerMap모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.
@RequestHeader("host") String host특정 HTTP 헤더를 조회한다.
속성
필수 값 여부:
required기본 값 속성:
defaultValue
@CookieValue(value = "myCookie", required = false) String cookie특정 쿠키를 조회한다.
속성
필수 값 여부:
required기본 값:
defaultValue
MultiValueMap
MAP과 유사한데, 하나의 키에 여러 값을 받을 수 있다.
HTTP header, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용한다.
keyA=value1&keyA=value2
4. 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
요청 파라미터 - 쿼리 파라미터, HTML Form
HttpServletRequest 의 request.getParameter() 를 사용하면 다음 두가지 요청 파라미터를 조회할 수 있다.
GET 쿼리 파리미터 전송 방식이든, POST HTML Form 전송 방식이든 둘다 형식이 같으므로 구분없이 조회할 수 있다.
이것을 간단히 요청 파라미터(request parameter) 조회라 한다.
GET, 쿼리 파라미터 전송
예시
http://localhost:8080/request-param?username=hello&age=20
POST, HTML Form 전송
예시
RequestParamController
request.getParamter()
여기서는 단순히 HttpServletRequest가 제공하는 방식으로 요청 파라미터를 조회했다.
5. HTTP 요청 파라미터 - @RequestParam
스프링이 제공하는 @RequestParam 을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다.
requestParamV2
@RequestParam: 파라미터 이름으로 바인딩@ResponseBody: View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
@RequestParam의 name(value) 속성이 파라미터 이름으로 사용
name(value) 속성이 파라미터 이름으로 사용@RequestParam("username") String memberName=>
request.getParameter("username")
requestParamV3
HTTP 파라미터 이름이 변수 이름과 같으면
@RequestParam(name="xx")생략 가능
requestParamV4
String,int,Integer등의 단순 타입이면@RequestParam도 생략 가능
참고이렇게 애노테이션을 완전히 생략해도 되는데, 너무 없는 것도 약간 과하다는 주관적 생각이 있다.
@RequestParam이 있으면 명확하게 요청 파리미터에서 데이터를 읽는 다는 것을 알 수 있다.
주의 - 스프링 부터 3.2 파라미터 이름 인식 문제다음 예외가 발생하면 해당 내용을 참고하자.
주로 다음 두 애노테이션에서 문제가 발생한다.
@RequestParam,@PathVariable
@RequestParam 관련
@PathVariable 관련(이후에 학습한다)
해결 방안1 (권장)애노테이션에 이름을 생략하지 않고 다음과 같이 이름을 항상 적어준다. 이 방법을 권장한다.
@RequestParam("username") String username
@PathVariable("userId") String userId
해결 방안 2,3
pass ...
문제 원인참고로 이 문제는 Build, Execution, Deployment -> Build Tools -> Gradle에서 Build and run using를 IntelliJ IDEA로 선택한 경우에만 발생한다. Gradle로 선택한 경우에는 Gradle이 컴파일 시점에 해당 옵션을 자동으로 적용해준다.
자바를 컴파일할 때 매개변수 이름을 읽을 수 있도록 남겨두어야 사용할 수 있다. 컴파일 시점에
-parameters옵션을 사용하면 매개변수 이름을 사용할 수 있게 남겨둔다.스프링 부트 3.2 전까지는 바이트코드를 파싱해서 매개변수 이름을 추론하려고 시도했다. 하지만 스프링 부트 3.2 부터는 이런 시도를 하지 않는다.
파라미터 필수 여부 - requestParamRequired
주의 - 파라미터 이름만 사용
/request-param-required?username=
파라미터 이름만 있고 값이 없는 경우 빈문자로 통과
주의 - 기본형(primitive) 에 null 입력
/request-param
@RequestParam(required = false) int agenull을int에 입력하는 것은 불가능(500 예외 발생)따라서
null을 받을 수 있는Integer로 변경하거나, 또는 다음에 나오는defaultValue사용
기본 값 적용 - requestParamDefault
파라미터에 값이 없는 경우
defaultValue를 사용하면 기본 값을 적용할 수 있다.이미 기본 값이 있기 때문에
required는 의미가 없다.defaultValue는 빈 문자의 경우에도 설정한 기본 값이 적용된다./request-param-default?username=
파라미터를 Map 으로 조회하기 - requestParamMap
6. HTTP 요청 파라미터 - @ModelAttribute
실제 개발을 하다 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어주어야 한다. 보통 다음과 같이 코드를 작성할 것이다.
스프링은 이 과정을 완전히 자동화해주는 @ModelAttribute 기능을 제공한다.
먼저 요청 파라미터를 바인딩 받을 객체를 만들자.
HelloData
@ModelAttribute 적용 - modelAttributeV1
마치 마법처럼 HelloData 객체가 생성되고, 요청 파라미터의 값도 모두 들어가 있다.
스프링MVC는 @ModelAttribute 가 있으면 다음을 실행한다.
HelloData객체를 생성한다.요청 파라미터의 이름으로
HelloData객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩) 한다.예) 파라미터 이름이
username이면setUsername()메서드를 찾아서 호출하면서 값을 입력한다.
바인딩 오류
age=abc 처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException 이 발생한다. 이런 바인딩 오류를 처리하는 방법은 검증 부분에서 다룬다.
@ModelAttribute 생략 - modelAttributeV2
@ModelAttribute 는 생략할 수 있다.
그런데 @RequestParam 도 생략할 수 있으니 혼란이 발생할 수 있다.
스프링은 파라미터 애노테이션 생략시 다음과 같은 규칙을 적용한다.
String,int,Integer같은 단순 타입 =@RequestParam나머지 =
@ModelAttribute(argument resolver 로 지정해둔 타입 외)
Last updated