CustomException + ErrorCode ๊ตฌ์กฐ ์ค๊ณ
๋ชฉ์ฐจ
Spring Boot ํ๋ก์ ํธ์์ ์์ธ ์๋ต ํ์์ ํต์ผํ๊ธฐ ์ํด CustomException, ErrorCode, GlobalExceptionHandler ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๋ค.
1. ๋ฐฐ๊ฒฝ
Spring Boot ํ๋ก์ ํธ์์ ์์ธ ์ฒ๋ฆฌ๋ฅผ ๋ณ๋๋ก ์ค๊ณํ์ง ์์ผ๋ฉด ์ฌ๋ฌ ๋ฌธ์ ๊ฐ ์๊ธด๋ค.
- ์๋น์ค ๋ ์ด์ด๋ง๋ค ์์ธ ์ฒ๋ฆฌ ๋ฐฉ์์ด ๋ฌ๋ผ์ง๋ค.
- ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ฌธ์์ด๋ก ์ง์ ์์ฑํ๋ฉด ์คํ๊ฐ ์๊ธฐ๊ฑฐ๋ ์ผ๊ด์ฑ์ด ๊นจ์ง๋ค.
- ํด๋ผ์ด์ธํธ์ ์ ๋ฌ๋๋ ์๋ฌ ์๋ต ํ์์ด ์ ๊ฐ๊ฐ์ด ๋๋ค.
- ์ด๋ค ์๋ฌ๊ฐ ์ด๋์ ๋ฐ์ํ๋์ง ์ถ์ ํ๊ธฐ ์ด๋ ต๋ค.
Booktine์์๋ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ชจ๋ ์๋ฌ ์๋ต์ ApiResponse ํ์์ผ๋ก ํต์ผํ๊ณ , ๋๋ฉ์ธ๋ณ ์์ธ๋ฅผ ํ ๊ณณ์์ ๊ด๋ฆฌํ๋ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๋ค.
2. ์ ์ฒด ๊ตฌ์กฐ
๋ค ๊ฐ์ง ํด๋์ค๊ฐ ์ญํ ์ ๋๋ ๋ด๋นํ๋ค.
| ํด๋์ค | ์ญํ |
|---|---|
ApiResponse |
์ฑ๊ณต/์คํจ ์๋ต์ ํต์ผ๋ ํ์์ผ๋ก ๋ํ |
ErrorCode |
HTTP ์ํ์ฝ๋ + ๋ฉ์์ง๋ฅผ enum์ผ๋ก ์ค์ ๊ด๋ฆฌ |
CustomException |
ErrorCode๋ฅผ ๊ฐ์ธ๋ RuntimeException |
GlobalExceptionHandler |
์์ธ๋ฅผ ์บ์นํด ApiResponse๋ก ๋ณํ |
3. ApiResponse — ๊ณตํต ์๋ต ๋ํผ
๋ชจ๋ API ์๋ต์ ์ฌ์ฉํ๋ ๊ณตํต ๋ํผ๋ค. Java record๋ก ์ ์ํด ๋ถ๋ณ ๊ฐ์ฒด๋ก ๊ด๋ฆฌํ๋ค.

์ธ ๊ฐ์ง ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ก ์ฌ์ฉํ๋ค.
ok(data)— ๋ฐ์ดํฐ๊ฐ ์๋ ์ฑ๊ณต ์๋ตok()— ๋ฐ์ดํฐ ์๋ ์ฑ๊ณต ์๋ตfail(message)— ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ด์ ์คํจ ์๋ต
์ปจํธ๋กค๋ฌ์์๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ค.
// ๋ฐ์ดํฐ ๋ฐํ
return ResponseEntity.ok(ApiResponse.ok(postService.getPost(postId)));
// ๋ฐ์ดํฐ ์๋ ์ฑ๊ณต
return ResponseEntity.ok(ApiResponse.ok());
// ์๋ฌ ์๋ต์ GlobalExceptionHandler์์ ์๋ ์ฒ๋ฆฌ
4. ErrorCode — ์๋ฌ ์ค์ ๊ด๋ฆฌ
๋๋ฉ์ธ ์ ๋ฐ์ ์๋ฌ๋ฅผ HTTP ์ํ์ฝ๋์ ๋ฉ์์ง๋ฅผ ๋ฌถ์ด enum์ผ๋ก ์ ์ํ๋ค.
public enum ErrorCode {
// ๊ณตํต
INVALID_INPUT(400, "์๋ชป๋ ์
๋ ฅ์
๋๋ค."),
UNAUTHORIZED(401, "์ธ์ฆ์ด ํ์ํฉ๋๋ค."),
FORBIDDEN(403, "์ ๊ทผ ๊ถํ์ด ์์ต๋๋ค."),
// ์ฌ์ฉ์
USER_NOT_FOUND(404, "์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค."),
DUPLICATE_EMAIL(409, "์ด๋ฏธ ์ฌ์ฉ ์ค์ธ ์ด๋ฉ์ผ์
๋๋ค."),
INVALID_PASSWORD(400, "๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค."),
// ์ปค๋ฎค๋ํฐ
COMMUNITY_POST_NOT_FOUND(404, "์ปค๋ฎค๋ํฐ ๊ฒ์๊ธ์ ์ฐพ์ ์ ์์ต๋๋ค."),
COMMUNITY_LIKE_ALREADY_EXISTS(409, "์ด๋ฏธ ์ข์์๋ฅผ ๋๋ฅธ ๊ฒ์๊ธ์
๋๋ค."),
COMMUNITY_REPLY_DEPTH_EXCEEDED(400, "๋๋๊ธ์๋ ๋๋๊ธ์ ์์ฑํ ์ ์์ต๋๋ค."),
// ์งํ๋ฅ /๋ชฉํ
MONTHLY_GOAL_ALREADY_EXISTS(409, "ํด๋น ์์ ์๊ฐ ๋ชฉํ๊ฐ ์ด๋ฏธ ์กด์ฌํฉ๋๋ค."),
// ์๋ฒ
INTERNAL_SERVER_ERROR(500, "์๋ฒ ๋ด๋ถ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.");
// .. ๋ฑ๋ฑ
private final int status;
private final String message;
}
์ํ์ฝ๋์ ๋ฉ์์ง๋ฅผ ํ ๊ณณ์์ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ ์๋ก์ด ์๋ฌ๊ฐ ์๊ธฐ๋ฉด ErrorCode์๋ง ์ถ๊ฐํ๋ฉด ๋๋ค. ๋๋ฉ์ธ๋ณ๋ก ErrorCode๋ฅผ ๋ถ๋ฆฌํ๋ ๋ฐฉ์๋ ์์ง๋ง, ํ์ฌ Booktine ๊ท๋ชจ์์๋ ๋จ์ผ ํ์ผ ๊ตฌ์กฐ๊ฐ ๋ ๋จ์ํ๋ค๊ณ ํ๋จํ๋ค.
5. CustomException — ๋น์ฆ๋์ค ์์ธ
ErrorCode๋ฅผ ๋ฉค๋ฒ๋ก ๊ฐ์ง๋ RuntimeException์ด๋ค.

์๋น์ค ๋ ์ด์ด์์๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ค.
// ์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค ์กฐํ
User user = userRepository.findById(userId)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
// ์ค๋ณต ๊ฒ์ฌ
if (userRepository.existsByEmail(email)) {
throw new CustomException(ErrorCode.DUPLICATE_EMAIL);
}
// ๊ถํ ๊ฒ์ฌ
if (!post.getUser().getId().equals(userId)) {
throw new CustomException(ErrorCode.FORBIDDEN);
}
6. GlobalExceptionHandler — ์ ์ญ ์์ธ ์ฒ๋ฆฌ
@RestControllerAdvice๋ก ์ ์ญ์์ ์์ธ๋ฅผ ์บ์นํ๊ณ ApiResponse ํ์์ผ๋ก ์๋ตํ๋ค.

7. ์ค์ ๋์ ํ๋ฆ
์ฌ์ฉ์๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒ์๋ฌผ์ ์กฐํํ๋ ๊ฒฝ์ฐ๋ฅผ ์์๋ก ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.

์์ฒญ์ด ๋ค์ด์ค๋ฉด Controller๋ Service๋ฅผ ํธ์ถํ๋ค. Service์์ ์ ์ ์ฒ๋ฆฌ์ ์ฑ๊ณตํ๋ฉด
ApiResponse.ok()๋ฅผ ๋ฐํํ๊ณ , ์์ธ๊ฐ ๋ฐ์ํ๋ฉด CustomException์ด ๋ฐ์ํ๋ค. ๋ฐ์ํ ์์ธ๋ GlobalExceptionHandler๊ฐ ์ ์ญ์์ ์ฒ๋ฆฌํ ๋ค, ์ต์ข
์ ์ผ๋ก ApiResponse.fail() ํํ์ ์๋ต์ผ๋ก ๋ณํ๋์ด ํด๋ผ์ด์ธํธ์ ์ ๋ฌ๋๋ค.ํด๋ผ์ด์ธํธ์๋ ์๋ ํ์์ผ๋ก ์คํจ ์๋ต์ด ๋ด๋ ค๊ฐ๋ค.
{
"success": false,
"data": null,
"message": "๊ฒ์๋ฌผ์ ์ฐพ์ ์ ์์ต๋๋ค."
}
์ฑ๊ณต ์๋ต์ ์๋ ํ์์ด๋ค.
{
"success": true,
"data": { ... },
"message": null
}
8. ์ ๋ฆฌ
์ด ๊ตฌ์กฐ์ ํต์ฌ์ ์ญํ ๋ถ๋ฆฌ๋ค.
- ์๋น์ค ๋ ์ด์ด๋ ์์ธ๋ฅผ ๋์ง๋ ๊ฒ๋ง ๋ด๋นํ๋ค.
- GlobalExceptionHandler๋ ์๋ต ๋ณํ๋ง ๋ด๋นํ๋ค.
- ErrorCode๋ ์๋ฌ ์ ์๋ง ๋ด๋นํ๋ค.
์๋ก์ด ์๋ฌ๊ฐ ํ์ํ๋ฉด ErrorCode์ ํ ์ค ์ถ๊ฐํ๊ณ throw new CustomException(ErrorCode.XXX) ํํ๋ก ๋์ง๋ฉด ๋์ด๋ค.
'๐ป PROJECT > [Spring Boot, React] ๋ ์ ์ต๊ด ๊ด๋ฆฌ ์๋น์ค' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [์ค๊ณ์์ฌ๊ฒฐ์ ] ์๋ฆฌ์ฆ ๋ชฉ๋ก (0) | 2026.05.21 |
|---|---|
| [์ค๊ณ์์ฌ๊ฒฐ์ ] JWT + Redis ์ธ์ฆ (0) | 2026.05.13 |
| [ํ๋ก์ ํธ ๊ฐ์] ํ๋ก์ ํธ ์๊ฐ ๋ฐ ๊ธฐํ (0) | 2026.05.12 |
| [์ค๊ณ์์ฌ๊ฒฐ์ ] ๊ตญ๋ด ๋์ ๊ฒ์ API ์ ํ ๊ณผ์ (0) | 2026.05.08 |
| [ํธ๋ฌ๋ธ์ํ ] JWT secret ํค ๊ธธ์ด ๋ถ์กฑ์ผ๋ก ์ธํ WeakKeyException (0) | 2026.05.07 |