๐ Spring MVC
Spring์์ ์ง์ํ๋ ๋ชจ๋ ๊ธฐ๋ฅ์ ํฌํจํด์ Spring Framework ๋ผ๊ณ ํ๋ค.
Spring์ ๋ชจ๋ ์ค์์๋ ์น ๊ณ์ธต์ ๋ด๋นํ๋ ๋ช ๊ฐ์ง ๋ชจ๋์ด ์๋๋ฐ, ๊ทธ ์ค์์ ์๋ธ๋ฆฟ(Servlet) API๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋ชจ๋์ด ์๋ค. ์ฐ๋ฆฌ๋ ์ด๊ฒ์ spring-webmvc ๋ผ๊ณ ํ๋ค. ์ด๋ Spring Web MVC, Spring MVC, Spring MVC ํ๋ ์์ํฌ๋ผ๊ณ ๋ถ๋ฆฌ๊ณ ์๋ค.
๊ฐ๋จํ ์ ๋ฆฌํ๋ฉด Spring MVC ๋ ๋ค์๊ณผ ๊ฐ๋ค.
โ๏ธ Spring MVC ํด๋ผ์ด์ธํธ ์์ฒญ์ ํธ๋ฆฌํ๊ฒ ์ฒ๋ฆฌํด์ฃผ๋ ํ๋ ์์ํฌ์ด๋ค.
โ๏ธ ์ฐ๋ฆฌ๊ฐ ๋ง๋ค๊ฒ ๋ ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ Spring MVC๊ฐ ์ ๊ณตํด์ฃผ๋ ๊ธฐ๋ฅ์ ์ด์ฉํด์ ๋ง๋ ๋ค.
์๋ธ๋ฆฟ(Servlet)์ด๋?
- ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋๋ก ํน์ ๊ท์ฝ์ ๋ง์ถฐ Java ์ฝ๋๋ก ์์ฑํ๋ ํด๋์ค ํ์ผ์ด๋ค.
- ์ํ์น ํฐ์บฃ (Apache Tomcat)์ ์๋ธ๋ฆฟ๋ค์ด ์น ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์คํ์ด ๋๋๋ก ํด์ฃผ๋ ์๋ธ๋ฆฟ ์ปจํ ์ด๋ (Servlet Container) ์ค ํ๋์ด๋ค.
Model
Model์ Spring MVC์์ M์ ํด๋นํ๋ค.
Spring MVC ๊ธฐ๋ฐ์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ด ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ ๋ฌ ๋ฐ์ผ๋ฉด ์์ฒญ ์ฌํญ์ ์ฒ๋ฆฌํ๊ธฐ ์ํ ์์ ์ ํ๋ค.
์ด๋ ๊ฒ ์ฒ๋ฆฌํ ์์ ์ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต์ผ๋ก ๋๋ ค์ค์ผ ํ๋๋ฐ, ์ด ๋ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต์ผ๋ก ๋๋ ค์ฃผ๋ ์์ ์ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ Model์ด๋ผ๊ณ ํ๋ค.
ํด๋ผ์ด์ธํธ์์ ์์ฒญ ์ฌํญ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ์์ญ์ ์๋น์ค ๊ณ์ธต(Service Layer)์ด๋ผ๊ณ ํ๋ฉฐ,
์ค์ ๋ก ์์ฒญ ์ฌํญ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด Java ์ฝ๋๋ก ๊ตฌํํ ๊ฒ์ ๋น์ฆ๋์ค ๋ก์ง(Business Logic) ์ด๋ผ ํ๋ค.
View
Model์ Spring MVC์์ V์ ํด๋นํ๋ค.
View๋ Model ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํด ์น ๋ธ๋ผ์ฐ์ ๊ฐ์ ํด๋ผ์ด์ธํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋ฉด์ ๋ณด์ด๋ ๋ฆฌ์์ค(Resource)๋ฅผ ์ ๊ณตํ๋ ์ญํ ์ ํ๋ค.
Spring MVC ์๋ ๋ค์ํ View ๊ธฐ์ ์ด ํฌํจ๋์ด ์๋๋ฐ View์ ํํ๋ ๋ค์๊ณผ ๊ฐ์ด ๋๋ ์ ์๋ค.
- HTML ํ์ด์ง์ ์ถ๋ ฅ
- PDF, Excel ๋ฑ์ ๋ฌธ์ ํํ๋ก ์ถ๋ ฅ
- XML, JSON(JavaScript Object Natation) ๋ฑ ํน์ ํ์์ ํฌ๋งท์ผ๋ก์ ๋ณํ
Controller
Model์ Spring MVC์์ C์ ํด๋นํ๋ค.
Controller๋ ํด๋ผ์ด์ธํธ ์ธก์ ์์ฒญ์ ์ง์ ์ ์ผ๋ก ์ ๋ฌ๋ฐ๋ ์๋ํฌ์ธํธ(Endpoint)๋ก์จ Model ๊ณผ View ์ ์ค๊ฐ์์ ์ํธ ์์ฉ์ ํด์ฃผ๋ ์ญํ ์ ํ๋ค.
ํด๋ผ์ด์ธํธ ์ธก์ ์์ฒญ์ ์ ๋ฌ ๋ฐ์์ ๋น์ฆ๋์ค ๋ก์ง์ ๊ฑฐ์น ํ Model ๋ฐ์ดํฐ๊ฐ ๋ง๋ค์ด์ง๋ฉด, ์ด Model ๋ฐ์ดํฐ๋ฅผ View๋ก ์ ๋ฌํ๋ ์ญํ ์ ํ๋ค.
Spring MVC ๋์ ๋ฐฉ์๊ณผ ๊ตฌ์ฑ ์์
(1) ๋จผ์ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ์ ์กํ๋ฉด DispatcherServlet์ด๋ผ๋ ํด๋์ค์ ์์ฒญ์ด ์ ๋ฌ๋๋ค.
(2) DispatcherServlet์ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ Controller์ ๋ํ ๊ฒ์์ HandlerMapping ์ธํฐํ์ด์ค์๊ฒ ์์ฒญํ๋ค.
(3) HandlerMapping์ ํด๋ผ์ด์ธํธ ์์ฒญ๊ณผ ๋งคํ๋๋ ํธ๋ค๋ฌ ๊ฐ์ฒด๋ฅผ ๋ค์ DispatcherServlet์๊ฒ ๋ฆฌํดํด์ค๋ค.
ํธ๋ค๋ฌ ๊ฐ์ฒด๋ ํด๋น ํธ๋ค๋ฌ์ Handler ๋ฉ์๋ ์ ๋ณด๋ฅผ ํฌํจํ๊ณ ์๋ค.
Handler ๋ฉ์๋๋ Controller ํด๋์ค ์์ ๊ตฌํ๋ ์์ฒญ ์ฒ๋ฆฌ ๋ฉ์๋๋ฅผ ์๋ฏธํ๋ค.
(4) ์์ฒญ์ ์ฒ๋ฆฌํ Controller ํด๋์ค๋ฅผ ์ฐพ์์ผ๋ ์ด์ ๋ ์ค์ ๋ก ํด๋ผ์ด์ธํธ ์์ฒญ์ ์ฒ๋ฆฌํ Handler ๋ฉ์๋๋ฅผ ์ฐพ์์ ํธ์ถํด์ผ ํฉ๋๋ค. DispatcherServlet์ Handler ๋ฉ์๋๋ฅผ ์ง์ ํธ์ถํ์ง ์๊ณ , HandlerAdpater์๊ฒ Handler ๋ฉ์๋ ํธ์ถ์ ์์ํ๋ค.
(5) HandlerAdapter๋ DispatcherServlet์ผ๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ Controller ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํด๋น Controller์ Handler ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
์ด์ ์ ์ฒด ์ฒ๋ฆฌ ํ๋ฆ์ ๋ฐํ์ ์ ๋์๋ค. ์ด์ ๋ถํฐ๋ ๋ฐ๋๋ก ๋๋์๊ฐ๋ณด์.
(6) Controller์ Handler ๋ฉ์๋๋ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ ํ ๋ฆฌํด ๋ฐ์ Model ๋ฐ์ดํฐ๋ฅผ HandlerAdapter์๊ฒ ์ ๋ฌํ๋ค.
(7) HandlerAdapter๋ ์ ๋ฌ๋ฐ์ Model ๋ฐ์ดํฐ์ View ์ ๋ณด๋ฅผ ๋ค์ DispatcherServlet์๊ฒ ์ ๋ฌํ๋ค.
(8) DispatcherServlet์ ์ ๋ฌ๋ฐ์ View ์ ๋ณด๋ฅผ ๋ค์ ViewResolver์๊ฒ ์ ๋ฌํด์ View ๊ฒ์์ ์์ฒญํ๋ค.
(9) ViewResolver๋ View ์ ๋ณด์ ํด๋นํ๋ View๋ฅผ ์ฐพ์์ View๋ฅผ ๋ค์ ๋ฆฌํดํด์ค๋ค.
(10) DispatcherServlet์ ViewResolver๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ View ๊ฐ์ฒด๋ฅผ ํตํด Model ๋ฐ์ดํฐ๋ฅผ ๋๊ฒจ์ฃผ๋ฉด์ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํ ์๋ต ๋ฐ์ดํฐ ์์ฑ์ ์์ฒญํ๋ค.
(11) View๋ ์๋ต ๋ฐ์ดํฐ๋ฅผ ์์ฑํด์ ๋ค์ DispatcherServlet์๊ฒ ์ ๋ฌํ๋ค.
(12) DispatcherServlet์ View๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ ์๋ต ๋ฐ์ดํฐ๋ฅผ ์ต์ข
์ ์ผ๋ก ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํ๋ค.
Front Controller Pattern
- DispatcherServlet์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ์ฅ ์๋จ์ ๋ฐฐ์น๋์ด ๋ค๋ฅธ ๊ตฌ์ฑ์์๋ค๊ณผ ์ํธ์์ฉํ๋ฉด์ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ํจํด
Controller ํด๋์ค ์ค๊ณ ๋ฐ ๊ตฌ์กฐ ์์ฑ
API ๊ณ์ธต์ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ง์ ์ ์ผ๋ก ์ ๋ฌ ๋ฐ๋ ๊ณ์ธต์ด๋ค
Spring MVC ๋์ ๋ฐฉ์๊ณผ ๊ตฌ์ฑ ์์๋ฅผ ์ดํด๋ณด๋ฉด ํด๋ผ์ด์ธํธ ์์ฒญ ํ๋ฆ์ ๋์๋ Controller๊ฐ ์๋ค.
์ด๊ณณ์ด ๋ฐ๋ก Spring MVC์์ ํด๋ผ์ด์ธํธ ์์ฒญ์ ์ต์ข ๋ชฉ์ ์ง๊ฐ ๋๋ค.
์ปคํผ ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ ๋ค๊ณ ๊ฐ์ ํ๊ณ , ํด๋น ์ ํ๋ฆฌ์ผ์ด์ ์ Controller์ ์ค๊ณํด๋ณด์.
๋จผ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ธฐ๋ฅ ์๊ตฌ์ฌํญ์ ์ ๋ฆฌํด๋ณด์.
์ฃผ์ธ์ด ์ปคํผ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ
- ์ปคํผ ์ ๋ณด ๋ฑ๋ก ๊ธฐ๋ฅ
- ๋ฑ๋กํ ์ปคํผ ์ ๋ณด ์์ ๊ธฐ๋ฅ
- ๋ฑ๋กํ ์ปคํผ ์ ๋ณด ์ญ์ ๊ธฐ๋ฅ
- ๋ฑ๋กํ ์ปคํผ ์ ๋ณด ์กฐํ ๊ธฐ๋ฅ
๊ณ ๊ฐ์ด ์ปคํผ ์ ๋ณด๋ฅผ ์กฐํํ๋ ๊ธฐ๋ฅ
- ์ปคํผ ์ ๋ณด ์กฐํ ๊ธฐ๋ฅ
๊ณ ๊ฐ์ด ์ปคํผ๋ฅผ ์ฃผ๋ฌธํ๋ ๊ธฐ๋ฅ
- ์ปคํผ ์ฃผ๋ฌธ ๋ฑ๋ก ๊ธฐ๋ฅ
- ์ปคํผ ์ฃผ๋ฌธ ์ทจ์ ๊ธฐ๋ฅ
- ์ปคํผ ์ฃผ๋ฌธ ์กฐํ ๊ธฐ๋ฅ
๊ณ ๊ฐ์ด ์ฃผ๋ฌธํ ์ปคํผ๋ฅผ ์ฃผ์ธ์ด ์กฐํํ๋ ๊ธฐ๋ฅ
- ์ปคํผ ์ฃผ๋ฌธ ์กฐํ ๊ธฐ๋ฅ
- ๊ณ ๊ฐ์๊ฒ ์ ๋ฌ ์๋ฃํ ์ปคํผ์ ๋ํ ์ฃผ๋ฌธ ์๋ฃ ์ฒ๋ฆฌ ๊ธฐ๋ฅ
์ปคํผ ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ํ ๋ฆฌ์์ค
REST API ๊ธฐ๋ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ผ๋ฐ์ ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ๊ณตํด์ผ ๋ ๊ธฐ๋ฅ์ ๋ฆฌ์์ค(Resource, ์์)์ผ๋ก ๋ถ๋ฅํ๋ค.
๋ฐ๋ผ์ ์๋์ ๊ฐ์ ๋ฆฌ์์ค๊ฐ ํ์ํ ๊ฒ์ ์์ํ ์ ์๋ค.
์ปคํผ ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์ Controller ๊ตฌ์กฐ ์์ฑ
MemberController ๊ตฌ์กฐ ์์ฑ
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // (1)
@RequestMapping("/v1/members") // (2)
public class MemberController {
}
โ๏ธ (1) @RestController
- Spring MVC์์ ํน์ ํด๋์ค์ ํด๋น ์ ๋ ธํ ์ด์ ์ด ์ถ๊ฐ๋๋ฉด, ํด๋น ํด๋์ค๊ฐ REST API์ ๋ฆฌ์์ค๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด API ์๋ํฌ์ธํธ๋ก ๋์ํจ์ ์ ์ํ๋ค.
- @RestController ๊ฐ ์ถ๊ฐ๋ ํด๋์ค๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ก๋ฉ ์, Spring Bean์ผ๋ก ๋ฑ๋กํ๋ค.
โ๏ธ (2) @RequestMapping
- ํด๋ผ์ด์ธํธ์ ์์ฒญ๊ณผ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ํธ๋ค๋ฌ ๋ฉ์๋ (Handler Method)๋ฅผ ๋งคํํด์ฃผ๋ ์ญํ ์ ํ๋ค.
- ํด๋์ค ์ ์ฒด์ ์ฌ์ฉํ๋ ๊ณตํต์ URL(Base URL) ์ค์ ์ ํ๋ค.
CoffeeController ๊ตฌ์กฐ ์์ฑ
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/v1/coffees")
public class CoffeeController {
}
OrderController ๊ตฌ์กฐ ์์ฑ
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/v1/orders")
public class OrderController {
}
ํธ๋ค๋ฌ ๋ฉ์๋ (Handler Method)
ํธ๋ค๋ฌ ๋ฉ์๋๋ ์ฐ๋ฆฌ๊ฐ ์์์ ์์ฑํ Controller ํด๋์ค์ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋ฉ์๋๋ฅผ ๋งํ๋ค.
์์์ ๊ตฌํํ ๊ฐ Controller์ ํธ๋ค๋ฌ ๋ฉ์๋๋ฅผ ์์ฑํด๋ณด์.
MemberController ๋ ๊ฑฐ์ ์ฝ๋
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/v1/members") // (1) produces ์ค์ ์ ๊ฑฐ๋จ
public class MemberController {
@PostMapping
public ResponseEntity postMember(@RequestParam("email") String email,
@RequestParam("name") String name,
@RequestParam("phone") String phone) {
// (2) JSON ๋ฌธ์์ด ์์์
์ Map ๊ฐ์ฒด๋ก ๋์ฒด
Map<String, String> map = new HashMap<>();
map.put("email", email);
map.put("name", name);
map.put("phone", phone);
// (3) ๋ฆฌํด ๊ฐ์ ResponseEntity ๊ฐ์ฒด๋ก ๋ณ๊ฒฝ
return new ResponseEntity<>(map, HttpStatus.CREATED);
}
@GetMapping("/{member-id}")
public ResponseEntity getMember(@PathVariable("member-id") long memberId) {
System.out.println("# memberId: " + memberId);
// not implementation
// (4) ๋ฆฌํด ๊ฐ์ ResponseEntity ๊ฐ์ฒด๋ก ๋ณ๊ฒฝ
return new ResponseEntity<>(HttpStatus.OK);
}
@GetMapping
public ResponseEntity getMembers() {
System.out.println("# get Members");
// not implementation
// (5) ๋ฆฌํด ๊ฐ์ ResponseEntity ๊ฐ์ฒด๋ก ๋ณ๊ฒฝ
return new ResponseEntity<>(HttpStatus.OK);
}
}
โ๏ธ (2) ์ฐ๋ฆฌ๋ JSON ๋ฌธ์์ด์ ์์์ ์ผ๋ก ์์ฑํ ํ์ ์์ด Map ๊ฐ์ฒด๋ก ๋์ฒดํ ์ ์๋ค.
- Map<String, String>์ ๊ฒฝ์ฐ key์ value๊ฐ ๋ชจ๋ String ์ด์ด์ผ ํ๋ค.
- key๊ฐ String์ด๊ณ , ๋ค๋ฅธ ํ์ ์ ๋ฐ์ดํฐ๋ฅผ map์ ์ถ๊ฐํ๊ธฐ ์ํด์๋ value ํ์ ์ Object๋ก ์ง์ ํด์ผ ํ๋ค.
โ๏ธ (3) ๋ฆฌํด ๊ฐ์ผ๋ก JSON ๋ฌธ์์ด์ ์ฒ๋ฆฌํ๋ ๋ถ๋ถ์ด ResponseEntity ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ ๊ฒ์ผ๋ก ๋ฐ๊ฟ ์ ์๋ค.
- return new ResponseEntity<>(map, HttpStatus.CREATED);
- ์ด๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฉด์ ์์ฑ์ ํ๋ผ๋ฏธํฐ๋ก ์๋ต ๋ฐ์ดํฐ(map)๊ณผ HTTP ์๋ต ์ํ๋ฅผ ํจ๊ป ์ ๋ฌํ๊ณ ์๋ค.
ํด๋ผ์ด์ธํธ์ ์๋ฒ์ ๊ด๊ณ
์น ๋ธ๋ผ์ฐ์ ๋ ์น ์๋ฒ๊ฐ ์๋ต์ผ๋ก ์ ๋ฌํด์ฃผ๋ HTML ์ฝํ ์ธ ๋ฅผ ์ ๋ฌ ๋ฐ์, ๋ธ๋ผ์ฐ์ ๋ด์ ๋ณด์ฌ์ค๋ค.
์ฌ๊ธฐ์ ์๋ฒ ์ชฝ ๋ฆฌ์์ค๋ฅผ ์ด์ฉํ๋ ์ธก์ด ํด๋ผ์ด์ธํธ๊ฐ ๋๋ค.
ํ์ง๋ง ์๋ฒ๋ ํญ์ ํด๋ผ์ด์ธํธ์๊ฒ ๋ฆฌ์์ค๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์๋, ์๋ฒ๋ ๋ค๋ฅธ ์๋ฒ๋ก๋ถํฐ ๋ฆฌ์์ค๋ฅผ ์ ๊ณต๋ฐ์์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค. ๋ํ์ ์ผ๋ก Frontend์ Backend์ ๊ด๊ณ๋ฅผ ์ดํด๋ณผ ์๊ฐ ์๋ค.
์ฌ๊ธฐ์ ์น ๋ธ๋ผ์ฐ์ ์ ์ ์ฅ์์๋ Frontend์ ๋ฆฌ์์ค๋ฅผ ์ ๊ณต๋ฐ์ผ๋ฏ๋ก ํด๋ผ์ด์ธํธ๊ฐ ๋๋ค.
Frontend์ ๊ฒฝ์ฐ๋ ๋ฆฌ์์ค๋ฅผ ์ ๊ณตํ๋ ์ ์ฅ์ด๊ธฐ ๋๋ฌธ์ ์๋ฒ๊ฐ ๋ง์ง๋ง, Frontend๊ฐ Backend์ ๋์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ฒ ๋๋ฉด, ์ด๋๋ Backend์ ๋ฆฌ์์ค๋ฅผ ์ด์ฉํ๋ํด๋ผ์ด์ธํธ๊ฐ ๋๋ ๊ฒ์ด๋ค.
๊ฒฐ๋ก ์ ์ด๋ค ์๋ฒ๊ฐ HTTP ํต์ ์ ํตํด ๋ค๋ฅธ ์๋ฒ์ ๋ฆฌ์์ค๋ฅผ ์ด์ฉํ๊ฒ ๋๋ฉด, ๊ทธ ๋๋ ํด๋ผ์ด์ธํธ์ ์ญํ ์ ํ๋ค๋ ๊ฒ์ด๋ค.
DTO(Data Transfer Object)๋?
DTO๋ ์ํฐํ๋ผ์ด์ฆ ์ ํ๋ฆฌ์ผ์ด์ ์ํคํ ์ฒ ํจํด์ ํ๋๋ก, ์ ํ๋ฆฌ์ผ์ด์ ์ํคํ ์ฒ ํจํด์ ํ๋ํด๋ผ์ด์ธํธ์์ ์๋ฒ ์ชฝ์ผ๋ก ์ ์กํ๋ ์์ฒญ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ๋ฐ์ ๋, ์๋ฒ์์ ํด๋ผ์ด์ธํธ ์ชฝ์ผ๋ก ์ ์กํ๋ ์๋ต ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ธฐ ์ํ ์ฉ๋๋ก ์ฌ์ฉ๋๋ค.
์ฐ๋ฆฌ๊ฐ DTO๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ํด๋ผ์ด์ธํธ์ RequestBody๋ฅผ ํ๋์ ๊ฐ์ฒด๋ก ๋ชจ๋ ์ ๋ฌ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์ ์ฝ๋ ์์ฒด๊ฐ ๊ฐ๊ฒฐํด์ง๋ค.
- RequsetBody์ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฆ์ด ๋จ์ํด์ง๋ค.
DTO ํด๋์ค ์ ์ฉ ์ MemberController ์ฝ๋
@RestController
@RequestMapping("/v1/members")
public class MemberController {
@PostMapping
public ResponseEntity postMember(@RequestParam("email") String email,
@RequestParam("name") String name,
@RequestParam("phone") String phone) {
Map<String, String> map = new HashMap<>();
map.put("email", email);
map.put("name", name);
map.put("phone", phone);
return new ResponseEntity<Map>(map, HttpStatus.CREATED);
}
...
...
}
DTO ํด๋์ค ์ ์ฉ ํ MemberController ์ฝ๋
@RestController
@RequestMapping("/v1/members")
public class MemberController {
@PostMapping
public ResponseEntity postMember(MemberDto memberDto) {
return new ResponseEntity<MemberDto>(memberDto, HttpStatus.CREATED);
}
...
...
}
์ ํจ์ฑ ๊ฒ์ฆ ๋ก์ง์ด ์ถ๊ฐ๋ MemberDto ํด๋์ค
public class MemberDto {
@Email
private String email;
private String name;
private String phone;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
- MemberDto ํด๋์ค์์ ์ด๋ฉ์ผ์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฆ์ ์งํํ๋ค.
์ ํจ์ฑ ๊ฒ์ฆ์ด ์ ์ฉ๋ MemberController ์ฝ๋
@RestController
@RequestMapping("/v1/members")
public class MemberController {
@PostMapping
public ResponseEntity postMember(@Valid MemberDto memberDto) {
return new ResponseEntity<MemberDto>(memberDto, HttpStatus.CREATED);
}
...
...
}
์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก Dto ํด๋์ค๋ฅผ ์์ฑํด๋ณด๊ณ , MemberController์ ์ ์ฉํด๋ณด์.
ํ์ ์ ๋ณด ๋ฑ๋ก์ ์ฌ์ฉ๋๋ MemberPostDto ํด๋์ค
public class MemberPostDto {
private String email;
private String name;
private String phone;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
ํ์ ์ ๋ณด ์์ ์ ์ฌ์ฉ๋๋ MemberPatchDto ํด๋์ค
public class MemberPatchDto {
private long memberId;
private String name;
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public long getMemberId() {
return memberId;
}
public void setMemberId(long memberId) {
this.memberId = memberId;
}
}
Dto๊ฐ ์ ์ฉ๋ MemberController
import com.codestates.member.MemberPatchDto;
import com.codestates.member.MemberPostDto;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/v1/members")
public class MemberController {
// ํ์ ์ ๋ณด ๋ฑ๋ก
@PostMapping
public ResponseEntity postMember(@RequestBody MemberPostDto memberPostDto) {
return new ResponseEntity<>(memberPostDto, HttpStatus.CREATED);
}
// ํ์ ์ ๋ณด ์์
@PatchMapping("/{member-id}")
public ResponseEntity patchMember(@PathVariable("member-id") long memberId,
@RequestBody MemberPatchDto memberPatchDto) {
memberPatchDto.setMemberId(memberId);
memberPatchDto.setName("ํ๊ธธ๋");
// No need Business logic
return new ResponseEntity<>(memberPatchDto, HttpStatus.OK);
}
// ํ๋ช
์ ํ์ ์ ๋ณด ์กฐํ
@GetMapping("/{member-id}")
public ResponseEntity getMember(@PathVariable("member-id") long memberId) {
System.out.println("# memberId: " + memberId);
// not implementation
return new ResponseEntity<>(HttpStatus.OK);
}
// ๋ชจ๋ ํ์ ์ ๋ณด ์กฐํ
@GetMapping
public ResponseEntity getMembers() {
System.out.println("# get Members");
// not implementation
return new ResponseEntity<>(HttpStatus.OK);
}
// ํ์ ์ ๋ณด ์ญ์
@DeleteMapping("/{member-id}")
public ResponseEntity deleteMember(@PathVariable("member-id") long memberId) {
// No need business logic
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
}
โ๏ธ @RequestBody ์ ๋ํ
์ด์
์ฝ๋ 3-32์์ MemberPostDto ํด๋์ค ์์ ๋ถ์ @RequestBody ์ ๋ํ
์ด์
์ JSON ํ์์ Request Body๋ฅผ MemberPostDto ํด๋์ค์ ๊ฐ์ฒด๋ก ๋ณํ์ ์์ผ์ฃผ๋ ์ญํ ์ ํ๋ค.
์ด ๋ง์ ์๋ฏธ๋ ํด๋ผ์ด์ธํธ ์ชฝ์์ ์ ์กํ๋ Request Body๊ฐ JSON ํ์์ด์ด์ผ ํ๋ค๋ ๋ง๊ณผ ๊ฐ๋ค.
๋ง์ผ JSON ํ์์ด ์๋ ๋ค๋ฅธ ํ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ค๋ฉด, Spring ๋ด๋ถ์์ ‘Unsupported Media Type’๊ณผ ๊ฐ์ ์๋ฌ ๋ฉ์์ง๋ฅผ ํฌํจํ ์๋ต์ ์ ๋ฌํ๋ค.
โ๏ธ @ResponseBody ์ ๋ํ
์ด์
@RequestBody์ ์ญํ ์ด ํด๋ผ์ด์ธํธ ์ชฝ์์ ์ ์กํ JSON ํ์์ Request Body๋ฅผ DTO ํด๋์ค์ ๊ฐ์ฒด๋ก ๋ณํํ๋ ๊ฒ์ด๋ผ๋ฉด, @ResponseBody๋ JSON ํ์์ Response Body๋ฅผ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํ๊ธฐ ์ํด DTO ํด๋์ค์ ๊ฐ์ฒด๋ฅผ Response Body๋ก ๋ณํํ๋ ์ญํ ์ ํ๋ค.
์ฌ๊ธฐ์ @ResponseBody๋ฅผ ์ฌ์ฉํ๋ ๊ณณ์ด ์๋ ์ด์ ๋ postMember(), patchMember() ํธ๋ค๋ฌ ๋ฉ์๋์ ๋ฆฌํด ๊ฐ์ด ResponseEntity ํด๋์ค์ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ด๋ค.
Spring MVC์์๋ ํธ๋ค๋ฌ ๋ฉ์๋์ @ResponseBody ์ ๋ํ
์ด์
์ด ๋ถ๊ฑฐ๋ ํธ๋ค๋ฌ ๋ฉ์๋์ ๋ฆฌํด ๊ฐ์ด ResponseEntity์ผ ๊ฒฝ์ฐ, ๋ด๋ถ์ ์ผ๋ก HttpMessageConverter๊ฐ ๋์ํ๊ฒ ๋์ด ์๋ต ๊ฐ์ฒด(์ฌ๊ธฐ์๋ DTO ํด๋์ค์ ๊ฐ์ฒด)๋ฅผ JSON ํ์์ผ๋ก๋ฐ๊ฟ์ค๋ค.
โ๏ธ JSON ์ง๋ ฌํ(Serialization)์ ์ญ์ง๋ ฌํ(Deserialization)
ํด๋ผ์ด์ธํธ ์ชฝ์์ JSON ํ์์ ๋ฐ์ดํฐ๋ฅผ ์๋ฒ ์ชฝ์ผ๋ก ์ ์กํ๋ฉด ์๋ฒ ์ชฝ์ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์ ๋ฌ๋ฐ์ JSON ํ์์ ๋ฐ์ดํฐ๋ฅผ DTO ๊ฐ์ Java์ ๊ฐ์ฒด๋ก ๋ณํํ๋๋ฐ ์ด๋ฅผ ์ญ์ง๋ ฌํ(Deserialization)์ด๋ผ๊ณ ํ๋ค.
๋ฐ๋ฉด์ ์๋ฒ ์ชฝ์์ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ธฐ ์ํด์ DTO ๊ฐ์ Java์ ๊ฐ์ฒด๋ฅผ JSON ํ์์ผ๋ก ๋ณํํ๋ ๊ฒ์ ์ง๋ ฌํ(Serialization)๋ผ๊ณ ํ๋ค.
JSON ์ง๋ ฌํ(Serialization): Java ๊ฐ์ฒด → JSON
JSON ์ญ์ง๋ ฌํ(Deserialization): JSON → Java ๊ฐ์ฒด
'CodeStates 45th' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Section 4. [์ธ์ฆ/๋ณด์] ๊ธฐ์ด (0) | 2023.07.17 |
---|---|
[Section 2] Spring Framework ํต์ฌ ๊ฐ๋ - DI (0) | 2023.05.30 |
[Section 2] SQL, MySQL Command practice (0) | 2023.05.25 |
[Section 2] Spring Framework ๊ธฐ๋ณธ (0) | 2023.05.21 |
[Section 1] ํ๊ณ (2) | 2023.05.09 |