Spring MVC ๊ธฐ๋ณธ๊ธฐ๋ฅ- HTTP ์์ฒญ [ ์์ฒญํ๋ผ๋ฏธํฐ, ์์ฒญ๋ฉ์์ง]
๐ฌ ํด๋ผ์ด์ธํธ์์ ์๋ฒ๋ก ์์ฒญ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๋๋ ์ฃผ๋ก 3๊ฐ์ง ๋ฐฉ๋ฒ์ ์ด์ฉํ๋ค.
โพ GET - ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ
- /?username=hello&age=20 ์ด๋ฐ ์์ผ๋ก ์ฌ์ฉํ๋ค.
- ๋ฉ์์ง ๋ฐ๋ ์์ด, url์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ์ ๋ฐ์ดํฐ๋ฅผ ํฌํจํด์ ์ ๋ฌํ๋ค.
- ๊ฒ์, ํํฐ, ํ์ด์ง์์ ๋ง์ด ์ฌ์ฉ
โพ POST - HTML Form
- content-type : application/x-www-form-urlencoded ํ์
- ๋ฉ์์ง ๋ฐ๋์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ ํ์์ผ๋ก ์ ๋ฌ (username=hello&age=20)
- ํ์๊ฐ์ , ์ํ์ฃผ๋ฌธ์์ ๋ง์ด ์ฌ์ฉ
โพ HTTP message body์ ๋ฐ์ดํฐ๋ฅผ ์ง์ ๋ด์์ ์์ฒญ
- HTTP API์์ ์ฃผ๋ก ์ฌ์ฉ (JSON, XML, TEXT)
- ๋ฐ์ดํฐ ํ์์ ์ฃผ๋ก JSON์ฌ์ฉ
- POST, PUT, PATCH
๐ GET๋ฐฉ์๊ณผ HTML Form๋ฐฉ์์ HttpServletRequest์ request.getParameter()์ฌ์ฉํ๋ฉด ์์ฒญ ํ๋ผ๋ฏธํฐ ์กฐํ ๊ฐ๋ฅ
[ ์์ฒญ ํ๋ผ๋ฏธํฐ ]
โผ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ์ฝ๋
@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"));
log.info("username={}, age={}", username, age);
response.getWriter().write("ok");
}
@RequestMapping์ ์์ ์๋ url๊ณผ ๋ง๋๋ค๋ฉด ๋ฐ์ ์๋ ์ฝ๋๊ฐ ์คํ๋๋ค.
GET๋ฐฉ์๊ณผ HTML Form ๋ฐฉ์์ getParameter()๋ก ์กฐํ๊ฐ ๊ฐ๋ฅํ๋ค.
response.getWriter().writer()๋ ํ์ด์ง์ ์ถ๋ ฅํ ๋ฌธ์๋ฅผ ์ธ ์ ์๋ค.
โ POST๋ฐฉ์์ผ๋ก ํ๋ ค๋ฉด 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>
์ด๊ณณ์ ์ ๋ณด๋ฅผ ์์ฑํ๋ฉด /request-param-v1์ผ๋ก ์ด๋ํด์ ์ ๋ณด๋ฅผ ์ฒ๋ฆฌํ๋ค.
โผ getParameter() ๋์ ์ ๋ ธํ ์ด์ ์ผ๋ก ๋์ฒดํ๊ธฐ
@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";
}
์๋ string์ ํ์ด์ง์ ์ถ๋ ฅ๋๊ฒ ํ๋ ค๋ฉด response.getWriter().write()๋ฅผ ์ฌ์ฉํ์๋๋ฐ,
@ResponseBody ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ๊ทธ๋ฅ ๋ฌธ์์ด๋ง ๋ฐํํด๋ ๋ฌธ์์ด์ด ์ถ๋ ฅ๋๋ค.
โ ์ ๋ ธํ ์ด์ ๋ ์๋ต ๊ฐ๋ฅ ( ๋จ, ์์ฒญ ํ๋ผ๋ฏธํฐ ํ์์ด๋ ๋ง์์ผ ๋๋ค. )
@ResponseBody
@RequestMapping("/request-param-v4")
public String RequestParamV4(String username, int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
โผ required ์ถ๊ฐ
๋งคํ ์ ๋ณด๊ฐ ์ฌ๋ฌ ๊ฐ์ฌ๋ ๊ผญ ํ์ํ ์ ๋ณด์ ๊ผญ ํ์ํ์ง ์์ ์ ๋ณด๊ฐ ์กด์ฌํ๋ค.
๊ทธ๋ด ๋๋ required๋ฅผ ์ถ๊ฐํด์ ํ์ํ ๊ฒ์ธ์ง ๊ผญ ํ์ํ์ง ์์ ๊ฒ์ธ์ง ๊ตฌ๋ณํ ์ ์๋ค.
true๋ ๊ผญ ํ์ํ ์์, false๋ ์์ด๋ ๋๋ ์์์ด๋ค.
@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";
}
์ด ์ฝ๋๋ฅผ ์ดํด๋ณด์๋ฉด username์ ๊ผญ ์์ด์ผ ํ๋ ํ๋ผ๋ฏธํฐ์ด๊ณ , age๋ ์ ๋ ฅํ์ง ์์๋ ๋๋ ํ๋ผ๋ฏธํฐ์ด๋ค.
* int๋ ๋ํดํธ ๊ฐ์ด null์ด ์๋๊ธฐ ๋๋ฌธ์ Integer๋ก ํ ๋ณํํด์ค๋ค.
โ ์ ๋ ธํ ์ด์ ์ ์๋ตํด๋ ๋๋๋ฐ ์ ๋ ธํ ์ด์ ์ ์๋ตํ๋ฉด ๋ํดํธ ๊ฐ์ required=false๋ฅผ ์ ์ฉํ๋ค.
localhost:8080/request-param-required?username=hello๋ก ๊ฒ์ํ๋ฉด.
์ฝ์์ ์ด๋ ๊ฒ ์ถ๋ ฅ๋๋ค.
โ null๊ฐ์ ๋ณ์ ๋ํดํธ ๊ฐ์ด ์๋๋ผ ๋ด๊ฐ ๋ํดํธ ๊ฐ์ ์ค์ ํ๊ณ ์ถ๋ค๋ฉด dafaultValue๊ฐ์ ์ง์ ํ๋ฉด ๋๋ค.
@RequestParam(required = true, defaultValue = "guest") String username;
@RequestParam(required = false, defaultValue = "-1") int age;
์ด๋ ๊ฒ ๋ฐ๊พธ๋ฉด ๋๋ค.
โผ Map ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
@ResponseBody
@RequestMapping("/request-param-map")
public String RequestParamMap(@RequestParam Map<String, Object> paramMap) {
log.info("username={}, age={}", paramMap.get("username"), paramMap.get("age"));
return "ok";
}
Map์ผ๋ก ๊ฐ๋จํ๊ฒ ๋ฌถ์ ์๋ ์๋ค.
์ด๋ ๊ฒ ๋๋ฉด Map์ ์๋ username์ด๋ age๋ฅผ ๊ฐ์ ธ์์ ์ถ๋ ฅํ๋ค.
required๋ ์ด๋ฏธ ์ค์ ์ด ๋์ด์์ด์ ๊ฐ์ ์ ์ง ์์ ๊ฒฝ์ฐ์๋ null๋ก ์ ๋ ฅ๋๋ค.
โ ํ๋ผ๋ฏธํฐ ๊ฐ์ด 1๊ฐ๊ฐ ํ์คํ๋ค๋ฉด Map์ ์ฌ์ฉํด๋ ๋๋๋ฐ ๊ทธ๋ ์ง ์๋ค๋ฉด MultiValueMap์ ์ฌ์ฉํ๋ ํธ์ด ์ข๋ค.
ํ์ง๋ง ํ๋ผ๋ฏธํฐ ๊ฐ์ด ์ฌ๋ฌ ๊ฐ์ผ ๊ฒฝ์ฐ๋ ๋ณ๋ก ์๋ค ( ๊ฐ์ key๊ฐ์ value๊ฐ ์ฌ๋ฌ ๊ฐ์ธ ๊ฒฝ์ฐ)
โผ ModelAttribute์ฌ์ฉ
์ค์ ๊ฐ๋ฐ์์๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์์ ๊ฐ์ฒด์ ๊ฐ์ ๋ฃ์ด์ฃผ๋๋ฐ, ์ด ๊ณผ์ ์ ModelAttribute๊ฐ ๋์ ํด์ค๋ค.
๋จผ์ ํด๋์ค๋ฅผ ํ๋ ๋ง๋ค์ด๋ณด์.
@Data
public class HelloData {
private String username;
private int age;
}
์ฌ๊ธฐ์์ @Data๋ lombok ์ ๋ ธํ ์ด์ ์ธ๋ฐ, @Getter, @Setter, @EqualsAndHashCode, @RequiredArgsConstructor๋ฅผ ์๋์ผ๋ก ์ ์ฉํด์ค๋ค.
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
์ด๋ ๊ฒ @ModelAttribute๋ฅผ ์ฌ์ฉํ๋ฉด ์๋์ผ๋ก ๊ฐ์ฒด์ ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ฅผ ์ฃผ์ ์์ผ์ฃผ๊ธฐ ๋๋ฌธ์ ํธํ๋ค.
โญ @ModelAttribute๋ ์๋ต ๊ฐ๋ฅํ๋ค.
[ ์์ฒญ ๋ฉ์์ง - TEXT ]
์์ฒญ ํ๋ผ๋ฏธํฐ์๋ ๋ค๋ฅด๊ฒ HTTP ๋ฉ์์ง ๋ฐ๋๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ์ง์ ๋์ด์ค๋ ๊ฒฝ์ฐ๋ @RequestParam, @ModelAttribute๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
๋์ InputStream์ ์ฌ์ฉํด์ ์ฝ์ ์ ์๋ค.
InputStream์ HTTP ์์ฒญ ๋ฉ์์ง ๋ฐ๋์ ๋ด์ฉ์ ์ง์ ์กฐํํ๋ค.
โผ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ
@PostMapping ("/request-body-string-v1")
public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
response.getWriter().write("ok");
}
โญ steam์ ๋ฐ์ดํธ ์ฝ๋์ฌ์ ํญ์ ์ด๋ค ์ธ์ฝ๋ฉ์ผ๋ก ํด์ ๋ฐ๊ฟ ๊ฑด์ง ์ง์ ํด์ค์ผ ๋๋ค.
ํฌ์คํธ๋งจ์ ์ฌ์ฉํด์ ๋ฉ์์ง ๋ฐ๋์ ์ ๋ณด๋ฅผ ๋ด์๋ณด์!
์ ์ฝ๋๋ฅผ ์ถ๋ ฅํด๋ณด๋ฉด ์ฝ์์ ์ด๋ ๊ฒ ๋์จ๋ค.
โผ InputStream ๋ฏธ๋ฆฌ ์ ์ธํ๊ธฐ
@PostMapping("/request-body-string-v2")
public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException {
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
responseWriter.write("ok");
}
โผ HttpEntity ์ฌ์ฉ
HttpEntity๋ฅผ ์ฌ์ฉํ๋ฉด HTTP header, body ์ ๋ณด๋ฅผ ํธ๋ฆฌํ๊ฒ ์กฐํํ ์ ์๋ค.
@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) throws IOException {
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new HttpEntity<>("ok");
}
HttpEntity<String>์ผ๋ก ํ๋ฉด ๋ฌธ์์ธ ๊ฒ์ ํ์ธํ๊ณ , http body์ ์๋ ๊ฑธ ๋ฌธ์๋ก ๋๊ฒจ์ค๋ค๋ ๋ป์ด๋ค.
http ๋ฉ์์ง ์ปจ๋ฒํฐ๊ฐ ๋์ํ๋ค.
โผ RequestBody ์ฌ์ฉ
@RequestBody๋ฅผ ์ฌ์ฉํ๋ฉด HTTP ๋ฉ์์ง ๋ฐ๋์ ์ ๋ณด๋ฅผ ํธ๋ฆฌํ๊ฒ ์กฐํํ ์ ์๋ค.
๋ง์ฝ ํค๋ ๋ด์ฉ์ด ํ์ํ๋ค๋ฉด ์์์ ์ฌ์ฉํ HttpEntity( or @RequestHeader)๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4(@RequestBody String messageBody) throws IOException {
log.info("messageBody={}", messageBody);
return "ok";
}
[ ์์ฒญ ๋ฉ์์ง - JSON ]
{"username":"hello", "age":20} ์ด ๋ฐฉ๋ฒ์ด JSON ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ ๊ฒ์ด๋ค.
private ObjectMapper objectMapper = new ObjectMapper();
objectMapper()๋ฅผ ์ฌ์ฉํ๊ธฐ ์์์ private๋ฅผ ๋จผ์ ์ ์ธํด์ค๋ค.
โผ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ
@PostMapping("/request-body-json-v1")
public void requestBodyJsonV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
response.getWriter().write("ok");
}
๐ POSTMAN์ผ๋ก ์คํํ ๊ฒฐ๊ณผ
์ฝ์ ์ฐฝ์๋ ์ด๋ ๊ฒ ์ถ๋ ฅ๋๋ค.
โผ RequestBody ์ฌ์ฉ
@ResponseBody
@PostMapping("/request-body-json-v2")
public String requestBodyJsonV2(@RequestBody String messageBody) throws IOException {
log.info("messageBody={}", messageBody);
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
text์ ์ฌ์ฉํ๋ @RequestBody๋ฅผ ์ฌ์ฉํ ์๋ ์๋ค.
โ @RequestBody์ ์ง์ ๋ง๋ ๊ฐ์ฒด๋ฅผ ์ง์ ํ ์๋ ์๋ค. ๊ทธ๋ผ ๊ฐ์ฒด๋ฅผ ์์์ ๋ฐ๋ก ์ ์ธํ์ง ์์๋ ๋จ
@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData data){
log.info("username={}, age={}", data.getUsername(), data.getAge());
return "ok";
}
โญ @RequestBody๋ ์๋ตํ๋ฉด ์ ๋ ์ ๋๋ค!!!
โ ๊ฐ์ฒด๋ฅผ ๋ฐํํด๋ ๋๋ค.
@ResponseBody
@PostMapping("/request-body-json-v5")
public HelloData requestBodyJsonV5(@RequestBody HelloData data){
log.info("username={}, age={}", data.getUsername(), data.getAge());
return data;
}
์ด๋ ๊ฒ ๋ฐํ๋ ๊ฐ์ฒด์ ์ ๋ณด๊ฐ ํ์ด์ง์ ์ถ๋ ฅ๋๋ค.
โผ HttpEntity ์ฌ์ฉ
์์์ ์ฌ์ฉํ๋ HttpEntity๋ฅผ ์ฌ์ฉํด๋ ๋๋ค.
@ResponseBody
@PostMapping("/request-body-json-v4")
public String requestBodyJsonV4(HttpEntity<HelloData> httpEntity){
HelloData data = httpEntity.getBody();
log.info("username={}, age={}", data.getUsername(), data.getAge());
return "ok";
}
์คํ๋ง mvc๋ฅผ ์ฌ์ฉํ๋ฉด์ ์คํ๋ง์ด ์ ๊ณตํด์ฃผ๋ ๊ธฐ๋ฅ๋ค์ ์ฌ์ฉํ๋ฉด์ ์ฝ๋์ ๊ธธ์ด๋ฅผ ์ค์ฌ๋๊ฐ๋๊น ์ ์คํ๋ง์ ์ฌ์ฉํ๋์ง ๋ ํ ๋ฒ ๋๊ผ๋ค... ์คํ๋ ค ๋๋ฌด ๋ง์ ๋ฐฉ๋ฒ์ด ์์ด์ ํท๊ฐ๋ฆด ์ง๊ฒฝ์ด๋คใ ใ ใ ใ ใ ๋ ์งง์ ๊ฒ ์ข์!
์ด ํฌ์คํ ์ ์ธํ๋ฐ ๊น์ํ๋์ [์คํ๋งMVC 1ํธ - ๋ฐฑ์๋ ์น๊ฐ๋ฐ ํต์ฌ ๊ธฐ์ ]์ ๋ฃ๊ณ ์์ฑ๋ ๋ณต์ต ๊ฒธ ์ ๋ฆฌ ํฌ์คํ ์ ๋๋ค.