From 044289408ebad8e2510454dcdc4cfc0e58d171f8 Mon Sep 17 00:00:00 2001 From: Hyoseop Song Date: Sat, 6 Jul 2024 00:50:59 +0900 Subject: [PATCH 1/5] =?UTF-8?q?:recycle:=20Refactor:=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=95=20=EC=A0=95=EB=B3=B4=20DTO=EB=A5=BC=20data=20?= =?UTF-8?q?=ED=95=98=EC=9C=84=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../khu/toyouserver/common/ApiResponse.java | 45 ++++--------------- 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/src/main/java/slvtwn/khu/toyouserver/common/ApiResponse.java b/src/main/java/slvtwn/khu/toyouserver/common/ApiResponse.java index 46122c7..03a6e63 100644 --- a/src/main/java/slvtwn/khu/toyouserver/common/ApiResponse.java +++ b/src/main/java/slvtwn/khu/toyouserver/common/ApiResponse.java @@ -14,55 +14,28 @@ public class ApiResponse { private final String message; @JsonInclude(Include.NON_NULL) - private final T data; - - private final PageInfoResponse pageInfo; + private final Object data; ApiResponse(String code, String message) { - this(code, message, null, null); - } - - ApiResponse(String code, String message, T data) { - this(code, message, data, null); + this(code, message, null); } - ApiResponse(String code, String message, T data, PageInfoResponse pageInfo) { + ApiResponse(String code, String message, Object data) { this.code = code; this.message = message; this.data = data; this.pageInfo = pageInfo; } - public static ApiResponse success(SuccessType successType) { - return new ApiResponse<>(successType.getCode(), successType.getMessage()); - } - - public static ApiResponse success(SuccessType successType, T data) { - return new ApiResponse<>(successType.getCode(), successType.getMessage(), data); - } - - public static ApiResponse success(SuccessType successType, T data, PageInfoResponse pageInfo) { - return new ApiResponse<>(successType.getCode(), successType.getMessage(), data, pageInfo); + public static ApiResponse success(SuccessType successType, Object data) { + return new ApiResponse(successType.getCode(), successType.getMessage(), data); } - public static ApiResponse error(ErrorType errorType) { - return new ApiResponse<>(errorType.getCode(), errorType.getMessage()); + public static ApiResponse error(ErrorType errorType) { + return new ApiResponse(errorType.code(), errorType.message()); } - public static ApiResponse error(ErrorType errorType, T data) { - return new ApiResponse<>(errorType.getCode(), errorType.getMessage(), data); + public static ApiResponse error(ErrorType errorType, Object data) { + return new ApiResponse(errorType.code(), errorType.message(), data); } - - public static ApiResponse error(ErrorType errorType, String message) { - return new ApiResponse<>(errorType.getCode(), message); - } - - public static ApiResponse error(ErrorType errorType, String message, T data) { - return new ApiResponse<>(errorType.getCode(), message, data); - } - - public static ApiResponse error(ErrorType errorType, Exception e) { - return new ApiResponse<>(errorType.getCode(), errorType.getMessage(), e); - } - } \ No newline at end of file From 5fe39452c932dc8be4b3cbf596109195a7cdc531 Mon Sep 17 00:00:00 2001 From: Hyoseop Song Date: Sat, 6 Jul 2024 00:53:40 +0900 Subject: [PATCH 2/5] =?UTF-8?q?:zap:=20Feat:=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=ED=9B=84=EC=B2=98=EB=A6=AC=20Advice=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../toyouserver/common/ApiResponseAdvice.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/slvtwn/khu/toyouserver/common/ApiResponseAdvice.java diff --git a/src/main/java/slvtwn/khu/toyouserver/common/ApiResponseAdvice.java b/src/main/java/slvtwn/khu/toyouserver/common/ApiResponseAdvice.java new file mode 100644 index 0000000..ab196f5 --- /dev/null +++ b/src/main/java/slvtwn/khu/toyouserver/common/ApiResponseAdvice.java @@ -0,0 +1,47 @@ +package slvtwn.khu.toyouserver.common; + + +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.http.server.ServletServerHttpResponse; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +@RestControllerAdvice(basePackages = "slvtwn.khu.toyouserver") +public class ApiResponseAdvice implements ResponseBodyAdvice { + + @Override + public boolean supports(MethodParameter returnType, Class converterType) { + return true; + } + + @Override + public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, + Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { + HttpServletResponse servletResponse = + ((ServletServerHttpResponse) response).getServletResponse(); + + HttpStatus resolve = HttpStatus.resolve(servletResponse.getStatus()); + + if (!(body instanceof ApiResponse)) { + assert resolve != null; + return createResponseByHttpStatus(resolve, body); + } + return body; + } + + private Object createResponseByHttpStatus(HttpStatus status, Object body) { + if (status.is2xxSuccessful()) { + return ApiResponse.success(SuccessType.OK, body); + } else if (status.is4xxClientError()) { + return ApiResponse.error(ErrorType.BAD_REQUEST); + } else if (status.is5xxServerError()) { + return ApiResponse.error(ErrorType.INTERNAL_SERVER_ERROR); + } + return ApiResponse.error(ErrorType.RESPONSE_FORMAT_ERROR, body); + } +} From 5b766b104e404e11460be992755ba68ca0942c41 Mon Sep 17 00:00:00 2001 From: Hyoseop Song Date: Sat, 6 Jul 2024 00:54:03 +0900 Subject: [PATCH 3/5] =?UTF-8?q?:zap:=20Feat:=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20timestamp=20=ED=95=84=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../slvtwn/khu/toyouserver/common/ApiResponse.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/slvtwn/khu/toyouserver/common/ApiResponse.java b/src/main/java/slvtwn/khu/toyouserver/common/ApiResponse.java index 03a6e63..d7aed6c 100644 --- a/src/main/java/slvtwn/khu/toyouserver/common/ApiResponse.java +++ b/src/main/java/slvtwn/khu/toyouserver/common/ApiResponse.java @@ -1,13 +1,20 @@ package slvtwn.khu.toyouserver.common; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.time.LocalDateTime; import lombok.Getter; @Getter -@JsonPropertyOrder({"code", "message", "data", "pageInfo"}) -public class ApiResponse { +@JsonPropertyOrder({"timestamp", "code", "message", "data"}) +public class ApiResponse { + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd HH:mm:ss", timezone = "Asia/Seoul") + @JsonProperty("timestamp") + private LocalDateTime timestamp = LocalDateTime.now(); private final String code; @@ -24,7 +31,6 @@ public class ApiResponse { this.code = code; this.message = message; this.data = data; - this.pageInfo = pageInfo; } public static ApiResponse success(SuccessType successType, Object data) { From 6cdf7c9ab4bcf54ebbbe866200380725731e8ae8 Mon Sep 17 00:00:00 2001 From: Hyoseop Song Date: Sat, 6 Jul 2024 00:54:29 +0900 Subject: [PATCH 4/5] =?UTF-8?q?:zap:=20Feat:=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=84=B1=EA=B3=B5/=EC=8B=A4=ED=8C=A8=20=ED=83=80=EC=9E=85=20Ht?= =?UTF-8?q?tpStatusCode=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80=20(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../khu/toyouserver/common/ErrorType.java | 41 +++++++++++++++---- .../khu/toyouserver/common/SuccessType.java | 5 ++- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/main/java/slvtwn/khu/toyouserver/common/ErrorType.java b/src/main/java/slvtwn/khu/toyouserver/common/ErrorType.java index 22222d3..10e2ea6 100644 --- a/src/main/java/slvtwn/khu/toyouserver/common/ErrorType.java +++ b/src/main/java/slvtwn/khu/toyouserver/common/ErrorType.java @@ -1,17 +1,42 @@ package slvtwn.khu.toyouserver.common; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; -@Getter -@AllArgsConstructor(access = AccessLevel.PRIVATE) public enum ErrorType { - // 404 (Not Found) - NOT_FOUND("TYU404", "Not Found"); + // 400 ~ 499 (요청 오류) + RESPONSE_FORMAT_ERROR(HttpStatus.BAD_REQUEST, "TYU-400", "응답 형식 오류"), + BAD_REQUEST(HttpStatus.BAD_REQUEST, "TYU-400", "잘못된 요청입니다."), + NOT_FOUND(HttpStatus.NOT_FOUND, "TYU-404", "요청한 자원을 찾을 수 없습니다."), - private final String code; + // 500 ~ 599 (서버 오류) + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "TYU-500", "서버 내부 오류"); + + ErrorType( + final HttpStatusCode httpStatusCode, + final String code, + final String message + ) { + this.httpStatusCode = httpStatusCode; + this.code = code; + this.message = message; + } + private final HttpStatusCode httpStatusCode; + private final String code; private final String message; + + public HttpStatusCode httpStatusCode() { + return httpStatusCode; + } + + public String code() { + return code; + } + + public String message() { + return message; + } + } diff --git a/src/main/java/slvtwn/khu/toyouserver/common/SuccessType.java b/src/main/java/slvtwn/khu/toyouserver/common/SuccessType.java index 10091f8..6e4928f 100644 --- a/src/main/java/slvtwn/khu/toyouserver/common/SuccessType.java +++ b/src/main/java/slvtwn/khu/toyouserver/common/SuccessType.java @@ -3,14 +3,17 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum SuccessType { // 200 (OK) - OK("TYU200", "success"); + OK(HttpStatus.OK, "TYU-200", "응답 성공"); + private final HttpStatusCode httpStatusCode; private final String code; private final String message; } From 8643b0982cab552e54b32e377584a719f0ac104a Mon Sep 17 00:00:00 2001 From: Hyoseop Song Date: Sat, 6 Jul 2024 01:18:03 +0900 Subject: [PATCH 5/5] =?UTF-8?q?:white=5Fcheck=5Fmark:=20Test:=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=ED=98=95=EC=8B=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../khu/toyouserver/response/PageableDto.java | 9 +++++ .../response/ResponseController.java | 19 +++++++++ .../response/ResponseControllerTest.java | 39 +++++++++++++++++++ .../toyouserver/response/ResponseService.java | 13 +++++++ 4 files changed, 80 insertions(+) create mode 100644 src/test/java/slvtwn/khu/toyouserver/response/PageableDto.java create mode 100644 src/test/java/slvtwn/khu/toyouserver/response/ResponseController.java create mode 100644 src/test/java/slvtwn/khu/toyouserver/response/ResponseControllerTest.java create mode 100644 src/test/java/slvtwn/khu/toyouserver/response/ResponseService.java diff --git a/src/test/java/slvtwn/khu/toyouserver/response/PageableDto.java b/src/test/java/slvtwn/khu/toyouserver/response/PageableDto.java new file mode 100644 index 0000000..cff7b70 --- /dev/null +++ b/src/test/java/slvtwn/khu/toyouserver/response/PageableDto.java @@ -0,0 +1,9 @@ +package slvtwn.khu.toyouserver.response; + +import slvtwn.khu.toyouserver.common.PageInfoResponse; + +public record PageableDto( + Long id, + String name, + PageInfoResponse pageInfo) { +} diff --git a/src/test/java/slvtwn/khu/toyouserver/response/ResponseController.java b/src/test/java/slvtwn/khu/toyouserver/response/ResponseController.java new file mode 100644 index 0000000..57aeca2 --- /dev/null +++ b/src/test/java/slvtwn/khu/toyouserver/response/ResponseController.java @@ -0,0 +1,19 @@ +package slvtwn.khu.toyouserver.response; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequestMapping("/test") +@RestController +public class ResponseController { + + private final ResponseService responseService; + + public ResponseController(ResponseService responseService) {this.responseService = responseService;} + + @GetMapping + public PageableDto health() { + return responseService.health(); + } +} diff --git a/src/test/java/slvtwn/khu/toyouserver/response/ResponseControllerTest.java b/src/test/java/slvtwn/khu/toyouserver/response/ResponseControllerTest.java new file mode 100644 index 0000000..86d09f7 --- /dev/null +++ b/src/test/java/slvtwn/khu/toyouserver/response/ResponseControllerTest.java @@ -0,0 +1,39 @@ +package slvtwn.khu.toyouserver.response; + +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import slvtwn.khu.toyouserver.common.PageInfoResponse; + +@AutoConfigureMockMvc +@SpringBootTest +public class ResponseControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private ResponseService responseService; + + @DisplayName("서버 응답 테스트를 실행한다.") + @Test + public void 응답_테스트() throws Exception { + PageableDto expect = new PageableDto(1L, "test", PageInfoResponse.of(1, 1, 1)); + given(responseService.health()) + .willReturn(expect); + mockMvc.perform(get("/test")) + .andExpect(status().isOk()) + .andExpect(result -> { + String contentAsString = result.getResponse().getContentAsString(); + System.out.println(contentAsString); + }); + } +} \ No newline at end of file diff --git a/src/test/java/slvtwn/khu/toyouserver/response/ResponseService.java b/src/test/java/slvtwn/khu/toyouserver/response/ResponseService.java new file mode 100644 index 0000000..e57fc07 --- /dev/null +++ b/src/test/java/slvtwn/khu/toyouserver/response/ResponseService.java @@ -0,0 +1,13 @@ +package slvtwn.khu.toyouserver.response; + +import org.springframework.stereotype.Service; +import slvtwn.khu.toyouserver.common.PageInfoResponse; + +@Service +public class ResponseService { + + public PageableDto health() { + PageInfoResponse pageInfo = PageInfoResponse.of(1, 1, 1); + return new PageableDto(1L, "health", pageInfo); + } +}