From c7adf26072c55d8246c35c1c0d59d5b5cfebab27 Mon Sep 17 00:00:00 2001 From: HongGit Date: Tue, 18 Feb 2025 20:02:17 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[feat/#57]=20=EA=B3=B5=ED=86=B5=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=EC=8A=A4=EC=9B=A8=EA=B1=B0=20=EC=8A=A4=ED=82=A4?= =?UTF-8?q?=EB=A7=88=EC=97=90=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/PresignedUrlResponse.java | 2 +- .../global/config/swagger/SwaggerConfig.java | 34 +++++++++++++++++ .../global/response/ResponseDto.java | 20 ++++++++++ .../global/response/ResponseDtoAdvice.java | 38 +++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/moplus/moplus_server/global/response/ResponseDto.java create mode 100644 src/main/java/com/moplus/moplus_server/global/response/ResponseDtoAdvice.java diff --git a/src/main/java/com/moplus/moplus_server/domain/problem/dto/response/PresignedUrlResponse.java b/src/main/java/com/moplus/moplus_server/domain/problem/dto/response/PresignedUrlResponse.java index 64b1011..2496345 100644 --- a/src/main/java/com/moplus/moplus_server/domain/problem/dto/response/PresignedUrlResponse.java +++ b/src/main/java/com/moplus/moplus_server/domain/problem/dto/response/PresignedUrlResponse.java @@ -1,7 +1,7 @@ package com.moplus.moplus_server.domain.problem.dto.response; public record PresignedUrlResponse( - String data + String presignedUrl ) { public static PresignedUrlResponse of(String presignedUrl) { return new PresignedUrlResponse( diff --git a/src/main/java/com/moplus/moplus_server/global/config/swagger/SwaggerConfig.java b/src/main/java/com/moplus/moplus_server/global/config/swagger/SwaggerConfig.java index 63543a2..32b9062 100644 --- a/src/main/java/com/moplus/moplus_server/global/config/swagger/SwaggerConfig.java +++ b/src/main/java/com/moplus/moplus_server/global/config/swagger/SwaggerConfig.java @@ -3,15 +3,20 @@ import com.moplus.moplus_server.global.properties.swagger.SwaggerProperties; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.servers.Server; import java.util.List; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.springdoc.core.customizers.OperationCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; @Configuration @RequiredArgsConstructor @@ -43,4 +48,33 @@ public OpenAPI openAPI() { .version("v0.0.1")) .servers(addServerUrl()); } + + @Bean + public OperationCustomizer operationCustomizer() { + return (operation, handlerMethod) -> { + this.addResponseBodyWrapperSchemaExample(operation); + return operation; + }; + } + + private void addResponseBodyWrapperSchemaExample(Operation operation) { + final Content content = operation.getResponses().get("200").getContent(); + if (content != null) { + content.forEach((mediaTypeKey, mediaType) -> { + Schema originalSchema = mediaType.getSchema(); + Schema wrappedSchema = wrapSchema(originalSchema); + mediaType.setSchema(wrappedSchema); + }); + } + } + + private Schema wrapSchema(Schema originalSchema) { + final Schema wrapperSchema = new Schema<>(); + + wrapperSchema.addProperty("data", originalSchema); + wrapperSchema.addProperty("message", new Schema<>().type("string").example("오류 메세지")); + wrapperSchema.addProperty("status", new Schema<>().type("string").example(HttpStatus.NOT_FOUND.name())); + + return wrapperSchema; + } } diff --git a/src/main/java/com/moplus/moplus_server/global/response/ResponseDto.java b/src/main/java/com/moplus/moplus_server/global/response/ResponseDto.java new file mode 100644 index 0000000..545e075 --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/global/response/ResponseDto.java @@ -0,0 +1,20 @@ +package com.moplus.moplus_server.global.response; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.moplus.moplus_server.global.error.ErrorResponse; +import org.springframework.http.HttpStatus; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public record ResponseDto( + T data, + String message, + HttpStatus status +) { + public static ResponseDto success(final T data) { + return new ResponseDto<>(data, null, null); + } + + public static ResponseDto fail(ErrorResponse errorResponse) { + return new ResponseDto<>(null, errorResponse.getMessage(), errorResponse.getStatus()); + } +} \ No newline at end of file diff --git a/src/main/java/com/moplus/moplus_server/global/response/ResponseDtoAdvice.java b/src/main/java/com/moplus/moplus_server/global/response/ResponseDtoAdvice.java new file mode 100644 index 0000000..dc406c0 --- /dev/null +++ b/src/main/java/com/moplus/moplus_server/global/response/ResponseDtoAdvice.java @@ -0,0 +1,38 @@ +package com.moplus.moplus_server.global.response; + +import com.moplus.moplus_server.global.error.ErrorResponse; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +@RestControllerAdvice( + basePackages = "com.moplus.moplus_server" +) + +public class ResponseDtoAdvice implements ResponseBodyAdvice { + + @Override + public boolean supports(MethodParameter returnType, Class converterType) { + return !(returnType.getParameterType() == ResponseDto.class) + && MappingJackson2HttpMessageConverter.class.isAssignableFrom(converterType); + } + + @Override + public Object beforeBodyWrite( + Object body, + MethodParameter returnType, + MediaType selectedContentType, + Class selectedConverterType, + ServerHttpRequest request, + ServerHttpResponse response + ) { + if (body instanceof ErrorResponse) { + return ResponseDto.fail((ErrorResponse) body); + } + return ResponseDto.success(body); + } +} \ No newline at end of file From 13598354e891f7a6045d22278aca15f76166ab54 Mon Sep 17 00:00:00 2001 From: HongGit Date: Tue, 18 Feb 2025 21:05:50 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[fix/#57]=20=EB=A9=A4=EB=B2=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20json=20path=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/controller/MemberControllerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/moplus/moplus_server/domain/member/controller/MemberControllerTest.java b/src/test/java/com/moplus/moplus_server/domain/member/controller/MemberControllerTest.java index 2ce90a3..3d3622d 100644 --- a/src/test/java/com/moplus/moplus_server/domain/member/controller/MemberControllerTest.java +++ b/src/test/java/com/moplus/moplus_server/domain/member/controller/MemberControllerTest.java @@ -70,9 +70,9 @@ public void setMockMvc() throws Exception { .contentType("application/json") .header(HttpHeaders.AUTHORIZATION, "Bearer " + validToken)) .andExpect(status().isOk()) // 200 응답 확인 - .andExpect(jsonPath("$.id").exists()) // MemberGetResponse의 필드 확인 - .andExpect(jsonPath("$.name").exists()) - .andExpect(jsonPath("$.email").exists()); + .andExpect(jsonPath("$.data.id").exists()) // MemberGetResponse의 필드 확인 + .andExpect(jsonPath("$.data.name").exists()) + .andExpect(jsonPath("$.data.email").exists()); } } } \ No newline at end of file