๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
BackEnd๐ŸŒฑ/Spring

[Spring] @RequestParam, @RequestBody, @ModelAttribute์˜ ์ฐจ์ด

by dkswnkk 2022. 3. 28.

์„œ๋ก 

@ModelAttribute๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ parameter์— ๊ฐ’์„ ๋„ฃ์œผ๋ฉด ์ž˜ ๋ฐ›์•„์˜ค์ง€๋งŒ body์— ๊ฐ’์„ ๋‹ด์•„ ์ „์†กํ•˜๋ฉด null๊ฐ’์ด ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ @RequestBody๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ”๋ฅด๊ฒŒ ๊ฐ’์ด ์ž˜ ๋‹ด์•„์ง€๋Š”๋ฐ ์™œ ๊ทธ๋Ÿฐ์ง€, ๊ทธ๋ฆฌ๊ณ  @ModelAttribute์™€ @RequestBody์˜ ์ฐจ์ด๋Š” ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด ๊ถ๊ธˆํ•˜์—ฌ ํ•œ๋ฒˆ ์ •๋ฆฌ๋ฅผ ํ•ด๋ณผ๊นŒ ํ•ฉ๋‹ˆ๋‹ค.

๋จผ์ € ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฐ›์€ ์š”์ฒญ์„ ๊ฐ์ฒด๋กœ ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์—๋Š” @RequestParam, @RequestBody, @ModelAttribute ์ด ์„ธ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณตํ†ต์ ์ธ ์•„๋ž˜์™€ ๊ฐ™์€ DTO๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•œ๋ฒˆ ๊ฐ๊ฐ์˜ ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import lombok.Data;

@Data
public class TestData {
    String name;
    int age;
}

 

1. @RequestParam

@RequestParam์€ ๊ฐ๊ฐ์˜ HTTP ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Body๋ฅผ ์ง์ ‘ ์กฐํšŒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

    @ResponseBody
    @PostMapping("test/request-param")
    public TestData requestParam(@RequestParam String name,
                                 @RequestParam int age) {
        TestData testData = new TestData();
        testData.setName(name);
        testData.setAge(age);
        return testData;
    }

์œ„ ์ฝ”๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ Postman์„ ์ด์šฉํ•ด Parameter์— ๊ฐ’์„ ๋„ฃ์–ด ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@RequestParam ์ „์†ก
@RequestParam ๋ฐ˜ํ™˜

์˜ˆ์ƒํ–ˆ๋˜ ๋Œ€๋กœ name๊ณผ age๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์— ๊ฐ’์„ ๋‹ด์•„์„œ ์ „์†กํ–ˆ๋”๋‹ˆ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ @ResponseBody๋ฅผ ๊ฑฐ์ณ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ JSONํ˜•์‹์œผ๋กœ ๊ฐ’์ด ๋‹ด๊ฒจ์„œ ์™”์Šต๋‹ˆ๋‹ค.

2. @RequestBody

@RequestBody๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ „์†กํ•˜๋Š” JSON(application/json) ํ˜•ํƒœ์˜ HTTP Body ๋‚ด์šฉ์„ Java Object๋กœ ๋ณ€ํ™˜์‹œ์ผœ ์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ํฐ ํŠน์ง•์€ ๋ฐ”์ธ๋”ฉ์ด ์•„๋‹Œ ๋ณ€ํ™˜์„ ์‹œํ‚ค๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€์ˆ˜๋“ค์˜ Setter ํ•จ์ˆ˜๊ฐ€ ์—†์–ด๋„ ์ •์ƒ์ ์œผ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

    @ResponseBody
    @PostMapping("/test/request-body")
    public TestData requestBody(@RequestBody TestData testData) {
        return testData;
    }

์œ„์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Postman์„ ์ด์šฉํ•˜์—ฌ Body์— JSONํ˜•ํƒœ๋กœ ๊ฐ’์„ ๋„ฃ์–ด ์•„๋ž˜ ์ด๋ฏธ์ง€์™€ ๊ฐ™์ด ์ „์†กํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

@RequestBody ์ „์†ก
@RequestBody ๋ฐ˜ํ™˜

์˜ˆ์ƒํ–ˆ๋˜ ๋Œ€๋กœ Body์— JSON ํ˜•์‹์œผ๋กœ name๊ณผ age๋ฅผ ๋‹ด์•„์„œ ์ „์†กํ–ˆ๋”๋‹ˆ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ @ResponseBody๋ฅผ ๊ฑฐ์ณ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ JSONํ˜•์‹์œผ๋กœ ๊ฐ’์ด ๋‹ด๊ฒจ์„œ ์™”์Šต๋‹ˆ๋‹ค.

3. @ModelAttribute

๊ทธ๋ ‡๋‹ค๋ฉด ์„œ๋ก ์—์„œ ์–ธ๊ธ‰ํ–ˆ๋‹ค์‹œํ”ผ ๊ฐ€์žฅ ๊ถ๊ธˆํ–ˆ๋˜ @ModelAttribute์ž…๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธํ•ด ๋ณผ ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

  1. Parameter์— ๊ฐ’์„ ๋„ฃ์–ด ์ „์†กํ•ด ๋ณธ๋‹ค.
  2. Body์— ๊ฐ’์„ ๋„ฃ์–ด ์ „์†กํ•ด ๋ณธ๋‹ค.
    @ResponseBody
    @PostMapping("/test/model-attribute/param")
    public TestData modelAttributeParam(@ModelAttribute TestData testData) {
        return testData;
    }
    
    @ResponseBody
    @PostMapping("/test/model-attribute/body")
    public TestData modelAttributeBody(@ModelAttribute TestData testData) {
        return testData;
    }

์ฒซ ๋ฒˆ์งธ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด Paramater์— ๊ฐ’์„ ๋„ฃ์–ด์„œ ์ „์†กํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

@ModelAttribute Paramter ์ „์†ก
@ModelAttribute Paramter ๋ฐ˜ํ™˜

parameter์— ๋„ฃ์€ ๊ฐ’๋“ค์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ JSONํ˜•์‹์œผ๋กœ Body์— ๋ฐ˜ํ™˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ๋กœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด Body์— ๊ฐ’์„ ๋„ฃ์–ด์„œ ์ „์†กํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

@ModelAttribute body ์ „์†ก
@ModelAttribute body ๋ฐ˜ํ™˜

์˜ˆ์ƒ๊ณผ๋Š” ๋‹ฌ๋ฆฌ  name = null, age = 0 ์ฆ‰ ๊ฐ’์ด ๋‹ด๊ธฐ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ๋œ ๊ฒƒ์ผ๊นŒ์š”? @ModelAttribute์—์„œ๋Š” Body๋ฅผ ์ด์šฉํ•ด ์ „์†กํ•˜๋ ค๋ฉด Content-Type์„ application/json์ด ์•„๋‹Œ multipart/form-data ํ˜•ํƒœ๋กœ ์ „์†กํ•ด์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. 

๋”ฐ๋ผ์„œ ํ•œ๋ฒˆ Content-Type์„ multipart/form-data ํ˜•ํƒœ๋กœ ๋ฐ”๊พผ ๋’ค ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

multipart/form-data ๋กœ ์ „์†กํ•œ @ModelAttribute body

 ์ด์ œ์•ผ ์˜ˆ์ƒํ–ˆ๋˜ ๋Œ€๋กœ name๊ณผ age์— ๊ฐ’์ด ๋‹ด๊ฒจ์„œ ๋ฐ˜ํ™˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

์ •๋ฆฌ

๋ฐ”์ธ๋”ฉ ์ข…๋ฅ˜ ํŠน์ง•
@ModelAttribute - ๋ณ€ํ™˜์ด ์•„๋‹Œ ๋ฐ”์ธ๋”ฉ์„ ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€์ˆ˜๋“ค์˜ Setter ํ•จ์ˆ˜๊ฐ€ ์—†์œผ๋ฉด ์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

- @ModelAttribute๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTTP Body์— ๋‚ด์šฉ์„ ๋‹ด๊ธฐ ์œ„ํ•ด์„œ๋Š” multipart/form-data ํ˜•์‹์œผ๋กœ ์ „์†กํ•ด์•ผ ํ•œ๋‹ค.

- HTTP ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์€ Setter๋ฅผ ํ†ตํ•ด ์ผ๋Œ€์ผ ๊ฐ์ฒด์— ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

- @ModelAttribute์—๋Š” ๋งคํ•‘์‹œํ‚ค๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ํƒ€์ž…์ด ๊ฐ์ฒด์˜ ํƒ€์ž…๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€๋ฅผ ํฌํ•จํ•œ ๋‹ค์–‘ํ•œ ๊ฒ€์ฆ(Validation) ์ž‘์—…์ด ์ถ”๊ฐ€์ ์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค.
@RequestParam - @RequestParam์€ 1๊ฐœ์˜ HTTP ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋œ๋‹ค.
@RequestBody - @RequestBody๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋Š” Spring์—์„œ ๊ด€๋ฆฌํ•˜๋Š” MessageConverter๋“ค ์ค‘ ํ•˜๋‚˜์ธ MappingJackson2 HttpMessageConverter๋ฅผ ํ†ตํ•ด Java ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜๋œ๋‹ค.

- Spring์€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณ€ํ™˜ํ•˜๋Š” ๊ณผ์ •์—์„œ ๊ฐ์ฒด์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋‚ด๋ถ€์ ์œผ๋กœ Reflection์„ ์‚ฌ์šฉํ•ด ๊ฐ’์„ ํ• ๋‹นํ•˜๋ฏ€๋กœ @RequestBody์—๋Š” ๊ฐ’์„ ์ฃผ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์ƒ์„ฑ์ž๋‚˜ Setter๊ฐ€ ํ•„์š” ์—†๋‹ค.

 

๋Œ“๊ธ€