From f0c37db68be872e62f5cdd8b1ce7c8f64b055f91 Mon Sep 17 00:00:00 2001 From: wjdtkdgns Date: Sun, 2 Jun 2024 15:34:56 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20presigned=20url=20=EB=B0=9C=EA=B8=89=20?= =?UTF-8?q?api=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20balance=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20api=20request=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 7 +-- .../balancemania/api/auth/model/AuthUser.kt | 2 +- .../api/balance/application/BalanceFacade.kt | 16 +++--- .../balance/application/MediaPipeService.kt | 10 +++- .../api/balance/model/BalanceModel.kt | 24 ++++---- .../model/request/CreateBalanceRequest.kt | 4 +- .../client/config/MediaPipeClientConfig.kt | 6 +- .../api/client/mediapipe/MediaPipeClient.kt | 4 +- .../mediapipe/SuspendableMediaPipeClient.kt | 4 +- .../model/MediaPipeImgAnalysisRequest.kt | 8 +++ .../model/MediaPipeImgAnalysisResponse.kt | 12 ++-- .../com/balancemania/api/config/S3Config.kt | 18 ++++++ .../api/config/filter/MdcFilter.kt | 1 - .../{SwaggerConfig.kt => SpringDocConfig.kt} | 23 ++++++-- .../api/extension/DateExtension.kt | 4 ++ .../api/s3/application/S3Facade.kt | 23 ++++++++ .../s3/application/S3PresignedUrlService.kt | 57 +++++++++++++++++++ .../balancemania/api/s3/model/ImageType.kt | 9 +++ .../api/s3/model/S3PresignedUrlModel.kt | 12 ++++ .../model/response/S3PresignedUrlResponse.kt | 12 ++++ .../api/s3/presentation/S3Controller.kt | 28 +++++++++ src/main/resources/config/application-dev.yml | 1 + src/main/resources/config/application.yml | 14 ++++- src/main/resources/logback-file-spring.xml | 7 +++ src/main/resources/logback-spring.xml | 29 +++++----- 25 files changed, 273 insertions(+), 62 deletions(-) create mode 100644 src/main/kotlin/com/balancemania/api/client/mediapipe/model/MediaPipeImgAnalysisRequest.kt create mode 100644 src/main/kotlin/com/balancemania/api/config/S3Config.kt rename src/main/kotlin/com/balancemania/api/config/swagger/{SwaggerConfig.kt => SpringDocConfig.kt} (61%) create mode 100644 src/main/kotlin/com/balancemania/api/s3/application/S3Facade.kt create mode 100644 src/main/kotlin/com/balancemania/api/s3/application/S3PresignedUrlService.kt create mode 100644 src/main/kotlin/com/balancemania/api/s3/model/ImageType.kt create mode 100644 src/main/kotlin/com/balancemania/api/s3/model/S3PresignedUrlModel.kt create mode 100644 src/main/kotlin/com/balancemania/api/s3/model/response/S3PresignedUrlResponse.kt create mode 100644 src/main/kotlin/com/balancemania/api/s3/presentation/S3Controller.kt create mode 100644 src/main/resources/logback-file-spring.xml diff --git a/build.gradle.kts b/build.gradle.kts index 9fb4d56..9c84f9f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -48,7 +48,6 @@ allOpen { dependencies { implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-actuator") implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-data-redis") @@ -63,10 +62,8 @@ dependencies { implementation("io.arrow-kt:arrow-fx-coroutines:1.2.1") implementation("io.arrow-kt:arrow-fx-stm:1.2.1") - implementation( - platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.1.0") - ) - implementation("io.awspring.cloud:spring-cloud-aws-starter-parameter-store") + implementation(platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.1.0")) + implementation("io.awspring.cloud:spring-cloud-aws-s3") implementation("io.github.oshai:kotlin-logging-jvm:6.0.3") implementation("net.logstash.logback:logstash-logback-encoder:7.4") diff --git a/src/main/kotlin/com/balancemania/api/auth/model/AuthUser.kt b/src/main/kotlin/com/balancemania/api/auth/model/AuthUser.kt index d0928d7..ef1d103 100644 --- a/src/main/kotlin/com/balancemania/api/auth/model/AuthUser.kt +++ b/src/main/kotlin/com/balancemania/api/auth/model/AuthUser.kt @@ -35,7 +35,7 @@ data class AuthUserImpl( } } -const val AUTH_TOKEN_KEY = "X-AUTH-TOKEN" +const val AUTH_TOKEN_KEY = "X-MANIA-AUTH-TOKEN" data class AuthUserToken( val key: String, diff --git a/src/main/kotlin/com/balancemania/api/balance/application/BalanceFacade.kt b/src/main/kotlin/com/balancemania/api/balance/application/BalanceFacade.kt index 0e0f8a0..d97929a 100644 --- a/src/main/kotlin/com/balancemania/api/balance/application/BalanceFacade.kt +++ b/src/main/kotlin/com/balancemania/api/balance/application/BalanceFacade.kt @@ -38,19 +38,19 @@ class BalanceFacade( suspend fun createBalance(user: AuthUser, request: CreateBalanceRequest): GetBalanceResponse { val analyzedData = mediaPipeService.requestImgAnalysis( - frontImgUrl = request.frontImgUrl, - sideImgUrl = request.sideImgUrl + frontImgKey = request.frontImgKey, + sideImgKey = request.sideImgKey ) return txTemplates.writer.coExecute { Balance( uid = user.uid, - frontShoulderAngle = analyzedData.frontShoulderAngle, - frontPelvisAngle = analyzedData.frontPelvisAngle, - frontKneeAngle = analyzedData.frontKneeAngle, - frontAnkleAngle = analyzedData.frontAnkleAngle, - sideNeckAngle = analyzedData.sideNeckAngle, - sideBodyAngle = analyzedData.sideBodyAngle, + frontShoulderAngle = analyzedData.frontShoulderAngle.toInteger(), + frontPelvisAngle = analyzedData.frontPelvisAngle.toInteger(), + frontKneeAngle = analyzedData.frontKneeAngle.toInteger(), + frontAnkleAngle = analyzedData.frontAnkleAngle.toInteger(), + sideNeckAngle = analyzedData.sideNeckAngle.toInteger(), + sideBodyAngle = analyzedData.sideBodyAngle.toInteger(), leftWeight = request.leftWeight.toInteger(), rightWeight = request.rightWeight.toInteger() ).run { balanceService.saveSync(this) } diff --git a/src/main/kotlin/com/balancemania/api/balance/application/MediaPipeService.kt b/src/main/kotlin/com/balancemania/api/balance/application/MediaPipeService.kt index a7638af..d402774 100644 --- a/src/main/kotlin/com/balancemania/api/balance/application/MediaPipeService.kt +++ b/src/main/kotlin/com/balancemania/api/balance/application/MediaPipeService.kt @@ -1,6 +1,7 @@ package com.balancemania.api.balance.application import com.balancemania.api.client.mediapipe.MediaPipeClient +import com.balancemania.api.client.mediapipe.model.MediaPipeImgAnalysisRequest import com.balancemania.api.client.mediapipe.model.MediaPipeImgAnalysisResponse import com.balancemania.api.extension.withMDCContext import kotlinx.coroutines.Dispatchers @@ -10,9 +11,14 @@ import org.springframework.stereotype.Service class MediaPipeService( private val mediaPipeClient: MediaPipeClient, ) { - suspend fun requestImgAnalysis(frontImgUrl: String, sideImgUrl: String): MediaPipeImgAnalysisResponse { + suspend fun requestImgAnalysis(frontImgKey: String, sideImgKey: String): MediaPipeImgAnalysisResponse { + val body = MediaPipeImgAnalysisRequest( + frontImgKey = frontImgKey, + sideImgKey = sideImgKey + ) + return withMDCContext(Dispatchers.IO) { - mediaPipeClient.getImgAnalysis(frontImgUrl, sideImgUrl) + mediaPipeClient.getImgAnalysis(body) } } } diff --git a/src/main/kotlin/com/balancemania/api/balance/model/BalanceModel.kt b/src/main/kotlin/com/balancemania/api/balance/model/BalanceModel.kt index 86c8540..1e57850 100644 --- a/src/main/kotlin/com/balancemania/api/balance/model/BalanceModel.kt +++ b/src/main/kotlin/com/balancemania/api/balance/model/BalanceModel.kt @@ -11,22 +11,22 @@ data class BalanceModel( val uid: Long, /** 정면 어깨 각도 */ - val frontShoulderAngle: Long, + val frontShoulderAngle: Float, /** 정면 골반 각도 */ - val frontPelvisAngle: Long, + val frontPelvisAngle: Float, /** 정면 무릎 각도 */ - val frontKneeAngle: Long, + val frontKneeAngle: Float, /** 정면 발목 각도 */ - val frontAnkleAngle: Long, + val frontAnkleAngle: Float, /** 측면 목 각도 */ - val sideNeckAngle: Long, + val sideNeckAngle: Float, /** 측면 신체 각도 */ - val sideBodyAngle: Long, + val sideBodyAngle: Float, /** 좌측 무게 */ val leftWeight: Float, @@ -45,12 +45,12 @@ data class BalanceModel( return BalanceModel( id = balance.id, uid = balance.uid, - frontPelvisAngle = balance.frontPelvisAngle, - frontShoulderAngle = balance.frontShoulderAngle, - frontKneeAngle = balance.frontKneeAngle, - frontAnkleAngle = balance.frontAnkleAngle, - sideBodyAngle = balance.sideBodyAngle, - sideNeckAngle = balance.sideNeckAngle, + frontPelvisAngle = balance.frontPelvisAngle.toRealNumber(), + frontShoulderAngle = balance.frontShoulderAngle.toRealNumber(), + frontKneeAngle = balance.frontKneeAngle.toRealNumber(), + frontAnkleAngle = balance.frontAnkleAngle.toRealNumber(), + sideBodyAngle = balance.sideBodyAngle.toRealNumber(), + sideNeckAngle = balance.sideNeckAngle.toRealNumber(), leftWeight = balance.leftWeight.toRealNumber(), rightWeight = balance.rightWeight.toRealNumber(), createdAt = balance.createdAt, diff --git a/src/main/kotlin/com/balancemania/api/balance/model/request/CreateBalanceRequest.kt b/src/main/kotlin/com/balancemania/api/balance/model/request/CreateBalanceRequest.kt index 65c5a85..f483bc5 100644 --- a/src/main/kotlin/com/balancemania/api/balance/model/request/CreateBalanceRequest.kt +++ b/src/main/kotlin/com/balancemania/api/balance/model/request/CreateBalanceRequest.kt @@ -1,8 +1,8 @@ package com.balancemania.api.balance.model.request data class CreateBalanceRequest( - val frontImgUrl: String, - val sideImgUrl: String, + val frontImgKey: String, + val sideImgKey: String, val leftWeight: Float, val rightWeight: Float, ) diff --git a/src/main/kotlin/com/balancemania/api/client/config/MediaPipeClientConfig.kt b/src/main/kotlin/com/balancemania/api/client/config/MediaPipeClientConfig.kt index 3424372..c3c3c24 100644 --- a/src/main/kotlin/com/balancemania/api/client/config/MediaPipeClientConfig.kt +++ b/src/main/kotlin/com/balancemania/api/client/config/MediaPipeClientConfig.kt @@ -16,7 +16,11 @@ class MediaPipeClientConfig( @Bean fun mediaPipeClient(): MediaPipeClient { - val webClient = WebClientFactory.generateWithoutBaseUrl() + val webClient = WebClientFactory.generateWithoutBaseUrl( + connectionTimeoutMillis = 1000 * 10, + readTimeoutMillis = 1000 * 10, + writeTimeoutMillis = 1000 * 10, + ) logger.info { "initialized mediaPipe client" } return SuspendableMediaPipeClient(webClient, mediaPipeConfig) } diff --git a/src/main/kotlin/com/balancemania/api/client/mediapipe/MediaPipeClient.kt b/src/main/kotlin/com/balancemania/api/client/mediapipe/MediaPipeClient.kt index 5836fad..123c0d4 100644 --- a/src/main/kotlin/com/balancemania/api/client/mediapipe/MediaPipeClient.kt +++ b/src/main/kotlin/com/balancemania/api/client/mediapipe/MediaPipeClient.kt @@ -1,10 +1,10 @@ package com.balancemania.api.client.mediapipe +import com.balancemania.api.client.mediapipe.model.MediaPipeImgAnalysisRequest import com.balancemania.api.client.mediapipe.model.MediaPipeImgAnalysisResponse interface MediaPipeClient { suspend fun getImgAnalysis( - frontImgUrl: String, - sideImgUrl: String, + body: MediaPipeImgAnalysisRequest ): MediaPipeImgAnalysisResponse } diff --git a/src/main/kotlin/com/balancemania/api/client/mediapipe/SuspendableMediaPipeClient.kt b/src/main/kotlin/com/balancemania/api/client/mediapipe/SuspendableMediaPipeClient.kt index 78ba49b..9bfe3fa 100644 --- a/src/main/kotlin/com/balancemania/api/client/mediapipe/SuspendableMediaPipeClient.kt +++ b/src/main/kotlin/com/balancemania/api/client/mediapipe/SuspendableMediaPipeClient.kt @@ -1,5 +1,6 @@ package com.balancemania.api.client.mediapipe +import com.balancemania.api.client.mediapipe.model.MediaPipeImgAnalysisRequest import com.balancemania.api.client.mediapipe.model.MediaPipeImgAnalysisResponse import com.balancemania.api.config.MediaPipeConfig import com.balancemania.api.exception.ErrorCode @@ -13,9 +14,10 @@ class SuspendableMediaPipeClient( ) : MediaPipeClient { private val logger = KotlinLogging.logger { } - override suspend fun getImgAnalysis(frontImgUrl: String, sideImgUrl: String): MediaPipeImgAnalysisResponse { + override suspend fun getImgAnalysis(body: MediaPipeImgAnalysisRequest): MediaPipeImgAnalysisResponse { return webClient.post() .uri(mediaPipeConfig.url) + .bodyValue(body) .retrieve() .bodyToMono(MediaPipeImgAnalysisResponse::class.java) .block() ?: throw FailToExecuteException(ErrorCode.EXTERNAL_SERVER_ERROR) diff --git a/src/main/kotlin/com/balancemania/api/client/mediapipe/model/MediaPipeImgAnalysisRequest.kt b/src/main/kotlin/com/balancemania/api/client/mediapipe/model/MediaPipeImgAnalysisRequest.kt new file mode 100644 index 0000000..e5750a1 --- /dev/null +++ b/src/main/kotlin/com/balancemania/api/client/mediapipe/model/MediaPipeImgAnalysisRequest.kt @@ -0,0 +1,8 @@ +package com.balancemania.api.client.mediapipe.model + +data class MediaPipeImgAnalysisRequest( + /** 정면 사진 키 */ + val frontImgKey: String, + /** 측면 사진 키 */ + val sideImgKey: String, +) diff --git a/src/main/kotlin/com/balancemania/api/client/mediapipe/model/MediaPipeImgAnalysisResponse.kt b/src/main/kotlin/com/balancemania/api/client/mediapipe/model/MediaPipeImgAnalysisResponse.kt index ebe941b..009466b 100644 --- a/src/main/kotlin/com/balancemania/api/client/mediapipe/model/MediaPipeImgAnalysisResponse.kt +++ b/src/main/kotlin/com/balancemania/api/client/mediapipe/model/MediaPipeImgAnalysisResponse.kt @@ -2,20 +2,20 @@ package com.balancemania.api.client.mediapipe.model data class MediaPipeImgAnalysisResponse( /** 정면 어깨 각도 */ - val frontShoulderAngle: Long, + val frontShoulderAngle: Float, /** 정면 골반 각도 */ - val frontPelvisAngle: Long, + val frontPelvisAngle: Float, /** 정면 무릎 각도 */ - val frontKneeAngle: Long, + val frontKneeAngle: Float, /** 정면 발목 각도 */ - val frontAnkleAngle: Long, + val frontAnkleAngle: Float, /** 측면 목 각도 */ - val sideNeckAngle: Long, + val sideNeckAngle: Float, /** 측면 신체 각도 */ - val sideBodyAngle: Long, + val sideBodyAngle: Float, ) diff --git a/src/main/kotlin/com/balancemania/api/config/S3Config.kt b/src/main/kotlin/com/balancemania/api/config/S3Config.kt new file mode 100644 index 0000000..f40a4bc --- /dev/null +++ b/src/main/kotlin/com/balancemania/api/config/S3Config.kt @@ -0,0 +1,18 @@ +package com.balancemania.api.config + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider +import software.amazon.awssdk.regions.Region +import software.amazon.awssdk.services.s3.presigner.S3Presigner + +@Configuration +class S3Config { + @Bean + fun s3Presigner(): S3Presigner { + return S3Presigner.builder() + .credentialsProvider(DefaultCredentialsProvider.create()) + .region(Region.AP_NORTHEAST_2) + .build() + } +} diff --git a/src/main/kotlin/com/balancemania/api/config/filter/MdcFilter.kt b/src/main/kotlin/com/balancemania/api/config/filter/MdcFilter.kt index d444c79..a74a5eb 100644 --- a/src/main/kotlin/com/balancemania/api/config/filter/MdcFilter.kt +++ b/src/main/kotlin/com/balancemania/api/config/filter/MdcFilter.kt @@ -33,6 +33,5 @@ class MdcFilter : Filter { logger.info { "[${MDC.get(MDC_KEY_TRACE_ID)}] ${httpRes.status} ${httpReq.requestURI} " } MDC.clear() } - } } diff --git a/src/main/kotlin/com/balancemania/api/config/swagger/SwaggerConfig.kt b/src/main/kotlin/com/balancemania/api/config/swagger/SpringDocConfig.kt similarity index 61% rename from src/main/kotlin/com/balancemania/api/config/swagger/SwaggerConfig.kt rename to src/main/kotlin/com/balancemania/api/config/swagger/SpringDocConfig.kt index fd302bd..0f5856d 100644 --- a/src/main/kotlin/com/balancemania/api/config/swagger/SwaggerConfig.kt +++ b/src/main/kotlin/com/balancemania/api/config/swagger/SpringDocConfig.kt @@ -1,25 +1,40 @@ package com.balancemania.api.config.swagger +import com.balancemania.api.auth.model.AUTH_TOKEN_KEY +import com.balancemania.api.auth.model.AuthUser import io.swagger.v3.oas.models.Components import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.oas.models.info.Info +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 org.springdoc.core.utils.SpringDocUtils import org.springframework.boot.info.BuildProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.web.reactive.result.view.RequestContext +import org.springframework.web.server.WebSession @Configuration -class SwaggerConfig( +class SpringDocConfig( private val buildProperties: BuildProperties, ) { + init { + SpringDocUtils + .getConfig() + .addRequestWrapperToIgnore( + AuthUser::class.java, + WebSession::class.java, + RequestContext::class.java + ) + } @Bean fun openApi(): OpenAPI { -// val securityRequirement = SecurityRequirement().addList(AUTH_TOKEN_KEY) + val securityRequirement = SecurityRequirement().addList(AUTH_TOKEN_KEY) return OpenAPI() -// .components(authSetting()) -// .security(listOf(securityRequirement)) + .components(authSetting()) + .security(listOf(securityRequirement)) .addServersItem(Server().url("/")) .info( Info() diff --git a/src/main/kotlin/com/balancemania/api/extension/DateExtension.kt b/src/main/kotlin/com/balancemania/api/extension/DateExtension.kt index f74f95d..996ea22 100644 --- a/src/main/kotlin/com/balancemania/api/extension/DateExtension.kt +++ b/src/main/kotlin/com/balancemania/api/extension/DateExtension.kt @@ -13,3 +13,7 @@ object Zone { fun LocalDateTime.toInstant(): Instant { return this.toInstant(ZoneOffset.of("+09:00")) } + +fun Instant.toCurrentZone(): Instant { + return this.plusSeconds(60 * 60 * 9) +} diff --git a/src/main/kotlin/com/balancemania/api/s3/application/S3Facade.kt b/src/main/kotlin/com/balancemania/api/s3/application/S3Facade.kt new file mode 100644 index 0000000..b5306ee --- /dev/null +++ b/src/main/kotlin/com/balancemania/api/s3/application/S3Facade.kt @@ -0,0 +1,23 @@ +package com.balancemania.api.s3.application + +import com.balancemania.api.auth.model.AuthUser +import com.balancemania.api.extension.toCurrentZone +import com.balancemania.api.s3.model.ImageType +import com.balancemania.api.s3.model.response.S3PresignedUrlResponse +import org.springframework.stereotype.Service + +@Service +class S3Facade( + private val s3PresignedUrlService: S3PresignedUrlService, +) { + suspend fun getPresignedUrl(user: AuthUser, imgType: ImageType): S3PresignedUrlResponse { + return s3PresignedUrlService.generatePresignedUrl(user, imgType) + .let { model -> + S3PresignedUrlResponse( + url = model.url, + exp = model.exp.toCurrentZone(), + key = model.key + ) + } + } +} diff --git a/src/main/kotlin/com/balancemania/api/s3/application/S3PresignedUrlService.kt b/src/main/kotlin/com/balancemania/api/s3/application/S3PresignedUrlService.kt new file mode 100644 index 0000000..208fcb8 --- /dev/null +++ b/src/main/kotlin/com/balancemania/api/s3/application/S3PresignedUrlService.kt @@ -0,0 +1,57 @@ +package com.balancemania.api.s3.application + +import com.balancemania.api.auth.model.AuthUser +import com.balancemania.api.s3.model.ImageType +import com.balancemania.api.s3.model.S3PresignedUrlModel +import io.awspring.cloud.s3.ObjectMetadata +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.beans.factory.annotation.Value +import org.springframework.stereotype.Service +import software.amazon.awssdk.services.s3.model.ObjectCannedACL +import software.amazon.awssdk.services.s3.model.PutObjectRequest +import software.amazon.awssdk.services.s3.presigner.S3Presigner +import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest +import java.time.Duration +import java.util.UUID + +@Service +class S3PresignedUrlService( + @Value("\${spring.cloud.aws.s3.bucket}") + private val bucket: String, + private val s3Presigner: S3Presigner, +) { + companion object { + /** 5분 */ + const val PRESIGNED_EXP_TIME = 5L + } + + val logger = KotlinLogging.logger { } + + suspend fun generatePresignedUrl(user: AuthUser, imageType: ImageType): S3PresignedUrlModel { + val fileName = "${user.uid}/${UUID.randomUUID()}.${imageType.type}" + + val metadata = ObjectMetadata.builder() + .acl(ObjectCannedACL.PUBLIC_READ) + .build() + + val putObjectRequest = PutObjectRequest.builder() + .key(fileName) + .contentType("image/${imageType.type}") + .bucket(bucket) + .metadata(metadata.metadata) + .build() + + val preSignRequest = PutObjectPresignRequest.builder() + .signatureDuration(Duration.ofMinutes(PRESIGNED_EXP_TIME)) + .putObjectRequest(putObjectRequest) + .build() + + val presignedRequest = s3Presigner.presignPutObject(preSignRequest) + + return S3PresignedUrlModel( + url = presignedRequest.url().toString(), + exp = presignedRequest.expiration(), + key = fileName + ) + } +} diff --git a/src/main/kotlin/com/balancemania/api/s3/model/ImageType.kt b/src/main/kotlin/com/balancemania/api/s3/model/ImageType.kt new file mode 100644 index 0000000..aecb5a4 --- /dev/null +++ b/src/main/kotlin/com/balancemania/api/s3/model/ImageType.kt @@ -0,0 +1,9 @@ +package com.balancemania.api.s3.model + +enum class ImageType(val type: String) { + JPEG("jpeg"), + PNG("png"), + JPG("jpeg"), + + ; +} diff --git a/src/main/kotlin/com/balancemania/api/s3/model/S3PresignedUrlModel.kt b/src/main/kotlin/com/balancemania/api/s3/model/S3PresignedUrlModel.kt new file mode 100644 index 0000000..06e5b47 --- /dev/null +++ b/src/main/kotlin/com/balancemania/api/s3/model/S3PresignedUrlModel.kt @@ -0,0 +1,12 @@ +package com.balancemania.api.s3.model + +import java.time.Instant + +data class S3PresignedUrlModel( + /** presinged url */ + val url: String, + /** expiration time */ + val exp: Instant, + /** presinged url */ + val key: String, +) diff --git a/src/main/kotlin/com/balancemania/api/s3/model/response/S3PresignedUrlResponse.kt b/src/main/kotlin/com/balancemania/api/s3/model/response/S3PresignedUrlResponse.kt new file mode 100644 index 0000000..3960b43 --- /dev/null +++ b/src/main/kotlin/com/balancemania/api/s3/model/response/S3PresignedUrlResponse.kt @@ -0,0 +1,12 @@ +package com.balancemania.api.s3.model.response + +import java.time.Instant + +class S3PresignedUrlResponse( + /** presinged url */ + val url: String, + /** expiration time */ + val exp: Instant, + /** presinged url */ + val key: String, +) diff --git a/src/main/kotlin/com/balancemania/api/s3/presentation/S3Controller.kt b/src/main/kotlin/com/balancemania/api/s3/presentation/S3Controller.kt new file mode 100644 index 0000000..4ed4d4a --- /dev/null +++ b/src/main/kotlin/com/balancemania/api/s3/presentation/S3Controller.kt @@ -0,0 +1,28 @@ +package com.balancemania.api.s3.presentation + +import com.balancemania.api.auth.model.AuthUser +import com.balancemania.api.extension.executeWithCoroutine +import com.balancemania.api.extension.wrapOk +import com.balancemania.api.s3.application.S3Facade +import com.balancemania.api.s3.model.ImageType +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.MediaType +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "AWS S3 API", description = "AWS S3 API") +@RestController +@RequestMapping(value = ["/api/v1/s3"], produces = [MediaType.APPLICATION_JSON_VALUE]) +class S3Controller( + private val s3Facade: S3Facade, +) { + @Operation(summary = "presigned url 발급") + @GetMapping("/presigned-url") + fun getPresignedUrl( + user: AuthUser, + @RequestParam(defaultValue = "jpg") imgType: ImageType, + ) = executeWithCoroutine { s3Facade.getPresignedUrl(user, imgType) }.wrapOk() +} diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index aadec1b..c930a6e 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -22,6 +22,7 @@ logging: org.springframework.orm.jpa.JpaTransactionManager: DEBUG org.springframework.web.server.adapter.HttpWebHandlerAdapter: DEBUG reactor.netty.http.client: DEBUG + io.awspring.cloud: DEBUG # SPRING spring: diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index 01fdff9..761e214 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -26,6 +26,17 @@ spring: redis: repositories: enabled: false + cloud: + aws: + credentials: + access-key: ${AWS_ACCESS_KEY_ID:testKey} + secret-key: ${AWS_SECRET_ACCESS_KEY:secretKey} + region: + static: ap-northeast-2 + s3: + bucket: ${AWS_S3_BUCKET:bucket} + stack: + auto: false # DOCS springdoc: @@ -79,4 +90,5 @@ oauth-url: redirect-url: ${KAKAO_REDIRECT_URL} media-pipe: - url: ${MEDIAPIPE_IMG_ANALYSIS_URL} \ No newline at end of file + url: ${MEDIAPIPE_IMG_ANALYSIS_URL} + diff --git a/src/main/resources/logback-file-spring.xml b/src/main/resources/logback-file-spring.xml new file mode 100644 index 0000000..4566fda --- /dev/null +++ b/src/main/resources/logback-file-spring.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 2c24d10..5e26513 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -1,6 +1,8 @@ + - + + @@ -10,37 +12,32 @@ - - - - + - - - + - ${console.format} + ${STDOUT_LOG_PATTERN} - + + WARN + WARN - ${console.format.prod} + %d{yyyy.MM.dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - + - + \ No newline at end of file