@PathVariable
을 사용해서 URL 경로에 있는데이터를 추출
할 수 있다.- 요즘은
Query String
보다 리소스 경로에 식별자를 넣은 스타일을 선호한다.
- /mapping/{userId}
- /users/{userId}
/**
* PathVariable 사용
* 변수명이 같으면 생략 가능
*
* @PathVariable("userId") String userId -> @PathVariable userId
* /mapping/userA
*/
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
log.info("mappingPath userId = {}", data);
return "ok";
}
@PathVariable
은 url 경로가 .../mapping/userA
라고 온다면 userA를 변수로 사용할 수 있게 해주는 애노테이션이다.
@RequestMapping
은 URL 경로를 템플릿화 할 수 있는데, @PathVariable
을 사용하면 매칭 되는 부분을 편리하게 조회할 수 있다.@PathVariable
의 이름과 파라미터 이름이 같으면 생략할 수 있다. @GetMapping("/mapping/users/{userId}/orders/{orderId}")
public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
log.info("mappingPath userId = {}, order={}", userId, orderId);
return "ok";
}
URL 경로가 /mapping/users/{userId}/orders/{orderId}
처럼 다중 변수가 들어올 때도 @PathVariable을 사용할 수 있다.
HTTP 요청 데이터 조회 - 개요
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 Post
로 오며 HTTP request Body에Query String
형식으로 데이터가 담겨온다.- 예) 회원 가입, 상품 주문, HTML Form 사용
HTTP message body
에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용, JSON, XML, TEXT
- 데이터 형식은 주로 JSON 사용
POST
,PUT
,PATCH
Query String
형식의 데이터를 받는 방법은 2가지가 있다.
@RequestParam
: 데이터를 단일 필드에 매핑@ModelAttribute
: 데이터를 객체에 매핑
지금부터 스프링으로 요청 파라미터를 조회하는 방법을 단계적으로 알아보겠다.
@Slf4j
@Controller
public class RequestParamController {
/**
* 변환 타입이 없으면서 이렇게 응답에 값을 직접 집어넣으면, view 조회X
**/
@RequestMapping("/request-param-v1")
public void requestParamV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
response.getWriter().write("ok");
}
}
request.getParameter()
여기서는 단순히 HttpServletRequest
가 제공하는 방식으로 요청 파라미터(request parameter)를 조회했다.
스프링이 제공하는 @RequestParam
을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다.
/**
* @RequestParam 사용
* 파라미터 이름으로 바인딩
* @ResponseBody 추가
* View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
**/
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(
@RequestParam("username") String memberName,
@RequestParam("age") int memberAge) {
log.info("username={}, age={}", memberName, memberAge);
return "ok";
}
@RequestParam
: 파라미터 이름으로 바인딩@ResponseBody
: View 조회
를 무시하고, HTTP message body
에 직접 해당 내용 입력@RequestParam
의 name(value)
속성이 파라미터 이름으로 사용/**
* @RequestParam 사용
* HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam의 name 생략 가능
**/
@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(
@RequestParam String username,
@RequestParam int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
@RequestParam
의 name과 파라미터 이름이 같다면 생략 가능하다.
@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(String username, int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
String
, int
, Integer
등의 단순 타입이면 @RequestParam
도 생략 가능
지금까지 요청 파라미터 조회를 1단계부터 4단계까지 살펴보았다. 4단계가 가장 간결해보이지만 @RequestParam
까지 완전히 생략하는 것은 과하다는 주장도 있다. 나 또한 애노테이션이 있는 것이 직관적이고 명확하다고 생각해서 3단계
를 사용하는 것을 권장
한다. 이는 뒤에서 설명할 ModelAttribute
와도 연관이 있다.
required
/**
* @RequestParam.required
* /request-param-required -> username이 없으므로 예외
*
* 주의!
* /request-param-required?username= -> 빈문자로 통과
*
* 주의!
* /request-param-required
* int age -> null을 int에 입력하는 것은 불가능, 따라서 Integer 변경해야 함(또는 다음에 나오는 defaultValue 사용) */
@ResponseBody
@RequestMapping("/request-param-required")
public String requestParamRequired(
@RequestParam(required = true) String username,
@RequestParam(required = false) Integer age) {
log.info("username={}, age={}", username, age);
return "ok";
}
@RequestParam.required
default
/**
* @RequestParam
* - defaultValue 사용
*
* 참고: defaultValue는 빈 문자의 경우에도 적용
* /request-param-default?username=
*/
@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(
@RequestParam(defaultValue = "guest") String username,
@RequestParam(defaultValue = "-1") int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
파라미터에 값이 없는 경우 defaultValue
를 사용하면 기본 값
을 적용할 수 있다. 이미 기본 값이 있기 때문에 위에서 소개한 required
는 사용 의미가 없다.
defalutValue
는 빈 문자의 경우에도 설정한 기본 값이 적용된다.
/url?username="hello"&age="20"
로그와, /url?username="hello"&age=
로그의 차이점을 출력을 통해 보여주겠다.
출력
위의 로그는/url?username="hello"&age="20"
이고, 아래 로그는/url?username="hello"&age=
이다. 아래 로그를 보면 빈 문자로 설정한age
의 값이default
값인 -1인 것을 알 수 있다.
우선 @ModelAttribute
를 설명하기에 앞서 요청 파라미터를 받아서 필요한 객체를 만들고, 그 객체에 값을 넣어주어야 하기에 다음과 같은 코드르 작성하겠다.
import lombok.Data;
@Data /*@Getter, @Setter, @ToString,
@EqualsAndHashCode, @RequiredArgsConstructor를 자동 저장*/
public class HelloData{
private String username;
private int age;
}
우선 들어가기에 앞서 @ModelAttribute
적용 전과 후의 차이를 보여주기 위해서 @ModelAttribute
적용 전 코드를 보여주겠다.
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelX(
@RequestParam String username, @RequestParam int age) {
HelloData helloData = new HelloData();
helloData.setUsername(username);
helloData.setAge(age);
log.info("username={}, age={}",
helloData.getUsername(), helloData.getAge());
return "ok";
}
/**
* @ModelAttribute 사용
* model.addAttribute(helloData) 코드도 함께 자동 적용
**/
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
log.info("username={}, age={}",
helloData.getUsername();
helloData.getAge());
return "ok";
}
@ModelAttribute
을 적용하니 마법처럼 HelloData
객체가 생성되고, 요청 파라미터의 값도 모두 들어가 있다.
Spring MVC는 @ModelAttribute가 있으면 다음을 실행한다.
1.HelloData
객체를 생성한다.
2. 요청 파라미터의 이름으로HelloData
객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의setter
를 호출해서 파라미터의 값을 입력한다.
- 예) 파라미터 이름이
username
이면setUsername()
메서드를 찾아서 호출하면서 값을 입력한다.
/**
* @ModelAttribute 생략 가능
* String, int 같은 단순 타입 = @RequestParam
* argument resolver 로 지정해둔 타입 외 = @ModelAttribute
*/
@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV2(HelloData helloData) {
log.info("username={}, age={}"
helloData.getUsername();
helloData.getAge());
return "ok";
}
@ModelAttribute
는 생략할 수 있다.
그런데 @RequestParam
도 생략이 가능하다. 어떻게 구분할 수 있을까?
스프링은 @ModelAttribute
, @RequestParam
생략시 다음과 같은 규칙을 적용한다.
String
, int
, Inter
같은 단순 타입 = @RequestParam
적용출처
김영한님의 Spring MVC 강의
https://velog.io/@neity16/6-%EC%8A%A4%ED%94%84%EB%A7%81-MVC-10-HTTP-request-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A1%B0%ED%9A%8C-PathVariable-RequestParam-HttpEntity-%EB%93%B1