Spring MVC-TIL (9)

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

Spring MVC

๋ชฉ๋ก ๋ณด๊ธฐ
9/11

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

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

โœ๏ธ ์š”์ฒญ ๋งคํ•‘

HTTP ๋ฉ”์„œ๋“œ ๋งคํ•‘

ํŽธ๋ฆฌํ•œ ์ถ•์•ฝ ์• ๋…ธํ…Œ์ด์…˜

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping

PathVariable(๊ฒฝ๋กœ ๋ณ€์ˆ˜) ๋‹ค์ค‘ ์‚ฌ์šฉ

@GetMapping("/mapping/users/{userId}/orders/{orderId}")
    public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
        log.info("mappingPath userId={}, orderId={}", userId, orderId);
        return "ok";
    }

ํŠน์ • ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐ๊ฑด ๋งคํ•‘

์‹คํ–‰ ์‹œํ‚ฌ๋•Œ http://localhost:8080/mapping-param?mode=debug
mode=debug ์กฐ๊ฑด์ด ๊ผญ ๋ถ™์–ด์•ผํ•จ

@GetMapping(value = "/mapping-param", params = "mode=debug")
    public String mappingParam() {
        log.info("mappingParam");
        return "ok";
    }

ํŠน์ • ํ—ค๋” ์กฐ๊ฑด ๋งคํ•‘

ํ—ค๋”์— ํŠน์ • ์กฐ๊ฑด์ด ํ•„์ˆ˜๋กœ ๋“ค์–ด๊ฐ€์•ผํ•จ

@GetMapping(value = "/mapping-header", headers = "mode=debug")
    public String mappingHeader() {
        log.info("mappingHeader");
        return "ok";
    }

๋ฏธ๋””์–ด ํƒ€์ž… ์กฐ๊ฑด ๋งคํ•‘

HTTP ์š”์ฒญ Content-Type, consume

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

โœ๏ธ ์š”์ฒญ ๋งคํ•‘ - API ์˜ˆ์‹œ

MappingClassController

@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {

    @GetMapping
    public String user() {
        return "get users";
    }

    @PostMapping
    public String addUser() {
        return "post user";
    }

    @GetMapping("/{userId}")
    public String findUser(@PathVariable String userId) {
        return "get userId = " + userId;
    }

    @PatchMapping("/{userId}")
    public String updateUser(@PathVariable String userId) {
        return "update userId = " + userId;
    }

    @DeleteMapping("/{userId}")
    public String deleteUser(@PathVariable String userId) {
        return "delete userId = " + userId;
    }
}
  • ํšŒ์› ๋ชฉ๋ก ์กฐํšŒ: GET /mapping/users
  • ํšŒ์› ๋“ฑ๋ก: POST /mapping/users
  • ํšŒ์› ์กฐํšŒ: GET /mapping/users/id1
  • ํšŒ์› ์ˆ˜์ •: PATCH /mapping/users/id1
  • ํšŒ์› ์‚ญ์ œ: DELETE /mapping/users/id1

โœ๏ธ HTTP ์š”์ฒญ - ๊ธฐ๋ณธ,ํ—ค๋” ์กฐํšŒ

HTTP ํ—ค๋” ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•

RequestHeaderController

@Slf4j
@RestController
public class RequestHeaderController {

    @RequestMapping("/headers")
    public String headers(HttpServletRequest request,
                          HttpServletResponse response,
                          HttpMethod httpMethod,
                          Locale locale,
                          @RequestHeader MultiValueMap<String, String> headerMap,
                          @RequestHeader("host") String host,
                          @CookieValue(value = "myCookie", required = false) String cookie
                          ){

        log.info("request={}", request);
        log.info("response={}", response);
        log.info("httpMethod={}", httpMethod);
        log.info("locale={}", locale);
        log.info("headerMap={}", headerMap);
        log.info("header host={}", host);
        log.info("myCookie={}", cookie);
        return "ok";
    }
}
  • HttpMethod : HTTP ๋ฉ”์„œ๋“œ๋ฅผ ์กฐํšŒํ•œ๋‹ค.
  • Locale : Locale ์ •๋ณด๋ฅผ ์กฐํšŒํ•œ๋‹ค
  • @RequestHeader MultiValueMap<String, String> headerMap
    : ๋ชจ๋“  HTTP ํ—ค๋”๋ฅผ MultiValueMap ํ˜•์‹์œผ๋กœ ์กฐํšŒํ•œ๋‹ค.
  • @RequestHeader("host") String host
    : ํŠน์ • HTTP ํ—ค๋”๋ฅผ ์กฐํšŒํ•œ๋‹ค.
    ์†์„ฑ (1) ํ•„์ˆ˜๊ฐ’ ์—ฌ๋ถ€: required
    ์†์„ฑ (2) ๊ธฐ๋ณธ ๊ฐ’ ์†์„ฑ: defaultValue
  • @CookieValue(value = "myCookie", required = false) String cookie
    : ํŠน์ • ์ฟ ํ‚ค๋ฅผ ์กฐํšŒํ•œ๋‹ค.
    ์†์„ฑ (1) ํ•„์ˆ˜๊ฐ’ ์—ฌ๋ถ€: required
    ์†์„ฑ (2) ๊ธฐ๋ณธ ๊ฐ’ ์†์„ฑ: defaultValue

์ฐธ๊ณ  1)
MultiValueMap

  • Map๊ณผ ์œ ์‚ฌํ•œ๋ฐ, ํ•˜๋‚˜์˜ ํ‚ค์— ์—ฌ๋Ÿฌ ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
  • HTTP header, HTTP ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๊ฐ™์ด ํ•˜๋‚˜์˜ ํ‚ค์— ์—ฌ๋Ÿฌ ๊ฐ’์„ ๋ฐ›์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
    • keyA=value1&keyA=value2
MultiValueMap<String, String> map = new LinkedMultiValueMap();
map.add("keyA", "value1");
map.add("keyA", "value2");
//[value1,value2]
List<String> values = map.get("keyA");

์ฐธ๊ณ  2)
@Slf4j
๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์„œ log๋ฅผ ์„ ์–ธํ•ด์ค€๋‹ค.

private static final org.slf4j.Logger log =
  org.slf4j.LoggerFactory.getLogger(RequestHeaderController.class);

โœ๏ธ HTTP ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ - ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ, HTML Form

ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ๋Š” ์ฃผ๋กœ ๋‹ค์Œ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค.

  • GET - ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ
    • /url?username=hello&age=20
    • ๋ฉ”์‹œ์ง€ ๋ฐ”๋”” ์—†์ด, URL์˜ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•ด์„œ ์ „๋‹ฌ
    • ๊ฒ€์ƒ‰, ํ•„ํ„ฐ, ํŽ˜์ด์ง•์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹
  • POST - HTML Form
    • content-type: application/x-www-form-urlencoded
    • ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ํ˜•์‹์œผ๋กœ ์ „๋‹ฌ username=hello&age=20
    • ํšŒ์› ๊ฐ€์ž…, ์ƒํ’ˆ ์ฃผ๋ฌธ, HTML Form ์‚ฌ์šฉ
  • HTTP message body์— ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๋‹ด์•„์„œ ์š”์ฒญ
    • HTTP API์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ, JSON, XML, TEXT
    • ๋ฐ์ดํ„ฐ ํ˜•์‹์€ ์ฃผ๋กœ JSON ์‚ฌ์šฉ
    • POST, PUT, PATCH

GET ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ „์†ก ๋ฐฉ์‹์ด๋“ , POST HTML Form ์ „์†ก ๋ฐฉ์‹์ด๋“  ๋‘˜๋‹ค ํ˜•์‹์ด ๊ฐ™์œผ๋ฏ€๋กœ ๊ตฌ๋ถ„์—†์ด ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๊ฒƒ์€ ๊ฐ„๋‹จํžˆ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํšŒ๋ผ ํ•œ๋‹ค.

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํšŒ

    @ResponseBody
    @RequestMapping("/request-param-v2")
    public String requestParamV2(
            @RequestParam("username") String memberName,
            @RequestParam("age") int memberAge) {

        log.info("username={}, age={}", memberName, memberAge);
        return "ok";
    }
  • @RequestParam : ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์œผ๋กœ ๋ฐ”์ธ๋”ฉ
  • @ResponseBody : View ์กฐํšŒ๋ฅผ ๋ฌด์‹œํ•˜๊ณ , HTTP message body์— ์ง์ ‘ ํ•ด๋‹น ๋‚ด์šฉ ์ž…๋ ฅ
    @RequestParam("username") String memberName
    โžก๏ธ request.getParameter("username")

HTTP ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด ๋ณ€์ˆ˜ ์ด๋ฆ„๊ณผ ๊ฐ™์œผ๋ฉด @RequestParam(name="xx") ์ƒ๋žต ๊ฐ€๋Šฅ

    @ResponseBody
    @RequestMapping("/request-param-v3")
    public String requestParamV3(
            @RequestParam String username,
            @RequestParam int age) {

        log.info("username={}, age={}", username, age);
        return "ok";
    }

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

์ฃผ์˜)
@RequestParam ์• ๋…ธํ…Œ์ด์…˜์„ ์ƒ๋žตํ•˜๋ฉด ์Šคํ”„๋ง MVC๋Š” ๋‚ด๋ถ€์—์„œ required=false ๋ฅผ ์ ์šฉํ•œ๋‹ค.

    @ResponseBody
    @RequestMapping("/request-param-v4")
    public String requestParamV4(String username, int age) {
        log.info("username={}, age={}", username, age);
        return "ok";
    }

ํŒŒ๋ผ๋ฏธํ„ฐ ํ•„์ˆ˜ ์—ฌ๋ถ€

    @ResponseBody
    @RequestMapping("/request-param-required")
    public String requestParamRequired(
            @RequestParam(required = true) String username,
            @RequestParam(required = false) Integer age) {
        log.info("username={}, age={}", username, age);
        return "ok";
    }

username ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํ•„์ˆ˜๋กœ ๋“ค์–ด๊ฐ€์•ผํ•œ๋‹ค.
int age -> null์„ int์— ์ž…๋ ฅํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
๋”ฐ๋ผ์„œ Integer ๋ณ€๊ฒฝํ•ด์•ผ ํ•จ. ๋˜๋Š” defaultValue ์‚ฌ์šฉ
/request-param?username=
ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„๋งŒ ์žˆ๊ณ  ๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ โžก๏ธ ๋นˆ๋ฌธ์ž๋กœ ํ†ต๊ณผ

๊ธฐ๋ณธ๊ฐ’ ์ ์šฉ

    @ResponseBody
    @RequestMapping("/request-param-default")
    public String requestParamDefault(
            @RequestParam(defaultValue="guest") String username,
            @RequestParam(defaultValue="-1") int age) {
        log.info("username={}, age={}", username, age);
        return "ok";
    }

defaultValue๋Š” ๋นˆ ๋ฌธ์ž์˜ ๊ฒฝ์šฐ์—๋„ ์„ค์ •ํ•œ ๊ธฐ๋ณธ ๊ฐ’์ด ์ ์šฉ๋œ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ Map์œผ๋กœ ์กฐํšŒํ•˜๊ธฐ

    @ResponseBody
    @RequestMapping("/request-param-map")
    public String requestParamMap(@RequestParam Map<String, Object> paramMap) {
        log.info("username={}, age={}", paramMap.get("username"), paramMap.get("age"));
        return "ok";
    }

โœ๏ธ @ModelAttribute

์‹ค์ œ ๊ฐœ๋ฐœ์„ ํ•˜๋ฉด ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์•„์„œ ํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ ๊ฐ์ฒด์— ๊ฐ’์„ ๋„ฃ์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.
์Šคํ”„๋ง์€ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์™„์ „ํžˆ ์ž๋™ํ™”ํ•ด์ฃผ๋Š” @ModelAttribute ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค

  @RequestParam String username;
  @RequestParam int age;
  
  HelloData data = new HelloData();
  data.setUsername(username);
  data.setAge(age);

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ”์ธ๋”ฉ ๋ฐ›์„ ๊ฐ์ฒด

@Data
public class HelloData {
    private String username;
    private int age;
}

๋กฌ๋ณต @Data :
@Getter , @Setter , @ToString , @EqualsAndHashCode , @RequiredArgsConstructor ๋ฅผ ์ž๋™์œผ๋กœ ์ ์šฉํ•ด์ค€๋‹ค.

@ModelAttribute ์ ์šฉ

    @ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV1(@ModelAttribute HelloData helloData) {
        log.info("username={}, age={}", helloData.getUsername(),
                helloData.getAge());
        return "ok";
    }

@ModelAttribute๋„ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.
์Šคํ”„๋ง์€ ์ƒ๋žต์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ทœ์น™์„ ์ ์šฉํ•œ๋‹ค.

String , int , Integer ๊ฐ™์€ ๋‹จ์ˆœ ํƒ€์ž… = @RequestParam
๋‚˜๋จธ์ง€ = @ModelAttribute (argument resolver ๋กœ ์ง€์ •ํ•ด๋‘” ํƒ€์ž… ์™ธ)

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

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