여기서는 단순히 HttpServletRequest가 제공하는 방식으로 요청 파라미터를 조회했다.
5. HTTP 요청 파라미터 - @RequestParam
스프링이 제공하는 @RequestParam 을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다.
requestParamV2
@RequestParam : 파라미터 이름으로 바인딩
@ResponseBody : View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
@RequestParam의 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 age
null 을 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 로 지정해둔 타입 외)
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(
@RequestParam("username") String memberName,
@RequestParam("age") int memberAge) {
log.info("username={}, age={}", memberName, memberAge);
return "ok";
}
@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(
@RequestParam String username,
@RequestParam int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(String username, int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
java.lang.IllegalArgumentException: Name for argument of type [java.lang.String]
not specified, and parameter name information not found in class file either.
//애노테이션에 username이라는 이름이 명확하게 있다. 문제 없이 작동한다.
@RequestMapping("/request")
public String request(@RequestParam("username") String username) {
...
}
//애노테이션에 이름이 없다. -parameters 옵션 필요
@RequestMapping("/request")
public String request(@RequestParam String username) {
...
}
//애노테이션도 없고 이름도 없다. -parameters 옵션 필요
@RequestMapping("/request")
public String request(String username) {
...
}
//애노테이션에 userId라는 이름이 명확하게 있다. 문제 없이 작동한다.
public String mappingPath(@PathVariable("userId") String userId) {
...
}
//애노테이션에 이름이 없다. -parameters 옵션 필요
public String mappingPath(@PathVariable String userId) {
...
}