diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 8001006..40b8c46 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -12,6 +12,8 @@ env: JWT_SECRET: ${{ secrets.JWT_SECRET }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} TMAP_APP_KEY: ${{ secrets.TMAP_APP_KEY }} + S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} + S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} jobs: build: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d41f9a..b4fb273 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,8 +9,15 @@ jobs: name: CI runs-on: ubuntu-latest env: + S3_BUCKET_NAME: ${{ secrets.AWS_S3_BUCKET_NAME }} + DEPLOYMENT_APPLICATION_NAME: MEY-WAS + DEPLOYMENT_GROUP_NAME: MEY-CD + PROJECT_NAME: MEY + JWT_SECRET: ${{ secrets.JWT_SECRET }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - TMAP_APP_KEY: ${{ secrets.TMAP_APP_KEY }} + TMAP_APP_KEY: ${{ secrets.TMAP_APP_KEY }} + S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} + S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} steps: - uses: actions/checkout@v2 diff --git a/build.gradle b/build.gradle index fbdaff5..12632b4 100644 --- a/build.gradle +++ b/build.gradle @@ -53,6 +53,9 @@ dependencies { testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testRuntimeOnly 'com.h2database:h2' + // s3 + implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' + // swagger implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.9' } diff --git a/src/main/java/com/mey/backend/global/config/AmazonConfig.java b/src/main/java/com/mey/backend/global/config/AmazonConfig.java new file mode 100644 index 0000000..58292d9 --- /dev/null +++ b/src/main/java/com/mey/backend/global/config/AmazonConfig.java @@ -0,0 +1,57 @@ +package com.mey.backend.global.config; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import jakarta.annotation.PostConstruct; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Getter +public class AmazonConfig { + private AWSCredentials credentials; + + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String secretKey; + + @Value("${cloud.aws.region.static}") + private String region; + + @Value("${cloud.aws.s3.bucket}") + private String bucket; + + @Value("${cloud.aws.s3.path.profile}") + private String profilePath; + + @Value("${cloud.aws.s3.path.place}") + private String placePath; + + @PostConstruct + public void init() { + this.credentials = new BasicAWSCredentials(accessKey, secretKey); + } + + @Bean + public AmazonS3 s3Client() { + BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + return AmazonS3ClientBuilder.standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) + .build(); + } + + @Bean + public AWSCredentialsProvider awsCredentialsProvider() { + return new AWSStaticCredentialsProvider(this.credentials); + } + +} diff --git a/src/main/java/com/mey/backend/global/util/S3Manager.java b/src/main/java/com/mey/backend/global/util/S3Manager.java new file mode 100644 index 0000000..bed1432 --- /dev/null +++ b/src/main/java/com/mey/backend/global/util/S3Manager.java @@ -0,0 +1,39 @@ +package com.mey.backend.global.util; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.mey.backend.global.config.AmazonConfig; +import java.io.IOException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +@Slf4j +@Component +@RequiredArgsConstructor +public class S3Manager { + private final AmazonS3 amazonS3; + private final AmazonConfig amazonConfig; + + public String uploadFile(String keyName, MultipartFile file) { + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentLength(file.getSize()); + try { + amazonS3.putObject(new PutObjectRequest(amazonConfig.getBucket(), keyName, file.getInputStream(), metadata)); + } catch (IOException e){ + log.error("error at AmazonS3Manager uploadFile : {}", (Object) e.getStackTrace()); + } + + return amazonS3.getUrl(amazonConfig.getBucket(), keyName).toString(); + } + + public String generateProfileKeyName(String fileName) { + return amazonConfig.getProfilePath() + "/" + System.currentTimeMillis() + "_" + fileName; + } + + public String generatePlaceKeyName(String fileName) { + return amazonConfig.getPlacePath() + "/" + System.currentTimeMillis() + "_" + fileName; + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 08d95e5..41bfb7e 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -4,6 +4,7 @@ spring: username: ${DB_USERNAME} password: ${DB_PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver + sql: init: mode: always @@ -13,13 +14,14 @@ spring: hibernate: ddl-auto: create-drop defer-datasource-initialization: true + show-sql: true properties: hibernate: dialect: org.hibernate.dialect.MySQL8Dialect - show-sql: true format-sql: true logging: level: com.mey.backend: DEBUG org.springframework.web: DEBUG + org.hibernate.tool.schema.internal: TRACE diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f7f4118..5ca6317 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -17,7 +17,6 @@ jwt: access-token-validity: 3600000 # 1시간 (밀리초) refresh-token-validity: 604800000 # 7일 (밀리초) - openai: api: key: ${OPENAI_API_KEY:dummy} @@ -29,3 +28,18 @@ tmap: app-key: ${TMAP_APP_KEY:dummy} lang: 0 # 0=Korean count: 1 + +cloud: + aws: + s3: + bucket: mey-cd-bucket + path: + profile: profile + place: place + region: + static: ap-northeast-2 + stack: + auto: false + credentials: + access-key: ${S3_ACCESS_KEY} + secret-key: ${S3_SECRET_KEY} diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 898cf0e..f73ce87 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -22,16 +22,29 @@ jwt: access-token-validity: 3600000 refresh-token-validity: 604800000 - - openai: api: - key: ${OPENAI_API_KEY} + key: ${OPENAI_API_KEY:testOpenAIApiKeyForDevelopmentAndTestingPurposesOnly} url: https://api.openai.com/v1/chat/completions tmap: transit: base-url: https://apis.openapi.sk.com/transit - app-key: ${TMAP_APP_KEY} + app-key: ${TMAP_APP_KEY:testTmapAppKeyForDevelopmentAndTestingPurposesOnly} lang: 0 # 0=Korean count: 1 + +cloud: + aws: + s3: + bucket: mey-cd-bucket + path: + profile: profile + place: place + region: + static: ap-northeast-2 + stack: + auto: false + credentials: + access-key: ${S3_ACCESS_KEY:testS3AccessKeyForDevelopmentAndTestingPurposesOnly} + secret-key: ${S3_SECRET_KEY:testS3SecretKeyForDevelopmentAndTestingPurposesOnly}