๐ฏ ์ฃผ์
Spring Boot์์ @RestController๋ก ๋ค์ด์จ HTTP ์์ฒญ์ด ์ฒ๋ฆฌ๋์ด ์๋ต์ผ๋ก ๋ณํ๋๋ ์ ์ฒด ๊ณผ์ + HTTP ๋ฉ์์ง ์ปจ๋ฒํฐ๊ฐ ๋์ํ๋ ์์ ๊ณผ ์ญํ
๐ @RestController
Controller-Service-Repository ํจํด์์
์ปจํธ๋กค๋ฌ๋ ์ฌ์ฉ์ ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ , ์ ์ ํ ์๋ต์ ๋ฐํํ๋ ์ญํ ์ ํ๋ค.
์ปจํธ๋กค๋ฌ๋ HTTP ์์ฒญ์ ์์ ํ๊ณ , ์๋น์ค ๊ณ์ธต์ ๋น์ฆ๋์ค ๋ก์ง ์ํ์ ์์ฒญํ ํ,
ํด๋ผ์ด์ธํธ์๊ฒ ์ ์ ํ ๋ทฐ(View) ๋๋ ๋ฐ์ดํฐ(JSON ๋ฑ) ์๋ต์ ๋ฐํํ๋ค.
์ด๋ฌํ ์ญํ ์ ์ํํ๊ธฐ ์ํด, ์ปจํธ๋กค๋ฌ ํด๋์ค๋ @Controller ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ์ ์ํ ์ ์๋ค.
@Controller
์ด๋
ธํ
์ด์
์ ์ฃผ๋ก View๋ฅผ ๋ฐํํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
๋ฐํ๋ ๊ฐ์ ๋ทฐ์ ์ด๋ฆ์ผ๋ก ํด์๋๋ฉฐ, ํด๋น ๋ทฐ๊ฐ ๋ ๋๋ง๋๋ค.
๐ @Controller ์์
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public String getUser(@PathVariable Long id, Model model) {
// ๋ก์ง ์ฒ๋ฆฌ ํ model์ ๋ฐ์ดํฐ ์ถ๊ฐ
model.addAttribute("user", "ํ๊ธธ๋");
return "userView"; // ๋ทฐ ์ด๋ฆ ๋ฐํ
}
}
์ ์ฝ๋์์ ์ปจํธ๋กค๋ฌ๋ GET /users/{id} ์์ฒญ์ด ๋ค์ด์ค๋ฉด userView.html๊ณผ ๊ฐ์ ํน์ ํ ๋ทฐ๋ฅผ ๋ณด์ฌ์ค ๊ฒ์ด๋ค.
@RestController
๋ ๋ทฐ๊ฐ ์๋๋ผ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ ๋ ์ฌ์ฉํ๋ค.
๊ทธ๋ฌ๋ฉด ๋ฐํ ๊ฐ์ ๋ทฐ๊ฐ ์๋๋ผ HTTP ์๋ต ๋ฐ๋(๋ณธ๋ฌธ)์ ์ง์ ๋ฃ์ด์ผ ํ๋ค.
@RestController
๋ @Controller
์
์ปจํธ๋กค๋ฌ ๋ฉ์๋ ๋ฐํ ๊ฐ์ ๋ฐ๋ก HTTP ์๋ต ๋ฐ๋๋ก ์ง๋ ฌํํ๋ @ResponseBody
์ด๋
ธํ
์ด์
์ ์ถ๊ฐํ ๊ฒ์ผ๋ก RESTful API๋ฅผ ๋ง๋๋ ํต์ฌ ์ด๋
ธํ
์ด์
์ด๋ค.
@RestController = @Controller + @ResponseBody
๐ HttpMessageConverter
@ResonponseBody
์ด๋
ธํ
์ด์
์ด ์ปจํธ๋กค๋ฌ ๋ฉ์๋์์ ๋ฐํ๋๋ ๊ฐ์ฒด๋ฅผ HTTP ์๋ต ๋ฐ๋์ ์ฐ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค๊ณ ํ๋ค.
๊ทธ๋ฆฌ๊ณ RESTful API์์๋ ํํ json ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐํํด์ผ ํ๋ค.
์ด๋ Java ๊ฐ์ฒด๋ฅผ json ํํ๋ก ๋ณํํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๊ฒ์ด HttpMessageConverter์ด๋ค.@Controller
๋ง ์๋ ๊ฒฝ์ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ทฐ๋ฅผ ๋ฐํํ๊ธฐ ์ํด ViewResolver๊ฐ ๋์ํ์ง๋ง,@ResponseBody
๋ฅผ ์ฌ์ฉํ๋ฉด ViewResolver๊ฐ ์๋ HttpMessageConverter๊ฐ ์๋ต์ ์ฒ๋ฆฌํ๊ฒ ๋๋ค.
StringHttpMessageConverter๋ MappingJackson2HttpMessageConverter ๋ฑ
๋ค์ํ HttpMessageConverter๊ฐ ์กด์ฌํ๋๋ฐ ํด๋ผ์ด์ธํธ์ HTTP Accept ํค๋์ String, Object ๋ฑ ์ปจํธ๋กค๋ฌ ๋ฉ์๋์ ๋ฐํ ํ์
์ ์กฐํฉํด ์ ์ ํ ์ปจ๋ฒํฐ๊ฐ ์ ํ๋๋ค.
HttpMessageConverter ์ธํฐํ์ด์ค ๋ด ์ผ๋ถ ๋ฉ์๋
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
default List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
return (canRead(clazz, null) || canWrite(clazz, null) ?
getSupportedMediaTypes() : Collections.emptyList());
}
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
์ปจํธ๋กค๋ฌ์์ @ResponseBody
๋ฅผ ์ด์ฉํด HTTP ์๋ต ๋ฐ๋์ ๊ฐ์ฒด๋ฅผ json ํํ๋ก ๋ฃ๊ณ ์ ํ๋ฉด
- MappingJackson2HttpMessageConverter๊ฐ ํธ์ถ๋์ด
- ์ปจ๋ฒํฐ๊ฐ ๋ฉ์๋ ๋ฐํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋์ ์ธ ์ ์๋์ง ํ์ธํ๊ธฐ ์ํด
canWrite()
๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.- ์ ํํ๋ ๋์ ํด๋์ค ํ์ ์ ์ง์ํ๋์ง, ํด๋ผ์ด์ธํธ๊ฐ Accept ํค๋๋ก ์ํ๋ ๋ฏธ๋์ด ํ์ ์ ์ง์ํ๋์ง ํ์ธํ๋ค.
canWrite()
์กฐ๊ฑด์ ๋ง์กฑํ ๊ฒฝ์ฐwrite()
๋ฉ์๋๋ก HTTP ์๋ต ๋ฉ์์ง ๋ด ๋ฐ๋๋ฅผ json ํํ๋ก ์์ฑํ๋ค.
์ ๋ฆฌํ์๋ฉด,@ResponseBody
์ด๋
ธํ
์ด์
์ ์ ์ฉํ๋ฉด ์๋ต ์ฒ๋ฆฌ ๊ณผ์ ์์
์ปจํธ๋กค๋ฌ ๋ฉ์๋์์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ ๋ HttpMessageConverter๊ฐ ๋์ํ์ฌ
๊ฐ์ฒด๋ฅผ json์ผ๋ก ๋ณํ(์ง๋ ฌํ)ํ์ฌ HTTP ์๋ต ๋ณธ๋ฌธ์ json์ ๋ฃ๋๋ค.
๐๏ธ RestController HTTP ์์ฒญ ์ฒ๋ฆฌ ๋ฐฉ์
@RestController๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋ผ์ด์ธํธ ์์ฒญ → ์ปจํธ๋กค๋ฌ ์ฒ๋ฆฌ → ์๋ต ๋ณํ ๊ณผ์ ์ด ์๋์ผ๋ก ์ด๋ฃจ์ด์ง๋ค.
์ด ๊ณผ์ ์์ DispatcherServlet, HandlerMapping, HttpMessageConverter ๋ฑ์ด ํต์ฌ์ ์ผ๋ก ๋์ํ๋ค.
@RestController๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ
๊ทธ๋ฆผ ์ ๊ณผ์ ๊ณผ ์ซ์๊ฐ ์ ํํ ์ผ์นํ์ง๋ ์๋ ์ ์ฐธ๊ณ ๋ฐ๋๋ค.
- ํด๋ผ์ด์ธํธ๊ฐ HTTP ์์ฒญ์ ๋ณด๋ธ๋ค.
- ์์) ํด๋ผ์ด์ธํธsms
GET /users/1
๊ณผ ๊ฐ์ ํน์ URI๋ก ์์ฒญ์ ๋ณด๋ผ ์ ์๋ค. - ์ด๋
Accep:application/json
์ ์ง์ ํ๋ฉด json ํ์์ ์๋ต์ ์๊ตฌํ๋ ๊ฒ์ด๋ค.
- ์์) ํด๋ผ์ด์ธํธsms
- ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์๋ฒ๋ก ์์ฒญ์ด ๋ค์ด์ค๋ฉด DispatcherServlet์ด ๋ฐ๋๋ค.
- DispatcherServlet์ด ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์๋ HandlerMapping์ ํตํด ์ ์ ํ ํธ๋ค๋ฌ(์ปจํธ๋กค๋ฌ)๋ฅผ ์กฐํํ๋ค.
- HandlerMapping์ด ์์ฒญ URL์ ์ ํฉํ ์ปจํธ๋กค๋ฌ ๋ฉ์๋๋ฅผ ์ฐพ๋๋ค.
GET /users/1
์ ๋ํด UserController์ getUser() ๋ฉ์๋๋ฅผ ์ฐพ๋๋ค.
- HandlerAdapter๊ฐ ์ปจํธ๋กค๋ฌ ๋ฉ์๋๋ฅผ ์คํํ๋ค.
- UserController์ getUser() ๋ฉ์๋๋ฅผ ์คํํ๋ค.
- ๋ฉ์๋ ์คํ ํ ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋ค.
- RequestMappingHandlerAdapter๊ฐ @RestController๋ฅผ ์ฒ๋ฆฌํ์ฌ ๋ฉ์๋ ์คํ ํ User ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋ค.
- HttpMessageConverter๊ฐ ๊ฐ์ฒด๋ฅผ json ํ์์ผ๋ก ๋ณํํ๋ค.
- MappingJackson2HttpMessageConverter๊ฐ User ๊ฐ์ฒด๋ฅผ json ํ์์ผ๋ก ์ง๋ ฌํ ๋ณํํ์ฌ ์๋ต ๋ณธ๋ฌธ์ ์์ฑํ๋ค.
- HTTP ์๋ต์ด ์์ฑ๋๊ณ DispatcherServlet์ด ํด๋ผ์ด์ธํธ์๊ฒ ๋ฐํํ๋ค.
์ด ์ฌ์ง์ @Controller๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ง๋ง ์ดํดํ๊ธฐ ์ฌ์ด ์ฌ์ง์ด๋ผ ํจ๊ป ์ฒจ๋ถํ๋ค.
View Resolver ์๋ฆฌ์ HttpMessageConverter๋ฅผ ๋์
ํ๋ฉด @RestController์ ๋์ ๊ณผ์ ์ด๋ผ๊ณ ๋ณผ ์ ์๋ค.
์ถ์ฒ: DyungE_100์ ๋ธ๋ก๊ทธ
์ฐธ๊ณ ์๋ฃ
https://velog.io/@dyunge_100/Spring-Controller%EC%99%80-RestController%EC%9D%98-%EC%B0%A8%EC%9D%B4
https://mangkyu.tistory.com/49
https://cheershennah.tistory.com/179
https://yeonyeon.tistory.com/151
https://velog.io/@qkrmekem/Spring-HTTP-%EB%A9%94%EC%84%B8%EC%A7%80-%EC%BB%A8%EB%B2%84%ED%84%B0
https://jaimemin.tistory.com/1823
https://velog.io/@dyunge_100/Spring-Controller%EC%99%80-RestController%EC%9D%98-%EC%B0%A8%EC%9D%B4