1. S3 버킷 생성 - 설정



퍼블릭 엑세스는 "새 ACL을 통해 부여된 버킷 및 객체에 대한 퍼블릭 엑세스 차단" 이 권한만 필요하지만 버킷 정책을 변경할 예정이니까 전부 풀어두겠습니다!

만든 버킷의 권한에 들어가서 정책 편집을 눌러줍니다.

저희는 정책 생성기로 들어가기 전에!!

ARN을 복사해둡시다!


액션은 사용하는 동작 넣으시면 됩니다!
ARN 뒤에 /*는 모든 파일에 적용이라는 뜻인데 폴더가 있다면 /foldername/* 이런식으로 응용하시면 됩니다.

설정 확인한번 해주고 버튼 누르면

이런 창이 뜨는데, 복사해서 버킷 정책 페이지에 넣어줍시다.

S3 설정 끝!
2. IAM 생성



추가할 수 있는 정책은 다양하지만, 지금은 S3만 필요하니 하나만 추가하였습니다.

AmazonS3FullAccess를 선택 후 다음으로~ (확인하고 인스턴스 생성하시면 됩니다.)

이후 만들어진 인스턴스의 보안 자격 증명 탭으로 가서 액세스 키를 만들어줍니다.

이건 아무거나 선택하셔도 됩니다 ㅎㅎ.

설명도 용도에 맞게 적어주면 이렇게 액세스 키와 시크릿 키가 나옵니다!
다시 볼 수 없으니 꼭꼭 .csv파일 다운로드 해두세요!!
저는 불안해서 파일다운+캡쳐+메모장,,.
휴 이제 코드를 작성하러 가볼까요!
3. 코드 작성
build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
Application.yml
cloud:
aws:
s3:
bucket: {버킷 이름}
credentials:
accessKey: {액세스 키}
secretKey: {시크릿 키}
region:
static: ap-northeast-2
auto: false
stack:
auto: false
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
아래에 spring.multipart 부분은 파일데이터 크기 제한(1MB)을 10MB로 바꾸는 설정입니다.
저는 여러개의 파일 데이터를 저장하는 예시를 들 것이기 때문에 설정해주었습니다!
S3Config.java
@Configuration
public class S3Config {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean(name = "s3Client")
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
}
s3 config 설정입니다.
@Value는 lombok이 아닌
import org.springframework.beans.factory.annotation.Value;
입니당! application.yml에 설정한 내용을 받아올 수 있어요.
S3Service.java
@Service
@RequiredArgsConstructor
public class S3Service {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final AmazonS3 s3Client;
// 여러개의 파일 업로드
public List<String> uploadFile(List<MultipartFile> multipartFile) {
List<String> fileNameList = new ArrayList<>();
multipartFile.forEach(file -> {
String fileName = createFileName(file.getOriginalFilename());
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(file.getSize());
objectMetadata.setContentType(file.getContentType());
try(InputStream inputStream = file.getInputStream()) {
s3Client.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata)
.withCannedAcl(CannedAccessControlList.PublicRead));
} catch(IOException e) {
throw new BusinessException(ErrorCode.FILE_UPLOAD_ERROR);
}
fileNameList.add(fileName);
});
return fileNameList;
}
// 파일 삭제
public void deleteFile(String fileName) {
s3Client.deleteObject(new DeleteObjectRequest(bucket, fileName));
}
// 파일명 중복 방지 (UUID)
private String createFileName(String fileName) {
return UUID.randomUUID().toString().concat(getFileExtension(fileName));
}
// 파일 유효성 검사
private String getFileExtension(String fileName) {
if (fileName.length() == 0) {
throw new BusinessException(ErrorCode.FILE_VALID_ERROR);
}
ArrayList<String> fileValidate = new ArrayList<>();
fileValidate.add(".jpg");
fileValidate.add(".jpeg");
fileValidate.add(".png");
fileValidate.add(".JPG");
fileValidate.add(".JPEG");
fileValidate.add(".PNG");
String idxFileName = fileName.substring(fileName.lastIndexOf("."));
if (!fileValidate.contains(idxFileName)) {
throw new BusinessException(ErrorCode.FILE_FORMAT_ERROR);
}
return fileName.substring(fileName.lastIndexOf("."));
}
}
이 파일을 작성할때
private final AmazonS3 s3Client;
이부분과 S3Config의
@Bean(name = "s3Client")
public AmazonS3Client amazonS3Client() {
빈 이름이 달라서 2개의 Bean이 사용중이라고 오류가 떴었습니다.
해결 방법은 2가지인데, 하나는 저처럼 @Bean(name="~~")로 @Bean에 옵션을 주는거고,
다른 하나는 s3Client 선언 부분에 @Autowired를 추가해주시면 됩니다!
@Autowired
Controller.java
@RequestMapping("/api/v1/log")
@RestController
@RequiredArgsConstructor
public class LogController {
private final S3Service s3Service;
@PostMapping
public ResponseEntity<ResultResponse> createLog(
@Valid @ModelAttribute LogCreateRequest request) {
// 파일 있는지 검사
if (request.getFiles() == null) {
throw new BusinessException(ErrorCode.EMPTY_FILES);
}
List<String> files = s3Service.uploadFile(request.getFiles());
System.out.println("Files: " + files);
return ResponseEntity.ok(ResultResponse.of(ResultCode.CREATE_LOG_SUCCESS, ""));
}
}
테스트용 컨트롤러를 만들어보았습니다!
LogCreateRequest는 파일데이터들과 단일 정보를 전달받는 클래스입니다.
@Builder
@Getter @Setter
@AllArgsConstructor
public class LogCreateRequest {
private List<MultipartFile> files;
private Long userId;
private Long branchId;
private String message;
}
이렇게 받는데요, 파일 데이터만 받을거라면 @RequestPart List<MultipartFile> files로 받아서 바로 넘기면 됩니다.
Postman Test

이렇게 포스트맨으로 요청을 보내보면,

테스트 성공! 링크를 클릭하면 사진이 잘 뜨네요 XD 저는 filename 앞에 S3주소를 추가해서 전체 링크가 반환되게 했습니다.
다들 화이팅하세요!!~
'Backend > Spring Boot' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 6장 (0) | 2023.05.02 |
---|---|
[Spring Boot] AWS S3 연결이 비공개로 설정되어 있지 않습니다. (0) | 2023.04.24 |
[Spring Boot] @modelAttribute로 여러 개의 파일과 단일 데이터 바인딩 (1) | 2023.04.19 |
[자바 ORM 표준 JPA 프로그래밍] 4장 (0) | 2023.04.11 |
[자바 ORM 표준 JPA 프로그래밍] 3장 (0) | 2023.04.11 |
1. S3 버킷 생성 - 설정



퍼블릭 엑세스는 "새 ACL을 통해 부여된 버킷 및 객체에 대한 퍼블릭 엑세스 차단" 이 권한만 필요하지만 버킷 정책을 변경할 예정이니까 전부 풀어두겠습니다!

만든 버킷의 권한에 들어가서 정책 편집을 눌러줍니다.

저희는 정책 생성기로 들어가기 전에!!

ARN을 복사해둡시다!


액션은 사용하는 동작 넣으시면 됩니다!
ARN 뒤에 /*는 모든 파일에 적용이라는 뜻인데 폴더가 있다면 /foldername/* 이런식으로 응용하시면 됩니다.

설정 확인한번 해주고 버튼 누르면

이런 창이 뜨는데, 복사해서 버킷 정책 페이지에 넣어줍시다.

S3 설정 끝!
2. IAM 생성



추가할 수 있는 정책은 다양하지만, 지금은 S3만 필요하니 하나만 추가하였습니다.

AmazonS3FullAccess를 선택 후 다음으로~ (확인하고 인스턴스 생성하시면 됩니다.)

이후 만들어진 인스턴스의 보안 자격 증명 탭으로 가서 액세스 키를 만들어줍니다.

이건 아무거나 선택하셔도 됩니다 ㅎㅎ.

설명도 용도에 맞게 적어주면 이렇게 액세스 키와 시크릿 키가 나옵니다!
다시 볼 수 없으니 꼭꼭 .csv파일 다운로드 해두세요!!
저는 불안해서 파일다운+캡쳐+메모장,,.
휴 이제 코드를 작성하러 가볼까요!
3. 코드 작성
build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
Application.yml
cloud:
aws:
s3:
bucket: {버킷 이름}
credentials:
accessKey: {액세스 키}
secretKey: {시크릿 키}
region:
static: ap-northeast-2
auto: false
stack:
auto: false
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
아래에 spring.multipart 부분은 파일데이터 크기 제한(1MB)을 10MB로 바꾸는 설정입니다.
저는 여러개의 파일 데이터를 저장하는 예시를 들 것이기 때문에 설정해주었습니다!
S3Config.java
@Configuration
public class S3Config {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean(name = "s3Client")
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
}
s3 config 설정입니다.
@Value는 lombok이 아닌
import org.springframework.beans.factory.annotation.Value;
입니당! application.yml에 설정한 내용을 받아올 수 있어요.
S3Service.java
@Service
@RequiredArgsConstructor
public class S3Service {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final AmazonS3 s3Client;
// 여러개의 파일 업로드
public List<String> uploadFile(List<MultipartFile> multipartFile) {
List<String> fileNameList = new ArrayList<>();
multipartFile.forEach(file -> {
String fileName = createFileName(file.getOriginalFilename());
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(file.getSize());
objectMetadata.setContentType(file.getContentType());
try(InputStream inputStream = file.getInputStream()) {
s3Client.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata)
.withCannedAcl(CannedAccessControlList.PublicRead));
} catch(IOException e) {
throw new BusinessException(ErrorCode.FILE_UPLOAD_ERROR);
}
fileNameList.add(fileName);
});
return fileNameList;
}
// 파일 삭제
public void deleteFile(String fileName) {
s3Client.deleteObject(new DeleteObjectRequest(bucket, fileName));
}
// 파일명 중복 방지 (UUID)
private String createFileName(String fileName) {
return UUID.randomUUID().toString().concat(getFileExtension(fileName));
}
// 파일 유효성 검사
private String getFileExtension(String fileName) {
if (fileName.length() == 0) {
throw new BusinessException(ErrorCode.FILE_VALID_ERROR);
}
ArrayList<String> fileValidate = new ArrayList<>();
fileValidate.add(".jpg");
fileValidate.add(".jpeg");
fileValidate.add(".png");
fileValidate.add(".JPG");
fileValidate.add(".JPEG");
fileValidate.add(".PNG");
String idxFileName = fileName.substring(fileName.lastIndexOf("."));
if (!fileValidate.contains(idxFileName)) {
throw new BusinessException(ErrorCode.FILE_FORMAT_ERROR);
}
return fileName.substring(fileName.lastIndexOf("."));
}
}
이 파일을 작성할때
private final AmazonS3 s3Client;
이부분과 S3Config의
@Bean(name = "s3Client")
public AmazonS3Client amazonS3Client() {
빈 이름이 달라서 2개의 Bean이 사용중이라고 오류가 떴었습니다.
해결 방법은 2가지인데, 하나는 저처럼 @Bean(name="~~")로 @Bean에 옵션을 주는거고,
다른 하나는 s3Client 선언 부분에 @Autowired를 추가해주시면 됩니다!
@Autowired
Controller.java
@RequestMapping("/api/v1/log")
@RestController
@RequiredArgsConstructor
public class LogController {
private final S3Service s3Service;
@PostMapping
public ResponseEntity<ResultResponse> createLog(
@Valid @ModelAttribute LogCreateRequest request) {
// 파일 있는지 검사
if (request.getFiles() == null) {
throw new BusinessException(ErrorCode.EMPTY_FILES);
}
List<String> files = s3Service.uploadFile(request.getFiles());
System.out.println("Files: " + files);
return ResponseEntity.ok(ResultResponse.of(ResultCode.CREATE_LOG_SUCCESS, ""));
}
}
테스트용 컨트롤러를 만들어보았습니다!
LogCreateRequest는 파일데이터들과 단일 정보를 전달받는 클래스입니다.
@Builder
@Getter @Setter
@AllArgsConstructor
public class LogCreateRequest {
private List<MultipartFile> files;
private Long userId;
private Long branchId;
private String message;
}
이렇게 받는데요, 파일 데이터만 받을거라면 @RequestPart List<MultipartFile> files로 받아서 바로 넘기면 됩니다.
Postman Test

이렇게 포스트맨으로 요청을 보내보면,

테스트 성공! 링크를 클릭하면 사진이 잘 뜨네요 XD 저는 filename 앞에 S3주소를 추가해서 전체 링크가 반환되게 했습니다.
다들 화이팅하세요!!~
'Backend > Spring Boot' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 6장 (0) | 2023.05.02 |
---|---|
[Spring Boot] AWS S3 연결이 비공개로 설정되어 있지 않습니다. (0) | 2023.04.24 |
[Spring Boot] @modelAttribute로 여러 개의 파일과 단일 데이터 바인딩 (1) | 2023.04.19 |
[자바 ORM 표준 JPA 프로그래밍] 4장 (0) | 2023.04.11 |
[자바 ORM 표준 JPA 프로그래밍] 3장 (0) | 2023.04.11 |