Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/main/java/cmf/commitField/global/error/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cmf.commitField.global.error;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ErrorCode {

// Common
INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "제곡된 μž…λ ₯ 값이 μœ νš¨ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."),
METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "ν—ˆμš©λ˜μ§€ μ•Šμ€ μš”μ²­ λ°©μ‹μž…λ‹ˆλ‹€."),
ENTITY_NOT_FOUND(HttpStatus.BAD_REQUEST, "μš”μ²­ν•œ μ—”ν‹°ν‹°λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."),
INVALID_TYPE_VALUE(HttpStatus.BAD_REQUEST, "제곡된 κ°’μ˜ νƒ€μž…μ΄ μœ νš¨ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."),
ERROR_PARSING_JSON_RESPONSE(HttpStatus.BAD_REQUEST, "JSON 응닡을 νŒŒμ‹±ν•˜λŠ” 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€."),
MISSING_INPUT_VALUE(HttpStatus.BAD_REQUEST, "ν•„μˆ˜ μž…λ ₯ 값이 λˆ„λ½λ˜μ—ˆμŠ΅λ‹ˆλ‹€."),
DATABASE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "λ°μ΄ν„°λ² μ΄μŠ€ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€."),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "μ„œλ²„ λ‚΄λΆ€ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€."),

// User
NOT_FOUND_USER(HttpStatus.BAD_REQUEST, "ν•΄λ‹Ή μœ μ €κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€"),
PASSWORD_MISMATCH(HttpStatus.BAD_REQUEST, "λΉ„λ°€λ²ˆν˜Έκ°€ μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."),

// Auth
ACCESS_DENIED(HttpStatus.UNAUTHORIZED, "μΈμ¦λ˜μ§€ μ•Šμ€ μœ μ €μž…λ‹ˆλ‹€."),
SC_FORBIDDEN(HttpStatus.UNAUTHORIZED, "κΆŒν•œμ΄ μ—†λŠ” μœ μ €μž…λ‹ˆλ‹€."),
INVALID_JWT_SIGNATURE(HttpStatus.UNAUTHORIZED, "μ„œλͺ… 검증에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€." ),
ILLEGAL_REGISTRATION_ID(HttpStatus.BAD_REQUEST,"ν•΄λ‹Ή 사항이 μ—†λŠ” 둜그인 κ²½λ‘œμž…λ‹ˆλ‹€."),

TOKEN_EXPIRED(HttpStatus.BAD_REQUEST, "토큰이 λ§Œλ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€."),

// member
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "μ‚¬μš©μžλ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€");


private final HttpStatus httpStatus;
private final String message;
}
32 changes: 32 additions & 0 deletions src/main/java/cmf/commitField/global/error/ErrorResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cmf.commitField.global.error;

import lombok.Builder;
import lombok.Getter;
import org.springframework.http.ResponseEntity;

import java.time.LocalDateTime;

@Getter
public class ErrorResponse {
private final String timestamp;
private final String error;
private final String message;

@Builder
public ErrorResponse(String timestamp, String error, String message){
this.timestamp = timestamp;
this.error = error;
this.message = message;
}
public static ResponseEntity<ErrorResponse> toResponseEntity(ErrorCode errorCode){
return ResponseEntity
.status(errorCode.getHttpStatus())
.body(ErrorResponse.builder()
.timestamp(LocalDateTime.now().toString())
.error(errorCode.getHttpStatus().name())
.message(errorCode.getMessage())
.build()
);

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cmf.commitField.global.exception;

import cmf.commitField.global.error.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class CustomException extends RuntimeException {
private final ErrorCode errorCode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cmf.commitField.global.exception;

import cmf.commitField.global.error.ErrorCode;
import cmf.commitField.global.error.ErrorResponse;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.sql.SQLIntegrityConstraintViolationException;

@Slf4j
@RestControllerAdvice
public class ExceptionControllerAdvice {

@ExceptionHandler(value = {ConstraintViolationException.class, MethodArgumentNotValidException.class, MethodArgumentTypeMismatchException.class})
public ResponseEntity<ErrorResponse> handleValidationExceptions(Exception e) {
log.error("Validation Exception: {}", e.getMessage(), e);
return ErrorResponse.toResponseEntity(ErrorCode.INVALID_INPUT_VALUE);
}

@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
public ResponseEntity<ErrorResponse> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
log.error("HTTP Method Not Supported: {}", e.getMessage(), e);
return ErrorResponse.toResponseEntity(ErrorCode.METHOD_NOT_ALLOWED);
}

@ExceptionHandler(value = CustomException.class)
protected ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
log.error("Custom Exception: {}", e.getErrorCode(), e);
return ErrorResponse.toResponseEntity(e.getErrorCode());
}

@ExceptionHandler(value = NullPointerException.class)
public ResponseEntity<ErrorResponse> handleNullPointerException(NullPointerException e) {
log.error("Null Pointer Exception: {}", e.getMessage(), e);
return ErrorResponse.toResponseEntity(ErrorCode.MISSING_INPUT_VALUE);
}

@ExceptionHandler(value = MissingServletRequestParameterException.class)
public ResponseEntity<ErrorResponse> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
log.error("Missing Request Parameter: {}", e.getMessage(), e);
return ErrorResponse.toResponseEntity(ErrorCode.MISSING_INPUT_VALUE);
}

@ExceptionHandler(value = HttpMessageNotReadableException.class)
public ResponseEntity<ErrorResponse> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
log.error("Message Not Readable: {}", e.getMessage(), e);
return ErrorResponse.toResponseEntity(ErrorCode.INVALID_INPUT_VALUE);
}

@ExceptionHandler(value = SQLIntegrityConstraintViolationException.class)
public ResponseEntity<ErrorResponse> handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) {
log.error("SQL Integrity Constraint Violation: {}", e.getMessage(), e);
return ErrorResponse.toResponseEntity(ErrorCode.DATABASE_ERROR);
}

@ExceptionHandler(value = Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(Exception e) {
log.error("Unhandled Exception: {}", e.getMessage(), e);
return ErrorResponse.toResponseEntity(ErrorCode.INTERNAL_SERVER_ERROR);
}
}
51 changes: 51 additions & 0 deletions src/main/java/cmf/commitField/global/globalDto/GlobalResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package cmf.commitField.global.globalDto;

import cmf.commitField.global.error.ErrorCode;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class GlobalResponse<T> {

private final LocalDateTime timestamp; // 응닡 생성 μ‹œκ°„
private final int statusCode; // HTTP μƒνƒœ μ½”λ“œ
private final String message; // 응닡 λ©”μ‹œμ§€
private final T data; // 응닡 데이터 (성곡 μ‹œ 데이터, μ‹€νŒ¨ μ‹œ μΆ”κ°€ 정보)

// 성곡 응닡 μƒμ„±μž
private GlobalResponse(GlobalResponseCode responseCode, T data) {
this.timestamp = LocalDateTime.now();
this.statusCode = responseCode.getCode();
this.message = responseCode.getMessage();
this.data = data;
}

// μ—λŸ¬ 응닡 μƒμ„±μž
private GlobalResponse(ErrorCode errorCode, T data) {
this.timestamp = LocalDateTime.now();
this.statusCode = errorCode.getHttpStatus().value();
this.message = errorCode.getMessage();
this.data = data;
}

// 성곡 응닡 (데이터 포함)
public static <T> GlobalResponse<T> success(T data) {
return new GlobalResponse<>(GlobalResponseCode.OK, data);
}

// 성곡 응닡 (데이터 μ—†μŒ)
public static <T> GlobalResponse<T> success() {
return success(null);
}

// μ—λŸ¬ 응닡 (데이터 포함)
public static <T> GlobalResponse<T> error(ErrorCode errorCode, T data) {
return new GlobalResponse<>(errorCode, data);
}

// μ—λŸ¬ 응닡 (데이터 μ—†μŒ)
public static <T> GlobalResponse<T> error(ErrorCode errorCode) {
return error(errorCode, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmf.commitField.global.globalDto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum GlobalResponseCode {

OK(200, "μš”μ²­μ΄ μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€."),
BAD_REQUEST(400, "잘λͺ»λœ μš”μ²­μž…λ‹ˆλ‹€."),
NOT_FOUND(404, "찾을 수 μ—†μŠ΅λ‹ˆλ‹€."),
INTERNAL_SERVER_ERROR(500, "μ„œλ²„ λ‚΄λΆ€ 였λ₯˜κ°€ λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€.");

private final int code; // HTTP μƒνƒœ μ½”λ“œ
private final String message; // 응닡 λ©”μ‹œμ§€
}
24 changes: 23 additions & 1 deletion src/main/java/cmf/commitField/global/jpa/BaseEntity.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
package cmf.commitField.global.jpa;

import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;

import java.time.LocalDateTime;

import static jakarta.persistence.GenerationType.IDENTITY;

public class BaseEntity {
}
@Id
@GeneratedValue(strategy = IDENTITY)
@EqualsAndHashCode.Include
private Long id;

@CreatedDate
@Getter
private LocalDateTime createdAt;

@CreatedDate
@Getter
private LocalDateTime modifiedAt;
}