Skip to content

Commit

Permalink
Merge pull request #30 from 9oormthon-univ/feature/GOORM-3-product
Browse files Browse the repository at this point in the history
[GOORM-3]-FIX: product 테이블에서 s3 엔티티 제거
  • Loading branch information
lilloo04 authored Nov 23, 2024
2 parents aa061a4 + f35c174 commit 99c53e5
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 6 deletions.
12 changes: 12 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ dependencies {
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

implementation 'io.github.cdimascio:java-dotenv:5.2.2'


//AWS-S3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
// Spring Cloud AWS Starter
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

// AWS SDK for S3
implementation 'com.amazonaws:aws-java-sdk-s3:1.12.418' // 최신 버전으로 변경 가능

// 전체 AWS SDK (필요 시)
// implementation 'com.amazonaws:aws-java-sdk:1.12.418'
}

tasks.named('test') {
Expand Down
15 changes: 15 additions & 0 deletions et --hard 90674c5
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
57e5542 (HEAD -> feature/GOORM-3-product, origin/feature/GOORM-3-product) HEAD@{0}: reset: moving to HEAD~1
90674c5 HEAD@{1}: commit: aws-s3 test api 구현
57e5542 (HEAD -> feature/GOORM-3-product, origin/feature/GOORM-3-product) HEAD@{2}: commit: fix: 개별 상품 조회
0a7e35a HEAD@{3}: commit: add ProductImage entity
46a2f30 HEAD@{4}: reset: moving to HEAD~1
602a28b HEAD@{5}: commit: fix: 참여자 수 조회하기
46a2f30 HEAD@{6}: reset: moving to HEAD
46a2f30 HEAD@{7}: commit: 개별 상품 조회 API 구현
72fd6db HEAD@{8}: commit: 상품 예약 테이블 구현 및 조회 API 구현
2911e8c (origin/master, origin/HEAD) HEAD@{9}: pull origin master: Fast-forward
f029646 HEAD@{10}: commit: 최근 상품 조회 API 구현
8ec3e22 (master) HEAD@{11}: checkout: moving from master to feature/GOORM-3-product
8ec3e22 (master) HEAD@{12}: reset: moving to origin/master
8ec3e22 (master) HEAD@{13}: reset: moving to origin/master
b161a20 HEAD@{14}: clone: from https://github.com/9oormthon-univ/2024_DANPOONG_TEAM_49_BE
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.goormthon3.team49.common.config;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; // import 추가
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class AmazonS3Config {

@Value("${cloud.aws.credentials.access-key}") // application.yml에서 설정한 AWS 액세스 키
private String accessKey;

@Value("${cloud.aws.credentials.secret-key}") // application.yml에서 설정한 AWS 비밀 키
private String secretKey;

@Value("${cloud.aws.region.static}") // application.yml에서 설정한 AWS 리전
private String region;

@Value("${cloud.aws.s3.bucket}") // application.yml에서 설정한 S3 버킷 이름
private String bucket;

/**
* AmazonS3Client 빈을 설정합니다.
* @return AmazonS3 클라이언트 인스턴스
*/
@Bean
public AmazonS3 amazonS3Client() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
return AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/goormthon3/team49/common/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.goormthon3.team49.common.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 모든 엔드포인트에 대해
.allowedOrigins("http://localhost:3000") // 허용할 origin
.allowedMethods("GET", "POST", "PUT", "DELETE") // 허용할 HTTP 메서드
.allowCredentials(true); // 인증 정보 포함 여부
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.goormthon3.team49.domain.awsS3;

import com.goormthon3.team49.domain.awsS3.application.AwsS3Service;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@RequiredArgsConstructor
@RestController
@RequestMapping("/file")
public class AmazonS3Controller {

private final AwsS3Service awsS3Service;

/**
* 파일 업로드를 처리하는 엔드포인트
* @param multipartFiles 업로드할 파일 목록
* @return 업로드된 파일 이름 목록
*/
@PostMapping
public ResponseEntity<List<String>> uploadFile(@RequestParam List<MultipartFile> multipartFiles) {
List<String> uploadedFiles = awsS3Service.uploadFile(multipartFiles);
return ResponseEntity.ok(uploadedFiles);
}

/**
* 파일 삭제를 처리하는 엔드포인트
* @param fileName 삭제할 파일의 이름
* @return 삭제된 파일 이름
*/
@DeleteMapping
public ResponseEntity<String> deleteFile(@RequestParam String fileName) {
awsS3Service.deleteFile(fileName);
return ResponseEntity.ok(fileName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.goormthon3.team49.domain.awsS3.application;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value; // @Value 어노테이션 import 추가
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class AwsS3Service {

@Value("${cloud.aws.s3.bucket}") // application.yml에서 설정한 버킷 이름
private String bucket;

private final AmazonS3 amazonS3;

/**
* 파일 업로드를 처리합니다.
* @param multipartFiles 업로드할 파일 목록
* @return 업로드된 파일들의 이름 목록
*/
public List<String> uploadFile(List<MultipartFile> multipartFiles) {
List<String> fileNameList = new ArrayList<>();

multipartFiles.forEach(file -> {
String fileName = createFileName(file.getOriginalFilename());
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(file.getSize());
objectMetadata.setContentType(file.getContentType());

try (InputStream inputStream = file.getInputStream()) {
amazonS3.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata)
.withCannedAcl(CannedAccessControlList.PublicRead));
} catch (IOException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "파일 업로드에 실패했습니다.", e);
}

fileNameList.add(fileName);
});

return fileNameList;
}

/**
* 업로드할 파일의 고유 이름을 생성합니다.
* @param fileName 원본 파일 이름
* @return 고유 파일 이름
*/
public String createFileName(String fileName) {
return UUID.randomUUID().toString().concat(getFileExtension(fileName));
}

/**
* 파일 이름에서 확장자를 추출합니다.
* @param fileName 파일 이름
* @return 파일 확장자
*/
private String getFileExtension(String fileName) {
try {
return fileName.substring(fileName.lastIndexOf("."));
} catch (StringIndexOutOfBoundsException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "잘못된 형식의 파일(" + fileName + ") 입니다.", e);
}
}

/**
* 파일 삭제를 처리합니다.
* @param fileName 삭제할 파일의 이름
*/
public void deleteFile(String fileName) {
amazonS3.deleteObject(bucket, fileName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class ProductDto {
private String link;
private String pickupLocation;
private Long productImgId;
private String s3Key;
//private String s3Key;

public static ProductDto fromEntity(Product product, ProductReservation productReservation) {
return ProductDto.builder()
Expand All @@ -34,7 +34,7 @@ public static ProductDto fromEntity(Product product, ProductReservation productR
.link(product.getLink())
.pickupLocation(product.getPickupLocation())
.productImgId(product.getProductImage() != null ? product.getProductImage().getProductImgId() : null)
.s3Key(product.getProductImage() != null ? product.getProductImage().getS3Key() : null)
// .s3Key(product.getProductImage() != null ? product.getProductImage().getS3Key() : null)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ public class SummaryProductDto {
private int savePrice;
private int participantCount;
private Long productImgId;
private String s3Key;
//private String s3Key;

public static SummaryProductDto fromEntity(Product product) {
Long productImgId = product.getProductImage() != null ? product.getProductImage().getProductImgId() : null;
String s3Key = product.getProductImage() != null ? product.getProductImage().getS3Key() : null;
// String s3Key = product.getProductImage() != null ? product.getProductImage().getS3Key() : null;

return SummaryProductDto.builder()
.productId(product.getProductId())
.title(product.getTitle())
.savePrice(product.getSavePrice())
//.participantCount(product.getParticipants().size()) // 수정 필요
.productImgId(productImgId)
.s3Key(s3Key)
// .s3Key(s3Key)
.build();
}
}
14 changes: 13 additions & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,20 @@ springdoc:
default-produces-media-type: application/json

kakao:
client_id: ${REST_API_KEY:cdd423a129bb50b1413fa39e3a72e142}
client_id: ${REST_API_KEY}
redirect_uri: ${KAKAO_REDIRECT_URI:http://localhost:8080/callback}

# AWS S3
cloud:
aws:
credentials:
access-key: ${ACCESS_KEY}
secret-key: ${SECRET_KEY}
region:
static: ap-northeast-2 # 버킷의 리전
s3:
bucket: danpoongteam49 # 버킷 이름
stack:
auto: false


0 comments on commit 99c53e5

Please sign in to comment.