[SPRING] ๐Ÿ“ฆ ์‘๋‹ต ํ†ต์ผ์˜ ์ค‘์š”์„ฑ - ์ œ๋„ค๋ฆญ, ๋นŒ๋”, Enum, ์ฒด์ด๋‹

๋ฆผ๋ฏผ์ง€ยท2025๋…„ 4์›” 8์ผ

Today I Learn

๋ชฉ๋ก ๋ณด๊ธฐ
42/62

๊ธฐ์กด ํ”„๋กœ์ ํŠธ๋ฅผ ํ•  ๋•, ์‘๋‹ต์„ ๋‚ด ๋งˆ์Œ๋Œ€๋กœ ๋ง‰ stringํ–ˆ๋‹ค๊ฐ€, responseDtoํ–ˆ๋‹ค๊ฐ€ booleanํ–ˆ๋‹ค๊ฐ€ voidํ–ˆ๋‹ค๊ฐ€ ๋‚œ๋ฆฌ ์—‰๋ง์ง„์ฐฝ ๋ถ€๋ฅด์Šค ์—๋ฐ”์Žผ๋ฐ” ์Œˆ๋ฐ” ์ท„์—ˆ๋Š”๋ฐ....

์‘๋‹ต์„ ํ†ต์ผํ•˜๋Š” ๊ฒƒ์˜ ์ค‘์š”์„ฑ์„ ๊นจ๋‹ฌ์•˜๋‹ค!!
(ํ”„๋ก ํŠธํ•œํ…Œ ์š• ์•ˆ๋จน์œผ๋ ค๋ฉด ํ•ด์•ผ๋จ์š”)

๊ทธ๋ฆฌ๊ณ  ์ด ๊ณผ์ •์—์„œ ํ•„์š”ํ•œ ๊ฐœ๋…๋“ค๊นŒ์ง€ ํ•จ๊ป˜ ์•Œ์•„๋ณด์ž !

  • ์ œ๋„ค๋ฆญ<Generic>
  • ๋นŒ๋” ํŒจํ„ด(Builder Pattern)
  • Enum์„ ์ด์šฉํ•œ ์ฝ”๋“œ ๊ด€๋ฆฌ
  • ์ฒด์ด๋‹(Method Chaining)์˜ ๊ตฌ์กฐ

๐Ÿค” ์‘๋‹ต ํ†ต์ผ ์™œํ•ด์•ผํ•จ?

ํด๋ผ์ด์–ธํŠธ๋Š” API ์š”์ฒญ ๊ฒฐ๊ณผ๋กœ JSON์„ ๋ฐ›๋Š”๋‹ค
๋ฐฑ์—”๋“œ๋Š” ํฐ ์ƒ๊ด€์—†์ง€๋งŒ, ์ด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š” ํ”„๋ก ํŠธ ์ž…์žฅ์—์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค
์š”์ฒญ์„ ๋‚ ๋ฆฌ๊ณ  ๋ฐ›์„๋•Œ๋งˆ๋‹ค ๋งค๋ฒˆ JSON ๊ตฌ์กฐ๊ฐ€ ๋‹ค๋ฅด๋ฉด, ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ์ด ์ฒ˜๋ฆฌ๋ฅผ ๊ฒฝ์šฐ๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•ด์ฃผ์–ด์•ผํ•˜๋‹ˆ ๋นก์น˜๊ฒŒ๋œ๋‹ค..

์˜ˆ๋ฅผ ๋“ค์–ด ํšŒ์›๊ฐ€์ž… ์‘๋‹ต์ด ์ด๋Ÿฐ ๊ตฌ์กฐ๋ผ๋ฉด:

{
  "code": 200,
  "data": {
    "name": "๋‚˜",
    "email": "itsmin@naver.com"
  },
  "comment": "ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต"
}

๋กœ๊ทธ์ธ๋„, ๊ฒŒ์‹œ๊ธ€ ์กฐํšŒ๋„, ์‚ญ์ œ ์‘๋‹ต ๋“ฑ๋“ฑ ๋ชจ๋‘ ์ด๋Ÿฐ ๊ตฌ์กฐ๋กœ ํ†ต์ผํ•˜๋ฉด ๋ชจ๋“  ์‘๋‹ต์„ ๋˜‘๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•˜๋‹ค! ์šฐ๋ฆฌ ๋ชจ๋‘ ํ‰ํ™”๋กœ์šธ ์ˆ˜ ์žˆ๋Š” ์กฐ์€ ๋ฐฉ๋ฒ•๐Ÿ‘

โœ… ์ผ๊ด€๋œ JSON ํฌ๋งท ์‘๋‹ต โ†’ ํ”„๋ก ํŠธ์—์„œ ์‘๋‹ต ์ฒ˜๋ฆฌ ๋กœ์ง์ด ๋‹จ์ˆœํ•ด์ง„๋‹ค
โœ… ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด โ†’ ์ƒํƒœ ์ฝ”๋“œ/๋ฉ”์‹œ์ง€๋ฅผ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌ
โœ… ํ…Œ์ŠคํŠธ ์šฉ์ด โ†’ ์‘๋‹ต์ด ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ํ…Œ์ŠคํŠธ๋„ ๋‹จ์ˆœํ•ด์ง (ํ…Œ์ŠคํŠธ ๊ฐ’ ์ž˜๋ชป ๋„ฃ์—ˆ์„ ๋•Œ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์Œ)
โœ… ํ™•์žฅ์„ฑ โ†’ ์ƒˆ๋กœ์šด ์‘๋‹ต ํƒ€์ž… ์ถ”๊ฐ€๋„ ์‰ฝ๊ฒŒ ๋Œ€์‘ ๊ฐ€๋Šฅ!


[ ๊ณตํ†ต ์‘๋‹ต ๋งŒ๋“ค๊ธฐ ]

1๏ธโƒฃ ์‘๋‹ต ์ฝ”๋“œ ๊ด€๋ฆฌ : SuccessCode Enum

๐Ÿ“Œ Enum์ด๋ž€?

Enum์€ ์—ด๊ฑฐํ˜• ์ƒ์ˆ˜๋ฅผ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Java์˜ ํŠน๋ณ„ํ•œ ํƒ€์ž…!

๐Ÿงฑ Enum ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•

public enum WeekDay {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}

โžก๏ธ WeekDay๋ผ๋Š” ์ƒˆ๋กœ์šด ํƒ€์ž…์ด ์ƒ๊ธฐ๊ณ , 7๊ฐœ์˜ ์ƒ์ˆ˜(์š”์ผ)๋งŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ!!

๐Ÿ›  Enum ์‚ฌ์šฉ๋ฒ•

public class Test {
    public static void main(String[] args) {
        WeekDay today = WeekDay.MONDAY;

        if (today == WeekDay.MONDAY) {
            System.out.println("์›”์š”์ผ ์—๋ฐ” ;;");
        }
    }
}

values() ๋ฉ”์„œ๋“œ๋กœ ๋ชจ๋“  enum ๊ฐ’ ์ˆœํšŒ ๊ฐ€๋Šฅ โ†’ enum ์•ˆ์— ์กด์žฌํ•˜๋Š”๊ฐ€? ๋กœ ํ™œ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค!

for (WeekDay day : WeekDay.values()) {
    System.out.println(day);
}

๊ทผ๋ฐ ์„ค๋ช… ๋ฉ”์‹œ์ง€, ์ˆซ์ž ์ฝ”๋“œ ๋“ฑ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ๋„ฃ๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ๋‹ค.
๊ทธ๋Ÿด ๋• ์ด๋ ‡๊ฒŒ ํ™œ์šฉํ•ด๋ณด์ž

@Getter
@RequiredArgsConstructor
public enum SuccessCode {
    SIGNUP_SUCCESS(HttpStatus.OK, 200, "ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต"), //๊ฐ’์„ ์ •์˜ํ•˜๊ธฐ
    LOGIN_SUCCESS(HttpStatus.OK, 200, "๋กœ๊ทธ์ธ ์„ฑ๊ณต"),
    POST_CREATED(HttpStatus.CREATED, 201, "๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑ ์™„๋ฃŒ");

    private final HttpStatus httpStatus;  //์›ํ•˜๋Š” ๊ฐ’ ์ •์˜ํ•ด์ฃผ๊ณ 
    private final int code;
    private final String message;
}

ํ™œ์šฉํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค!

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋ฉด~

SuccessCode code = SuccessCode.SIGNUP_SUCCESS;
System.out.println(code.getMessage()); //๋ฉ”์„ธ์ง€ ๊ฐ€์ ธ์˜ค๊ธฐ

โ†’ ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต ์ถœ๋ ฅ!!

๐Ÿ‘ Enum ์‚ฌ์šฉ ์‹œ ์žฅ์ 
1. ์ฝ”๋“œ ์ค‘๋ณต ์ค„์ด๊ธฐ
2. ์ƒํƒœ ์ฝ”๋“œ, ๋ฉ”์‹œ์ง€ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌ
3. ์ƒํƒœ ๊ด€๋ฆฌ ์ผ๊ด€์„ฑ ์œ ์ง€


2๏ธโƒฃ ๊ณตํ†ต ์‘๋‹ต ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ CommonResponse

์•„๊นŒ ๋งŒ๋“ค์–ด๋‘” Enum ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ •ํ˜•ํ™”๋œ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” CommonResponse ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ž

๐ŸŒŸ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š”?

๊ณตํ†ต ์‘๋‹ต ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ, ๊ทธ ์•ˆ์— ๋“ค์–ด๊ฐˆ data๋Š” ์ƒํ™ฉ๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค

-ํšŒ์›๊ฐ€์ž…์—๋Š” UserResponseDto
-ํ•  ์ผ ์กฐํšŒ๋ฉด TodoResponseDto
-์ƒํ’ˆ ์ •๋ณด๋ฉด ProductResponseDto
๐Ÿ‘‰ ์‘๋‹ต ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…์ด ์–ธ์ œ๋‚˜ ๋‹ค๋ฅด๋‹ค!

๊ทธ๋ž˜์„œ ์ด๊ฑธ ๋‹ค Object๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋งค๋ฒˆ ํ˜•๋ณ€ํ™˜์„ ํ•ด์•ผ ํ•˜๊ณ , ํƒ€์ž… ์•ˆ์ •์„ฑ์ด โ†“

โžก๏ธ ์ œ๋„ค๋ฆญ(Generic)์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•˜๋‚˜์˜ ํด๋ž˜์Šค์— ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค!!

๐Ÿšง Builder?

: ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ๋•Œ, ์ƒ์„ฑ์ž ๋Œ€์‹  ์‚ฌ์šฉํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜

๐Ÿ“Œ ์™œ ์จ์•ผํ•ด???
: ํ•„๋“œ๊ฐ€ ๋งŽ์€ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ๋•Œ, ์ƒ์„ฑ์ž๋‚˜ setter๋กœ ํ•˜๋ฉด ๋„ˆ๋ฌด๋„ˆ๋ฌด ๋ณต์žกํ•ด์ง€๋‹ˆ๊นŒ ๊น๋”ดํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ!
โ†’ ๊ฐ€๋…์„ฑ & ๋ถˆ๋ณ€์„ฑ์„ ์œ„ํ•ด์„œ (๊ฐ์ฒด๊ฐ€ ํ•œ ๋ฒˆ ์ƒ์„ฑ๋˜๋ฉด ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ฒŒ)

User user = new User("ํ™๊ธธ๋™", "hong@test.com", "1234");

์ด๋Ÿฐ์‹์œผ๋กœ ๋งŒ๋“ค ๋•Œ, ๊ฐ์ฒด๊ฐ€ ๋ช‡๊ฐœ ์—†์œผ๋ฉด ์“ธ๋งŒํ•˜์ง€๋งŒ,,,
์—„์ฒญ ๋งŽ์•„์ง„๋‹ค๋ฉด?? 100๊ฐœ๋ฅผ ๋„ฃ์–ด์•ผํ•œ๋‹ค๋ฉด?? ๊ฐ€๋…์„ฑ์ด ๋˜ฅ๋ง์ด ๋˜๊ฒ ์ฃ ?
๊ทธ๋Ÿด๋•Œ Builder ํŒจํ„ด์„ ์ ์šฉํ•˜๋ฉด ๋œ๋‹น!!

User user = User.builder()
    .name("ํ™๊ธธ๋™")
    .email("hong@test.com")
    .password("1234")
    .build();

@Builder ์ด ์–ด๋…ธํ…Œ์ด์…˜์„ ํด๋ž˜์Šค์— ๋ถ™์—ฌ์ฃผ๋ฉด, ์ด๋Ÿฐ์‹์œผ๋กœ ๋ฐ”๊ฟ”์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋”ฐ! ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์กŒ์ฃต

์ฝ”๋“œ์— ์ ์šฉํ•ด๋ณด๊ธฐ

@Getter
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CommonResponse<T> {
    private final int code;
    private final T data;
    private final String comment;

    public static <T> CommonResponse<T> of(SuccessCode code, T data) {
        return CommonResponse.<T>builder()
                .code(code.getCode())
                .data(data)
                .comment(code.getMessage())
                .build();
    }

    public static <T> CommonResponse<T> of(SuccessCode code) {
        return CommonResponse.<T>builder()
                .code(code.getCode())
                .comment(code.getMessage())
                .build();
    }
}

๐Ÿ’ก ํ•ต์‹ฌ!!
1. @Builder
: ๋นŒ๋” ํŒจํ„ด ์ ์šฉ โ†’ ํ•„๋“œ ์ˆœ์„œ ์ƒ๊ด€์—†์ด ๊ฐ์ฒด ์ƒ์„ฑ ๊ฐ€๋Šฅ
2. <T> ์ œ๋„ค๋ฆญ ์‚ฌ์šฉ
: ์–ด๋–ค ํƒ€์ž…์ด๋“  data์— ๋„ฃ์„ ์ˆ˜ ์žˆ๋„๋ก! (response๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ ์•ˆํ•ด์ค˜๋„ ๋˜๋‹ˆ๊นŒ ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ๋จ)
3. @JsonInclude.NON_NULL
: null ํ•„๋“œ๋Š” JSON์— ํฌํ•จ๋˜์ง€ ์•Š์Œ (๊ฐ„๊ฒฐํ•œ ์‘๋‹ต)


3๏ธโƒฃ Controller์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ

@PostMapping("/signup")
public ResponseEntity<CommonResponse<UserResponseDto>> signup(@RequestBody SignUpRequestDto request) {
    UserResponseDto userResponseDto = userService.signup(request);
    
    return ResponseEntity
        .status(SuccessCode.SIGNUP_SUCCESS.getHttpStatus()) // ์ƒํƒœ ์ฝ”๋“œ ์„ค์ •
        .body(CommonResponse.of(SuccessCode.SIGNUP_SUCCESS, userResponseDto)); // ์‘๋‹ต ๋ณธ๋ฌธ ์„ค์ •
}

๐Ÿง  ์™œ ์ด๋Ÿฐ ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅผ๊นŒ?
ResponseEntity.status(...).body(...)
โžก๏ธ ๋นŒ๋” ํŒจํ„ด ๊ธฐ๋ฐ˜์˜ ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹ ๋ฐฉ์‹

(์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ”์„œ body(...).status(...)์ฒ˜๋Ÿผ ์“ฐ๋ฉด ๋ฌธ๋ฒ• ์˜ค๋ฅ˜ ๋ฐœ์ƒ)

๋”ฐ๋ผ์„œ ์ˆœ์ฐจ์ ์œผ๋กœ ์จ์•ผํ•จ
1. ์ƒํƒœ์ฝ”๋“œ ์„ค์ •
2. ์‘๋‹ต ๋ฐ์ดํ„ฐ ์„ค์ •

ResponseEntity.status(...)
: ์‘๋‹ต์˜ HTTP ์ƒํƒœ์ฝ”๋“œ ์„ค์ • (200, 201, 400, 500 ๋“ฑ)
.body(...)
: ์‘๋‹ต ๋ณธ๋ฌธ์— ๋‹ด์„ ๋ฐ์ดํ„ฐ ์„ค์ •
(CommonResponse.of(...) SuccessCode์™€ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ณตํ†ต ์‘๋‹ต ๊ฐ์ฒด ์ƒ์„ฑ)
โžก๏ธ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ!


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