๐ŸŒฟSpring

Spring BOOT์˜ @RestController: HTTP ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต ์ฒ˜๋ฆฌ ๊ณผ์ •

์†Œ์˜ ๐Ÿ€ 2025. 3. 4. 00:29

๐ŸŽฏ ์ฃผ์ œ

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 ํ˜•ํƒœ๋กœ ๋„ฃ๊ณ ์ž ํ•˜๋ฉด

  1. MappingJackson2HttpMessageConverter๊ฐ€ ํ˜ธ์ถœ๋˜์–ด
  2. ์ปจ๋ฒ„ํ„ฐ๊ฐ€ ๋ฉ”์„œ๋“œ ๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋””์— ์“ธ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด canWrite() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
    • ์ •ํ™•ํžˆ๋Š” ๋Œ€์ƒ ํด๋ž˜์Šค ํƒ€์ž…์„ ์ง€์›ํ•˜๋Š”์ง€, ํด๋ผ์ด์–ธํŠธ๊ฐ€ Accept ํ—ค๋”๋กœ ์›ํ•˜๋Š” ๋ฏธ๋””์–ด ํƒ€์ž…์„ ์ง€์›ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  3. canWrite() ์กฐ๊ฑด์„ ๋งŒ์กฑํ•  ๊ฒฝ์šฐ write() ๋ฉ”์„œ๋“œ๋กœ HTTP ์‘๋‹ต ๋ฉ”์‹œ์ง€ ๋‚ด ๋ฐ”๋””๋ฅผ json ํ˜•ํƒœ๋กœ ์ƒ์„ฑํ•œ๋‹ค.

์ •๋ฆฌํ•˜์ž๋ฉด,
@ResponseBody ์–ด๋…ธํ…Œ์ด์…˜์„ ์ ์šฉํ•˜๋ฉด ์‘๋‹ต ์ฒ˜๋ฆฌ ๊ณผ์ •์—์„œ
์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ์—์„œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋•Œ HttpMessageConverter๊ฐ€ ๋™์ž‘ํ•˜์—ฌ
๊ฐ์ฒด๋ฅผ json์œผ๋กœ ๋ณ€ํ™˜(์ง๋ ฌํ™”)ํ•˜์—ฌ HTTP ์‘๋‹ต ๋ณธ๋ฌธ์— json์„ ๋„ฃ๋Š”๋‹ค.


๐Ÿ”„๏ธ RestController HTTP ์š”์ฒญ ์ฒ˜๋ฆฌ ๋ฐฉ์‹

@RestController๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ → ์ปจํŠธ๋กค๋Ÿฌ ์ฒ˜๋ฆฌ → ์‘๋‹ต ๋ณ€ํ™˜ ๊ณผ์ •์ด ์ž๋™์œผ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.
์ด ๊ณผ์ •์—์„œ DispatcherServlet, HandlerMapping, HttpMessageConverter ๋“ฑ์ด ํ•ต์‹ฌ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

@RestController๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ

๊ทธ๋ฆผ ์† ๊ณผ์ •๊ณผ ์ˆซ์ž๊ฐ€ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜์ง€๋Š” ์•Š๋Š” ์  ์ฐธ๊ณ  ๋ฐ”๋ž€๋‹ค.

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ HTTP ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.
    • ์˜ˆ์‹œ) ํด๋ผ์ด์–ธํŠธsms GET /users/1๊ณผ ๊ฐ™์€ ํŠน์ • URI๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
    • ์ด๋•Œ Accep:application/json์„ ์ง€์ •ํ•˜๋ฉด json ํ˜•์‹์˜ ์‘๋‹ต์„ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  2. ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์„œ๋ฒ„๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด DispatcherServlet์ด ๋ฐ›๋Š”๋‹ค.
  3. DispatcherServlet์ด ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” HandlerMapping์„ ํ†ตํ•ด ์ ์ ˆํ•œ ํ•ธ๋“ค๋Ÿฌ(์ปจํŠธ๋กค๋Ÿฌ)๋ฅผ ์กฐํšŒํ•œ๋‹ค.
  4. HandlerMapping์ด ์š”์ฒญ URL์— ์ ํ•ฉํ•œ ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐพ๋Š”๋‹ค.
    • GET /users/1์— ๋Œ€ํ•ด UserController์˜ getUser() ๋ฉ”์„œ๋“œ๋ฅผ ์ฐพ๋Š”๋‹ค.
  5. HandlerAdapter๊ฐ€ ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
    • UserController์˜ getUser() ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
  6. ๋ฉ”์„œ๋“œ ์‹คํ–‰ ํ›„ ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.
    • RequestMappingHandlerAdapter๊ฐ€ @RestController๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ํ›„ User ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.
  7. HttpMessageConverter๊ฐ€ ๊ฐ์ฒด๋ฅผ json ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.
    • MappingJackson2HttpMessageConverter๊ฐ€ User ๊ฐ์ฒด๋ฅผ json ํ˜•์‹์œผ๋กœ ์ง๋ ฌํ™” ๋ณ€ํ™˜ํ•˜์—ฌ ์‘๋‹ต ๋ณธ๋ฌธ์— ์ž‘์„ฑํ•œ๋‹ค.
  8. 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

 

๋ฐ˜์‘ํ˜•