Skip to content

Commit 816d311

Browse files
committed
Merge branch 'dev' of https://github.com/CommitField/commitField into dev
2 parents 4dea8cd + fffcfd7 commit 816d311

File tree

8 files changed

+263
-22
lines changed

8 files changed

+263
-22
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package cmf.commitField.global.error;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
import org.springframework.http.HttpStatus;
6+
7+
@Getter
8+
@AllArgsConstructor
9+
public enum ErrorCode {
10+
11+
// Common
12+
INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "제공된 입력 값이 유효하지 않습니다."),
13+
METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "허용되지 않은 요청 방식입니다."),
14+
ENTITY_NOT_FOUND(HttpStatus.BAD_REQUEST, "요청한 엔티티를 찾을 수 없습니다."),
15+
INVALID_TYPE_VALUE(HttpStatus.BAD_REQUEST, "제공된 값의 타입이 유효하지 않습니다."),
16+
ERROR_PARSING_JSON_RESPONSE(HttpStatus.BAD_REQUEST, "JSON 응답을 파싱하는 중 오류가 발생했습니다."),
17+
MISSING_INPUT_VALUE(HttpStatus.BAD_REQUEST, "필수 입력 값이 누락되었습니다."),
18+
DATABASE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "데이터베이스 오류가 발생했습니다."),
19+
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 오류가 발생했습니다."),
20+
21+
// User
22+
NOT_FOUND_USER(HttpStatus.BAD_REQUEST, "해당 유저가 존재하지 않습니다"),
23+
PASSWORD_MISMATCH(HttpStatus.BAD_REQUEST, "비밀번호가 일치하지 않습니다."),
24+
25+
// Auth
26+
ACCESS_DENIED(HttpStatus.UNAUTHORIZED, "인증되지 않은 유저입니다."),
27+
SC_FORBIDDEN(HttpStatus.UNAUTHORIZED, "권한이 없는 유저입니다."),
28+
INVALID_JWT_SIGNATURE(HttpStatus.UNAUTHORIZED, "서명 검증에 실패했습니다." ),
29+
ILLEGAL_REGISTRATION_ID(HttpStatus.BAD_REQUEST,"해당 사항이 없는 로그인 경로입니다."),
30+
31+
TOKEN_EXPIRED(HttpStatus.BAD_REQUEST, "토큰이 만료되었습니다."),
32+
33+
// member
34+
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "사용자를 찾을 수 없습니다");
35+
36+
37+
private final HttpStatus httpStatus;
38+
private final String message;
39+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package cmf.commitField.global.error;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
import org.springframework.http.ResponseEntity;
6+
7+
import java.time.LocalDateTime;
8+
9+
@Getter
10+
public class ErrorResponse {
11+
private final String timestamp;
12+
private final String error;
13+
private final String message;
14+
15+
@Builder
16+
public ErrorResponse(String timestamp, String error, String message){
17+
this.timestamp = timestamp;
18+
this.error = error;
19+
this.message = message;
20+
}
21+
public static ResponseEntity<ErrorResponse> toResponseEntity(ErrorCode errorCode){
22+
return ResponseEntity
23+
.status(errorCode.getHttpStatus())
24+
.body(ErrorResponse.builder()
25+
.timestamp(LocalDateTime.now().toString())
26+
.error(errorCode.getHttpStatus().name())
27+
.message(errorCode.getMessage())
28+
.build()
29+
);
30+
31+
}
32+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package cmf.commitField.global.exception;
2+
3+
import cmf.commitField.global.error.ErrorCode;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
7+
@Getter
8+
@AllArgsConstructor
9+
public class CustomException extends RuntimeException {
10+
private final ErrorCode errorCode;
11+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package cmf.commitField.global.exception;
2+
3+
import cmf.commitField.global.error.ErrorCode;
4+
import cmf.commitField.global.error.ErrorResponse;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.hibernate.exception.ConstraintViolationException;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.http.converter.HttpMessageNotReadableException;
9+
import org.springframework.web.HttpRequestMethodNotSupportedException;
10+
import org.springframework.web.bind.MethodArgumentNotValidException;
11+
import org.springframework.web.bind.MissingServletRequestParameterException;
12+
import org.springframework.web.bind.annotation.ExceptionHandler;
13+
import org.springframework.web.bind.annotation.RestControllerAdvice;
14+
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
15+
16+
import java.sql.SQLIntegrityConstraintViolationException;
17+
18+
@Slf4j
19+
@RestControllerAdvice
20+
public class ExceptionControllerAdvice {
21+
22+
@ExceptionHandler(value = {ConstraintViolationException.class, MethodArgumentNotValidException.class, MethodArgumentTypeMismatchException.class})
23+
public ResponseEntity<ErrorResponse> handleValidationExceptions(Exception e) {
24+
log.error("Validation Exception: {}", e.getMessage(), e);
25+
return ErrorResponse.toResponseEntity(ErrorCode.INVALID_INPUT_VALUE);
26+
}
27+
28+
@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
29+
public ResponseEntity<ErrorResponse> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
30+
log.error("HTTP Method Not Supported: {}", e.getMessage(), e);
31+
return ErrorResponse.toResponseEntity(ErrorCode.METHOD_NOT_ALLOWED);
32+
}
33+
34+
@ExceptionHandler(value = CustomException.class)
35+
protected ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
36+
log.error("Custom Exception: {}", e.getErrorCode(), e);
37+
return ErrorResponse.toResponseEntity(e.getErrorCode());
38+
}
39+
40+
@ExceptionHandler(value = NullPointerException.class)
41+
public ResponseEntity<ErrorResponse> handleNullPointerException(NullPointerException e) {
42+
log.error("Null Pointer Exception: {}", e.getMessage(), e);
43+
return ErrorResponse.toResponseEntity(ErrorCode.MISSING_INPUT_VALUE);
44+
}
45+
46+
@ExceptionHandler(value = MissingServletRequestParameterException.class)
47+
public ResponseEntity<ErrorResponse> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
48+
log.error("Missing Request Parameter: {}", e.getMessage(), e);
49+
return ErrorResponse.toResponseEntity(ErrorCode.MISSING_INPUT_VALUE);
50+
}
51+
52+
@ExceptionHandler(value = HttpMessageNotReadableException.class)
53+
public ResponseEntity<ErrorResponse> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
54+
log.error("Message Not Readable: {}", e.getMessage(), e);
55+
return ErrorResponse.toResponseEntity(ErrorCode.INVALID_INPUT_VALUE);
56+
}
57+
58+
@ExceptionHandler(value = SQLIntegrityConstraintViolationException.class)
59+
public ResponseEntity<ErrorResponse> handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) {
60+
log.error("SQL Integrity Constraint Violation: {}", e.getMessage(), e);
61+
return ErrorResponse.toResponseEntity(ErrorCode.DATABASE_ERROR);
62+
}
63+
64+
@ExceptionHandler(value = Exception.class)
65+
public ResponseEntity<ErrorResponse> handleGeneralException(Exception e) {
66+
log.error("Unhandled Exception: {}", e.getMessage(), e);
67+
return ErrorResponse.toResponseEntity(ErrorCode.INTERNAL_SERVER_ERROR);
68+
}
69+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package cmf.commitField.global.globalDto;
2+
3+
import cmf.commitField.global.error.ErrorCode;
4+
import lombok.Getter;
5+
6+
import java.time.LocalDateTime;
7+
8+
@Getter
9+
public class GlobalResponse<T> {
10+
11+
private final LocalDateTime timestamp; // 응답 생성 시간
12+
private final int statusCode; // HTTP 상태 코드
13+
private final String message; // 응답 메시지
14+
private final T data; // 응답 데이터 (성공 시 데이터, 실패 시 추가 정보)
15+
16+
// 성공 응답 생성자
17+
private GlobalResponse(GlobalResponseCode responseCode, T data) {
18+
this.timestamp = LocalDateTime.now();
19+
this.statusCode = responseCode.getCode();
20+
this.message = responseCode.getMessage();
21+
this.data = data;
22+
}
23+
24+
// 에러 응답 생성자
25+
private GlobalResponse(ErrorCode errorCode, T data) {
26+
this.timestamp = LocalDateTime.now();
27+
this.statusCode = errorCode.getHttpStatus().value();
28+
this.message = errorCode.getMessage();
29+
this.data = data;
30+
}
31+
32+
// 성공 응답 (데이터 포함)
33+
public static <T> GlobalResponse<T> success(T data) {
34+
return new GlobalResponse<>(GlobalResponseCode.OK, data);
35+
}
36+
37+
// 성공 응답 (데이터 없음)
38+
public static <T> GlobalResponse<T> success() {
39+
return success(null);
40+
}
41+
42+
// 에러 응답 (데이터 포함)
43+
public static <T> GlobalResponse<T> error(ErrorCode errorCode, T data) {
44+
return new GlobalResponse<>(errorCode, data);
45+
}
46+
47+
// 에러 응답 (데이터 없음)
48+
public static <T> GlobalResponse<T> error(ErrorCode errorCode) {
49+
return error(errorCode, null);
50+
}
51+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package cmf.commitField.global.globalDto;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
6+
@Getter
7+
@RequiredArgsConstructor
8+
public enum GlobalResponseCode {
9+
10+
OK(200, "요청이 성공하였습니다."),
11+
BAD_REQUEST(400, "잘못된 요청입니다."),
12+
NOT_FOUND(404, "찾을 수 없습니다."),
13+
INTERNAL_SERVER_ERROR(500, "서버 내부 오류가 발생하였습니다.");
14+
15+
private final int code; // HTTP 상태 코드
16+
private final String message; // 응답 메시지
17+
}
Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,26 @@
11
package cmf.commitField.global.jpa;
22

3+
import jakarta.persistence.GeneratedValue;
4+
import jakarta.persistence.Id;
5+
import lombok.EqualsAndHashCode;
6+
import lombok.Getter;
7+
import org.springframework.data.annotation.CreatedDate;
8+
9+
import java.time.LocalDateTime;
10+
11+
import static jakarta.persistence.GenerationType.IDENTITY;
12+
313
public class BaseEntity {
4-
}
14+
@Id
15+
@GeneratedValue(strategy = IDENTITY)
16+
@EqualsAndHashCode.Include
17+
private Long id;
18+
19+
@CreatedDate
20+
@Getter
21+
private LocalDateTime createdAt;
22+
23+
@CreatedDate
24+
@Getter
25+
private LocalDateTime modifiedAt;
26+
}

src/main/resources/application.yml

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
server:
2-
port: 8090
3-
timezone: Asia/Seoul
4-
spring:
5-
config:
6-
import: application-secret.yml
7-
output:
8-
ansi:
9-
enabled: ALWAYS
10-
profiles:
11-
active: dev
12-
include: secret
13-
datasource:
14-
url: jdbc:mysql://localhost:3306/cmf_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Seoul
15-
username: root
16-
password: cmfgogo!!1236
17-
driver-class-name: com.mysql.cj.jdbc.Driver
18-
jpa:
19-
open-in-view: false
20-
hibernate:
21-
ddl-auto: update
1+
#server:
2+
# port: 8090
3+
# timezone: Asia/Seoul
4+
#spring:
5+
# config:
6+
# import: application-secret.yml
7+
# output:
8+
# ansi:
9+
# enabled: ALWAYS
10+
# profiles:
11+
# active: dev
12+
# include: secret
13+
# datasource:
14+
# url: jdbc:mysql://localhost:3306/cmf_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Seoul
15+
# username: root
16+
# password: cmfgogo!!1236
17+
# driver-class-name: com.mysql.cj.jdbc.Driver
18+
# jpa:
19+
# open-in-view: false
20+
# hibernate:
21+
# ddl-auto: update

0 commit comments

Comments
 (0)