02.MVC

Spring MVC Framework

MVC Pattern

Model

  • View ์— ์ถœ๋ ฅํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” ์—ญํ• (View ๋Š” ํ™”๋ฉด ๋ Œ๋”๋ง์—๋งŒ ์ง‘์ค‘)

View

  • Model ์— ๋‹ด๊ฒจ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ™”๋ฉด(HTML)์„ ๊ทธ๋ฆฌ๋Š” ์—ญํ• 

Controller

  • HTTP ์š”์ฒญ์„ ๋ฐ›์•„์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์‹คํ–‰ํ•˜๋Š” ์—ญํ• 

  • ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ด์„œ Model ์„ ํ†ตํ•ด View ๋กœ ์ „๋‹ฌ

์Šคํ”„๋ง MVC ์ „์ฒด ๊ตฌ์กฐ

Result

DispacherServlet

  • DispatcherServlet โžœ FrameworkServlet โžœ HttpServletBean โžœ HttpServlet

  • ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” DispacherServlet ์„ ์„œ๋ธ”๋ฆฟ์œผ๋กœ ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ , ๋ชจ๋“  ๊ฒฝ๋กœ(urlPatterns="/")๋ฅผ ๋งคํ•‘

  • DispacherServlet.doDispatch() ์ฐธ๊ณ 

  1. ํ•ธ๋“ค๋Ÿฌ ์กฐํšŒ : ํ•ธ๋“ค๋Ÿฌ ๋งคํ•‘์„ ํ†ตํ•ด ์š”์ฒญ URL์— ๋งคํ•‘๋œ ํ•ธ๋“ค๋Ÿฌ(์ปจํŠธ๋กค๋Ÿฌ)๋ฅผ ์กฐํšŒ

  2. ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ ์กฐํšŒ : ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ๋ฅผ ์กฐํšŒ

  3. ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ ์‹คํ–‰ : ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ๋ฅผ ์‹คํ–‰

  4. ํ•ธ๋“ค๋Ÿฌ ์‹คํ–‰ : ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ๊ฐ€ ์‹ค์ œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‹คํ–‰

  5. ModelAndView ๋ฐ˜ํ™˜ : ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ๋Š” ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ •๋ณด๋ฅผ ModelAndView๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๋ฐ˜ํ™˜

  6. viewResolver ํ˜ธ์ถœ : viewResolver๋ฅผ ์ฐพ๊ณ  ์‹คํ–‰ (JSP์˜ ๊ฒฝ์šฐ InternalResourceViewResolver ๊ฐ€ ์ž๋™ ๋“ฑ๋ก&์‚ฌ์šฉ)

  7. View ๋ฐ˜ํ™˜ : viewResolver๋Š” ๋ทฐ์˜ ๋…ผ๋ฆฌ ์ด๋ฆ„์„ ๋ฌผ๋ฆฌ ์ด๋ฆ„์œผ๋กœ ๋ฐ”๊พธ๊ณ , ๋ Œ๋”๋ง ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋Š” ๋ทฐ ๊ฐ์ฒด ๋ฐ˜ํ™˜ (JSP์˜ ๊ฒฝ์šฐ InternalResourceView(JstlView) ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ, ๋‚ด๋ถ€์— forward() ๋กœ์ง ์กด์žฌ)

  8. ๋ทฐ ๋ Œ๋”๋ง : ๋ทฐ๋ฅผ ํ†ตํ•ด์„œ ๋ทฐ๋ฅผ ๋ Œ๋”๋ง

์ฃผ์š” ์ธํ„ฐํŽ˜์ด์Šค

HandlerMapping, HandlerAdapter, ViewResolver, View

HandlerMapping & HandlerAdapter

์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ ๊ณผ์ •

(1) ํ•ธ๋“ค๋Ÿฌ ๋งคํ•‘์œผ๋กœ ํ•ธ๋“ค๋Ÿฌ ์กฐํšŒ

  • HandlerMapping ์„ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•ด์„œ, ํ•ธ๋“ค๋Ÿฌ ์ฐพ๊ธฐ

    • RequestMappingHandlerMapping : ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ ์ปจํŠธ๋กค๋Ÿฌ์ธ @RequestMapping์—์„œ ์‚ฌ์šฉ

    • BeanNameUrlHandlerMapping : ์Šคํ”„๋ง ๋นˆ์˜ ์ด๋ฆ„์œผ๋กœ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฐพ๋Š”๋‹ค.

  • ๋นˆ ์ด๋ฆ„์œผ๋กœ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฐพ์„ ๊ฒฝ์šฐ, ๋นˆ ์ด๋ฆ„์œผ๋กœ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฐพ์•„์ฃผ๋Š” BeanNameUrlHandlerMapping ๊ฐ€ ์‹คํ–‰์— ์„ฑ๊ณตํ•˜๊ณ  ํ•ธ๋“ค๋Ÿฌ์ธ Controller ๋ฅผ ๋ฐ˜ํ™˜

(2) ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ ์กฐํšŒ

  • HandlerAdapter ์˜ supports() ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ํ˜ธ์ถœ

    • RequestMappingHandlerAdapter : ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ ์ปจํŠธ๋กค๋Ÿฌ์ธ @RequestMapping์—์„œ์‚ฌ์šฉ

    • HttpRequestHandlerAdapter : HttpRequestHandler ์ฒ˜๋ฆฌ

    • SimpleControllerHandlerAdapter : Controller ์ธํ„ฐํŽ˜์ด์Šค (์• ๋…ธํ…Œ์ด์…˜X, ๊ณผ๊ฑฐ์— ์‚ฌ์šฉ) ์ฒ˜๋ฆฌ

  • SimpleControllerHandlerAdapter ๊ฐ€ Controller ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ ๋Œ€์ƒ์ด ๋œ๋‹ค.

(3) ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ ์‹คํ–‰

  • ๋””์ŠคํŒจ์ฒ˜ ์„œ๋ธ”๋ฆฟ์ด ์กฐํšŒํ•œ SimpleControllerHandlerAdapter ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด์„œ ํ•ธ๋“ค๋Ÿฌ ์ •๋ณด๋„ ํ•จ๊ป˜ ๋„˜๊ฒจ์ค€๋‹ค.

  • SimpleControllerHandlerAdapter ๋Š” ํ•ธ๋“ค๋Ÿฌ์ธ Controller ๋ฅผ ๋‚ด๋ถ€์—์„œ ์‹คํ–‰ํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜

ViewResolver

ViewResolver ํ˜ธ์ถœ ๊ณผ์ •

(1) ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ ํ˜ธ์ถœ

  • ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ๋ฅผ ํ†ตํ•ด ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์„ ํš๋“

(2) ViewResolver ํ˜ธ์ถœ

  • ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์œผ๋กœ viewResolver๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ํ˜ธ์ถœ

    • BeanNameViewResolver : ๋นˆ ์ด๋ฆ„์œผ๋กœ ๋ทฐ๋ฅผ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜

    • InternalResourceViewResolver : JSP๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ทฐ๋ฅผ ๋ฐ˜ํ™˜

  • ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์˜ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ ๋ทฐ๊ฐ€ ์—†๋‹ค๋ฉด InternalResourceViewResolver ๊ฐ€ ํ˜ธ์ถœ

(3)InternalResourceViewResolver

  • InternalResourceView ๋ฅผ ๋ฐ˜ํ™˜

(4) ๋ทฐ - InternalResourceView

  • InternalResourceView ๋Š” JSP์ฒ˜๋Ÿผ ํฌ์›Œ๋“œ forward() ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉ

(5) view.render() view.render() ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  InternalResourceView ๋Š” forward() ๋ฅผ ์‚ฌ์šฉํ•ด์„œ JSP๋ฅผ ์‹คํ–‰

Spring MVC ๊ธฐ๋ณธ ๊ธฐ๋Šฅ

ํ”„๋กœ์ ํŠธ ์„ค์ •

  • Jar ์‚ฌ์šฉ ์‹œ ํ•ญ์ƒ ๋‚ด์žฅ ์„œ๋ฒ„(tomcat..)๋ฅผ ์‚ฌ์šฉ (๋‚ด์žฅ ์„œ๋ฒ„ ์ตœ์ ํ™”)

  • War ์‚ฌ์šฉ ์‹œ ์ฃผ๋กœ ์™ธ๋ถ€ ์„œ๋ฒ„์— ๋ฐฐํฌํ•˜๋Š” ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ

Logging

  • SpringBoot ๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” Logback ์„ ๋Œ€๋ถ€๋ถ„ ์‚ฌ์šฉ

    • SLF4J interface ์˜ ๊ตฌํ˜„์ฒด์ธ Logback

  • ๋กœ๊ทธ ๋ ˆ๋ฒจ ์„ค์ •

    • application.properties ์—์„œ log level ์„ค์ • ๊ฐ€๋Šฅ

      • TRACE > DEBUG > INFO > WARN > ERROR

      • ๋ณดํ†ต ๊ฐœ๋ฐœ ์„œ๋ฒ„๋Š” debug, ์šด์˜ ์„œ๋ฒ„๋Š” info level

      # ์ „์ฒด ๋กœ๊ทธ ๋ ˆ๋ฒจ ์„ค์ • (default: info)
      logging.level.root=info
      
      # ํŠน์ • ํŒจํ‚ค์ง€์™€ ๊ทธ ํ•˜์œ„ ๋กœ๊ทธ ๋ ˆ๋ฒจ ์…€์ •
      logging.level.hello.springmvc=trace
  • ๋กœ๊ทธ ์„ ์–ธ

    • Lombok ์‚ฌ์šฉ ์‹œ

      @Slf4j
    • java ์ฝ”๋“œ๋กœ ์„ ์–ธ ์‹œ

      private final Logger log = LoggerFactory.getLogger(getClass());
      // OR
      private static final Logger log = LoggerFactory.getLogger(Xxx.class)
  • ๋กœ๊ทธ ํ˜ธ์ถœ

    // 2021-08-31 22:11:10.267  INFO 6688 --- [nio-8080-exec-6] hello.springmvc.basic.LogTestController  :  info log = Spring
    // ์‹œ๊ฐ„ / ๋กœ๊ทธ / ํ”„๋กœ์„ธ์Šค ID / Thread Name / Class Name // Message
    log.trace(" trace log = {}", name);
    log.debug(" debug log = {}", name);
    log.info("   info log = {}", name);
    log.warn("   warn log = {}", name);
    log.error(" error log = {}", name);

SLF4J

Logback

์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋กœ๊ทธ ๊ธฐ๋Šฅ

์š”์ฒญ ๋งคํ•‘

  • Controller Annotation

    • @Controller : ๋ฐ˜ํ™˜ ๊ฐ’์ด String ์ด๋ฉด ๋ทฐ ์ด๋ฆ„์œผ๋กœ ์ธ์‹(๋ทฐ๋ฅผ ์ฐพ๊ณ  ๋žœ๋”๋ง)

    • @RestController : ๋ฐ˜ํ™˜ ๊ฐ’์œผ๋กœ ๋ทฐ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ๋ฐ”๋กœ ์ž…๋ ฅ

  • ์ถ•์•ฝ Annotation

      /**
       * ํšŒ์› ๋ชฉ๋ก ์กฐํšŒ: GET /users
       * ํšŒ์› ๋“ฑ๋ก:      POST /users
       * ํšŒ์› ์กฐํšŒ:      GET /users/{userId}
       * ํšŒ์› ์ˆ˜์ •:      PATCH /users/{userId}
       * ํšŒ์› ์‚ญ์ œ:      DELETE /users/{userId}
       */
      @GetMapping(value = "/mapping-get-v2")
      public String mappingGetV2() {
          log.info("mapping-get-v2");
          return "ok";
      }
  • @PathVariable : ์ตœ๊ทผ HTTP API๋Š” ๋ฆฌ์†Œ์Šค ๊ฒฝ๋กœ์— ์‹๋ณ„์ž๋ฅผ ๋„ฃ๋Š” ์Šคํƒ€์ผ์„ ์„ ํ˜ธ

    @GetMapping("/mapping/users/{userId}/orders/{orderId}")
    public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
    
      log.info("mappingPath userId={}, orderId={}", userId, orderId);
      return "ok";
    }
  • ํŠน์ • ํŒŒ๋ผ๋ฏธํ„ฐ/ํ—ค๋”๋กœ ์ถ”๊ฐ€ ๋งคํ•‘

    • ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฒฝ์šฐ params, ํ—ค๋”์˜ ๊ฒฝ์šฐ headers

    • params = {"mode=debug","data=good"}

    /**
       * headers="mode",
       * headers="!mode"
       * headers="mode=debug"
       * headers="mode!=debug" (! = )
       */
      @GetMapping(value = "/mapping-header", headers = "mode=debug")
      public String mappingHeader() {
          log.info("mappingHeader");
          return "ok";
      }
  • Content-Type ํ—ค๋” ๊ธฐ๋ฐ˜ ์ถ”๊ฐ€ ๋งคํ•‘ Media Type

    • Server ์ž…์žฅ์—์„œ ํŠน์ • Media Type๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์š”์ฒญ ํ—ค๋”์˜ Content-Type์œผ๋กœ ์ „๋‹ฌ

      /**
       * Content-Type ํ—ค๋” ๊ธฐ๋ฐ˜ ์ถ”๊ฐ€ ๋งคํ•‘ Media Type
       * consumes="application/json"
       * consumes="!application/json"
       * consumes="application/*"
       * consumes="*\/*"
       * MediaType.APPLICATION_JSON_VALUE
       */
      @PostMapping(value = "/mapping-consume", consumes = MediaType.APPLICATION_JSON_VALUE)
      public String mappingConsumes() {
          log.info("mappingConsumes");
          return "ok";
      }
  • Accept ํ—ค๋” ๊ธฐ๋ฐ˜ Media Type

    • Client ์ž…์žฅ์—์„œ ํŠน์ • Media Type๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์š”์ฒญ ํ—ค๋”์˜ Accept๋กœ ์ „๋‹ฌ

      /**
       * Accept ํ—ค๋” ๊ธฐ๋ฐ˜ Media Type
       * produces = "text/html"
       * produces = "!text/html"
       * produces = "text/*"
       * produces = "*\/*"
       */
      @PostMapping(value = "/mapping-produce", produces = MediaType.TEXT_HTML_VALUE)
      public String mappingProduces() {
          log.info("mappingProduces");
          return "ok";
      }

HTTP Request

  • HttpServletRequest request

  • HttpServletResponse response

  • HttpMethod httpMethod

    • HTTP ๋ฉ”์„œ๋“œ๋ฅผ ์กฐํšŒ (org.springframework.http.HttpMethod)

  • Locale locale

    • Locale ์ •๋ณด๋ฅผ ์กฐํšŒ

  • @RequestHeader MultiValueMap<String, String> headerMap

    • ๋ชจ๋“  HTTP ํ—ค๋”๋ฅผ MultiValueMap ํ˜•์‹์œผ๋กœ ์กฐํšŒ

  • @RequestHeader("host") String host

    • ํŠน์ • HTTP ํ—ค๋”๋ฅผ ์กฐํšŒ

    • ์†์„ฑ (required, defaultValue)

  • @CookieValue(value = "myCookie", required = false) String cookie

    • ํŠน์ • ์ฟ ํ‚ค๋ฅผ ์กฐํšŒ

    • ์†์„ฑ (required, defaultValue)

Spring Method Arguments

Spring Return Values

Http Request Data

ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•

  • GET - Query Parameter

    • /url?username=hello&age=20

    • URL Query Parameter์— ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•ด์„œ ์ „๋‹ฌ

      • ex) ๊ฒ€์ƒ‰, ํ•„ํ„ฐ, ํŽ˜์ด์ง• ๋“ฑ

  • POST - HTML Form

    • content-type: application/x-www-form-urlencoded

    • Message Body์— Query Parameter ํ˜•์‹์œผ๋กœ ์ „๋‹ฌ (username=hello&age=20)

      • ex) ํšŒ์› ๊ฐ€์ž…, ์ƒํ’ˆ ์ฃผ๋ฌธ, HTML Form

  • HTTP message body์— ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๋‹ด์•„์„œ ์š”์ฒญ

    • HTTP API์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ, JSON, XML, TEXT

    • POST, PUT, PATCH

@RequestParam

  • Get, Post ๋ฐฉ์‹์˜ Query Parameter binding

@RequestParam(value="name" required = false, defaultValue = "-1") String name
  • ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์œผ๋กœ ๋ฐ”์ธ๋”ฉ

    • request.getParameter("name") ์™€ ๋™์ผํ•œ ํšจ๊ณผ

  • ์ƒ๋žต

    • HTTP ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด ๋ณ€์ˆ˜ ์ด๋ฆ„๊ณผ ๊ฐ™์œผ๋ฉด value name ์ƒ๋žต ๊ฐ€๋Šฅ

    • String, int ๋“ฑ ๋‹จ์ˆœ ํƒ€์ž…์ด๋ฉด @RequestParam ์ƒ๋žต ๊ฐ€๋Šฅ

  • required

    • ํŒŒ๋ผ๋ฏธํ„ฐ ํ•„์ˆ˜ ์—ฌ๋ถ€ (default = true )

  • defaultValue

    • ๊ธฐ๋ณธ ๊ฐ’ ์ ์šฉ (๋นˆ ๋ฌธ์ž๋„ ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ ์ฒ˜๋ฆฌ)

  • requestParamMap

    • ๋ชจ๋“  ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ›๊ธฐ

    • @RequestParam Map<String, Object> paramMap

      • paramMap.get("username")

    • ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์ด ์—ฌ๋Ÿฌ๊ฐœ๋ผ๋ฉด MultiValueMap ์‚ฌ์šฉ

@ResponseBody

  • String return ์‹œ View ์กฐํšŒ๋ฅผ ๋ฌด์‹œํ•˜๊ณ , HTTP message body์— ์ง์ ‘ ํ•ด๋‹น ๋‚ด์šฉ ์ž…๋ ฅ

@ModelAttribute

  • ๋ฐ”์ธ๋”ฉํ•  ๊ฐ์ฒด ์ƒ์„ฑ

  • ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์ด๋ฆ„์œผ๋กœ ๋ฐ”์ธ๋”ฉ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐพ๊ณ , ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ์˜ setter๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐ’์„ ์ž…๋ ฅ(๋ฐ”์ธ๋”ฉ)

    • ex) ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด username ์ด๋ฉด setUsername() ๋ฉ”์„œ๋“œ๋ฅผ ์ฐพ์•„ ํ˜ธ์ถœํ•˜๋ฉด์„œ ๊ฐ’์„ ์ž…๋ ฅ

HTTP message body

TEXT

  • HTTP Message Body Data ๋ฅผ InputStream ์„ ์‚ฌ์šฉํ•ด์„œ ์ง์ ‘ ์ฝ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, Spring MVC๋Š” HttpEntity ์ง€์›

     /**
       * HttpEntity: HTTP header, body ์ •๋ณด๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์กฐํšŒ ๋ฐ ์‘๋‹ต
       * - HttpMessageConverter ์‚ฌ์šฉ -> StringHttpMessageConverter ์ ์šฉ
       */
      @PostMapping("/request-body-string")
      public HttpEntity<String> requestBodyString(HttpEntity<String> httpEntity) {
    
          String messageBody = httpEntity.getBody();
          log.info("messageBody={}", messageBody);
          return new HttpEntity<>("ok");
      }
  • HttpEntity๋ฅผ ์ƒ์†๋ฐ›์€ RequestEntity, ResponseEntity

    • RequestEntity : HttpMethod, url ์ •๋ณด ๋“ฑ ์ถ”๊ฐ€ ์ •๋ณด ์ œ๊ณต

    • ResponseEntity : HTTP ์ƒํƒœ ์ฝ”๋“œ ์„ค์ • ๊ฐ€๋Šฅ

      return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED)
  • @RequestBody ์‚ฌ์šฉ

    • header ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด @RequestHeader

    @ResponseBody
    @PostMapping("/request-body-string")
    public String requestBodyString(@RequestBody String messageBody) {
    
        log.info("messageBody={}", messageBody);
        return "ok";
    }

JSON

@RequestBody

  • ์ƒ๋žต ๋ถˆ๊ฐ€๋Šฅ(์ƒ๋žต ์‹œ @ModelAttribute ์ ์šฉ)

  • HttpMessageConverter ์‚ฌ์šฉ -> MappingJackson2HttpMessageConverter

    • content-type: application/json

  • ์‘๋‹ต์˜ ๊ฒฝ์šฐ์—๋„ @ResponseBody ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ์ง์ ‘ ๋„ฃ์–ด์ค„ ์ˆ˜ ์žˆ์Œ

    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    @PostMapping("/request-body-json")
    public String requestBodyJson(@RequestBody HelloData data) {
    
        log.info("username={}, age={}", data.getUsername(), data.getAge());
        return "ok";
    }
  • @RequestBody ์š”์ฒญ : JSON ์š”์ฒญ -> HttpMessageConverter(JSON) -> ๊ฐ์ฒด

    • contenttype: application/json

  • @ResponseBody ์‘๋‹ต : ๊ฐ์ฒด -> HttpMessageConverter(JSON) -> JSON ์‘๋‹ต

    • Accept: application/json

HTTP Response

Spring Response Data ์ƒ์„ฑ ๋ฐฉ๋ฒ•

  • ์ •์  ๋ฆฌ์†Œ์Šค

    • HTML, css, js ์ œ๊ณต

    • ๊ธฐ๋ณธ ๊ฒฝ๋กœ : src/main/resources/static

      • Path : src/main/resources/static/basic/hello-form.html

      • URI : http://localhost:8080/basic/hello-form.html

  • View Template ์‚ฌ์šฉ

    • ๋™์ ์ธ HTML ์ œ๊ณต

    • ๊ธฐ๋ณธ ๊ฒฝ๋กœ : src/main/resources/templates

      • Path : src/main/resources/templates/response/hello.html

      @RequestMapping("/response-view")
      public String responseView(Model model) {
          model.addAttribute("data", "hello!!");
      
          return "response/hello";
      }
  • HTTP Message ์‚ฌ์šฉ

    • HTTP API - HTTP Message Body์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„ ์ œ๊ณต

Templating Properties

HTTP message body

TEXT

  • ResponseBody

    @ResponseBody
    @GetMapping("/response-body-string")
    public String responseBody() {
        return "ok";
    }
  • ResponseEntity

    • ์‘๋‹ต์ฝ”๋“œ๋ฅผ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ ์‹œ ์‚ฌ์šฉ

    @GetMapping("/response-body-string")
    public ResponseEntity<String> responseBody() {
        return new ResponseEntity<>("ok", HttpStatus.OK);
    }

JSON

  • ResponseBody

    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    @GetMapping("/response-body-json")
    public HelloData responseBodyJson() {
    
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);
    
        return helloData;
    }
  • ResponseEntity

    • ์‘๋‹ต์ฝ”๋“œ๋ฅผ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ ์‹œ ์‚ฌ์šฉ

    @GetMapping("/response-body-json")
    public ResponseEntity<HelloData> responseBodyJson() {
    
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);
    
        return new ResponseEntity<>(helloData, HttpStatus.OK);
    }

HTTP Message Converter

HTTP Message Converter ์ ์šฉ ์‹œ๊ธฐ

  • HTTP ์š”์ฒญ: @RequestBody, HttpEntity(RequestEntity)

  • HTTP ์‘๋‹ต: @ResponseBody, HttpEntity(ResponseEntity)

Spring Boot Base Message Converter

  • 0_ ByteArrayHttpMessageConverter

    • byte[] ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌ

    • ํด๋ž˜์Šค ํƒ€์ž…: byte[] , content-type: */*

    • ์š”์ฒญ ex) @RequestBody byte[] data

    • ์‘๋‹ต ex) @ResponseBody return byte[] ์“ฐ๊ธฐ content-type application/octet-stream

  • 1_ StringHttpMessageConverter

    • String ๋ฌธ์ž๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.

    • ํด๋ž˜์Šค ํƒ€์ž…: String , content-type: */*

    • ์š”์ฒญ ex) @RequestBody String data

    • ์‘๋‹ต ex) @ResponseBody return "ok" ์“ฐ๊ธฐ content-type text/plain

  • 2_ MappingJackson2HttpMessageConverter

    • application/json

    • ํด๋ž˜์Šค ํƒ€์ž…: ๊ฐ์ฒด ๋˜๋Š” HashMap, content-type: application/json ๊ด€๋ จ

    • ์š”์ฒญ ex) @RequestBody HelloData data

    • ์‘๋‹ต ex) @ResponseBody return helloData ์“ฐ๊ธฐ content-type application/json ๊ด€๋ จ

Request Mapping Handler Adapter ๊ตฌ์กฐ

  • HTTP Message Converter ๋Š” RequestMappingHandlerAdapter -> ArgumentResolver, Handler -> ReturnValueHandler ์—์„œ ์‚ฌ์šฉ๋˜์–ด ํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ

ArgumentResolver

  • ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌ

    • ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” HandlerMethodArgumentResolver ๋Š” supportsParameter() ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํ•ด๋‹น ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ง€์›ํ•˜๋Š”์ง€ ์ฒดํฌ

    • ์ง€์›ํ•˜๋ฉด resolveArgument() ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๋‹ค์–‘ํ•œ ๊ฐ’(๊ฐ์ฒด)์„ ์ƒ์„ฑ

    • ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ๊ฐ์ฒด๊ฐ€ ํ•ธ๋“ค๋Ÿฌ(์ปจํŠธ๋กค๋Ÿฌ) ํ˜ธ์ถœ ์‹œ ๋„˜์–ด ๊ฐ

    Method Arguments (ํŒŒ๋ผ๋ฏธํ„ฐ ๋ชฉ๋ก)

ReturnValueHandler

PRG (Post/Redirect/Get)

  • ๋“ฑ๋ก์„ ์™„๋ฃŒํ•˜๊ณ  ์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ์ค‘๋ณต ๋“ฑ๋ก๋˜๋Š” ์˜ค๋ฅ˜ ํ•ด๊ฒฐ

    1. ์ƒํ’ˆ ๋“ฑ๋ก ํผ ์ด๋™

    2. ์ƒํ’ˆ ์ €์žฅ ๋ฐ ์‚ผํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ redirect

    3. ์ƒํ’ˆ ์ƒ์„ธํŽ˜์ด์ง€ ์ด๋™

Last updated