지난 포스팅에서 GET, POST 방식의 경우,
요청 데이터를 HttpServletRequest 객체의 getParameter 메소드로 가져온다고 말했다.
@RequestMapping("/request-param-v1") // HttpServlet 사용하기
public void requestParamV1(HttpServletRequest request, HttpServletResponse response) throws IOException{
String username = request.getParameter("username"); //getParameter
int age = Integer.parseInt(request.getParameter("age")); //getParameter
log.info("username = {}, age={}",username,age);
response.getWriter().write("OK");
}
위 코드와 같이, GET방식, POST방식으로 들어온 요청데이터는 HttpServletRequest가 제공하는 getParameter 메소드로 쉽게 가져올 수 있다. 그러나 Conroller가 직접 Request 객체와 연관되는 것은 좋지 못하다. Controller는 비즈니스 로직을 담당하는 클래스로 비즈니스 관련 데이터와 연관되어야 응집력이 높아진다.
그래서 SpringMVC는 프론트 컨트롤러 패턴을 적용하여, 모든 Request가 DispatcherServlet을 거치도록 구현해놓았다. DispatcherServlet은 HandlerAdapter에게 Handler(Controller) 실행권한을 위임했다. Handler, 즉 Controller는 파라미터로 필요한 데이터를 HandlerAdapter에게 요구하고 HandlerAdapter는 Request 객체에서 추출하여 요구에 맞는 데이터를 파라미터에 주입한다.
Controller가 원하는 데이터를 파라미터로 요구할 때, 어노테이션이 사용되는데,
대표적으로 @RequestParam이 있다.
@RequestParam
@RequestMapping("/request-param")
public String requestParam(@RequestParam("username") String memberName,
@RequestParam("age") int memberAge){
// [ 비즈니스 로직 ]
return "OK";
}
@RequestParam의 의미는 다음과 같다. HttpServletRequest에서 getParameter의 결과를 파라미터로 전달해달라는 의미이다.
예를들어,
@RequestParam("username") String memberName 을 보자.
위 파라미터의 의미는 현재 들어온 Request 객체의 getParameter("username") 반환값을 파라미터로 전달해달라는 의미다.
@RequestParam 생략1
@RequestMapping("/request-param")
public String requestParam(@RequestParam String username,
@RequestParam int age){
// [ 비즈니스 로직 ]
return "OK";
}
만약 getParameter 메소드로 넘기고 싶은 key값과 파라미터명이 같다면 @RequestParam에 key값을 설정하지 않아도 된다. key값이 설정되지 않으면 디폴트로 파라미터명이 key값으로 설정된다.
@RequestParam 생략2
@RequestMapping("/request-param")
public String requestParam(String username, int age){
// [ 비즈니스 로직 ]
return "OK";
}
@RequestParam 을 아예 생략해도 된다. String, int, Integer 같은 단순타입은 자동으로 @RequestParam가 선언되어, Request 객체에서 데이터를 가져오도록 요청한다. 그러나 명확한 표현이 직관적이고 좋으니 @RequestParam을 굳이 생략하지 않아도 된다.
required 속성
Controller가 파라미터로 데이터를 요구했지만, HandlerAdapter가 데이터를 찾지 못하면 NULL 값을 전달한다. 파라미터로 NULL이 들어오면 int같은 primitive 타입은 500 에러를 발생시킨다. 그러므로 Null 발생할 수 있는 위험이 있는 경우, Primitive 타입을 사용하면 안된다. Integer, Double 같은 데이터 타입을 사용해야 한다.
@RequestParam은 파라미터로 Null이 들어오는 상황을 제어할 수 있는 속성을 제공하는데, 그것이 required이다.
@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";
}
required가 true이면 파라미터로 Null이 들어올 때 400에러를 발생시킨다. false이면 에러를 발생시키지 않고 Null값을 그대로 받는다. required 속성은 디폴트로 true가 설정되어 있으니 참고 바란다.
defaultValue 속성
파라미터로 Null값이 들어오면 디폴트값을 설정하여 대처할 수도 있다.
@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를 설정하면 int와 같은 Primitive 타입도 사용 가능해진다. 그러므로 Null값이 들어 왔을 때, required 속성이 디폴트로 true여도 defaultValue에 설정된 값이 있기에 400 에러가 발생하지 않는다.
Map, MultiValueMap
지금까지는 요청데이터를 하나씩 요구했다면 이번에는 요청데이터 전체를 받아볼 것이다.
@RequestMapping("/request-param-map")
public String requestParamMap( @RequestParam Map<String,Object> paramMap ){
log.info("username = {}, age={}", paramMap.get("username"),paramMap.get("age") );
return "OK";
}
@RequestParam 으로 표시된 파라미터가 자료형이 Map이나 MultiValueMap이면 요청데이터 전체를 Map구조로 받을 수 있다. MultiValueMap 타입은 동일한 key에 여러가지 value를 저장할 수 있는 Map으로, key1=value1&key1=value2 와 같이 &연산자로 동일한 key에 여러 value를 받는 HTTP key-value 구조에 적합한 자료구조이다. 그런데 실무환경에서 동일한 key에 여러 value를 저장하는 구조는 잘 사용하지 않는다.
참고자료
'SPRING > Spring MVC' 카테고리의 다른 글
[SpringMVC] HTTP 요청 메시지 - TEXT, JSON (0) | 2023.08.12 |
---|---|
[SpringMVC] HTTP 요청 파라미터 - @ModelAttribute (0) | 2023.08.11 |
[SpringMVC] HTTP 요청 파라미터 - @RequestHeader (0) | 2023.08.11 |
[SpringMVC] @RequestMapping의 다양한 속성 (0) | 2023.08.10 |
[SpringMVC] @RequestMapping, @Controller (0) | 2023.08.10 |