Spring MVC-TIL (10)

YulHee Kimยท2021๋…„ 9์›” 16์ผ
0

Spring MVC

๋ชฉ๋ก ๋ณด๊ธฐ
10/11
post-thumbnail

[์ฐธ๊ณ  ๊ฐ•์˜] ๊น€์˜ํ•œ๋‹˜์˜ ์Šคํ”„๋ง MVC 1ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ•ต์‹ฌ ๊ธฐ์ˆ 

๐Ÿ’ก ์Šคํ”„๋ง MVC - ๊ธฐ๋ณธ๊ธฐ๋Šฅ

โœ๏ธ HTTP ์‘๋‹ต - ์ •์  ๋ฆฌ์†Œ์Šค, ๋ทฐ ํ…œํ”Œ๋ฆฟ

์„œ๋ฒ„์—์„œ ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ 3๊ฐ€์ง€๋‹ค

  • ์ •์  ๋ฆฌ์†Œ์Šค
    • ์˜ˆ) ์›น ๋ธŒ๋ผ์šฐ์ €์— ์ •์ ์ธ HTML, css, js๋ฅผ ์ œ๊ณตํ•  ๋•Œ๋Š” ์ •์  ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ
  • ๋ทฐ ํ…œํ”Œ๋ฆฟ ์‚ฌ์šฉ
    • ์˜ˆ) ์›น ๋ธŒ๋ผ์šฐ์ €์— ๋™์ ์ธ HTML์„ ์ œ๊ณตํ•  ๋•Œ๋Š” ๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉ
  • HTTP ๋ฉ”์‹œ์ง€ ์‚ฌ์šฉ
    • ์˜ˆ) HTTP API๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” HTML์ด ์•„๋‹ˆ๋ผ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋ฏ€๋กœ, HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— JSON ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์–ด ๋ณด๋‚ธ๋‹ค.

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

์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ํด๋ž˜์ŠคํŒจ์Šค์˜ ๋‹ค์Œ ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ๋Š” ์ •์  ๋ฆฌ์†Œ์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
/static, /public, /resources, /META-INF/resources

src/main/resources๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ๊ณณ์ด๊ณ , ๋˜ ํด๋ž˜์ŠคํŒจ์Šค์˜ ์‹œ์ž‘ ๊ฒฝ๋กœ์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค์Œ ๋””๋ ‰ํ† ๋ฆฌ์— ๋ฆฌ์†Œ์Šค๋ฅผ ๋„ฃ์–ด๋‘๋ฉด ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ •์  ๋ฆฌ์†Œ์Šค๋กœ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

์ •์  ๋ฆฌ์†Œ์Šค ๊ฒฝ๋กœ

src/main/resources/static
๋‹ค์Œ ๊ฒฝ๋กœ์— ํŒŒ์ผ์ด ๋“ค์–ด์žˆ์œผ๋ฉด
src/main/resources/static/basic/hello-form.html
์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค.
http://localhost:8080/basic/hello-form.html
์ •์  ๋ฆฌ์†Œ์Šค๋Š” ํ•ด๋‹น ํŒŒ์ผ์„ ๋ณ€๊ฒฝ ์—†์ด ๊ทธ๋Œ€๋กœ ์„œ๋น„์Šคํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๋ทฐ ํ…œํ”Œ๋ฆฟ

๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ๊ฑฐ์ณ์„œ HTML์ด ์ƒ์„ฑ๋˜๊ณ , ๋ทฐ๊ฐ€ ์‘๋‹ต์„ ๋งŒ๋“ค์–ด์„œ ์ „๋‹ฌํ•œ๋‹ค.
์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ๊ธฐ๋ณธ ๋ทฐ ํ…œํ”Œ๋ฆฟ ๊ฒฝ๋กœ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
๋ทฐ ํ…œํ”Œ๋ฆฟ ๊ฒฝ๋กœ
src/main/resources/templates
๋ทฐ ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p th:text="${data}">empty</p>
</body>
</html>

๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ํ˜ธ์ถœํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ

@Controller
public class ResponseViewController {

    @RequestMapping("/response-view-v1")
    public ModelAndView responseViewV1() {
        ModelAndView mav = new ModelAndView("response/hello")
                .addObject("data", "hello!");
        return mav;
    }

    @RequestMapping("/response-view-v2")
    public String responseViewV2(Model model) {
        model.addAttribute("data","hello!");
        return "response/hello";
    }

    //๊ถŒ์žฅ X
    @RequestMapping("/response/hello")
    public void responseViewV3(Model model) {
        model.addAttribute("data","hello!");
    }
}

String์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ - View or HTTP ๋ฉ”์‹œ์ง€

@ResponseBody๊ฐ€ ์—†์œผ๋ฉด response/hello๋กœ ๋ทฐ ๋ฆฌ์กธ๋ฒ„๊ฐ€ ์‹คํ–‰๋˜์–ด์„œ ๋ทฐ๋ฅผ ์ฐพ๊ณ , ๋ Œ๋”๋งํ•œ๋‹ค.
@ResponseBody๊ฐ€ ์žˆ์œผ๋ฉด ๋ทฐ ๋ฆฌ์กธ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ์ง์ ‘ response/hello๋ผ๋Š” ๋ฌธ์ž๊ฐ€ ์ž…๋ ฅ๋œ๋‹ค.

๋ทฐ ๋…ผ๋ฆฌ ์ด๋ฆ„์ธ response.hello๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋‹ค์Œ ๊ฒฝ๋กœ์˜ ๋ทฐ ํ…œํ”Œ๋ฆฟ์ด ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์‹คํ–‰ : templates/response/hello.html

HTTP ๋ฉ”์‹œ์ง€

@ResponseBody, HttpEntity๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, HTTP๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ์ง์ ‘ ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ๏ธ HTTP ์‘๋‹ต - HTTP API, ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ์ง์ ‘ ์ž…๋ ฅ

HTTP API๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— JSON ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์–ด ๋ณด๋‚ธ๋‹ค.

ResponseBodyController

@Slf4j
@Controller
@ResponseBody
// @RestController
public class ResponseBodyController {

    @GetMapping("/response-body-string-v1")
    public void responseBodyV1(HttpServletResponse response) throws IOException {
        response.getWriter().write("ok");
    }

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

 //   @ResponseBody
    @GetMapping("/response-body-string-v3")
    public String responseBodyV3() {
        return "ok";
    }

    @GetMapping("/response-body-json-v1")
    public ResponseEntity<HelloData> responseBodyJsonV1() {
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);

        return new ResponseEntity<>(helloData, HttpStatus.OK);
    }

    @ResponseStatus(HttpStatus.OK)
//    @ResponseBody
    @GetMapping("/response-body-json-v2")
    public HelloData responseBodyJsonV2() {
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);

        return helloData;
    }
}

responseBodyV1
์„œ๋ธ”๋ฆฟ์„ ์ง์ ‘ ๋‹ค๋ฃฐ ๋•Œ ์ฒ˜๋Ÿผ HttpServletResponse ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด์„œ HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ์ง์ ‘ ok ์‘๋‹ต ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.
response.getWriter().write("ok")

responseBodyV2
responseEntity ์—”ํ‹ฐํ‹ฐ๋Š” HttpEntity๋ฅผ ์ƒ์† ๋ฐ›์•˜๋Š”๋ฐ, HttpEntity๋Š” HTTP ๋ฉ”์‹œ์ง€์˜ ํ—ค๋”, ๋ฐ”๋”” ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ResponseEntity๋Š” ์—ฌ๊ธฐ์— ๋”ํ•ด์„œ HTTP ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

responseBodyV3
@ResponseBody๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด view๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , HTTP ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ํ†ตํ•ด์„œ HTTP ๋ฉ”์‹œ์ง€๋ฅผ ์ง์ ‘ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค. ResponseEntity๋„ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘.

responseBodyJsonV1
ResponseEntity๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. HTTP ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ํ†ตํ•ด์„œ JSON ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜๋˜์–ด์„œ ๋ฐ˜ํ™˜๋œ๋‹ค.

responseBodyJsonV2
ResponseEntity๋Š” HTTP ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, @ResponseBody๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฐ ๊ฒƒ์„ ์„ค์ •ํ•˜๊ธฐ ๊นŒ๋‹ค๋กญ๋‹ค.
@ResponseStatus(HttpStatus.OK) ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์‘๋‹ต ์ฝ”๋“œ๋„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

@RestController
@RestController๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ์— ๋ชจ๋‘ @ResponseBody๊ฐ€ ์ ์šฉ๋˜๋Š” ํšจ๊ณผ๊ฐ€ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•œ๋‹ค. ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ REST API๋ฅผ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ์ด๋‹ค.
์ฐธ๊ณ ๋กœ @ResponseBody ๋Š” ํด๋ž˜์Šค ๋ ˆ๋ฒจ์— ๋‘๋ฉด ์ „์ฒด์— ๋ฉ”์„œ๋“œ์— ์ ์šฉ๋˜๋Š”๋ฐ, @RestController ์—๋…ธํ…Œ์ด์…˜ ์•ˆ์— @ResponseBody ๊ฐ€ ์ ์šฉ๋˜์–ด ์žˆ๋‹ค.

โœ๏ธ HTTP ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ

HTTP API์ฒ˜๋Ÿผ JSON ๋ฐ์ดํ„ฐ๋ฅผ HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์—์„œ ์ง์ ‘ ์ฝ๊ฑฐ๋‚˜ ์“ฐ๋Š” ๊ฒฝ์šฐ HTTP ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŽธ๋ฆฌํ•˜๋‹ค.

@ResponseBody ์‚ฌ์šฉ ์›๋ฆฌ

  • @ResponseBody๋ฅผ ์‚ฌ์šฉ
    • HTTP์˜ BODY์— ๋ฌธ์ž ๋‚ด์šฉ์„ ์ง์ ‘ ๋ฐ˜ํ™˜
    • viewResolver ๋Œ€์‹ ์— HttpMessageConverter๊ฐ€ ๋™์ž‘
    • ๊ธฐ๋ณธ ๋ฌธ์ž์ฒ˜๋ฆฌ: StringHttpMessageConverter
    • ๊ธฐ๋ณธ ๊ฐ์ฒด์ฒ˜๋ฆฌ: MappingJackson2HttpMessageConverter

์Šคํ”„๋ง MVC๋Š” ๋‹ค์Œ์˜ ๊ฒฝ์šฐ์— HTTP ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ์ ์šฉํ•œ๋‹ค.

  • HTTP ์š”์ฒญ: @RequestBody, HttpEntity(RequestEntity)
  • HTTP ์‘๋‹ต : @ResponseBody, HttpEntity(ResponseEntity)

HTTP ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๋Š” HTTP ์š”์ฒญ, HTTP ์‘๋‹ต ๋‘˜ ๋‹ค ์‚ฌ์šฉ๋œ๋‹ค.

  • canRead(), canWrite(): ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๊ฐ€ ํ•ด๋‹น ํด๋ž˜์Šค, ๋ฏธ๋””์–ด ํƒ€์ž…์„ ์ง€์›ํ•˜๋Š”์ง€ ์ฒดํฌ
  • read(), write(): ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ํ†ตํ•ด์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ๊ณ  ์“ฐ๋Š” ๊ธฐ๋Šฅ

์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ๋Œ€์ƒ ํด๋ž˜์Šค ํƒ€์ž…๊ณผ ๋ฏธ๋””์–ด ํƒ€์ž… ๋‘˜์„ ์ฒดํฌํ•ด์„œ ์‚ฌ์šฉ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.๋งŒ์•ฝ ๋งŒ์กฑํ•˜์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๋กœ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋„˜์–ด๊ฐ„๋‹ค.

  • ByteArrayHttpMessageConverter : byte[] ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ํด๋ž˜์Šค ํƒ€์ž…: byte[], ๋ฏธ๋””์–ดํƒ€์ž…: /
    • ์š”์ฒญ ์˜ˆ) @RequestBody byte[] data
    • ์‘๋‹ต ์˜ˆ) @ResponseBody return byte[]
      ์“ฐ๊ธฐ ๋ฏธ๋””์–ด ํƒ€์ž… application/octet-stream
  • StringHttpMessageConverter: String ๋ฌธ์ž๋กœ ๋ฐ์ดํ„ธ๋ฅด ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ํด๋ž˜์Šค ํƒ€์ž…: String, ๋ฏธ๋””์–ดํƒ€์ž… /
    • ์š”์ฒญ ์˜ˆ) @RequestBody String data
    • ์‘๋‹ต ์˜ˆ) @ResponseBody return "ok"
      ์“ฐ๊ธฐ ๋ฏธ๋””์–ดํƒ€์ž… text/plain
  • MappingJackson2HttpMessageConverter: application/json
    • ํด๋ž˜์Šค ํƒ€์ž…: ๊ฐ์ฒด ๋˜๋Š” HashMap, ๋ฏธ๋””์–ดํƒ€์ž… application/json ๊ด€๋ จ
    • ์š”์ฒญ ์˜ˆ) @RequestBody HelloData data
    • ์‘๋‹ต ์˜ˆ) @ResponseBody return helloData
      ์“ฐ๊ธฐ ๋ฏธ๋””์–ด ํƒ€์ž… application/json ๊ด€๋ จ

์š”์ฒญ ๋งคํ•‘ ํ•ธ๋“ค๋Ÿฌ ์–ด๋Žํ„ฐ ๊ตฌ์กฐ๋Š” ์ œ๊ฐ€ ์ดํ•ด๋ฅผ ์ž˜ ๋ชปํ•ด์„œ ๋” ์ดํ•ดํ•˜๊ณ  ์ •๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹น ..๐Ÿคซ

profile
๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€