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

feature: API Response, Exception 공통 처리 #12

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions blog/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cloudclub.blog.common.enums;

import org.springframework.http.HttpStatus;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum FailResponseStatus {

// example
// HttpStatus 관련 논의 필요
BAD_REQUEST("BAD_REQUEST", "E400", HttpStatus.BAD_REQUEST, "잘못된 요청입니다."),
INVALID_PARAM_ERROR("INVALID_PARAM_ERROR", "E401", HttpStatus.BAD_REQUEST, "파라미터가 유효하지 않습니다."),
INTERNAL_SERVER_ERROR("INTERNAL_SERVER_ERROR",
"E500",
HttpStatus.INTERNAL_SERVER_ERROR,
"내부 서버 오류입니다.");

private final String statusName;
private final String statusCode;
private final HttpStatus httpStatusCode;
private final String message;


@Override
public String toString() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cloudclub.blog.common.enums;

import org.springframework.http.HttpStatus;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum SuccessResponseStatus {

// S1XX : Server response success
SUCCESS(HttpStatus.OK ,"S101", "요청이 성공하였습니다."),
REDIRECT(HttpStatus.FOUND, "S102", "지정된 URL로 이동합니다.");
// S2XX : something

private HttpStatus httpStatus;
private String statusCode;
private String message;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package cloudclub.blog.common.exception;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import cloudclub.blog.common.enums.FailResponseStatus;
import cloudclub.blog.common.model.ResponseDto;

@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RestApiException.class)
public <T> ResponseEntity<ResponseDto<T>> handleCustomException(final RestApiException e) {
final FailResponseStatus errorCode = e.getFailResponseStatus();
e.printStackTrace();
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(false)
.statusCode(errorCode.getStatusCode().toString())
.message(errorCode.getMessage())
.data(null)
.build();
return new ResponseEntity<>(dto, errorCode.getHttpStatusCode());
}

@ExceptionHandler({Exception.class})
public <T> ResponseEntity<ResponseDto<T>> handleAllException(final Exception ex) {
final FailResponseStatus errorCode = FailResponseStatus.INTERNAL_SERVER_ERROR;
ex.printStackTrace();
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(false)
.statusCode(errorCode.getStatusCode().toString())
.message(errorCode.getMessage())
.data(null)
.build();
return new ResponseEntity<>(dto, errorCode.getHttpStatusCode());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cloudclub.blog.common.exception;

import cloudclub.blog.common.enums.FailResponseStatus;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class RestApiException extends RuntimeException {

private FailResponseStatus failResponseStatus;

public RestApiException(FailResponseStatus e) {
super(e.getMessage());
this.failResponseStatus = e;
}

}
53 changes: 53 additions & 0 deletions blog/src/main/java/cloudclub/blog/common/log/BlogLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package cloudclub.blog.common.log;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;

@Aspect
@Slf4j
public class BlogLogger {

@Pointcut("execution(* cloudclub.blog.*.*(..))")
private void publicTarget(){
}


@Before("publicTarget()")
public void beforeController(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String requestId = request.getRequestId();
String className = joinPoint.getTarget().getClass().getSimpleName();
log.info("[{}] #BEFORE >> {}.{}()", requestId, className, method.getName());
Object[] args = joinPoint.getArgs();
for(Object arg : args) {
if(arg != null) {
log.info(" type = {}", arg.getClass().getSimpleName());
log.info(" value = {}", arg);
}
}
}

@After("publicTarget()")
public void afterController(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String requestId = request.getRequestId();
String className = joinPoint.getTarget().getClass().getSimpleName();
log.info("[{}] #After >> {}.{}()", requestId, className, method.getName());
}

}
16 changes: 16 additions & 0 deletions blog/src/main/java/cloudclub/blog/common/log/LoggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cloudclub.blog.common.log;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class LoggerConfig {

@Bean
public BlogLogger blogLogger() {
return new BlogLogger();
}

}
20 changes: 20 additions & 0 deletions blog/src/main/java/cloudclub/blog/common/model/ResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cloudclub.blog.common.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResponseDto<T> {

private boolean successOrNot;
private String statusCode;
private String message;
private T data;

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cloudclub.blog.common.model;

import java.net.http.HttpResponse;

import lombok.Builder;

@Builder
public class ResponsePagingDto<T> {
private String statusCode;

private String message;

private Long page;

private Integer size;

private T data;

}
118 changes: 118 additions & 0 deletions blog/src/main/java/cloudclub/blog/common/util/ResponseUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package cloudclub.blog.common.util;

import cloudclub.blog.common.enums.SuccessResponseStatus;
import cloudclub.blog.common.model.ResponseDto;
import cloudclub.blog.common.model.ResponsePagingDto;
import lombok.experimental.UtilityClass;

import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;

@UtilityClass
public class ResponseUtil {

public static <T> ResponseEntity<ResponseDto<T>> createSuccessResponse() {
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(true)
.statusCode(SuccessResponseStatus.SUCCESS.getStatusCode())
.message(SuccessResponseStatus.SUCCESS.getMessage())
.data(null)
.build();
return new ResponseEntity<>(dto, SuccessResponseStatus.SUCCESS.getHttpStatus());
}

public static <T> ResponseEntity<ResponseDto<T>> createSuccessResponse(HttpHeaders httpHeaders) {
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(true)
.statusCode(SuccessResponseStatus.SUCCESS.getStatusCode())
.message(SuccessResponseStatus.SUCCESS.getMessage())
.data(null)
.build();
return new ResponseEntity<>(dto, httpHeaders, SuccessResponseStatus.SUCCESS.getHttpStatus());
}

public static <T> ResponseEntity<ResponseDto<T>> createSuccessResponse(T data) {
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(true)
.statusCode(SuccessResponseStatus.SUCCESS.getStatusCode())
.message(SuccessResponseStatus.SUCCESS.getMessage())
.data(data)
.build();
return new ResponseEntity<>(dto, SuccessResponseStatus.SUCCESS.getHttpStatus());
}

public static <T> ResponseEntity<ResponseDto<T>> createSuccessResponse(T data, HttpHeaders httpHeaders) {
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(true)
.statusCode(SuccessResponseStatus.SUCCESS.getStatusCode())
.message(SuccessResponseStatus.SUCCESS.getMessage())
.data(data)
.build();
return new ResponseEntity<>(dto, httpHeaders, SuccessResponseStatus.SUCCESS.getHttpStatus());
}

public static <T> ResponseEntity<ResponseDto<T>> createSuccessResponse(SuccessResponseStatus status) {
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(true)
.statusCode(status.getStatusCode())
.message(status.getMessage())
.data(null)
.build();
return new ResponseEntity<>(dto, status.getHttpStatus());
}

public static <T> ResponseEntity<ResponseDto<T>> createSuccessResponse(SuccessResponseStatus status, HttpHeaders httpHeaders) {
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(true)
.statusCode(status.getStatusCode())
.message(status.getMessage())
.data(null)
.build();
return new ResponseEntity<>(dto, httpHeaders, status.getHttpStatus());
}

public static <T> ResponseEntity<ResponseDto<T>> createSuccessResponse(SuccessResponseStatus status, T data) {
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(true)
.statusCode(status.getStatusCode())
.message(status.getMessage())
.data(data)
.build();
return new ResponseEntity<>(dto, status.getHttpStatus());
}

public static <T> ResponseEntity<ResponseDto<T>> createSuccessResponse(SuccessResponseStatus status, T data, HttpHeaders httpHeaders) {
ResponseDto<T> dto = ResponseDto.<T>builder()
.successOrNot(true)
.statusCode(status.getStatusCode())
.message(status.getMessage())
.data(data)
.build();
return new ResponseEntity<>(dto, httpHeaders, status.getHttpStatus());
}



public static <T> ResponseEntity<ResponsePagingDto<T>> createSuccessResponse(T data, Pageable pageable) {
ResponsePagingDto<T> dto = ResponsePagingDto.<T>builder()
.statusCode(SuccessResponseStatus.SUCCESS.getStatusCode())
.message(SuccessResponseStatus.SUCCESS.getMessage())
.data(data)
.page(pageable.getOffset())
.size(pageable.getPageSize())
.build();
return new ResponseEntity<>(dto, SuccessResponseStatus.SUCCESS.getHttpStatus());
}

public static <T> ResponseEntity<ResponsePagingDto<T>> createSuccessResponse(T data, HttpHeaders httpHeaders, Pageable pageable) {
ResponsePagingDto<T> dto = ResponsePagingDto.<T>builder()
.statusCode(SuccessResponseStatus.SUCCESS.getStatusCode())
.message(SuccessResponseStatus.SUCCESS.getMessage())
.data(data)
.page(pageable.getOffset())
.size(pageable.getPageSize())
.build();
return new ResponseEntity<>(dto, httpHeaders, SuccessResponseStatus.SUCCESS.getHttpStatus());
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cloudclub.blog.posts.controller;

import cloudclub.blog.posts.dto.PostDto;
import cloudclub.blog.posts.dto.PostRequestsDto;
import cloudclub.blog.posts.config.ResultMessage;
import cloudclub.blog.posts.entity.Post;
import cloudclub.blog.posts.service.PostService;
import lombok.RequiredArgsConstructor;
import org.apache.coyote.Response;
Expand All @@ -27,7 +29,16 @@ public ResponseEntity<ResultMessage> getPost(@RequestParam Long postId, @Request

@GetMapping("/MyBlog.io/@{userId}/{slug}")
public ResponseEntity<ResultMessage> getPost(@PathVariable Long userId, @PathVariable String slug) {
return postService.getPostByUrl(userId, slug);
return postService.getPostDtoByUrl(userId, slug);
}

@DeleteMapping("/v1/post")
public void deletePost(@RequestParam Long postId) {
postService.deletePost(postId);
}

@PatchMapping("/v1/post")
public ResponseEntity<ResultMessage> updatePost(@RequestParam Long postId, @RequestBody PostRequestsDto requestsDto) throws Exception {
return postService.update(postId, requestsDto);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
Expand Down
Loading