[MVC] controller
Categories: Spring
Tags: MVC, Spring, ๊ฐ๋ ์ ๋ฆฌ
๐ ๊ฐ์ธ์ ์ธ ๊ณต๊ฐ์ผ๋ก ๊ณต๋ถ๋ฅผ ๊ธฐ๋กํ๊ณ ๋ณต์ตํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ๋ธ๋ก๊ทธ์
๋๋ค.
์ ํํ์ง ์์ ์ ๋ณด๊ฐ ์์ ์ ์์ผ๋ ์ฐธ๊ณ ๋ฐ๋๋๋ค :๐ธ
[ํ๋ฆฐ ๋ด์ฉ์ ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์๋ฉด ๋ณต๋ฐ์ผ์ค๊ฑฐ์์]
Spring MVC
- ์คํ๋ง์ ์๋ธ๋ฆฟ ๊ธฐ๋ฐ์ผ๋ก ๋์ํจ.
- Spring์ ๋ชจ๋ ์ค์์ ์๋ธ๋ฆฟ(Servlet) API๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋ชจ๋์ด ๋ฐ๋ก
spring-webmvc
= Spring MVC = Spring MVC ํ๋ ์์ํฌ- ์๋ธ๋ฆฟ : ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋๋ก ํน์ ๊ท์ฝ์ ๋ง์ถ์ด์ Java ์ฝ๋๋ก ์์ฑํ๋ํด๋์ค ํ์ผ
- ์ํ์น ํฐ์บฃ(Apache Tomcat)์ ์ด๋ฌํ ์๋ธ๋ฆฟ๋ค์ด ์น ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์คํ์ด ๋๋๋ก ํด์ฃผ๋ ์๋ธ๋ฆฟ ์ปจํ ์ด๋(Servlet Container) ์ค ํ๋
M
Model์ Spring MVC์์ M์ ํด๋น
์ฒ๋ฆฌํ ์์ ์ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต์ผ๋ก ๋๋ ค์ค์ผ ํ๋๋ฐ, ์ด๋ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต์ผ๋ก ๋๋ ค์ฃผ๋ ์์ ์ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ Model
ํด๋ผ์ด์ธํธ์ ์์ฒญ ์ฌํญ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ์์ญ์ ์๋น์ค ๊ณ์ธต(Service Layer)์ด๋ผ๊ณ ํ๋ฉฐ, ์ค์ ๋ก ์์ฒญ ์ฌํญ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด Java ์ฝ๋๋ก ๊ตฌํํ ๊ฒ์ ๋น์ฆ๋์ค ๋ก์ง(Business Logic)์ด๋ผ๊ณ ํฉ๋๋ค.
V
View๋ Spring MVC์์ V์ ํด๋น
View๋ ์์์ ์ค๋ช ํ Model ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํด์ ์น๋ธ๋ผ์ฐ์ ๊ฐ์ ํด๋ผ์ด์ธํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋ฉด์ ๋ณด์ด๋ ๋ฆฌ์์ค(Resource)๋ฅผ ์ ๊ณตํ๋ ์ญํ
- HTML ํ์ด์ง์ ์ถ๋ ฅ
- Spring MVC์์ ์ง์ํ๋ HTML ํ์ด์ง ์ถ๋ ฅ ๊ธฐ์ ์๋ Thymeleaf, FreeMarker, JSP + JSTL, Tiles ๋ฑ์ด ์์ต๋๋ค.
โ ์์ผ๋ก V๋ ์ํ๊ณ jsonํ์ ์ผ๋ก ๋ง๋ค ์์
๐ JSON(JavaScript Object Notation)์ด๋?
- JSON์ ๊ธฐ๋ณธ ํฌ๋งท
{โ์์ฑโ:โ๊ฐโ}
ํํ์ ๋๋ค.- https://jsonformatter.org/json-to-java
C
Controller๋ ํด๋ผ์ด์ธํธ ์ธก์ ์์ฒญ์ ์ง์ ์ ์ผ๋ก ์ ๋ฌ๋ฐ๋ ์๋ํฌ์ธํธ(Endpoint)๋ก์จ Model๊ณผ View์ ์ค๊ฐ์์ ์ํธ ์์ฉ์ ํด์ฃผ๋ ์ญํ
์ฆ, ํด๋ผ์ด์ธํธ ์ธก์ ์์ฒญ์ ์ ๋ฌ๋ฐ์์ ๋น์ฆ๋์ค ๋ก์ง์ ๊ฑฐ์น ํ์ Model ๋ฐ์ดํฐ๊ฐ ๋ง๋ค์ด์ง๋ฉด, ์ด Model ๋ฐ์ดํฐ๋ฅผ View๋ก ์ ๋ฌํ๋ ์ญํ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
@RequestMapping(path = "/v1/coffee")
public class CoffeeController {
private final CoffeeService coffeeService;
CoffeeController(CoffeeService coffeeService) {
this.coffeeService = coffeeService;
}
@GetMapping("/{coffee-id}") // (1)
public Coffee getCoffee(@PathVariable("coffee-id") long coffeeId) {
return coffeeService.findCoffee(coffeeId); // (2)
}
}
- (1)์
@GetMapping
์ ๋ ธํ ์ด์ ์ ํตํด ํด๋ผ์ด์ธํธ ์ธก์ ์์ฒญ์ ์์ - (2)์์
CoffeeService
ํด๋์ค์findCoffee()
๋ฉ์๋๋ฅผ ํธ์ถํด์ ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌ - (2)์์ ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํ ๋ค์ ๋ฆฌํด ๋ฐ๋ Coffee๊ฐ ์ฌ๊ธฐ์๋ Model ๋ฐ์ดํฐ
MVC์ ์ ์ฒด์ ์ธ ๋์ํ๋ฆ
-
Client๊ฐ ์์ฒญ ๋ฐ์ดํฐ ์ ์ก
โ Controller๊ฐ ์์ฒญ ๋ฐ์ดํฐ ์์ โ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ โ Model ๋ฐ์ดํฐ ์์ฑ
โ Controller์๊ฒ Model ๋ฐ์ดํฐ ์ ๋ฌ โ Controller๊ฐ View์๊ฒ Model ๋ฐ์ดํฐ ์ ๋ฌ
โ View๊ฐ ์๋ต ๋ฐ์ดํฐ ์์ฑ
Spring MVC์ ๋์ ๋ฐฉ์๊ณผ ๊ตฌ์ฑ ์์ ( ์์ ์ค์ โจโจโจโจ)
-
์ง์ ๋ค๋ฃจ์ง๋ ์์๋ ํ๋ฆ์ด ์ด๋ ๋ค๋ ๊ฒ์ ๊ผญ ์์์ผ ํจ.
- ์์ฒญ์ ์กํ๋ฉด ๋ฐ๋ก Controller๋ก ๊ฐ์ง์์ - DispatcherServlet ์ด ์์ฒญ์ ๋ฐ์.
- DispatcherServlet์ด handlerMapping์๊ฒ ๋ณด๋(ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ Controller์ ๋ํ ๊ฒ์์ ์์ฒญ). โ handlerMapping์ด ์ปจํธ๋กค๋ฌ ๊ฐ์ฒด๋ฅผ ๋ค ์๊ณ ์์. controller ์ฐพ์์ ์๋ ค์ค
- HandlerMapping์ ํด๋ผ์ด์ธํธ ์์ฒญ๊ณผ ๋งคํ๋๋ ํธ๋ค๋ฌ ๊ฐ์ฒด๋ฅผ ๋ค์ DispatcherServlet์๊ฒ ๋ฆฌํด
DispatcherServlet
์ Handler ๋ฉ์๋๋ฅผ ์ง์ ํธ์ถํ์ง ์๊ณ , HandlerAdpater์๊ฒ Handler ๋ฉ์๋ ํธ์ถ์ ์์HandlerAdapter
๋ DispatcherServlet์ผ๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ Controller ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํด๋น Controller์ Handler ๋ฉ์๋๋ฅผ ํธ์ถController
์ Handler ๋ฉ์๋๋ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ ํ ๋ฆฌํด ๋ฐ์ Model ๋ฐ์ดํฐ๋ฅผ HandlerAdapter์๊ฒ ์ ๋ฌHandlerAdapter
๋ ์ ๋ฌ๋ฐ์ Model ๋ฐ์ดํฐ์ View ์ ๋ณด๋ฅผ ๋ค์ DispatcherServlet์๊ฒ ์ ๋ฌDispatcherServlet
์ ์ ๋ฌ๋ฐ์ View ์ ๋ณด๋ฅผ ๋ค์ ViewResolver์๊ฒ ์ ๋ฌํด์ View ๊ฒ์์ ์์ฒญViewResolver
๋ View ์ ๋ณด์ ํด๋นํ๋ View๋ฅผ ์ฐพ์์ View๋ฅผ ๋ค์ ๋ฆฌํดDispatcherServlet
์ ViewResolver๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ View ๊ฐ์ฒด๋ฅผ ํตํด Model ๋ฐ์ดํฐ๋ฅผ ๋๊ฒจ์ฃผ๋ฉด์ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํ ์๋ต ๋ฐ์ดํฐ ์์ฑ์ ์์ฒญView
๋ ์๋ต ๋ฐ์ดํฐ๋ฅผ ์์ฑํด์ ๋ค์ DispatcherServlet์๊ฒ ์ ๋ฌDispatcherServlet
์ View๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ ์๋ต ๋ฐ์ดํฐ๋ฅผ ์ต์ข ์ ์ผ๋ก ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ
-
DispatcherServlet์ ์ญํ
- ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์์ฒญ์ ์ ๋ฌ ๋ฐ์ผ๋ฉด HandlerMapping, HandlerAdapter, ViewResolver, View ๋ฑ ๋๋ถ๋ถ์ Spring MVC ๊ตฌ์ฑ ์์๋ค๊ณผ ์ํธ ์์ฉ์ ํจ
- ๋ฐ๋น ๋ณด์ด์ง๋ง ์ค์ ๋ก ์์ฒญ์ ๋ํ ์ฒ๋ฆฌ๋ ๋ค๋ฅธ ๊ตฌ์ฑ ์์๋ค์๊ฒ ์์(Delegate)ํ๊ณ ์์.
- DispatcherServlet์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ์ฅ ์๋จ์ ๋ฐฐ์น๋์ด ๋ค๋ฅธ ๊ตฌ์ฑ์์๋ค๊ณผ ์ํธ์์ฉํ๋ฉด์ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ํจํด์ Front Controller Pattern์ด๋ผ๊ณ ํ๋ค.
Controller
์ปคํผ ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์ค์ต์ผ๋ก MVC ๋ฐฐ์ฐ๊ธฐ
[์๊ตฌ์กฐ๊ฑด]
- ์ฃผ์ธ์ด ์ปคํผ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ
- ์ปคํผ ์ ๋ณด ๋ฑ๋ก ๊ธฐ๋ฅ
- ๋ฑ๋กํ ์ปคํผ ์ ๋ณด ์์ ๊ธฐ๋ฅ
- ๋ฑ๋กํ ์ปคํผ ์ ๋ณด ์ญ์ ๊ธฐ๋ฅ
- ๋ฑ๋กํ ์ปคํผ ์ ๋ณด ์กฐํ ๊ธฐ๋ฅ
- ๊ณ ๊ฐ์ด ์ปคํผ ์ ๋ณด๋ฅผ ์กฐํํ๋ ๊ธฐ๋ฅ
- ์ปคํผ ์ ๋ณด ์กฐํ ๊ธฐ๋ฅ
- ๊ณ ๊ฐ์ด ์ปคํผ๋ฅผ ์ฃผ๋ฌธํ๋ ๊ธฐ๋ฅ
- ์ปคํผ ์ฃผ๋ฌธ ๋ฑ๋ก ๊ธฐ๋ฅ
- ์ปคํผ ์ฃผ๋ฌธ ์ทจ์ ๊ธฐ๋ฅ
- ์ปคํผ ์ฃผ๋ฌธ ์กฐํ ๊ธฐ๋ฅ
์ปคํผ ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ํ ๋ฆฌ์์ค
- ๊ณ ๊ฐ์ด ์ฃผ๋ฌธํ ์ปคํผ๋ฅผ ์ฃผ์ธ์ด ์กฐํํ๋ ๊ธฐ๋ฅ
- ์ปคํผ ์ฃผ๋ฌธ ์กฐํ ๊ธฐ๋ฅ
- ๊ณ ๊ฐ์๊ฒ ์ ๋ฌ ์๋ฃํ ์ปคํผ์ ๋ํ ์ฃผ๋ฌธ ์๋ฃ ์ฒ๋ฆฌ ๊ธฐ๋ฅ
Controller ์ค๊ณ
- REST API ๊ธฐ๋ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ผ๋ฐ์ ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ๊ณตํด์ผ ๋ ๊ธฐ๋ฅ์ ๋ฆฌ์์ค(Resource, ์์)๋ก ๋ถ๋ฅ
- ์ปคํผ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ํ Resourse๋ ํ์/์ปคํผ/์ฃผ๋ฌธ ์ ํด๋น
-
์ฃผ์ธ์ ๊ธฐ๋ฅ์ ๋ฐ๋ก ๋ถ๋ฆฌํด์ผ ๋๋ ๊ฒ ์๋๋๋ ์๋ฌธ์ด ๋ค ์๋ ์์ง๋ง
โ ๊ณ ๊ฐ๊ณผ ์ฃผ์ธ์ ์ธ์ฆ ํ๋ก์ธ์ค๊ฐ ๋ณต์กํด์ง ๊ฐ๋ฅ์ฑ์ด ๋์
โ ์ค์ ํฐ ์ ์ฒด์๋ ๋ฐฑ์คํผ์ค๋ฅผ ๊ตฌํํด์ ์ฌ์ฉํจ
ํจํค์ง ๊ตฌ์กฐ ์์ฑ
์ผ์ชฝ์ ๊ธฐ๋ฅ ๊ธฐ๋ฐ, ์ค๋ฅธ์ชฝ์ ๊ณ์ธต ๊ธฐ๋ฐ
๊ณ์ธต ๊ธฐ๋ฐ์ผ๋ก ๋๋ ์ ์์ง๋ง ๊ธฐ๋ฅ ๊ธฐ๋ฐ ๊ธฐ์ค์ผ๋ก ๋๋ ์์ ์.
โ ์๋๋ฉด ? Spring Boot ํ์์๋ ํ ์คํธ์ ๋ฆฌํฉํ ๋ง์ด ์ฉ์ดํ๊ณ , ํฅํ์ ๋ง์ดํฌ๋ก ์๋น์ค ์์คํ ์ผ๋ก์ ๋ถ๋ฆฌ๊ฐ ์๋์ ์ผ๋ก ์ฉ์ดํ ๊ธฐ๋ฅ ๊ธฐ๋ฐ ํจํค์ง ๊ตฌ์กฐ ์ฌ์ฉ์ ๊ถ์ฅํ๊ธฐ ๋๋ฌธ
์ํธ๋ฆฌํฌ์ธํธ(Entrypoint) ํด๋์ค ์์ฑ
@SpringBootApplication
- ์๋ ๊ตฌ์ฑ์ ํ์ฑํ
@Component
๊ฐ ๋ถ์ ํด๋์ค๋ฅผ ๊ฒ์ํ ํ(scan), Spring Bean์ผ๋ก ๋ฑ๋กํ๋ ๊ธฐ๋ฅ์ ํ์ฑํ@Configuration
์ด ๋ถ์ ํด๋์ค๋ฅผ ์๋์ผ๋ก ์ฐพ์์ฃผ๊ณ , ์ถ๊ฐ์ ์ผ๋ก Spring Bean์ ๋ฑ๋กํ๋ ๊ธฐ๋ฅ์ ํ์ฑํ
SpringApplication.run(SpringStartApplication.class, args);
- Spring ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ถํธ์คํธ๋ฉํ๊ณ , ์คํํ๋ ์ญํ ์ ํจ
๋ถํธ์คํธ๋ฉ(Bootstrap)์ด๋?
์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋๊ธฐ ์ ์ ์ฌ๋ฌ ๊ฐ์ง ์ค์ ์์ ์ ์ํํ์ฌ ์คํ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ๋ง๋๋ ๋จ๊ณ๋ฅผ ์๋ฏธ
์ปคํผ ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์ Controller ๊ตฌ์กฐ ์์ฑ
-
MemberController ๊ตฌ์กฐ ์์ฑ
1 2 3 4 5 6 7 8 9
package com.springboot.member; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/v1/members") public class MemberController { }
-
@RestController
โ ์คํ๋ง์ปจํ ์ด๋๋ฅผ ๋ฑ๋ก์์ผ์ค๊ณผ ๋์์ ์ปจํธ๋กค๋ฌ๋ฅผ ๊ตฌํํ ๊ฑฐ๋ผ๋ ๊ฒ์ ์๋ฆผ -
ํด๋น ์ฃผ์(/v1/members)๋ก ๋ค์ด์ค๋ ์์ฒญ์ MemberController๊ฐ ๋ด๋น
-
-
OrderController ๊ตฌ์กฐ ์์ฑ
1 2 3 4 5 6 7 8 9
package com.springboot.order; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/v1/orders") public class OrderController { }
-
CoffeeController ๊ตฌ์กฐ ์์ฑ
1 2 3 4 5 6 7 8 9 10
package com.springboot.coffee; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/v1/coffees") public class CoffeeController { }
ํธ๋ค๋ฌ ๋ฉ์๋(Handler Method)
-
ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ ๋ฌ๋ฐ์์ ์ฒ๋ฆฌํ๊ธฐ ์ํด์๋ ์์ฒญ ํธ๋ค๋ฌ ๋ฉ์๋(Request Handler Method)๊ฐ ํ์
- Postman ์ฌ์ฉ๋ฒ : https://itvillage.tistory.com/38
-
ํ๊ธฐ ์ฝ๋์ ๋์ค๋ annotation์ ๋งํฌ ์ฐธ์กฐ, ๋ฐ๋ก ์ ๋ฆฌํ ์์ !
โ https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods.html
1 - ๋ ๊ฑฐ์์ฝ๋
-
MemberController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
package com.springboot.member; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping(value = "/v1/members", produces = {MediaType.APPLICATION_JSON_VALUE}) public class MemberController { @PostMapping public String postMember(@RequestParam("email") String email, @RequestParam("name") String name, @RequestParam("phone") String phone) { System.out.println("# email: " + email); System.out.println("# name: " + name); System.out.println("# phone: " + phone); String response = "{\"" + "email\":\"" + email + "\"," + "\"name\":\"" + name + "\"," + "\"phone\":\"" + phone + "\"}"; return response; } @GetMapping("/{member-id}") public String getMember(@PathVariable("member-id")long memberId) { System.out.println("# memberId: " + memberId); // not implementation return null; } @GetMapping public String getMembers() { System.out.println("# get Members"); // not implementation return null; } }
1) postMember() ๋ฉ์๋๋ ํ์ ์ ๋ณด๋ฅผ ๋ฑ๋กํด ์ฃผ๋ ํธ๋ค๋ฌ ๋ฉ์๋
2) @PostMapping
ํด๋ผ์ด์ธํธ์ ์์ฒญ ๋ฐ์ดํฐ(request body)๋ฅผ ์๋ฒ์ ์์ฑํ ๋ ์ฌ์ฉํ๋ ์ ๋ํ ์ด์ , ํด๋ผ์ด์ธํธ ์ชฝ์์ ์์ฒญ ์ ์ก ์, HTTP Method ํ์ ์ ๋์ผํ๊ฒ ๋ง์ถฐ์ฃผ์ด์ผ ํจ.
3) @RequestParam
ํธ๋ค๋ฌ ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ ์ข ๋ฅ ์ค ํ๋, ํด๋ผ์ด์ธํธ ์ชฝ์์ ์ ์กํ๋ ์์ฒญ ๋ฐ์ดํฐ๋ฅผ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ(Query Parmeter ๋๋ Query String), ํผ ๋ฐ์ดํฐ(form-data), x-www-form-urlencoded ํ์์ผ๋ก ์ ์กํ๋ฉด ์ด๋ฅผ ์๋ฒ ์ชฝ์์ ์ ๋ฌ๋ฐ์ ๋ ์ฌ์ฉํ๋ ์ ๋ํ ์ด์
4) ํด๋ผ์ด์ธํธ ์ชฝ์์ JSON ํ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ก๋ฐ์์ผ ํ๊ธฐ ๋๋ฌธ์ ์๋ต ๋ฌธ์์ด์ JSON ํ์์ ๋ง๊ฒ ์์ฑ
-
Postman : postMember() ํธ๋ค๋ฌ ๋ฉ์๋ ๋งคํ URI๋ก์ ์์ฒญ/์๋ต ๋ชจ์ต
6) GetMapping
ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ๋ฆฌ์์ค๋ฅผ ์กฐํํ ๋ ์ฌ์ฉํ๋ ์ ๋ํ ์ด์
7) PathVariable :
ํธ๋ค๋ฌ ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ ์ข ๋ฅ ์ค ํ๋, ๊ดํธ ์์ ์ ๋ ฅํ ๋ฌธ์์ด ๊ฐ์
@GetMapping("/{member-id}")
์ฒ๋ผ ์ค๊ดํธ({ }) ์์ ๋ฌธ์์ด๊ณผ ๋์ผํด์ผ ํจ,๋ ๋ฌธ์์ด์ด ๋ค๋ฅด๋ค๋ฉด
MissingPathVariableException
์ด ๋ฐ์7) GetMember
getMember() ๋ฉ์๋๋ ํน์ ํ์์ ์ ๋ณด๋ฅผ ํด๋ผ์ด์ธํธ ์ชฝ์ ์ ๊ณตํ๋ ํธ๋ค๋ฌ ๋ฉ์๋
7) GetMembers
- ํ์ ๋ชฉ๋ก์ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๊ณตํ๋ ํธ๋ค๋ฌ ๋ฉ์๋
@GetMapping
์๋ ๋ณ๋์ URI๋ฅผ ์ง์ ํด์ฃผ์ง ์์๊ธฐ ๋๋ฌธ์ ํด๋์ค ๋ ๋ฒจ์ URI(โ/v1/membersโ)์ ๋งคํ
-
-
OrderController
โ๏ธ ์์ฒญ์ ํ์ํ ์ฃผ๋ฌธ(Order) ์ ๋ณด
- ํ์ ์๋ณ์: memberId
- ์ปคํผ ์๋ณ์: coffeeId
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
package com.springboot.order; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping(value = "/v1/orders", produces = MediaType.APPLICATION_JSON_VALUE) public class OrderController { @PostMapping public String postOrder(@RequestParam("memberId") long memberId, @RequestParam("coffeeId") long coffeeId) { System.out.println("# memberId: " + memberId); System.out.println("# coffeeId: " + coffeeId); String response = "{\\"" + "memberId\\":\\""+memberId+"\\"," + "\\"coffeeId\\":\\""+coffeeId+"\\"" + "}"; return response; } @GetMapping("/{order-id}") public String getOrder(@PathVariable("order-id") long orderId) { System.out.println("# orderId: " + orderId); // not implementation return null; } @GetMapping public String getOrders() { System.out.println("# get Orders"); // not implementation return null; } }
1) postOrder() ๋ฉ์๋๋ ํ์ ๊ณ ๊ฐ์ด ์ฃผ๋ฌธํ ์ปคํผ ์ฃผ๋ฌธ ์ ๋ณด๋ฅผ ๋ฑ๋กํด ์ฃผ๋ ํธ๋ค๋ฌ ๋ฉ์๋
- ๊ณ ๊ฐ์ด ์ฃผ๋ฌธํ ์ปคํผ์ ํ์ํ ์ฃผ๋ฌธ ์ ๋ณด๋ ์ด๋ค ๊ณ ๊ฐ์ด ์ด๋ค ์ปคํผ๋ฅผ ์ฃผ๋ฌธํ๋๋ ํ๋ ๊ฒ
- โ์ด๋ค ๊ณ ๊ฐโ์ ํด๋นํ๋ ์ ๋ณด๊ฐ ํ์ ์๋ณ์(memberId)
- โ์ด๋ค ์ปคํผโ์ ํด๋นํ๋ ์ ๋ณด๊ฐ ๋ฐ๋ก ์ปคํผ ์๋ณ์(coffeeId)
๊ฐ์ ํฌ์ธํธ
-
์ ์ผ ๋ถํธํ ๊ฒ response
โ JSON ๋ฌธ์์ด ์์์ ์ Map ๊ฐ์ฒด๋ก ๋์ฒดํ์ฌ ๊ฐ์ ๊ฐ๋ฅ
โ ๋ฆฌํด ๊ฐ์ ResponseEntity ๊ฐ์ฒด๋ก ๋ณ๊ฒฝ Ex) return new ResponseEntity<>(HttpStatus.OK);
-
@RequestParam
์ ๋ํ ์ด์ ์ ์ฌ์ฉํ ์์ฒญ ํ๋ผ๋ฏธํฐ ์์โ ์์ฒญ ํ๋ผ๋ฏธํฐ๋ค์ด ๋ค์ฏ ๊ฐ๋ผ๋ฉด ์ด ๋ค์ฏ ๊ฐ์ @RequestParameter๋ฅผ ์ฌ์ฉํด์ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ ฅ
2 - ResponseEntity ์ ์ฉ
๊ธฐ์กด 1์ ๋ ๊ฑฐ์ ์ฝ๋์์ ๊ฐ์ฅ ๋ถํธํ๋ ๋ถ๋ถ์ ๊ฐ์ ํ ์ฝ๋
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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);
}
}
@RequestMapping
์ โproducesโ ์ attribute ์ฌ๋ผ์ง.-
JSON ๋ฌธ์์ด์ ๊ฐ๋ฐ์๊ฐ ์ง์ ์์์ ์ผ๋ก ์์ฑํ๋ ๋ถ๋ถ์ด
Map
๊ฐ์ฒด๋ก ๋์ฒดโ ์ด๋ฅผ ํตํด
@RequestMapping
์ โproducesโ attribute๋ฅผ ์๋ต๊ฐ๋ฅํด์งโ Map ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๊ฒ ๋๋ฉด ๋ด๋ถ์ ์ผ๋ก โ์ด ๋ฐ์ดํฐ๋ JSON ํ์์ ์๋ต ๋ฐ์ดํฐ๋ก ๋ณํํด์ผ ๋๋๊ตฌ๋โ๋ผ๊ณ ์ดํดํ๊ณ JSON ํ์์ผ๋ก ์๋ ๋ณํํด์ค
- ๋ฆฌํด ๊ฐ์ผ๋ก JSON ๋ฌธ์์ด์ ๋ฆฌํดํ๋ ๋ถ๋ถ์ด ResponseEntity ๊ฐ์ฒด๋ฅผ ๋ฆฌํด
- new ResponseEntity<>(map, HttpStatus.CREATED);์ฒ๋ผ ResponseEntity ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฉด์ ์์ฑ์ ํ๋ผ๋ฏธํฐ๋ก ์๋ต ๋ฐ์ดํฐ(map)์ HTTP ์๋ต ์ํ๋ฅผ ํจ๊ป ์ ๋ฌ
- HTTP ์๋ต ์ํ๋ฅผ ๋ช ์์ ์ผ๋ก ํจ๊ป ์ ๋ฌํ๋ฉด ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์๋ฒ๊ฐ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์ง๋ฅผ ์ฝ๊ฒ ์ ์ ์์
- ResponseEntity ์ฐธ๊ณ ๋งํฌ : https://itvillage.tistory.com/44
- (4), (5) getMember(), getMembers() ํธ๋ค๋ฌ ๋ฉ์๋ ์ญ์ ResponseEntity ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ ๊ฑธ๋ก ์์ ํ์์ผ๋ฉฐ, HttpStatus.OK ์๋ต ์ํ๋ฅผ ์ ๋ฌํ๋๋ก ์์
-
Postman ๊ฒฐ๊ณผ -
postMember()
ํธ๋ค๋ฌ ๋ฉ์๋์ ์์ฒญ- POST Method ํ์์ ํด๋ผ์ด์ธํธ ์์ฒญ์ ๋ํ ์๋ต ์ํ๋
HttpStatus.OK
๋ณด๋ค๋HttpStatus.CREATED
๊ฐ ์กฐ๊ธ ๋ ์์ฐ์ค๋ฌ
- POST Method ํ์์ ํด๋ผ์ด์ธํธ ์์ฒญ์ ๋ํ ์๋ต ์ํ๋
HTTP ํค๋(Header)
- HTTP ๋ฉ์์ง(Messages)์ ๊ตฌ์ฑ ์์ ์ค ํ๋๋ก์จ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด๋ ์๋ฒ์ ์๋ต์ ํฌํจ๋์ด ๋ถ๊ฐ์ ์ธ ์ ๋ณด๋ฅผ HTTP ๋ฉ์์ง์ ํฌํจํ ์ ์๋๋ก ํจ.
- ๊ฐ๋ฐ์๊ฐ ํค๋๋ฅผ ๊ฑด๋๋ฆด ์ผ์ ๋ง์ด ์์ง๋ง, ์ฝ๋ ๋ ๋ฒจ์์ ์ง์ ์ปจํธ๋กค ํด์ผ ํ ๊ฒฝ์ฐ๊ฐ ์์
- Authorization
- ํด๋ผ์ด์ธํธ๊ฐ ์ ์ ํ ์๊ฒฉ ์ฆ๋ช ์ ๊ฐ์ง๊ณ ์๋์ง๋ฅผ ํ์ธํ๊ธฐ ์ํ ์ ๋ณด
- REST API ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฒฝ์ฐ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ๋ก๊ทธ์ธ(์ฌ์ฉ์ ID/๋น๋ฐ๋ฒํธ) ์ธ์ฆ์ ํต๊ณผํ ํด๋ผ์ด์ธํธ๋ค์ โAuthorizationโ ํค๋ ์ ๋ณด๋ฅผ ๊ธฐ์ค์ผ๋ก ์ธ์ฆ์ ํต๊ณผํ ํด๋ผ์ด์ธํธ๊ฐ ๋ง๋์ง ํ์ธํ๋ ์ ์ฐจ๋ฅผ ๊ฑฐ์นจ
- User-Agent
- ๋ฐ์คํฌํฑ, ๋ ธํธ๋ถ. ์ค๋งํธํฐ, ํ๋ธ๋ฆฟ ๋ฑ ๋ค์ด์ค๋ ์์ฒญ์ ๊ตฌ๋ถํด์ ์๋ต ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅด๊ฒ ๋ณด๋ด์ค์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ ๊ตฌ๋ถํด์ ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ค.
- ํนํ ๊ฐค๋ญ์ ํด๋ ๊ฐ์ ๊ฒฝ์ฐ๋ ํ๋ฉด ํฌ๊ธฐ๋ฅผ ๋ฏธ๋ฆฌ ์ฒดํฌํด์ ๋ด๋ณด๋ด์ผ ํจ.
HTTP Request ํค๋ ์ ๋ณด ์ป๊ธฐ
Spring MVC๋ ์๋์ ๊ฐ์ด HTTP ํค๋ ์ ๋ณด๋ฅผ ์ฝ์ด์ค๋ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ๊ณตํ๊ณ ์์
-
@RequestHeader๋ก ๊ฐ๋ณ ํค๋ ์ ๋ณด ๋ฐ๊ธฐ
-
@RequestHeader
๋ก ์ ์ฒด ํค๋ ์ ๋ณด ๋ฐ๊ธฐ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
import com.codestates.section3.week1.api.mvc_examples.common.Member; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Map; @RestController @RequestMapping(path = "/v1/members") public class MemberController { @PostMapping public ResponseEntity postMember(@RequestHeader Map<String, String> headers,//(1) @RequestParam("email") String email, @RequestParam("name") String name, @RequestParam("phone") String phone) { for (Map.Entry<String, String> entry : headers.entrySet()) { System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue()); } return new ResponseEntity<>(new Member(email, name, phone), HttpStatus.CREATED); } } //์ถ๋ ฅ๊ฒฐ๊ณผ key: user-agent, value: PostmanRuntime/7.29.0 key: accept, value: */* key: cache-control, value: no-cache key: postman-token, value: 6082ccc2-3195-4726-84ed-6a2009cbae95 key: host, value: localhost:8080 key: accept-encoding, value: gzip, deflate, br key: connection, value: keep-alive key: content-type, value: application/x-www-form-urlencoded key: content-length, value: 54
-
HttpServletRequest ๊ฐ์ฒด๋ก ํค๋์ ๋ณด ์ป๊ธฐ
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@RestController @RequestMapping(path = "/v1/orders") public class OrderController { @PostMapping public ResponseEntity postOrder(HttpServletRequest httpServletRequest,//(1) @RequestParam("memberId") long memberId, @RequestParam("coffeeId") long coffeeId) { System.out.println("user-agent: " + httpServletRequest.getHeader("user-agent")); return new ResponseEntity<>(new Order(memberId, coffeeId), HttpStatus.CREATED); } }
- ์ ์ ์
- ์ด ์ฝ๋๊ฐ ๋ค์ด์ค๋ ์๊ฐ http์นํ๊ฒฝ์ ์ข ์๋์ด๋ฒ๋ ค์ ๊ฐ๋ฅํ ํผํ๋ ๊ฒ์ด ์ข์
-
HttpEntity
๊ฐ์ฒด๋ก ํค๋ ์ ๋ณด ์ป๊ธฐ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
@RestController @RequestMapping(path = "/v1/coffees") public class CoffeeController{ @PostMapping public ResponseEntity postCoffee(@RequestHeader("user-agent") String userAgent,//(1) @RequestParam("korName") String korName, @RequestParam("engName") String engName, @RequestParam("price") int price) { System.out.println("user-agent: " + userAgent); return new ResponseEntity<>(new Coffee(korName, engName, price), HttpStatus.CREATED); } @GetMapping public ResponseEntity getCoffees(**HttpEntity httpEntity**) { for(Map.Entry<String, List<String>> entry : httpEntity.getHeaders().entrySet()){ System.out.println("key: " + entry.getKey() + ", " + "value: " + entry.getValue()); } System.out.println("host: " + httpEntity.getHeaders().getHost()); return null; } } //์ถ๋ ฅ๊ฒฐ key: user-agent, value: [PostmanRuntime/7.29.0] key: accept, value: [*/*] key: cache-control, value: [no-cache] key: postman-token, value: [368ad61b-b196-4f75-9222-b9a5af750414] key: host, value: [localhost:8080] key: accept-encoding, value: [gzip, deflate, br] key: connection, value: [keep-alive] host: localhost:8080
- HttpEntity๋ Request ํค๋์ ๋ฐ๋ ์ ๋ณด๋ฅผ ๋ํํ๊ณ ์์ผ๋ฉฐ, ์กฐ๊ธ ๋ ์ฝ๊ฒ ํค๋์ ๋ฐ๋์ ์ ๊ทผํ ์ ์๋ ๋ค์ํ API๋ฅผ ์ง์
HTTP Response ํค๋ ์ ๋ณด ์ถ๊ฐ
-
ResponseEntity
์HttpHeaders
๋ฅผ ์ด์ฉํด ํค๋ ์ ๋ณด ์ถ๊ฐ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@RestController @RequestMapping(path = "/v1/members") public class MemberController{ @PostMapping public ResponseEntity postMember(@RequestParam("email") String email, @RequestParam("name") String name, @RequestParam("phone") String phone) { // (1) ์์น ์ ๋ณด๋ฅผ ํค๋์ ์ถ๊ฐ HttpHeaders headers = new HttpHeaders(); headers.set("Client-Geo-Location", "Korea,Seoul"); return new ResponseEntity<>(new Member(email, name, phone), headers, HttpStatus.CREATED); } }
- HttpHeaders์ set() ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ํค๋ ์ ๋ณด๋ฅผ ์ถ๊ฐํ๋ ๊ฒ
-
HttpServletResponse
๊ฐ์ฒด๋ก ํค๋ ์ ๋ณด ์ถ๊ฐ1 2 3 4 5 6 7 8 9 10 11
@RestController @RequestMapping(path = "/v1/members") public class MemberController{ @GetMapping public ResponseEntity getMembers(HttpServletResponse response) { response.addHeader("Client-Geo-Location", "Korea,Seoul"); return null; } }
HttpServletRequest์ HttpServletResponse๋ ์ ์์ค(Low Level)์ ์๋ธ๋ฆฟ API๋ฅผ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ณต์กํ HTTP Request/Response๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๊ฐ๋ฅ
๋ฐ๋ฉด์ ResponseEntity๋ HttpHeaders๋ Spring์์ ์ง์ํ๋ ๊ณ ์์ค(High Level) API๋ก์จ ๊ฐ๋จํ HTTP Request/Response ์ฒ๋ฆฌ๋ฅผ ๋น ๋ฅด๊ฒ ์งํ๊ฐ๋ฅ
๋ณต์กํ ์ฒ๋ฆฌ๊ฐ ์๋๋ผ๋ฉด ์ฝ๋์ ๊ฐ๊ฒฐ์ฑ์ด๋ ์์ฐ์ฑ ๋ฉด์์ ๊ฐ๊ธ์ Spring์์ ์ง์ํ๋ ๊ณ ์์ค API๋ฅผ ์ฌ์ฉํ๊ธธ ๊ถ์ฅ
Rest Client
ํด๋ผ์ด์ธํธ(Client)์ ์๋ฒ(Server)์ ๊ด๊ณ
โ
-
์น ๋ธ๋ผ์ฐ์ ๋ ์น ์๋ฒ๋ก๋ถํฐ HTML ์ฝํ ์ธ ๋ฅผ ์ ๊ณต๋ฐ๋ ํด๋ผ์ด์ธํธ
์ฆ, ์๋ฒ ์ชฝ์ ๋ฆฌ์์ค(Resource, ์์)๋ฅผ ์ด์ฉํ๋ ์ธก์ด ํด๋ผ์ด์ธํธ
-
์๋ฒ๋ ๋ค๋ฅธ ์๋ฒ๋ก๋ถํฐ ๋ฆฌ์์ค๋ฅผ ์ ๊ณต๋ฐ์์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๊ต์ฅํ ๋ง์
โ ๋ํ์ ์ธ ์ : Frontend ์๋ฒ์ Backend ์๋ฒ์ ๊ด๊ณ
ํด๋ผ์ด์ธํธ์ ์๋ฒ์ ๊ด๊ณ๋ ์๋์
- ๋ธ๋ผ์ฐ์ ์ ์ฅ์์๋ Frontend์ ๋ฆฌ์์ค๋ฅผ ์ ๊ณต๋ฐ๊ธฐ ๋๋ฌธ์ ๋ช ๋ฐฑํ ํด๋ผ์ด์ธํธ
- Frontend๊ฐ Backend์ ๋์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ฒ ๋๋ค๋ฉด ํด๋ผ์ด์ธํธ๊ฐ ๋จ
- ๋ฐฑ์๋ ์๋ฒ
- Backend ์๋ฒ ๋ด๋ถ์ ์ผ๋ก ๋ค๋ฅธ ์๋ฒ์๊ฒ HTTP ์์ฒญ์ ์ ์กํด์ ์์ ์ ๋๋์ด ์ฒ๋ฆฌํ๋ ๊ฒฝ์ฐ๊ฐ ๊ต์ฅํ ๋ง์.
- backend A๊ฐ Frontend์๊ฒ ๋ฆฌ์์ค๋ฅผ ์ ๊ณตํด ์ฃผ๊ธฐ ๋๋ฌธ์ ์๋ฒ ์ญํ ์ ํ์ง๋ง Backend A์์ Backend B์ ๋ฆฌ์์ค๋ฅผ ๋ค์ ์ด์ฉํ๊ธฐ ๋๋ฌธ์ Backend B์ ๋ฆฌ์์ค๋ฅผ ์ด์ฉํ ๋๋ Backend A๋ ํด๋ผ์ด์ธํธ์ ์ญํ ์ ํ๊ฒ ๋จ.
- ์ด๋ค ์๋ฒ๊ฐ HTTP ํต์ ์ ํตํด์ ๋ค๋ฅธ ์๋ฒ์ ๋ฆฌ์์ค๋ฅผ ์ด์ฉํ๋ค๋ฉด ๊ทธ๋๋งํผ์ ํด๋ผ์ด์ธํธ์ ์ญํ ์ ํ๋ ๊ฒ์ ๊ธฐ์ตํ๊ธฐ
Rest Client๋?
- Rest API ์๋ฒ์ HTTP ์์ฒญ์ ๋ณด๋ผ ์ ์๋ ํด๋ผ์ด์ธํธ ํด ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์๋ฏธ
- Postman์ UI๊ฐ ๊ฐ์ถฐ์ง Rest Client๋ผ ๋ณผ ์ ์์
- RestTemplate
- Spring์์ ์ ๊ณตํ๋ RestClient API
- HTTP Client ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋๋ฅผ ์ด์ฉํด์ ์๊ฒฉ์ง์ ์๋ ๋ค๋ฅธ Backend ์๋ฒ์ HTTP ์์ฒญ์ ๋ณด๋ผ ์ ์์
- Rest ์๋ ํฌ์ธํธ ์ง์ , ํค๋ ์ค์ , ํ๋ผ๋ฏธํฐ ๋ฐ body ์ค์ ์ ํ ์ค์ ์ฝ๋๋ก ์์ฝ๊ฒ ์ ์ก ๊ฐ๋ฅ
- java.net.HttpURLConnection, Apache HttpComponents, OkHttp 3, Netty ๊ฐ์ HTTP Client ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋๋ฅผ ์ ์ฐํ๊ฒ ์ฌ์ฉ ๊ฐ๋ฅ
Rest Template
-
๊ฐ์ฒด ์์ฑ
1 2 3 4 5 6 7 8
public class RestClientExample01 { public static void main(String[] args) { // (1) ๊ฐ์ฒด ์์ฑ RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); } }
RestTemplate
์ ์์ฑ์ ํ๋ผ๋ฏธํฐ๋ก HTTP Client ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์ ๋ฌHttpComponentsClientHttpRequestFactory
ํด๋์ค๋ฅผ ํตํด Apache HttpComponents๋ฅผ ์ ๋ฌ- Apache HttpComponents๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ builde.gradle์ dependencies ํญ๋ชฉ์ ์๋์ ๊ฐ์ด ์์กด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํด์ผ ํจ
1 2 3 4 5 6
dependencies { ... ... implementation 'org.apache.httpcomponents:httpclient' }
-
URI ์์ฑ
๊ฐ์ฒด ์์ฑ ๋์๋ค๋ฉด HTTP Request๋ฅผ ์ ์กํ Rest ์๋ํฌ์ธํธ์ URI๋ฅผ ์ง์ ํด ์ฃผ์ด์ผ ํจ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; public class RestClientExample01 { public static void main(String[] args) { // (1) ๊ฐ์ฒด ์์ฑ RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); // (2) URI ์์ฑ UriComponents uriComponents = UriComponentsBuilder .newInstance() .scheme("http") .host("worldtimeapi.org") // .port(80) .path("/api/timezone/{continents}/{city}") .encode() .build(); URI uri = uriComponents.expand("Asia", "Seoul").toUri(); } }
- UriComponentsBuilder ํด๋์ค์์ ์ ๊ณตํ๋ API ๋ฉ์๋์ ๊ธฐ๋ฅ
newInstance()
UriComponentsBuilder
๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
scheme()
- URI์ scheme์ ์ค์ ํฉ๋๋ค.
host()
- ํธ์คํธ ์ ๋ณด๋ฅผ ์ ๋ ฅํฉ๋๋ค.
port()
- ๋ํดํธ ๊ฐ์ 80์ด๋ฏ๋ก 80 ํฌํธ๋ฅผ ์ฌ์ฉํ๋ ํธ์คํธ๋ผ๋ฉด ์๋ต ๊ฐ๋ฅ
path()
- URI์ ๊ฒฝ๋ก(path)๋ฅผ ์ ๋ ฅํฉ๋๋ค.
- [์ฝ๋ 3-18]์์๋ URI์ path์์ {continents}, {city}์ ๋ ๊ฐ์ ํ ํ๋ฆฟ ๋ณ์๋ฅผ ์ฌ์ฉํ๊ณ ์์
- ๋ ๊ฐ์ ํ
ํ๋ฆฟ ๋ณ์๋
uriComponents.expand("Asia", "Seoul").toUri();
์์expand()
๋ฉ์๋ ํ๋ผ๋ฏธํฐ์ ๋ฌธ์์ด๋ก ์ฑ์์ง - ์ฆ, ๋น๋ ํ์์ {continents}๋ โAsiaโ, {city}๋ โSeoulโ๋ก ๋ณํ๋จ
encode()
- URI์ ์ฌ์ฉ๋ ํ ํ๋ฆฟ ๋ณ์๋ค์ ์ธ์ฝ๋ฉํด์ค๋๋ค.
- ์ฌ๊ธฐ์ ์ธ์ฝ๋ฉ์ ์๋ฏธ๋ non-ASCII ๋ฌธ์์ URI์ ์ ์ ํ์ง ์์ ๋ฌธ์๋ฅผ Percent Encoding ํ๋ค๋ ์๋ฏธ
build()
UriComponents
๊ฐ์ฒด๋ฅผ ์์ฑ
UriComponents
์ ์ฌ์ฉ๋ API ๋ฉ์๋expand()
- ํ๋ผ๋ฏธํฐ๋ก ์ ๋ ฅํ ๊ฐ์ URI ํ ํ๋ฆฟ ๋ณ์์ ๊ฐ์ผ๋ก ๋์ฒด
toUri()
URI
๊ฐ์ฒด๋ฅผ ์์ฑ
- UriComponentsBuilder ํด๋์ค์์ ์ ๊ณตํ๋ API ๋ฉ์๋์ ๊ธฐ๋ฅ
-
์์ฒญ ์ ์ก
-
getForObject()
๋ฅผ ์ด์ฉํ ๋ฌธ์์ด ์๋ต ๋ฐ์ดํฐ ์ ๋ฌ๋ฐ๊ธฐ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
public class RestClientExample01 { public static void main(String[] args) { // (1) ๊ฐ์ฒด ์์ฑ RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); // (2) URI ์์ฑ UriComponents uriComponents = UriComponentsBuilder .newInstance() .scheme("http") .host("worldtimeapi.org") // .port(80) .path("/api/timezone/{continents}/{city}") .encode() .build(); URI uri = uriComponents.expand("Asia", "Seoul").toUri(); // (3) Request ์ ์ก String result = restTemplate.getForObject(uri, String.class); System.out.println(result); } }
getForObject(URI uri, Class<T> responseType)
-
๊ธฐ๋ฅ ์ค๋ช
getForObject()
๋ฉ์๋๋ HTTP Get ์์ฒญ์ ํตํด ์๋ฒ์ ๋ฆฌ์์ค๋ฅผ ์กฐํ
-
ํ๋ผ๋ฏธํฐ ์ค๋ช
URI uri
- Request๋ฅผ ์ ์กํ ์๋ํฌ์ธํธ์ URI ๊ฐ์ฒด๋ฅผ ์ง์
Class<T> responseType
- ์๋ต์ผ๋ก ์ ๋ฌ๋ฐ์ ํด๋์ค์ ํ์ ์ ์ง์
- ์ฝ๋ 3-19์์๋ ์๋ต ๋ฐ์ดํฐ๋ฅผ ๋ฌธ์์ด๋ก ๋ฐ์ ์ ์๋๋ก
String.class
๋ก ์ง์
-
์คํ๊ฒฐ๊ณผ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
abbreviation: KST client_ip: 125.129.191.130 datetime: 2022-04-28T09:49:44.492621+09:00 day_of_week: 4 day_of_year: 118 dst: false dst_from: dst_offset: 0 dst_until: raw_offset: 32400 timezone: Asia/Seoul unixtime: 1651106984 utc_datetime: 2022-04-28T00:49:44.492621+00:00 utc_offset: +09:00 week_number: 17
-
-
getForObject()
๋ฅผ ์ด์ฉํ ์ปค์คํ ํด๋์ค ํ์ ์ผ๋ก ์ํ๋ ์ ๋ณด๋ง ์๋ต์ผ๋ก ์ ๋ฌ๋ฐ๊ธฐ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
public class RestClientExample02 { public static void main(String[] args) { // (1) ๊ฐ์ฒด ์์ฑ RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); // (2) URI ์์ฑ UriComponents uriComponents = UriComponentsBuilder .newInstance() .scheme("http") .host("worldtimeapi.org") // .port(80) .path("/api/timezone/{continents}/{city}") .encode() .build(); URI uri = uriComponents.expand("Asia", "Seoul").toUri(); // (3) Request ์ ์ก. WorldTime ํด๋์ค๋ก ์๋ต ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ๋ฐ๋๋ค. WorldTime worldTime = restTemplate.getForObject(uri, WorldTime.class); System.out.println("# datatime: " + worldTime.getDatetime()); System.out.println("# timezone: " + worldTime.getTimezone()); System.out.println("# day_of_week: " + worldTime.getDay_of_week()); } }
[์๋ต๋ฐ์ดํฐ ๋ฐ๊ธฐ ์ํ
WorldTime
ํด๋์ค]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public class WorldTime { private String datetime; private String timezone; private int day_of_week; public String getDatetime() { return datetime; } public String getTimezone() { return timezone; } public int getDay_of_week() { return day_of_week; } }
[์คํ๊ฒฐ๊ณผ]
1 2 3
# datatime: 2021-10-10T11:39:15.099207+09:00 # timezone: Asia/Seoul # day_of_week: 4
-
getForEntity()
๋ฅผ ์ฌ์ฉํ Response Body(๋ฐ๋, ์ฝํ ์ธ ) + Header(ํค๋) ์ ๋ณด ์ ๋ฌ๋ฐ๊ธฐ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
public class RestClientExample02 { public static void main(String[] args) { // (1) ๊ฐ์ฒด ์์ฑ RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); // (2) URI ์์ฑ UriComponents uriComponents = UriComponentsBuilder .newInstance() .scheme("http") .host("worldtimeapi.org") // .port(80) .path("/api/timezone/{continents}/{city}") .encode() .build(); URI uri = uriComponents.expand("Asia", "Seoul").toUri(); // (3) Request ์ ์ก. ResponseEntity๋ก ํค๋์ ๋ฐ๋ ์ ๋ณด๋ฅผ ๋ชจ๋ ์ ๋ฌ๋ฐ์ ์ ์๋ค. ResponseEntity<WorldTime> response = restTemplate.getForEntity(uri, WorldTime.class); System.out.println("# datatime: " + response.getBody().getDatetime()); System.out.println("# timezone: " + response.getBody().getTimezone()()); System.out.println("# day_of_week: " + response.getBody().getDay_of_week()); System.out.println("# HTTP Status Code: " + response.getStatusCode()); System.out.println("# HTTP Status Value: " + response.getStatusCodeValue()); System.out.println("# Content Type: " + response.getHeaders().getContentType()); System.out.println(response.getHeaders().entrySet()); } }
getForEntity()
๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ํค๋ ์ ๋ณด์ ๋ฐ๋ ์ ๋ณด๋ฅผ ๋ชจ๋ ์ ๋ฌ๋ฐ๊ณ ์์ -
exchange()
๋ฅผ ์ฌ์ฉํ ์๋ต ๋ฐ์ดํฐ ๋ฐ๊ธฐ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
public class RestClientExample03 { public static void main(String[] args) { // (1) ๊ฐ์ฒด ์์ฑ RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); // (2) URI ์์ฑ UriComponents uriComponents = UriComponentsBuilder .newInstance() .scheme("http") .host("worldtimeapi.org") // .port(80) .path("/api/timezone/{continents}/{city}") .encode() .build(); URI uri = uriComponents.expand("Asia", "Seoul").toUri(); // (3) Request ์ ์ก. exchange()๋ฅผ ์ฌ์ฉํ ์ผ๋ฐํ ๋ ๋ฐฉ์ ResponseEntity<WorldTime> response = restTemplate.exchange(uri, HttpMethod.GET, null, WorldTime.class); System.out.println("# datatime: " + response.getBody().getDatetime()); System.out.println("# timezone: " + response.getBody().getTimezone()); System.out.println("# day_of_week: " + response.getBody().getDay_of_week()); System.out.println("# HTTP Status Code: " + response.getStatusCode()); System.out.println("# HTTP Status Value: " + response.getStatusCodeValue()); } }
exchange(URI uri, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType)
- ๊ธฐ๋ฅ ์ค๋ช
getForObject()
,getForEntity()
๋ฑ๊ณผ ๋ฌ๋ฆฌexchange()
๋ฉ์๋๋ HTTP Method, RequestEntity, ResponseEntity๋ฅผ ์ง์ ์ง์ ํด์ HTTP Request๋ฅผ ์ ์กํ ์ ์๋ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๋ฐฉ์
- ํ๋ผ๋ฏธํฐ ์ค๋ช
URI url
- Request๋ฅผ ์ ์กํ ์๋ํฌ์ธํธ์ URI ๊ฐ์ฒด๋ฅผ ์ง์
HttpMethod method
- HTTP Method ํ์ ์ ์ง์
HttpEntity<?> requestEntity
- HttpEntity ๊ฐ์ฒด๋ฅผ ์ง์
- HttpEntity ๊ฐ์ฒด๋ฅผ ํตํด ํค๋ ๋ฐ ๋ฐ๋, ํ๋ผ๋ฏธํฐ ๋ฑ์ ์ค์ ๊ฐ๋ฅ
Class<T> responseType
- ์๋ต์ผ๋ก ์ ๋ฌ๋ฐ์ ํด๋์ค์ ํ์ ์ ์ง์
- ๊ธฐ๋ฅ ์ค๋ช
-
### comment
๋ฐฐ์ด๋ฏ ์๋ฐฐ์ด๋ฏ ์์ํ ๋๋, ์ด๊ฑฐ ์๋๋ฐ ์ถ๋ค๊ฐ๋ ๋ชจ๋ฅด๊ฒ ๋คโฆ
๐ ๊ณต์ง
Leave a comment