📖 개요
클라이언트에서 서버로 요청 데이터를 전달하는 경우는 크게 3가지가 있다.
- GET - 쿼리 파라미터 (ex: ~~/url?username=yeonLog)
- POST - html form 태그
- HTTP 메시지 바디에 데이터 직접 담기 (ex: json, xml, text, ...)
위 3가지 방법을 통해 요청 데이터를 실제로 조회해보자.
📕 1. GET - 쿼리 파라미터
url 뒤에 파라미터를 직접 넣어주는 방식
RequestParamController.java
@Slf4j
@Controller
public class RequestParamController {
@RequestMapping("/request-param-v1")
public void requestParamV1(HttpServletRequest req, HttpServletResponse res) throws IOException {
String name = req.getParameter("username");
Integer age = Integer.parseInt(req.getParameter("age"));
log.info("username={}, age={}",name, age);
res.getWriter().write("ok");
}
}
/request-param-v1 경로로 접근하며 username과 age 파라미터를 보내주면
( ex: http://localhost:8080/request-param?username=yeonLog&age=20 )
request와 response를 받아 변수에 저장하고 "ok"를 반환한다.
📒 2. POST - html form 태그
html의 form 태그를 이용해 POST 요청을 보내는 방식
(물론 form 태그를 이용하지 않아도 POST요청은 다양한 방식으로 받을 수 있다.)
java 코드는 위 내용을 재사용하면 되며 form 태그를 사용하기 위해 html 파일을 하나 생성한다.
hello-form.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/request-param-v1" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
</body>
</html>
위 html 파일에 접근해서 데이터를 입력한 뒤, 전송 버튼을 눌러주면 requestParamV1 메소드가 실행된다.
실행을 확인했다면 이제 requestParamV1 메소드를 발전시켜 보자.
🍃 @RequestParam 이용하기
Spring이 제공하는 @RequestParam을 이용해 요청 파라미터를 더욱 쉽게 가져오자.
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(@RequestParam("username") String name,
@RequestParam("age") int age) {
log.info("username={}, age={}",name, age);
return "ok";
}
- @ResponseBody: HTTP message body에 "ok"를 직접 입력. view를 찾지 않음.
- @RequestParam: 파라미터 이름으로 바인딩
- 파라미터 명과 변수명을 동일한 경우 ' @RequestParam int age ' 식으로 요약 가능
🔻 @RequestParam의 추가 기능
@RequestParam은 (required = true) 와 같이 추가적으로 설정할 수 있다.
아래 예제 코드를 보자.
@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(
@RequestParam(required = true, defaultVale="guest") String username,
@RequestParam int age) {
log.info("username={}, age={}",username, age);
return "ok";
}
- required: 필수 값 여부
- defaultValue: 기본 값 설정
위와 같이 String, int 뿐만 아니라 Map을 이용할 수도 있다.
모든 파라미터를 알고있지 않아도 쉽게 받아올 수 있다.
(Map 뿐만 아니라 MultiValueMap도 사용 가능)
@ResponseBody
@RequestMapping("/request-param-map")
public String requestParamMap(@RequestParam Map<String, Object> map) {
log.info("username={}, age={}",map.get("username"), map.get("age"));
return "ok";
}
🍃 @ModelAttribute 이용하기
username과 age 필드를 가진 HelloData 객체가 존재한다고 가정하자.
여태까지의 방식으로는 @RequestParam을 통해 username, age 파라미터를 받아오고,
HelloData 객체를 생성한 후, 받아온 파라미터들을 저장해야 한다. (아래 코드 참고)
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@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를 이용한다면 알아서 매핑해주기 때문에 위와 같은 과정을 생략할 수 있다.
@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV2(@ModelAttribute HelloData helloData) {
log.info("username={}, age={}",helloData.getUsername(), helloData.getAge());
return "ok";
}
추가로, @RequestParam이나 @ModelAttribute를 생략하고 바로 int age, HelloData helloData 식으로 데이터를 받아도 파라미터를 무사히 받아와지는 것을 확인할 수 있다.
Spring이 자동으로 적용을 시켜주기 때문이다.
(하지만 너무 많은 코드를 생략할 경우 혼란이 올 수 있으니 쓰는 것을 권장한다.)
📘 3. HTTP 메시지 바디에 데이터 직접 담기
HTTP 메시지 바디에 담는 데이터는 TEXT, JSON, XML 다양한 종류가 있다.
메시지 바디를 직접 조회하는 것으로, 파라미터랑 다른 개념이라는 것을 분명히 인지해야 한다.
먼저 TEXT를 담는 것부터 살펴보자.
🍃 HttpServletRequest, HttpServletResponse 이용하기
가장 기초적인 방법이다.
HttpServlet에서 InputStream을 가져온다.
@PostMapping("/request-body-string-v1")
public void requestBodyStringV1 (HttpServletRequest req, HttpServletResponse res) throws IOException {
ServletInputStream inputStream = req.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("msgBody = {}", messageBody);
res.getWriter().write("ok");
}
🍃 InputStream 이용하기
위에서는 HttpServlet을 가져온 후 InputStream 변수에 값을 넣었지만, 아래와 같이 InputStream을 직접 받아올 수 있다.
@PostMapping("/request-body-string-v2")
public void requestBodyStringV2 (InputStream inputStream, Writer resWriter) throws IOException {
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("msgBody = {}", messageBody);
resWriter.write("ok");
}
🍃 HttpEntity 이용하기
StreamUtils를 이용해 InputStream을 가져올 필요 없이 HttpEntity를 이용할 수 있다.
HttpEntity는 응답에서 사용하는 경우, 헤더 정보를 포함할 수 있고 view를 조회하지 않는다.
ResponseEntity를 이용해 상태코드를 직접 지정할 수도 있다.
@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3 (HttpEntity<String> httpEntity) throws IOException {
String messageBody = httpEntity.getBody();
log.info("msgBody = {}", messageBody);
return new HttpEntity<>("ok");
//return new ResponseEntity<>("ok", HttpStatus.CREATED); // 상태코드 지정 가능
}
🔻 ResponseEntity란?
ResponseEntity는 HttpEntity를 상속받은 객체이다.
응답에서 사용하며, HTTP 상태 코드를 설정할 수 있다.
🍃 @RequestBody 이용하기
가장 편리한 @RequestBody 어노테이션을 이용하는 방법도 있다.
헤더 정보가 필요하다면 @RequestHeader 또는 HttpEntity를 이용하면 된다.
추가로 @ResponseBody를 이용하면 return "ok"에서 "ok"라는 이름의 뷰를 찾는 것이 아니라, "ok"라는 문자열을 응답하게 된다.
( =HTTP 메시지 바디에 직접 텍스트를 담는다. )
@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4 (@RequestBody String messageBody) throws IOException {
log.info("msgBody = {}", messageBody);
return "ok"; // @ResponseBody 활용
}
다음은 JSON을 이용하는 방식을 살펴보자.
기본적으로 JSON을 받는 방식도 TEXT와 유사한 방식으로 얻을 수 있다.
다만 추가적으로 객체에 자동적으로 매핑해주는 기능을 사용할 수 있다.
🍃 @RequestBody 이용하기
기본적으로 json을 받으면 객체(HelloData)를 생성한 뒤, Jackson과 같은 mapper를 이용해 json을 객체로 변환시켜준다.
아래와 같은 경우, {"username":"hello", "age":20}라는 json을 messageBody에 저장하고,
mapper를 거쳐 HelloData의 username과 age 필드에 매핑된다.
@ResponseBody
@PostMapping("/request-body-json-v2")
public String requestBodyJsonV2 (@RequestBody String messageBody) throws IOException {
log.info("msgBody = {}", messageBody);
HelloData helloData = mapper.readValue(messageBody, HelloData.class);
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
하지만 Spring은 위 과정을 생략하고 바로 json을 객체로 반환시켜줄 수 있다.
뿐만 아니라 객체를 반환시키면 자동으로 json으로 변환시켜주는 기능도 있다.
@ResponseBody
@PostMapping("/request-body-json-v5")
public HelloData requestBodyJsonV5 (@RequestBody HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return helloData; // 자동으로 json으로 바뀌어서 return
}
추가로 @RequestBody를 사용할 때 주의해야하는 점이 있다.
@RequestParam이나 @ModelAttribute와는 달리 생략이 불가능하다는 것!!!
해당 어노테이션을 생략하면 기본적으로 @RequestParam이나 @ModelAttribute가 적용되므로, @RequestBody를 이용하고 싶다면 어노테이션을 꼭 적어주자.
다음 글에서는 HTTP 응답에 관해 공부해보겠다.
본 게시글은 김영한 님의 '스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술' 강의를 구매 후 정리하기 위한 포스팅입니다.
내용을 임의로 추가, 수정, 삭제한 부분이 많으며 정확한 이해를 위해서 강의를 구매하시는 것을 추천 드립니다.
'Develop > Spring+JPA' 카테고리의 다른 글
[Spring] HTTP 메시지 컨버터 (0) | 2021.10.10 |
---|---|
[Spring] HTTP 응답 (0) | 2021.08.11 |
[Spring] 헤더 조회 (0) | 2021.07.14 |
[Spring] 요청 매핑 (0) | 2021.06.25 |
[스프링 MVC] @Controller, @RequestMapping (0) | 2021.05.27 |