[Spring MVC] URL 매핑, 데이터 전송/조회
- [ Backend ]/Spring Web
- 2022. 2. 19.
@RequestMapping("uri")
uri에 들어간 url 호출이 오면 애노테이션이 표시된 메소드가 실행되도록 매핑해준다.
RequestMapping에 method속성으로 HTTP메서드(GET, POST, PUT...)를 지정하지 않으면 HTTP메서드와 무관하게 모두 호출되므로, 적절한 사용을 위해서는 method속성을 명시해주자
@RequestMapping(method = RequestMethod.GET)
다음과 같이 메서드를 지정해주면 GET방식의 요청만 받아들이게 되고, POST등의 다른 요청이 오면 MVC는 HTTP 405 상태코드를 반환한다 (Method Not Allowed)
또 @GetMapping 애노테이션 코드를 보면 안에 @RequestMapping 애노테이션의 method가 설정되어있기 때문에 다음과 같이 치환할 수도 있다.
@GetMapping
경로 변수 (PathVariable) 사용 - @PathVariable
@RequestMapping같은 경우 url경로를 템플릿화 할 수 있는데, @PathVariable을 사용하면 매칭되는 부분을 편리하게 조회할 수 있다.
@GetMapping("/mapping/users/{userId}/orders/{orderId}")
public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
log.info("mappingPath userId={}, orderId={}", userId, orderId);
return "ok";
}
위와 같이 url경로에 템플릿을 이용해서 GET방식으로 리소스를 받고, @PathVariable 애노테이션을 통해서 받은 리소스를 활용할 수 있다.
+ 경로 변수를 사용하여 매핑받을 때, 경로 변수 자리에 고정 uri값이 있다면 고정 uri값이 우선시되어 매핑된다.
@GetMapping("/mapping/users")
public String methodA() {...}
@GetMapping("/mapping/{userId}")
public String methodB(@PathVariable("userId") String data) {...}
methodB함수만 존재한다면 "/mapping/users"로 url경로가 들어오면 userId에 users가 매핑되어 methodB의 로직이 실행될 것이다. 하지만 methodA가 존재하면 동일한 users로 매핑되어 methodA가 실행된다.
데이터 전송
클라이언트에서 서버로 요청 데이터를 보낼 때는 주로 다음 3가지 방법을 사용한다.
1. GET방식 쿼리 파라미터 전송
2. POST방식 HTML Form 전송
3. HTTP Message Body에 데이터를 직접 받아서 요청
1. GET방식 쿼리 파라미터 전송
localhost:8080?username=userA&age=20
HTTP 메세지 바디 없이 URL의 쿼리 파라미터에 데이터를 포함하여 전달하는 방식이다. 검색, 필터, 페이징에서 많이 사용되는 방식이다.
2. POST방식 HTML Form전송
{
username=userA&age=20
}
HTML form태그를 이용해서 메세지 바디에 쿼리 파라미터 형식으로 전달한다. 회원 가입이나 상품 주문시와 같은 상황에 많이 사용된다.
3. HTTP message body에 데이터를 직접 요청
POST, PUT, PATCH등의 방식으로 HTTP의 body부분에 데이터를 직접 담아서 요청하는 방식이다. 2번방식과는 다르게 쿼리 파라미터 방식이 아닌 JSON, xml, text/html등의 다양한 방법으로 직접 전달한다.
데이터 조회 (client 요청 바인딩)
ㆍHttpServletRequest
@RequestMapping("url")
public void requestParamHttpServlet(HttpServletRequest request, HttpServletResponse response) throws IOException {
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
response.getWriter().write("ok");
}
HttpServletRequest를 이용하여 파라미터로 들어오는 요청에서 username과 age 파라미터를 조회했다.
ㆍ@RequestParam(name = "")
@ResponseBody //view조회가 아닌 body에 String 입력 (@RestController와 같은 역할을 한다)
@RequestMapping("url")
public String requestParamSpring(
@RequestParam("username") String memberName,
@RequestParam("age") int memberAge) {
Member member = new Member();
member.setName(memberName);
member.setAge(memberAge);
return "ok";
}
요청 파라미터에서 @RequestParam 어노테이션이 선언된 객체에 1대1로 값을 받아와 저장한다. setter나 getter등을 이용하여 저장하는 과정을 생략하려면 뒤에 나오는 @ModelAttribute를 사용해주면 된다.
ㆍ Spring을 이용하면 @RequestParam 어노테이션을 매개변수에 표기해주는 방법을 이용해서 파라미터 이름으로 바인딩하여 조회할 수 있다. 변수 이름을 파라미터 이름과 같게 설정해주면 애노테이션에 붙는 이름을 생략 가능하다.
(@RequestParam String username, @RequestParam int age)
ㆍ@RequestParam(required = true)
파라미터가 반드시 입력되어야 하는지 여부를 설정 가능하다. (기본값이 true이다)
required값이 false로 되어있으면 파라미터를 선택적으로 받아들인다(없어도 오류가 발생하지 않는다). 다만 주의해야 할 점은 파라미터값이 들어오지 않으면 null을 저장하는데, primitive type의 경우 null을 저장할 수 없기 때문에 Wrapper클래스(Integer와 같은)로 선언해주어야 한다.
ㆍ@RequestParam(defaultValue = "A")
파라미터의 값이 들어오지 않는 경우 설정한 기본값으로 값을 세팅한다. 이미 기본값이 있기 때문에 required옵션은 무시된다.
ㆍ@RequestBody
클라이언트가 전송하는 Json형태의 HTTP Body를 자바객체로 변환할 수 있다.
ㆍ@ModelAttribute
@ResponseBody
@RequestMapping("url")
public String modelAttribute(@ModelAttribute Data data) {
log.info("username={}, age={}", data.getUsername(), data.getAge());
return "ok";
}
@ModelAttribute 애노테이션을 이용하면 뷰에서 객체를 직접 전달받아서 사용 가능하다. @ModelAttribute 선언후 자동으로 진행되는 작업은 다음과 같다.
1. 파라미터로 넘겨 준 타입의 객체를 자동으로 생성한다.
2. 요청 파라미터의 이름으로 생성된 오브젝트 HTTP로 넘어온 값들을 setter를 이용하여 객체에 바인딩(입력)한다(자동으로 model.addAttribute()가 실행된다). 이때 반드시 해당 객체에는 setter가 존재해야 한다. 객체에 setter가 존재하지 않으면 값을 입력받지 못해서 null이나 0같은 기본값이 저장된다.
3. 매핑 파라미터 타입이 객체의 타입과 일치하는지 여부를 검증한다.
그 이후 객체를 조회하면 데이터를 객체 단위로 데이터를 전달받아서 사용할 수 있다.
(@ModelAttribute와 @RequestParam 모두 변수명이 일치하거나, 동일하게 사용할 경우 생략할 수 있는데, primitive 타입은 @RequestParam, 객체 타입들은 @ModelAttribute가 자동으로 적용된다.) 하지만 명시해주는게 좋을듯하다
데이터 조회 - 추가
요청 파라미터(쿼리 스트링, x-www-form-urlencoded)와 다르게, HTTP 메세지 바디를 통해 데이터를 직접 전송할 경우 @RequestParam이나 @ModelAttribute의 사용이 불가능하다.
ㆍHttpServletRequest
먼저 요청 파라미터와 유사하게 HttpServletRequest의 InputStream를 이용하여 직접 조회할 수 있다. InputStream을 이용하면 HTTP요청 메세지 바디의 내용을 직접 조회할 수 있다.
@PostMapping("url")
public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
response.getWriter().write("ok")
}
ㆍHttpEntity<>
@PostMapping("url")
public HttpEntity<String> requestBodyString(HttpEntity<String> httpEntity) throws IOException {
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new HttpEntity<>("ok");
}
HttpEntity<>객체를 통해서 http요청 header와 body의 내용을 편리하게 조회하고, http응답에도 직접 사용할 수 있다. 이 객체를 사용하면 스프링mvc 내부에서 http 메세지 바디를 읽어서 문자로 변환해서 전달해준다.
ㆍ@RequestBody
@ResponseBody
@PostMapping("url")
public String requestBodyString(@RequestBody String messageBody) {
log.info("messageBody={}", messageBody);
return "ok";
}
@ResponseBody와 @RequestBody를 이용하면 위와 비슷하지만 HttpEntity<>를 직접 사용하지 않고 편리하게 조회, 전송할 수 있다.
ㆍJSON 조회
http메세지 바디를 통해서 json형식의 메세지를 직접 조회할 수 있다. ObjectMapper를 통해서 문자열 형식으로 Body message를 가져온 이후 readValue함수로 객체형식으로 변환하는 방법도 있지만, spring을 이용하면 자동으로 객체형태로 변환시켜서 가져올 수도 있다.
@ResponseBody
@PostMapping("url")
public String requestBodyJson(@RequestBody HelloData helloData) throws IOException {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
@RequestBody를 선언해주면 http 메세지 컨버터가 body의 내용을 우리가 명시한 객체로 자동 변환해준다. http메세지 컨버터는 문자뿐 아니라 json도 객체로 반환해주기 때문에 이 경우 별도의 처리 없이 편리하게 사용할 수 있다.
주의할 점은 여기서 @RequestBody를 생략할 경우, http바디가 아니라 @RequestParam이나 @ModelAttribute를 적용시켜서 요청 파라미터를 처리하므로 생략하지 말자.
===========================================================================
정리
- 요청 파라미터 조회 : @RequestParam, @ModelAttribute
- http 메세지 바디 직접 조회 : @RequestBody
'[ Backend ] > Spring Web' 카테고리의 다른 글
[Spring MVC] 검증 - BindingResult, @InitBinder (0) | 2022.07.08 |
---|---|
[Spring MVC] 메세지, 국제화 (0) | 2022.07.08 |
[Spring MVC] 서블릿과 스프링, 프론트 컨트롤러 (0) | 2022.02.09 |
[Spring MVC] 웹 서버, WAS, 서블릿 (0) | 2022.02.08 |
[Spring MVC] @~Mapping 사용시 참고 (0) | 2022.02.04 |