public class AuthException extends BaseException {
// 이메일 중복 예외
public static class EmailDuplicateException extends AuthException {
public EmailDuplicateException() {
super("이미 사용 중인 이메일입니다.", HttpStatus.CONFLICT, "AUTH_EMAIL_DUPLICATE");
}
}
// 인증 실패 예외
public static class AuthenticationFailedException extends AuthException {
public AuthenticationFailedException() {
super("인증에 실패했습니다.", HttpStatus.UNAUTHORIZED, "AUTH_FAILED");
}
}
// 리프레시 토큰 만료 예외
public static class RefreshTokenExpiredException extends AuthException {
public RefreshTokenExpiredException() {
super("리프레시 토큰이 만료되었습니다.", HttpStatus.UNAUTHORIZED, "REFRESH_TOKEN_EXPIRED");
}
}
// 리프레시 토큰 없음 예외
public static class RefreshTokenNotFoundException extends AuthException {
public RefreshTokenNotFoundException() {
super("리프레시 토큰을 찾을 수 없습니다.", HttpStatus.NOT_FOUND, "REFRESH_TOKEN_NOT_FOUND");
}
}
public static class PasswordResetTokenNotFoundException extends AuthException {
public PasswordResetTokenNotFoundException() {
super("비밀번호 재설정 토큰을 찾을 수 없습니다.", HttpStatus.NOT_FOUND, "PASSWORD_RESET_TOKEN_NOT_FOUND");
}
}
public static class PasswordResetTokenExpiredException extends AuthException {
public PasswordResetTokenExpiredException() {
super("비밀번호 재설정 토큰이 만료되었습니다.", HttpStatus.BAD_REQUEST, "PASSWORD_RESET_TOKEN_EXPIRED");
}
}
public static class InvalidRefreshTokenException extends AuthException {
public InvalidRefreshTokenException() {
super("유효하지 않은 토큰입니다.", HttpStatus.UNAUTHORIZED, "INVALID_REFRESH_TOKEN");
}
}
public static class ExpiredRefreshTokenException extends AuthException {
public ExpiredRefreshTokenException() {
super("토큰이 만료되었습니다.", HttpStatus.UNAUTHORIZED, "EXPIRED_REFRESH_TOKEN");
}
}
public AuthException(String message, HttpStatus status, String errorCode) {
super(message, status, errorCode);
}
}
// 토큰 검증
PasswordResetToken resetToken = passwordResetTokenRepository.findByToken(token)
.orElseThrow(() -> new AuthException.PasswordResetTokenNotFoundException());
public class EmailVerificationException extends BaseException {
public static class EmailNotVerifiedException extends EmailVerificationException {
public EmailNotVerifiedException() {
super("학교 이메일 인증이 필요합니다.", HttpStatus.FORBIDDEN, "EMAIL_NOT_VERIFIED");
}
}
public static class VerificationNotFoundException extends EmailVerificationException {
public VerificationNotFoundException(String email) {
super("인증 정보를 찾을 수 없습니다: " + email, HttpStatus.NOT_FOUND, "VERIFICATION_NOT_FOUND");
}
}
public static class InvalidEmailDomainException extends EmailVerificationException {
public InvalidEmailDomainException(String email) {
super("학교 이메일만 사용 가능합니다: " + email, HttpStatus.BAD_REQUEST, "INVALID_EMAIL_DOMAIN");
}
}
public static class VerificationCodeExpiredException extends EmailVerificationException {
public VerificationCodeExpiredException() {
super("인증 코드가 만료되었습니다.", HttpStatus.BAD_REQUEST, "VERIFICATION_CODE_EXPIRED");
}
}
public static class InvalidVerificationCodeException extends EmailVerificationException {
public InvalidVerificationCodeException() {
super("인증 코드가 일치하지 않습니다.", HttpStatus.BAD_REQUEST, "INVALID_VERIFICATION_CODE");
}
}
public EmailVerificationException(String message, HttpStatus status, String errorCode) {
super(message, status, errorCode);
}
}
if (!verification.getVerificationCode().equals(code)) {
throw new EmailVerificationException.InvalidVerificationCodeException();
}
public class FileException extends BaseException {
public static class FileUploadException extends FileException {
public FileUploadException(String fileName) {
super("파일 업로드에 실패했습니다: " + fileName, HttpStatus.INTERNAL_SERVER_ERROR, "FILE_UPLOAD_FAILED");
}
public FileUploadException(String fileName, Throwable cause) {
super("파일 업로드에 실패했습니다: " + fileName, HttpStatus.INTERNAL_SERVER_ERROR, "FILE_UPLOAD_FAILED");
}
}
public static class ThumbnailCreationException extends FileException {
public ThumbnailCreationException(String fileName) {
super("썸네일 생성에 실패했습니다: " + fileName, HttpStatus.INTERNAL_SERVER_ERROR, "THUMBNAIL_CREATION_FAILED");
}
public ThumbnailCreationException(String fileName, Throwable cause) {
super("썸네일 생성에 실패했습니다: " + fileName, HttpStatus.INTERNAL_SERVER_ERROR, "THUMBNAIL_CREATION_FAILED");
}
}
public static class FileNotFoundException extends FileException {
public FileNotFoundException(String fileName) {
super("파일을 찾을 수 없습니다: " + fileName, HttpStatus.NOT_FOUND, "FILE_NOT_FOUND");
}
}
public static class DirectoryCreationException extends FileException {
public DirectoryCreationException(String path) {
super("디렉토리 생성에 실패했습니다: " + path, HttpStatus.INTERNAL_SERVER_ERROR, "DIRECTORY_CREATION_FAILED");
}
public DirectoryCreationException(String path, Throwable cause) {
super("디렉토리 생성에 실패했습니다: " + path, HttpStatus.INTERNAL_SERVER_ERROR, "DIRECTORY_CREATION_FAILED");
}
}
public static class FileDeletionException extends FileException {
public FileDeletionException(String path) {
super("파일 삭제에 실패했습니다: " + path, HttpStatus.INTERNAL_SERVER_ERROR, "FILE_DELETION_FAILED");
}
public FileDeletionException(String path, Throwable cause) {
super("파일 삭제에 실패했습니다: " + path, HttpStatus.INTERNAL_SERVER_ERROR, "FILE_DELETION_FAILED");
}
}
public static class EmptyFileException extends FileException {
public EmptyFileException() {
super("업로드할 파일이 없습니다.", HttpStatus.BAD_REQUEST, "EMPTY_FILE");
}
}
public FileException(String message, HttpStatus status, String errorCode) {
super(message, status, errorCode);
}
}
private void deleteFileIfExists(Path filePath) {
try {
if (Files.exists(filePath)) Files.delete(filePath);
} catch (IOException e) {
log.error("파일 삭제 실패: {}", filePath, e);
throw new FileException.FileDeletionException(filePath.toString(), e);
}
}
public class OAuth2Exception extends BaseException {
public static class UnsupportedProviderException extends OAuth2Exception {
public UnsupportedProviderException(String provider) {
super("지원하지 않는 소셜 로그인입니다: " + provider, HttpStatus.BAD_REQUEST, "UNSUPPORTED_OAUTH_PROVIDER");
}
}
public static class OAuth2AttributeParsingException extends OAuth2Exception {
public OAuth2AttributeParsingException(String provider) {
super(provider + " 사용자 정보를 파싱하는데 실패했습니다,", HttpStatus.INTERNAL_SERVER_ERROR, "OAUTH_ATTRIBUTE_PARSING_FAILED");
}
}
public static class OAuth2ProcessingException extends OAuth2Exception {
public OAuth2ProcessingException(String message) {
super(message, HttpStatus.INTERNAL_SERVER_ERROR, "OAUTH_PROCESSING_FAILED");
}
}
public static class EmailAlreadyExistsException extends OAuth2Exception {
public EmailAlreadyExistsException(String email) {
super("이미 가입된 이메일입니다: " + email, HttpStatus.CONFLICT, "EMAIL_ALREADY_EXISTS");
}
}
public static class MissingAttributeException extends OAuth2Exception {
public MissingAttributeException(String provider, String attribute) {
super(provider + " 응답에서 필수 속성(" + attribute + ")을 찾을 수 없습니다.", HttpStatus.BAD_REQUEST, "MISSING_OAUTH_ATTRIBUTE");
}
}
public static class InvalidResponseException extends OAuth2Exception {
public InvalidResponseException(String provider) {
super(provider + " 응답 형식이 올바르지 않습니다.", HttpStatus.BAD_REQUEST, "INVALID_OAUTH_RESPONSE");
}
}
public OAuth2Exception(String message, HttpStatus status, String errorCode) {
super(message, status, errorCode);
}
}
if (responseData == null || !responseData.containsKey("id")) {
log.error("네이버 응답에서 사용자 정보를 찾을 수 없습니다. attributes: {}", attributes);
throw new OAuth2Exception.MissingAttributeException("naver", "id");
}
public class ProductException extends BaseException {
public static class ProductNotFoundException extends ProductException {
public ProductNotFoundException(Long productId) {
super("해당 ID의 상품을 찾을 수 없습니다: " + productId, HttpStatus.NOT_FOUND, "PRODUCT_NOT_FOUND");
}
}
public static class SellerMismatchException extends ProductException {
public SellerMismatchException() {
super("해당 상품의 판매자가 아닙니다.", HttpStatus.FORBIDDEN, "SELLER_MISMATCH");
}
}
public static class ProductCreationException extends ProductException {
public ProductCreationException(String message) {
super("상품 등록 중 오류가 발생했습니다: " + message, HttpStatus.INTERNAL_SERVER_ERROR, "PRODUCT_CREATION_FAILED");
}
}
public static class ProductUpdateException extends ProductException {
public ProductUpdateException(String message) {
super("상품 수정 중 오류가 발생했습니다: " + message, HttpStatus.INTERNAL_SERVER_ERROR, "PRODUCT_UPDATE_FAILED");
}
}
public static class AlreadySoldProductException extends ProductException {
public AlreadySoldProductException() {
super("이미 판매 완료된 상품입니다.", HttpStatus.BAD_REQUEST, "ALREADY_SOLD_PRODUCT");
}
}
public static class NotSoldProductException extends ProductException {
public NotSoldProductException() {
super("판매 완료 상태가 아닌 상품은 취소할 수 없습니다.", HttpStatus.BAD_REQUEST, "NOT_SOLD_PRODUCT");
}
}
public static class ProductNotAvailableException extends ProductException {
public ProductNotAvailableException() {
super("해당 상품은 구매할 수 없는 상태입니다.", HttpStatus.BAD_REQUEST, "PRODUCT_NOT_AVAILABLE");
}
}
public static class ProductAccessDeniedException extends ProductException {
public ProductAccessDeniedException() {
super("해당 상품에 대한 권한이 없습니다.", HttpStatus.FORBIDDEN, "PRODUCT_ACCESS_DENIED");
}
}
public static class ProductStockException extends ProductException {
public ProductStockException() {
super("상품 재고가 부족합니다.", HttpStatus.BAD_REQUEST, "PRODUCT_STOCK_INSUFFICIENT");
}
}
public ProductException(String message, HttpStatus status, String errorCode) {
super(message, status, errorCode);
}
}
private static void emailVerification(User seller) {
if (!seller.isEmailVerified()) {
throw new EmailVerificationException.EmailNotVerifiedException();
}
}
예시 이미지
