From f12e03d87715f4b14f5fcfd4ef78f3fb73c228ff Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:19:35 +0900 Subject: [PATCH 01/10] =?UTF-8?q?chore:=20component=20scan=20target=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=84=A4=EC=A0=95=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doorip-api/src/main/java/org/doorip/DooripApplication.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doorip-api/src/main/java/org/doorip/DooripApplication.java b/doorip-api/src/main/java/org/doorip/DooripApplication.java index d81e403..6a59713 100644 --- a/doorip-api/src/main/java/org/doorip/DooripApplication.java +++ b/doorip-api/src/main/java/org/doorip/DooripApplication.java @@ -3,7 +3,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -@SpringBootApplication +@SpringBootApplication( + scanBasePackageClasses = {DomainRoot.class, CommonRoot.class, ExternalRoot.class} +) public class DooripApplication { public static void main(String[] args) { SpringApplication.run(DooripApplication.class, args); From 2cde67cbb70846988093b8e025eb037671b9ec4d Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:19:45 +0900 Subject: [PATCH 02/10] =?UTF-8?q?chore:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/doorip/{ => common}/HealthCheckApiController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename doorip-api/src/main/java/org/doorip/{ => common}/HealthCheckApiController.java (93%) diff --git a/doorip-api/src/main/java/org/doorip/HealthCheckApiController.java b/doorip-api/src/main/java/org/doorip/common/HealthCheckApiController.java similarity index 93% rename from doorip-api/src/main/java/org/doorip/HealthCheckApiController.java rename to doorip-api/src/main/java/org/doorip/common/HealthCheckApiController.java index 8ccfa22..a15c8bc 100644 --- a/doorip-api/src/main/java/org/doorip/HealthCheckApiController.java +++ b/doorip-api/src/main/java/org/doorip/common/HealthCheckApiController.java @@ -1,4 +1,4 @@ -package org.doorip; +package org.doorip.common; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; From 4e3ec198fcd355fd8327d2765a1b844dbef64cce Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:20:43 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=EC=98=A4=EB=A5=98=20message=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20enum=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/doorip/message/ErrorMessage.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 doorip-common/src/main/java/org/doorip/message/ErrorMessage.java diff --git a/doorip-common/src/main/java/org/doorip/message/ErrorMessage.java b/doorip-common/src/main/java/org/doorip/message/ErrorMessage.java new file mode 100644 index 0000000..bf59122 --- /dev/null +++ b/doorip-common/src/main/java/org/doorip/message/ErrorMessage.java @@ -0,0 +1,49 @@ +package org.doorip.message; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public enum ErrorMessage { + /** + * 400 Bad Request + */ + BAD_REQUEST(HttpStatus.BAD_REQUEST, "e4000", "잘못된 요청입니다."), + + /** + * 401 Unauthorized + */ + UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "e4010", "리소스 접근 권한이 없습니다."), + + /** + * 403 Forbidden + */ + FORBIDDEN(HttpStatus.FORBIDDEN, "e4030", "리소스 접근 권한이 없습니다."), + + /** + * 404 Not Found + */ + ENTITY_NOT_FOUND(HttpStatus.NOT_FOUND, "e4040", "대상을 찾을 수 없습니다."), + + /** + * 405 Method Not Allowed + */ + METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "e4050", "잘못된 HTTP method 요청입니다."), + + /** + * 409 Conflict + */ + CONFLICT(HttpStatus.CONFLICT, "e4090", "이미 존재하는 리소스입니다."), + + /** + * 500 Internal Server Error + */ + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "e5000", "서버 내부 오류입니다."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; +} From da357d8f37528da22a5a97c891e4a7cb455d90a2 Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:20:56 +0900 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20=EC=84=B1=EA=B3=B5=20message=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20enum=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doorip/message/SuccessMessage.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 doorip-common/src/main/java/org/doorip/message/SuccessMessage.java diff --git a/doorip-common/src/main/java/org/doorip/message/SuccessMessage.java b/doorip-common/src/main/java/org/doorip/message/SuccessMessage.java new file mode 100644 index 0000000..f5eb271 --- /dev/null +++ b/doorip-common/src/main/java/org/doorip/message/SuccessMessage.java @@ -0,0 +1,23 @@ +package org.doorip.message; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public enum SuccessMessage { + /** + * 200 Ok + */ + OK(HttpStatus.OK, "요청이 성공했습니다."), + + /** + * 201 Created + */ + CREATED(HttpStatus.CREATED, "요청이 성공했습니다."); + + private final HttpStatus httpStatus; + private final String message; +} From c4ade7701790a34b57d1fc82121e33eb92582cc1 Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:21:44 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20custom=20exception=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EA=B5=AC=ED=98=84=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doorip/exception/BusinessException.java | 14 ++++++++++++++ .../org/doorip/exception/ConflictException.java | 13 +++++++++++++ .../doorip/exception/EntityNotFoundException.java | 13 +++++++++++++ .../doorip/exception/InvalidValueException.java | 13 +++++++++++++ .../doorip/exception/UnauthorizedException.java | 13 +++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 doorip-common/src/main/java/org/doorip/exception/BusinessException.java create mode 100644 doorip-common/src/main/java/org/doorip/exception/ConflictException.java create mode 100644 doorip-common/src/main/java/org/doorip/exception/EntityNotFoundException.java create mode 100644 doorip-common/src/main/java/org/doorip/exception/InvalidValueException.java create mode 100644 doorip-common/src/main/java/org/doorip/exception/UnauthorizedException.java diff --git a/doorip-common/src/main/java/org/doorip/exception/BusinessException.java b/doorip-common/src/main/java/org/doorip/exception/BusinessException.java new file mode 100644 index 0000000..a890a0f --- /dev/null +++ b/doorip-common/src/main/java/org/doorip/exception/BusinessException.java @@ -0,0 +1,14 @@ +package org.doorip.exception; + +import lombok.Getter; +import org.doorip.message.ErrorMessage; + +@Getter +public class BusinessException extends RuntimeException { + private final ErrorMessage errorMessage; + + public BusinessException(ErrorMessage errorMessage) { + super(errorMessage.getMessage()); + this.errorMessage = errorMessage; + } +} diff --git a/doorip-common/src/main/java/org/doorip/exception/ConflictException.java b/doorip-common/src/main/java/org/doorip/exception/ConflictException.java new file mode 100644 index 0000000..386b24b --- /dev/null +++ b/doorip-common/src/main/java/org/doorip/exception/ConflictException.java @@ -0,0 +1,13 @@ +package org.doorip.exception; + +import org.doorip.message.ErrorMessage; + +public class ConflictException extends BusinessException { + public ConflictException() { + super(ErrorMessage.CONFLICT); + } + + public ConflictException(ErrorMessage errorMessage) { + super(errorMessage); + } +} diff --git a/doorip-common/src/main/java/org/doorip/exception/EntityNotFoundException.java b/doorip-common/src/main/java/org/doorip/exception/EntityNotFoundException.java new file mode 100644 index 0000000..d5cbac5 --- /dev/null +++ b/doorip-common/src/main/java/org/doorip/exception/EntityNotFoundException.java @@ -0,0 +1,13 @@ +package org.doorip.exception; + +import org.doorip.message.ErrorMessage; + +public class EntityNotFoundException extends BusinessException { + public EntityNotFoundException() { + super(ErrorMessage.ENTITY_NOT_FOUND); + } + + public EntityNotFoundException(ErrorMessage errorMessage) { + super(errorMessage); + } +} diff --git a/doorip-common/src/main/java/org/doorip/exception/InvalidValueException.java b/doorip-common/src/main/java/org/doorip/exception/InvalidValueException.java new file mode 100644 index 0000000..a4b352c --- /dev/null +++ b/doorip-common/src/main/java/org/doorip/exception/InvalidValueException.java @@ -0,0 +1,13 @@ +package org.doorip.exception; + +import org.doorip.message.ErrorMessage; + +public class InvalidValueException extends BusinessException { + public InvalidValueException() { + super(ErrorMessage.BAD_REQUEST); + } + + public InvalidValueException(ErrorMessage errorMessage) { + super(errorMessage); + } +} diff --git a/doorip-common/src/main/java/org/doorip/exception/UnauthorizedException.java b/doorip-common/src/main/java/org/doorip/exception/UnauthorizedException.java new file mode 100644 index 0000000..c29137e --- /dev/null +++ b/doorip-common/src/main/java/org/doorip/exception/UnauthorizedException.java @@ -0,0 +1,13 @@ +package org.doorip.exception; + +import org.doorip.message.ErrorMessage; + +public class UnauthorizedException extends BusinessException { + public UnauthorizedException() { + super(ErrorMessage.UNAUTHORIZED); + } + + public UnauthorizedException(ErrorMessage errorMessage) { + super(errorMessage); + } +} From b28093240f0891ea3ae668b40501d047c04694e5 Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:22:15 +0900 Subject: [PATCH 06/10] =?UTF-8?q?feat:=20api=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/doorip/common/ApiResponse.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 doorip-api/src/main/java/org/doorip/common/ApiResponse.java diff --git a/doorip-api/src/main/java/org/doorip/common/ApiResponse.java b/doorip-api/src/main/java/org/doorip/common/ApiResponse.java new file mode 100644 index 0000000..83c50d9 --- /dev/null +++ b/doorip-api/src/main/java/org/doorip/common/ApiResponse.java @@ -0,0 +1,44 @@ +package org.doorip.common; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import org.doorip.message.ErrorMessage; +import org.doorip.message.SuccessMessage; + +@Builder(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Getter +public class ApiResponse { + private final int status; + @JsonInclude(value = JsonInclude.Include.NON_NULL) + private final String code; + private final String message; + @JsonInclude(value = JsonInclude.Include.NON_NULL) + private final T data; + + public static ApiResponse of(SuccessMessage successMessage) { + return builder() + .status(successMessage.getHttpStatus().value()) + .message(successMessage.getMessage()) + .build(); + } + + public static ApiResponse of(SuccessMessage successMessage, T data) { + return builder() + .status(successMessage.getHttpStatus().value()) + .message(successMessage.getMessage()) + .data(data) + .build(); + } + + public static ApiResponse of(ErrorMessage errorMessage) { + return builder() + .status(errorMessage.getHttpStatus().value()) + .code(errorMessage.getCode()) + .message(errorMessage.getMessage()) + .build(); + } +} \ No newline at end of file From d43d8ea70b70af1a493e19eba7a6c008a954ef21 Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:22:27 +0900 Subject: [PATCH 07/10] =?UTF-8?q?feat:=20api=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20util=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doorip/common/ApiResponseUtil.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 doorip-api/src/main/java/org/doorip/common/ApiResponseUtil.java diff --git a/doorip-api/src/main/java/org/doorip/common/ApiResponseUtil.java b/doorip-api/src/main/java/org/doorip/common/ApiResponseUtil.java new file mode 100644 index 0000000..7d1eee8 --- /dev/null +++ b/doorip-api/src/main/java/org/doorip/common/ApiResponseUtil.java @@ -0,0 +1,22 @@ +package org.doorip.common; + +import org.doorip.message.ErrorMessage; +import org.doorip.message.SuccessMessage; +import org.springframework.http.ResponseEntity; + +public interface ApiResponseUtil { + static ResponseEntity> success(SuccessMessage successMessage) { + return ResponseEntity.status(successMessage.getHttpStatus()) + .body(ApiResponse.of(successMessage)); + } + + static ResponseEntity> success(SuccessMessage successMessage, T data) { + return ResponseEntity.status(successMessage.getHttpStatus()) + .body(ApiResponse.of(successMessage, data)); + } + + static ResponseEntity> failure(ErrorMessage errorMessage) { + return ResponseEntity.status(errorMessage.getHttpStatus()) + .body(ApiResponse.of(errorMessage)); + } +} From 076967521737a55bec06558c72a604a46787b7c6 Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:22:42 +0900 Subject: [PATCH 08/10] =?UTF-8?q?chore:=20jpa=20auditing=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/doorip/config/JpaConfig.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doorip-domain/src/main/java/org/doorip/config/JpaConfig.java diff --git a/doorip-domain/src/main/java/org/doorip/config/JpaConfig.java b/doorip-domain/src/main/java/org/doorip/config/JpaConfig.java new file mode 100644 index 0000000..302b39f --- /dev/null +++ b/doorip-domain/src/main/java/org/doorip/config/JpaConfig.java @@ -0,0 +1,9 @@ +package org.doorip.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@EnableJpaAuditing +@Configuration +public class JpaConfig { +} From 2f1498e00872f054ccb88981e4e841e5b4720b7d Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:23:01 +0900 Subject: [PATCH 09/10] =?UTF-8?q?feat:=20base=20time=20entity=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EA=B5=AC=ED=98=84=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doorip/common/BaseTimeEntity.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 doorip-domain/src/main/java/org/doorip/common/BaseTimeEntity.java diff --git a/doorip-domain/src/main/java/org/doorip/common/BaseTimeEntity.java b/doorip-domain/src/main/java/org/doorip/common/BaseTimeEntity.java new file mode 100644 index 0000000..7f766bd --- /dev/null +++ b/doorip-domain/src/main/java/org/doorip/common/BaseTimeEntity.java @@ -0,0 +1,22 @@ +package org.doorip.common; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Getter +@EntityListeners(AuditingEntityListener.class) +@MappedSuperclass +public abstract class BaseTimeEntity { + @Column(updatable = false) + @CreatedDate + private LocalDateTime createdDate; + @LastModifiedDate + private LocalDateTime lastModifiedDate; +} From d5692add5512cd4995ac2e0433ff6a5e40c3bb49 Mon Sep 17 00:00:00 2001 From: sunwoong Date: Sun, 31 Dec 2023 01:23:26 +0900 Subject: [PATCH 10/10] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=20=ED=95=B8?= =?UTF-8?q?=EB=93=A4=EB=A7=81=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../doorip/common/GlobalExceptionHandler.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 doorip-api/src/main/java/org/doorip/common/GlobalExceptionHandler.java diff --git a/doorip-api/src/main/java/org/doorip/common/GlobalExceptionHandler.java b/doorip-api/src/main/java/org/doorip/common/GlobalExceptionHandler.java new file mode 100644 index 0000000..0335aff --- /dev/null +++ b/doorip-api/src/main/java/org/doorip/common/GlobalExceptionHandler.java @@ -0,0 +1,52 @@ +package org.doorip.common; + +import lombok.extern.slf4j.Slf4j; +import org.doorip.exception.BusinessException; +import org.doorip.message.ErrorMessage; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +@Slf4j +@ControllerAdvice +public class GlobalExceptionHandler { + @ExceptionHandler(MethodArgumentNotValidException.class) + protected ResponseEntity> handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) { + log.error(">>> handle: MethodArgumentNotValidException ", e); + return ApiResponseUtil.failure(ErrorMessage.BAD_REQUEST); + } + + @ExceptionHandler(BindException.class) + protected ResponseEntity> handleBindException(final BindException e) { + log.error(">>> handle: BindException ", e); + return ApiResponseUtil.failure(ErrorMessage.BAD_REQUEST); + } + + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + protected ResponseEntity> handleMethodArgumentTypeMismatchException(final MethodArgumentTypeMismatchException e) { + log.error(">>> handle: MethodArgumentTypeMismatchException ", e); + return ApiResponseUtil.failure(ErrorMessage.BAD_REQUEST); + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + protected ResponseEntity> handleHttpRequestMethodNotSupportedException(final HttpRequestMethodNotSupportedException e) { + log.error(">>> handle: HttpRequestMethodNotSupportedException ", e); + return ApiResponseUtil.failure(ErrorMessage.METHOD_NOT_ALLOWED); + } + + @ExceptionHandler(BusinessException.class) + protected ResponseEntity> handleBusinessException(final BusinessException e) { + log.error(">>> handle: BusinessException ", e); + return ApiResponseUtil.failure(e.getErrorMessage()); + } + + @ExceptionHandler(Exception.class) + protected ResponseEntity> handleException(final Exception e) { + log.error(">>> handle: Exception ", e); + return ApiResponseUtil.failure(ErrorMessage.INTERNAL_SERVER_ERROR); + } +} \ No newline at end of file