💻 뚝딱뚝딱/북북클럽
[개발일지 #038] 공통모듈 구조 만들기, 예외 처리 분리하기
뚜루리
2025. 6. 10. 15:42
728x90
320x100
🎯 오늘 개발 할 기능
- 공통모듈 만들기
- 예외 처리 분리하기
🛠️ 개발내용
📌 멀티모듈 구조 만들기
✅ 멀티모듈(Multi Module)이란?
- 하나의 메인 프로젝트 안에서 여러 개의 서브 프로젝트(모듈)로 기능을 분리하는 방식
bookbookclub/
├── bbc-user-service
├── bbc-post-service
├── bbc-common
└── build.gradle (루트)
✅ 멀티모듈을 사용하는 이유?
이유 | 설명 |
💡 역할 분리 (SRP) | 도메인마다 책임을 나누고 관심사를 분리함 |
🔁 재사용성 | 공통 코드(common)을 여러 서비스에서 재사용 가능 |
🧪 테스트 용이성 | 각 모듈별로 독립적인 단위 테스트/통합 테스트 수행 가능 |
🚀 빌드 효율성 | 변경된 모듈만 빌드해서 속도 향상 (Gradle Incremental Build) |
⚙️ MSA 전환 준비 | 나중에 각 모듈을 독립 마이크로서비스로 분리하기 쉬움 |
✅ 멀티모듈(Multi Module) 설정하기
1. 루트 프로젝트 생성 (BookBookClub-MSA)
settings.gradle
rootProject.name = 'BookBookClub-MSA'
include 'bbc-common'
include 'bbc-user-service'
include 'bbc-post-service'
그냥 원하는 위치에 폴더를 하나 생성하면 됨.
2. 서브모듈 생성 (bbc-user-service, bbc-post-service, bbc-common)
- 생성한 루프 프로젝트 아래에 이미 만들어진 bbc-user-service, bbc-post-service의 프로젝트를 복사해서 넣어준다. (혹시 망할까봐 복사해줌)
- bbc-common는 새로 만드는 것이라 폴더 하나 만들어서 루트 프로젝트 아래 넣어줌.
- bbc-user-service, bbc-post-service, bbc-common 각각 build.gradle 작성.
dependencies {
implementation project(':bbc-common') // 공통 모듈 참조
implementation 'org.springframework.boot:spring-boot-starter-web'
...
}
3. IntelliJ에서 멀티모듈 구성 인식시키기
- settings.gradle이 제대로 작성되었으면 IntelliJ가 자동 인식함
- 안 되면: Gradle → Reload All Projects 클릭
📦 예시 구조
bookbookclub/
├── bbc-common/
│ └── ApiResponse.java, ErrorCode.java ...
├── bbc-user-service/
│ └── 회원가입, 로그인, OAuth ...
├── bbc-post-service/
│ └── 피드 CRUD, 좋아요 기능 ...
├── build.gradle
└── settings.gradle
그리고 나서 공통으로 사용하는 것들을 분리해주고 기존에 있던 것들을 삭제 해주는 작업을 해준다.
📌 예외 처리 분리하기
기존에 클래스만 분리하고 에러코드랑 핸들러는 공통으로 사용했는데, 도메인에 따라서 핸들러와 에러코드 클래스도 분리하기로 한다.
예시) EmailVerificationErrorCode
package com.bookbookclub.bbc_user_service.emailverification.exception;
import com.bookbookclub.common.exception.BaseErrorCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
public enum EmailVerificationErrorCode implements BaseErrorCode {
EMAIL_NOT_VERIFIED("EMAIL_NOT_VERIFIED", "이메일 인증이 완료되지 않았습니다."),
EMAIL_VERIFICATION_TOO_MANY_ATTEMPTS("TOO_MANY_ATTEMPTS",
"이메일 인증 시도 횟수를 초과했습니다. 잠시 후 다시 시도해주세요.");
private final String code;
private final String message;
EmailVerificationErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
}
예시) EmailNotVerifiedException
package com.bookbookclub.bbc_user_service.emailverification.exception;
import lombok.Getter;
/**
* 이메일 인증 미완료 예외
* - 회원가입 시 인증되지 않은 경우 발생
*/
@Getter
public class EmailNotVerifiedException extends RuntimeException {
private final EmailVerificationErrorCode errorCode;
public EmailNotVerifiedException() {
super(EmailVerificationErrorCode.EMAIL_NOT_VERIFIED.getMessage());
this.errorCode = EmailVerificationErrorCode.EMAIL_NOT_VERIFIED;
}
}
예시) EmailVerificationExceptionHandler
package com.bookbookclub.bbc_user_service.emailverification.exception;
import com.bookbookclub.common.response.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 이메일 인증 관련 예외 처리 핸들러
*/
@Slf4j
@RestControllerAdvice(basePackages = "com.bookbookclub.bbc_user_service.emailverification")
public class EmailVerificationExceptionHandler {
/**
* 이메일 인증 미완료 예외 처리
*/
@ExceptionHandler(EmailNotVerifiedException.class)
public ApiResponse<?> handleEmailNotVerified(EmailNotVerifiedException e) {
log.warn("Email not verified: {}", e.getMessage());
return ApiResponse.fail(e.getErrorCode());
}
/**
* 이메일 인증 시도 횟수 초과 예외 처리
*/
@ExceptionHandler(EmailVerificationLimitExceededException.class)
public ApiResponse<?> handleLimitExceeded(EmailVerificationLimitExceededException e) {
log.warn("Email verification limit exceeded: {}", e.getMessage());
return ApiResponse.fail(e.getErrorCode());
}
}
728x90
320x100