728x90
마지막 프로젝트를 진행중이며 유저가 업로드 하는 이미지 파일을 S3 클라우드에 저장하는 방식을 사용헤보기로 했다.
먼저 AWS S3 Bucket을 생성하고 코드 구현을 했다.
S3 버킷 생성
- S3에서 버킷 만들기 클릭
1) 버킷 이름과 리전 설정
- 버킷 이름은 고유값으로 설정
2) 퍼블릭 액세스 설정
※ 외부에 S3을 공개할 경우 모든 퍼블릭 액세스 차단을 체크 해제하고, 공개하지 않는다면 체크를 해주면 된다.
3) 버킷 정책 생성
- 버킷 생성까지 완료 되었으면 외부에서 접근이 가능하도록 버킷 정책을 설정해줘야 한다.
- 생성된 버킷명을 클릭해서 들어가면 아래와 같은 탭이 있는데 [권한] 탭을 클릭해서 들어가면
버킷 정책이 있다. 편집으로 들어가자.
- 정책 생성기를 클릭하고 설정해야한다.
(버킷 ARN은 복사를 미리해둔다)
- 버킷 생성기에 들어가면 아래와 같은 화면이 나올거고 해당 항목들을 채워 나간다.
- Select Type of Policy - S3 Bucket Policy
- Effect - Allow
- Principal - *
- Action - GetObject, PutObject
- ARN - arn:aws:s3:::{버킷이름}/*
Add Statement 클릭 -> 아래 Generate Policy를 클릭하여 생성된 정책을 복사 후
S3 정책 편집에 돌아가서 수정해주면 된다.
4) access key 발급
- S3에 접근하려면 별도의 인증 과정이 필요하다.
- 액세스 키를 가지고 있는 사람만 자격을 증명할 수 있다.
- 액세스 키는 AWSAccessKeyId와 AWSSecretKey로 구성된다.
- 보안 자격 증명(IAM) > 액세스 키 > 새 액세스 키 만들기
- '키 파일 다운로드' 클릭(반드시 다운받고 따로 보관하자)
- AccessKeyId와 SecretKey는 외부에 노출되어서는 안된다.
AWS 의존성 추가 및 설정
- build.gradle
implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-aws', version: '2.2.1.RELEASE'
- apllication.properties
ccloud.aws.credentials.accessKey= 사용자 엑세스 키 cloud.aws.credentials.secretKey= 비밀 엑세스 키 cloud.aws.stack.auto=false
AWS S3 Service bucket
cloud.aws.s3.bucket=버킷이름 (자신이 설정한 버킷이름)
cloud.aws.region.static=ap-northeast-2 (버킷 지역/서울)
AWS S3 Bucket URL
cloud.aws.s3.bucket.url=https://s3.ap-northeast-2.amazonaws.com/버킷이름
# Config 및 Util 클래스 생성
- S3 Config Class
``` java
@Configuration
public class S3Config {
@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;
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
}
- S3 Service
public class S3Uploader { private final AmazonS3Client amazonS3Client; @Value("${cloud.aws.s3.bucket}") public String bucket; // S3 버킷 이름 // 전달 받은 데이터를 바로 S3에 업로드하는 메소드 // 1. 사전 준비 - 메타데이터와 파일명 생성 // 2. S3에 전달 받은 파일 업로드 // 3. S3에 저장된 파일 이름과 주소 반환 // 파라미터로 multipartFile(업로드하려는 파일)과 dirName(이 파일을 업로드하고 싶은 S3 버킷의 폴더 이름)을 받는다. public HashMap<String, String> uploadImage(MultipartFile multipartFile, String dirName) throws IOException { // 0. 이미지 파일인지 체크 isImage(multipartFile); // 1. 사전 준비 // 1-1 메타데이터 생성 // InputStream을 통해 Byte만 전달되고 해당 파일에 대한 정보가 없기 때문에 파일의 정보를 담은 메타데이터가 필요하다. ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType(multipartFile.getContentType()); metadata.setContentLength(multipartFile.getSize()); // 1-2 S3에 저장할 파일명 생성 // UUID 사용 이유 : 이름이 같은 파일들이 서로 덮어쓰지 않고 구분될 수 있도록 String fileName = createFileName(multipartFile); String uploadImageName = dirName + "/" + UUID.randomUUID() + fileName; // 2. s3로 업로드 amazonS3Client.putObject(new PutObjectRequest(bucket,uploadImageName, multipartFile.getInputStream(),metadata) .withCannedAcl(CannedAccessControlList.PublicRead)); // S3에 업로드한 이미지의 주소를 받아온다. String uploadImageUrl = amazonS3Client.getUrl(bucket, uploadImageName).toString();
// 4. S3에 저장된 파일 이름과 주소 반환
HashMap<String, String> imgInfo = new HashMap<>();
imgInfo.put("fileName", uploadImageName);
imgInfo.put("img",uploadImageUrl);
return imgInfo;
}
// 파일 삭제하기
public void deleteImageFile(String fileName) {
amazonS3Client.deleteObject(bucket, fileName);
}
// 파일 이름 생성 메소드
private String createFileName(MultipartFile multipartFile) {
String name = multipartFile.getOriginalFilename();
String ext = "";
// 확장자와 파일명 분리
if (name.contains(".")) {
int position = name.lastIndexOf(".");
ext = name.substring(position+1);
name = name.substring(0,position);
}
// 파일 이름의 길이가 길면 100자로 자르기 (디비의 varchar(255) 제한에 걸리지 않으려고)
if (name.length()>100){
name = name.substring(0,100);
}
// S3에 저장할 파일 이름 생성
String fileName = !ext.equals("")?name+"."+ext:name;
return fileName;
}
// 이미지 파일인지 확인하는 메소드
private void isImage(MultipartFile multipartFile) throws IOException {
// tika를 이용해 파일 MIME 타입 체크
// 파일명에 .jpg 식으로 붙는 확장자는 없앨 수도 있고 조작도 가능하므로 MIME 타입을 체크하는 것이 좋다.
Tika tika = new Tika();
String mimeType = tika.detect(multipartFile.getInputStream());
// MIME타입이 이미지가 아니면 exception 발생생
if (!mimeType.startsWith("image/")) {
throw new CustomException(ErrorCode.NOT_IMAGES);
}
}
}
- S3 Controller
```java
@RequiredArgsConstructor
@RestController
public class AwsController {
private final S3Uploader s3Uploader;
@PostMapping("/images/upload")
public HashMap<String,String> upload(@RequestParam("images") MultipartFile multipartFile) throws IOException {
String imgUrl = "";
String fileName = "";
HashMap<String,String> imgInfo = s3Uploader.upload(multipartFile, "static");
imgUrl = imgInfo.get("img");
fileName = imgInfo.get("fileName");
HashMap<String,String> imageUrl = new HashMap<>();
imageUrl.put("url",imgUrl);
return imageUrl;
}
// 사진 삭제 테스트
@DeleteMapping("/image/delete")
public String deleteimage(@RequestParam("path") String fileName) {
s3Uploader.deleteFile(fileName);
return "삭제완료";
}
}
'Spring' 카테고리의 다른 글
CI/CD (1) | 2024.04.16 |
---|---|
WebSocket_2 (0) | 2024.04.15 |
트랜잭션의 ACID란? (0) | 2024.04.15 |
트랜잭션(Transaction) (0) | 2024.04.15 |
SQL vs NoSQL (0) | 2024.04.15 |