미소를뿌리는감자의 코딩
[AWS] S3 스토리지 - 이미지 업로드 본문
** 수정
IAM 생성 시 (Amazons3bucket ..), 프로그래밍 방식 액세스가 보이지 않음 ㅜ
https://livefordev.tistory.com/42
어찌저찌, 이걸로 root user에 대한 액세스 키 발급 후 처리
----
가 아니라...
생성된 iam 에서 보안 자격 증명으로 들어간 후 액세스 키 만들기를 클릭해야 함.
AWS 외부에서 실행되는 애플리케이션을 선택하고 만들기~~~
최종
이거 보고 IAM 까지 만들기. -> .csv파일 다운로드 해서 가지고 있기 나중에 키 넣을 때 필요.
버킷 정책에 복붙하다가 에러가 나면, 아래 블로그 보고 /* 붙이기 -> 에러 처리 맨 밑.
https://taxijjang.tistory.com/117
Intellij로 돌아가서, command + , 를 누르고, AWS Toolkit Install하기
Install한 후 껐다 키기
이거 클릭.
https://blog.jetbrains.com/ko/idea/2022/03/aws-in-intellij-idea/#Installing_AWS_Toolkit_Plugin
이후 이거 보고 따라하기, 중간에 IAM 키 받는 부분은 이미 한 거니까, 건너 뛰기
application.properties 파일에 아래 부분 추가하기.
build.gradle 의존성 추가부터 따라하기. 만들고자 하는거에 따라 조금 수정이 필요할 수도 있음. entity 형성 시.
위 코드에서 조금 수정해야할 부분
** 코드 수정.
S3Uploader.java에서,
.withCannedAcl(CannedAccessControlList.publicRead) 를 제거해 주었다.
이를 통해 필요한 권한을 버킷 정책을 통해 관리.
private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, uploadFile)
//.withCannedAcl(CannedAccessControlList.PublicRead) // PublicRead 권한으로 업로드 됨
);
return amazonS3Client.getUrl(bucket, fileName).toString();
}
** 코드 수정.
JAXB관련 경고가 발생
build.gradle에 아래를 추가해 주었다.
implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation 'com.sun.xml.bind:jaxb-impl:2.3.3'
implementation 'com.sun.xml.bind:jaxb-core:2.3.0.1'
** 코드 수정
S3Uploader.java에서 코드를 다음과 같이 수정했다. - 밑에 최종 S3Uploader.java 파일도 올려두었다.
-- 이전 -- 파일 변환 오류 해결
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(file.getOriginalFilename());
if(convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
-- 이후 --
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = File.createTempFile("temp", null); // 임시 파일 생성
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
} catch (IOException e) {
log.error("파일 변환 중 오류 발생", e);
return Optional.empty();
}
return Optional.of(convertFile);
}
-- 이전 -- .temp로 이미지 저장되는 문제 해결
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = File.createTempFile("temp", null); // 임시 파일 생성
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
} catch (IOException e) {
log.error("파일 변환 중 오류 발생", e);
return Optional.empty();
}
return Optional.of(convertFile);
}
-- 이후 --
private Optional<File> convert(MultipartFile file) throws IOException {
String originalFileName = file.getOriginalFilename();
String extension = originalFileName.substring(originalFileName.lastIndexOf(".")); // 파일 확장자 추출
// 임시 파일 생성 시, 확장자를 원본 파일의 확장자로 설정
File convertFile = File.createTempFile("temp", extension); // 확장자 지정
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
} catch (IOException e) {
log.error("파일 변환 중 오류 발생", e);
return Optional.empty();
}
return Optional.of(convertFile);
}
최종 S3Uploader.java
package com.sparta.spartagoods.service;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Optional;
@Slf4j
@RequiredArgsConstructor
@Service
public class S3Uploader {
private final AmazonS3 amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
// MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
public String upload(MultipartFile multipartFile, String dirName) throws IOException {
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
return upload(uploadFile, dirName);
}
private String upload(File uploadFile, String dirName) {
String fileName = dirName + "/" + uploadFile.getName();
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile); // 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)
return uploadImageUrl; // 업로드된 파일의 S3 URL 주소 반환
}
private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, uploadFile)
// .withCannedAcl(CannedAccessControlList.PublicRead) // PublicRead 권한으로 업로드 됨
);
return amazonS3Client.getUrl(bucket, fileName).toString();
}
private void removeNewFile(File targetFile) {
if(targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
}else {
log.info("파일이 삭제되지 못했습니다.");
}
}
private Optional<File> convert(MultipartFile file) throws IOException {
String originalFileName = file.getOriginalFilename();
String extension = originalFileName.substring(originalFileName.lastIndexOf(".")); // 파일 확장자 추출
// 임시 파일 생성 시, 확장자를 원본 파일의 확장자로 설정
File convertFile = File.createTempFile("temp", extension); // 확장자 지정
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
} catch (IOException e) {
log.error("파일 변환 중 오류 발생", e);
return Optional.empty();
}
return Optional.of(convertFile);
}
}
최종 build.gradle dependencies
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
// JWT
compileOnly group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
implementation 'org.springframework.boot:spring-boot-starter-validation'
//AWS
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation 'com.sun.xml.bind:jaxb-impl:2.3.3'
implementation 'com.sun.xml.bind:jaxb-core:2.3.0.1'
}
Postman은 아래와 같이 정보를 넣어주었다.
-- 참고 사이트 --
https://taxijjang.tistory.com/117
-> Add Statement -> Generate Policy 할 때, 에러 대처법
https://aws.amazon.com/ko/blogs/korea/aws-toolkit-for-intellij-now-generally-available/
https://blog.jetbrains.com/ko/idea/2022/03/aws-in-intellij-idea/#Installing_AWS_Toolkit_Plugin
-> 역시 공식이 제일 좋다. - 이걸 메인으로 보고 하면 됨.
-> 공식이 좋다 22
'스크랩' 카테고리의 다른 글
배포 - AWS EC2, RDS 이용 (0) | 2024.03.14 |
---|---|
Swagger (0) | 2024.03.14 |
[MySQL] 비밀번호 바꾸기 (0) | 2024.03.13 |
[Intellij] port 8080 was already in use... (0) | 2024.03.08 |
[Spring] Interface 에 대해서 + Service Interface (0) | 2024.03.05 |