Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 프로젝트 공통 기능 생성 #10

Merged
merged 10 commits into from
Sep 26, 2023
40 changes: 40 additions & 0 deletions src/test/java/com/kakao/golajuma/common/BaseEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.kakao.golajuma.common;

import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@MappedSuperclass
@EntityListeners({AuditingEntityListener.class, SoftDeleteListener.class})
@SuperBuilder(toBuilder = true)
public class BaseEntity {

@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdDate;

@LastModifiedDate
@Column(nullable = false)
private LocalDateTime updatedDate;

@Builder.Default
@Column(nullable = false)
private Boolean deleted = false;

public void delete() {
this.deleted = true;
}
}
11 changes: 11 additions & 0 deletions src/test/java/com/kakao/golajuma/common/SoftDeleteListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.kakao.golajuma.common;

import javax.persistence.PreRemove;

public class SoftDeleteListener {

@PreRemove
private void preRemove(BaseEntity entity) {
entity.delete();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.kakao.golajuma.common.exception;

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

@Getter
public class BusinessException extends RuntimeException {
private final HttpStatus httpStatus;

public BusinessException(String message, HttpStatus httpStatus) {
super(message);
this.httpStatus = httpStatus;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.kakao.golajuma.common.exception;

import com.kakao.golajuma.common.support.respnose.ApiResponse;
import com.kakao.golajuma.common.support.respnose.ApiResponseBody.FailureBody;
import com.kakao.golajuma.common.support.respnose.ApiResponseGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

/** javax.validation.Valid 또는 @Validated binding error가 발생할 경우 */
@ExceptionHandler(BindException.class)
protected ApiResponse<FailureBody> handleBindException(BindException e) {
log.error("handleBindException", e);
return ApiResponseGenerator.fail(e.getMessage(), HttpStatus.BAD_REQUEST);
}

/** 주로 @RequestParam enum으로 binding 못했을 경우 발생 */
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
protected ApiResponse<FailureBody> handleMethodArgumentTypeMismatchException(
MethodArgumentTypeMismatchException e) {
log.error("handleMethodArgumentTypeMismatchException", e);
return ApiResponseGenerator.fail(e.getMessage(), HttpStatus.BAD_REQUEST);
}

/** 지원하지 않은 HTTP method 호출 할 경우 발생 */
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
protected ApiResponse<FailureBody> handleHttpRequestMethodNotSupportedException(
HttpRequestMethodNotSupportedException e) {
log.error("handleHttpRequestMethodNotSupportedException", e);
return ApiResponseGenerator.fail(e.getMessage(), HttpStatus.METHOD_NOT_ALLOWED);
}

/** 비즈니스 로직 실행 중 오류 발생 */
@ExceptionHandler(value = {BusinessException.class})
protected ApiResponse<FailureBody> handleConflict(BusinessException e) {
log.error("BusinessException", e);
return ApiResponseGenerator.fail(e.getMessage(), e.getHttpStatus());
}

/** 나머지 예외 발생 */
@ExceptionHandler(Exception.class)
protected ApiResponse<FailureBody> handleException(Exception e) {
log.error("Exception", e);
return ApiResponseGenerator.fail(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.kakao.golajuma.common.marker;

public interface AbstractDto {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.kakao.golajuma.common.marker;

public interface AbstractRequestDto extends AbstractDto {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.kakao.golajuma.common.marker;

public interface AbstractResponseDto extends AbstractDto {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.kakao.golajuma.common.support.respnose;

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

@Getter
public class ApiResponse<B> extends ResponseEntity<B> {

public ApiResponse(final HttpStatus status) {
super(status);
}

public ApiResponse(final B body, final HttpStatus status) {
super(body, status);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.kakao.golajuma.common.support.respnose;

import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Getter;

public class ApiResponseBody {
@Getter
@AllArgsConstructor
public static class FailureBody implements Serializable {

private String code;
private String message;
}

@Getter
@AllArgsConstructor
public static class SuccessBody<D> implements Serializable {
private D data;
private String message;
private String code;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.kakao.golajuma.common.support.respnose;

import lombok.experimental.UtilityClass;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;

@UtilityClass
public class ApiResponseGenerator {
public static ApiResponse<ApiResponseBody.SuccessBody<Void>> success(
final HttpStatus status, MessageCode code) {
return new ApiResponse<>(
new ApiResponseBody.SuccessBody<>(null, code.getMessage(), code.getCode()), status);
}

public static <D> ApiResponse<ApiResponseBody.SuccessBody<D>> success(
final D data, final HttpStatus status, MessageCode code) {
return new ApiResponse<>(
new ApiResponseBody.SuccessBody<>(data, code.getMessage(), code.getCode()), status);
}

public static <D> ApiResponse<ApiResponseBody.SuccessBody<PageResponse<D>>> success(
final Page<D> data, final HttpStatus status, final MessageCode code) {
return new ApiResponse<>(
new ApiResponseBody.SuccessBody<>(
new PageResponse<>(data), code.getMessage(), code.getCode()),
status);
}

public static ApiResponse<ApiResponseBody.FailureBody> fail(
final ApiResponseBody.FailureBody body, final HttpStatus status) {
return new ApiResponse<>(body, status);
}

public static ApiResponse<ApiResponseBody.FailureBody> fail(
final String message, final HttpStatus status) {
return new ApiResponse<>(
new ApiResponseBody.FailureBody(String.valueOf(status.value()), message), status);
}

public static ApiResponse<ApiResponseBody.FailureBody> fail(
final String code, final String message, final HttpStatus status) {
return new ApiResponse<>(new ApiResponseBody.FailureBody(code, message), status);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.kakao.golajuma.common.support.respnose;

public enum MessageCode {
CREATE("200", "생성 성공");
private final String code;
private final String message;

MessageCode(String code, String message) {
this.code = code;
this.message = message;
}

public String getCode() {
return code;
}

public String getMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.kakao.golajuma.common.support.respnose;

import java.util.List;
import lombok.Getter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

@Getter
public class PageResponse<T> {

/** 페이지를 구성하는 일정 수의 크기 */
private final int pageSize;
/** 데이터를 가져온 페이지 번호 */
private final int pageNumber;
/** size 크기에 맞춰 페이징했을 때 나오는 총 페이지 개수 */
private final int totalPageCount;
/** 전체 데이터 개수 */
private final Long totalCount;

private final List<T> data;

public PageResponse(final Page<T> source) {
final Pageable pageable = source.getPageable();
this.pageSize = pageable.getPageSize();
this.pageNumber = pageable.getPageNumber();
this.totalPageCount = source.getTotalPages();
this.totalCount = source.getTotalElements();
this.data = source.getContent();
}
}
Loading