From 2cfe0117da22aadd12efd61e39d75135af88c8c5 Mon Sep 17 00:00:00 2001 From: 0-wook Date: Mon, 27 Nov 2023 20:06:03 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20OpenApi=20docs=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/user-server/build.gradle | 1 + .../global/config/swagger/OpenApiConfig.java | 24 +++++++++++++++++++ .../src/main/resources/application.yml | 16 +++++++++++++ docs/README.md | 2 ++ 4 files changed, 43 insertions(+) create mode 100644 app/user-server/src/main/java/kr/co/automl/global/config/swagger/OpenApiConfig.java diff --git a/app/user-server/build.gradle b/app/user-server/build.gradle index 134b3853..ce2ddc0c 100644 --- a/app/user-server/build.gradle +++ b/app/user-server/build.gradle @@ -21,6 +21,7 @@ repositories { } dependencies { + implementation 'org.springdoc:springdoc-openapi-ui:1.6.12' implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/app/user-server/src/main/java/kr/co/automl/global/config/swagger/OpenApiConfig.java b/app/user-server/src/main/java/kr/co/automl/global/config/swagger/OpenApiConfig.java new file mode 100644 index 00000000..10c69068 --- /dev/null +++ b/app/user-server/src/main/java/kr/co/automl/global/config/swagger/OpenApiConfig.java @@ -0,0 +1,24 @@ +package kr.co.automl.global.config.swagger; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Swagger springdoc-ui 구성 파일 + */ +@Configuration +public class OpenApiConfig { + @Bean + public OpenAPI openAPI() { + Info info = new Info() + .title("WS-AutoML User API Document") + .version("v0.0.1") + .description("WS-AutoML 사용자 API 명세서입니다."); + return new OpenAPI() + .components(new Components()) + .info(info); + } +} diff --git a/app/user-server/src/main/resources/application.yml b/app/user-server/src/main/resources/application.yml index 2b1ea4cf..3f421347 100644 --- a/app/user-server/src/main/resources/application.yml +++ b/app/user-server/src/main/resources/application.yml @@ -11,6 +11,22 @@ cloud: accessKey: ${AWS_ACCESS_KEY} secretKey: ${AWS_SECRET_KEY} +# Swagger springdoc-ui Configuration +springdoc: + packages-to-scan: kr.co.automl + default-consumes-media-type: application/json;charset=UTF-8 + default-produces-media-type: application/json;charset=UTF-8 + swagger-ui: + path: demo-ui.html # Swagger UI 경로 => localhost:8000/demo-ui.html + tags-sorter: alpha # alpha: 알파벳 순 태그 정렬, method: HTTP Method 순 정렬 + operations-sorter: alpha # alpha: 알파벳 순 태그 정렬, method: HTTP Method 순 정렬 + api-docs: + path: /api-docs/json + groups: + enabled: true + cache: + disabled: true + spring: h2: console: diff --git a/docs/README.md b/docs/README.md index 73cf9f2e..35fea801 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,6 +5,7 @@ CI - [Gradle 빌드 속도 개선](ci/Gradle_빌드_속도_개선.md) +- [Npm 빌드 속도 개선](ci/Npm_빌드_속도_개선.md) ECS @@ -17,3 +18,4 @@ SSL ### 노트 - [2022.08.07 장애 기록 및 회고](2022_08_07.md) +- [2022.08.01 장애 기록 및 회고](2023_08_01.md) From bd2fc492a9e1c4cb676879d7d06ba921aac76b34 Mon Sep 17 00:00:00 2001 From: 0-wook Date: Mon, 27 Nov 2023 20:07:15 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EB=AA=A8=EB=8D=B8=ED=99=9C?= =?UTF-8?q?=EC=9A=A9=EC=9D=84=20=EC=9C=84=ED=95=9C=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20presigned=20Url=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/kr/co/automl/api/UrlApi.java | 21 ++++++ .../co/automl/dto/PreSignedUrlResponse.java | 5 ++ .../kr/co/automl/global/utils/DateUtils.java | 25 +++++++ .../automl/service/PreSignedUrlProvider.java | 73 +++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 app/user-server/src/main/java/kr/co/automl/api/UrlApi.java create mode 100644 app/user-server/src/main/java/kr/co/automl/dto/PreSignedUrlResponse.java create mode 100644 app/user-server/src/main/java/kr/co/automl/global/utils/DateUtils.java create mode 100644 app/user-server/src/main/java/kr/co/automl/service/PreSignedUrlProvider.java diff --git a/app/user-server/src/main/java/kr/co/automl/api/UrlApi.java b/app/user-server/src/main/java/kr/co/automl/api/UrlApi.java new file mode 100644 index 00000000..8ffd033c --- /dev/null +++ b/app/user-server/src/main/java/kr/co/automl/api/UrlApi.java @@ -0,0 +1,21 @@ +package kr.co.automl.api; + +import kr.co.automl.dto.PreSignedUrlResponse; +import kr.co.automl.service.PreSignedUrlProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.websocket.server.PathParam; + +@RestController +@RequiredArgsConstructor +public class UrlApi { + + private final PreSignedUrlProvider preSignedUrlProvider; + + @GetMapping("/url/presigned") + public PreSignedUrlResponse getPreSignedUrls(@PathParam("filename") String filename) { + return preSignedUrlProvider.getUploadAndDownloadUrl(filename); + } +} diff --git a/app/user-server/src/main/java/kr/co/automl/dto/PreSignedUrlResponse.java b/app/user-server/src/main/java/kr/co/automl/dto/PreSignedUrlResponse.java new file mode 100644 index 00000000..c0029df8 --- /dev/null +++ b/app/user-server/src/main/java/kr/co/automl/dto/PreSignedUrlResponse.java @@ -0,0 +1,5 @@ +package kr.co.automl.dto; + +public record PreSignedUrlResponse( + String uploadUrl, String downloadUrl) { +} diff --git a/app/user-server/src/main/java/kr/co/automl/global/utils/DateUtils.java b/app/user-server/src/main/java/kr/co/automl/global/utils/DateUtils.java new file mode 100644 index 00000000..cecadecc --- /dev/null +++ b/app/user-server/src/main/java/kr/co/automl/global/utils/DateUtils.java @@ -0,0 +1,25 @@ +package kr.co.automl.global.utils; + +import org.joda.time.DateTime; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DateUtils { + + private static final String DATE_FORMAT = "yyyyMMdd-HHmmss"; + + /** + * 날짜를 포맷된 문자열로 리턴합니다. + * @param dateTime 포맷할 날짜 + * @return 포맷된 문자열 + */ + public static String getFormattedDateString(DateTime dateTime) { + Date date = dateTime.toDate(); + + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); + + return dateFormat.format(date); + } +} diff --git a/app/user-server/src/main/java/kr/co/automl/service/PreSignedUrlProvider.java b/app/user-server/src/main/java/kr/co/automl/service/PreSignedUrlProvider.java new file mode 100644 index 00000000..9c6011a3 --- /dev/null +++ b/app/user-server/src/main/java/kr/co/automl/service/PreSignedUrlProvider.java @@ -0,0 +1,73 @@ +package kr.co.automl.service; + +import com.amazonaws.HttpMethod; +import com.amazonaws.services.s3.AmazonS3Client; + +import kr.co.automl.dto.PreSignedUrlResponse; +import kr.co.automl.global.utils.DateUtils; +import lombok.RequiredArgsConstructor; +import org.joda.time.DateTime; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.net.URL; +import java.util.Date; + +/** + * PreSignedUrl 제공을 담당합니다. + */ +@Component +@RequiredArgsConstructor +public class PreSignedUrlProvider { + + private static final int EXPIRATION_DAYS = 1; + + private final AmazonS3Client amazonS3Client; + private final String bucketName; + + /** + * 파일 이름을 통해 생성한 PreSignedUrl을 리턴합니다. + * + * @param filename 생성할 파일 이름 + * @return 생성한 PreSignedUrl + */ + public PreSignedUrlResponse getUploadAndDownloadUrl(String filename) { + validateEmpty(filename); + + Date expiration = DateTime.now().plusDays(EXPIRATION_DAYS).toDate(); + String key = getKey(filename); + + // 업로드를 위한 PUT 요청용 URL 생성 + URL uploadUrl = amazonS3Client.generatePresignedUrl(bucketName, key, expiration, HttpMethod.PUT); + + // 다운로드를 위한 GET 요청용 URL 생성 + URL downloadUrl = amazonS3Client.generatePresignedUrl(bucketName, key, expiration, HttpMethod.GET); + + return new PreSignedUrlResponse(uploadUrl.toString(), downloadUrl.toString()); + } + + /** + * 비어있는지 검증합니다. + * + * @param filename 검증할 파일 이름 + * + * @throws IllegalArgumentException 파일 이름 검증에 실패할경우 + */ + private void validateEmpty(String filename) { + if (ObjectUtils.isEmpty(filename)) { + throw new IllegalArgumentException("파일이름은 비어있을 수 없습니다."); + } + } + + /** + * 키를 리턴합니다. 키는 파일 저장소에서 유일한 값이자 저장되는 파일 이름입니다. + * + * @param filename 파일 이름 + * @return 키 + */ + String getKey(String filename) { + String keyPrefix = DateUtils.getFormattedDateString(DateTime.now()); + + return "TmpFile-" + keyPrefix + "-" + filename; + } +}