백엔드 서버에 S3와 어떻게 연동할까?
라이브러리 추가
--
build.gradle 파일
dependencies {
...
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
...
}
--
기본 설정 추가
--
application.yml 파일
cloud:
aws:
s3:
bucket: <S3 버킷 이름>
credentials:
access-key: <저장해놓은 IAM 액세스 키>
secret-key: <저장해놓은 IAM 비밀 액세스 키>
region:
static: ap-northeast-2
auto: false
stack:
auto: false
cloud.aws.region.static
AWS S3를 사용하는 리전을 지정한다. (서울 = ap-norheast-2)
cloud.aws.region.auto
리전을 자동으로 설정할지 여부를 지정한다.
위에 서울리전으로 직접 지정했으니 false로 한다.
cloud.aws.stack.auto
AWS 리소스 스택을 자동으로 관리할지 여부를 지정한다.
만약 EC2에서 해당 프로젝트를 실행시키면 기본으로 CloudFormation 구성을 시작하기 때문에
설정한 CloudFormation이 없다면 해당 프로젝트가 실행되지 않는다.
--
Spring Boot에서 S3를 사용하기 위한 설정 클래스
--
application.yml 파일에 AWS S3 관련 설정값을 정의했지만
AWS SDK와 연동하기 위해서는 AWS S3 클라이언트를 생성할 필요가 있다.
S3Config.java 클래스 파일 (위치는 상관없지만 보통 config 디렉터리를 생성하여 안에 넣는다.)
@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 credentials = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder
.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
}
}
- @Configuration을 통해 해당 클래스가 Spring 설정 클래스임을 정의한다.
- @Value를 통해 application.yml파일에 정의했던 환경변수를 가져온다.
- AmazonS3Client를 빈(Bean)으로 등록하여 AWS S3와의 상호작용을 쉽게 하도록 구성한다.
- AWS SDK에서 제공하는 BasicAWSCredentials 클래스를 사용하여 AWS API 인증한 객체를 생성한다.
(액세스 키와 비밀 액세스 키를 사용하여 AWS API 인증) - AmazonS3ClientBuilder를 통해 클라이언트를 생성한다.
- withRegion : 리전 설정
- withCredentials : AWS 인증 정보
- build() : 해당 설정을 기반으로 AmazonS3Client 객체 생성
해당 코드는
amazonS3Client()를 호출할 때마다 해당 객체(AWS S3에 접근하는 객체)를 만들어 반환해 주는 코드다.
--
요청 받기 (DTO, Controller)
--
DTO 클래스 파일 코드
public class testDto{
private String name;
private MultipartFile mainImg;
private List<MultipartFile> serveImg;
}
파일을 받는 타입은 MultipartFile 타입이며, 파일 이외의 데이터도 함께 받는다면 MultipartRequest 타입을 사용한다.
Controller 클래스 파일 코드
// 상품 추가
@PostMapping("/admin/image")
public String saveImage(testDto request) throws IOException {
fileService.saveImage(request);
return "이미지 등록 완료!";
}
일반적으로 프론트 서버에서 백엔드 서버로 파일을 전달하는 경우 폼데이터를 이용해서 요청한다.
(물론 다른 방법으로도 요청가능하지만 폼데이터를 사용하면 파일과 다른 형태의 데이터도 함께 전송이 가능)
그래서 Controller에서 폼데이터로 요청이 오는 경우
@RequestBody가 아닌 @RequestParam 또는 @ModelAttribute를 사용하여 데이터를 받는다.
하지만 보통 위 코드처럼 어노테이션을 생략하기도 한다.
--
파일 처리하기 (Entity, Service)
--
S3File.java 엔티티 클래스 파일 코드
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class S3File extends TimeCheck {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long s3FileId;
// 기본 크기가 작아서 초과로 컬럼을 이용해서 크기 변경
@Column(length = 1024)
private String fileName;
@Column(length = 1024)
private String fileUrl;
public S3File(String fileName, String fileUrl){
this.fileName = fileName;
this.fileUrl = fileUrl;
}
}
- fileName : 파일명
- fileUrl : 해당 파일을 다운로드할 링크 (AWS S3에서 다운 링크 제공)
Service 클래스 파일 코드
@Service
@RequiredArgsConstructor
@Slf4j
public class AdminItemService {
private final AmazonS3Client amazonS3Client;
private final S3FileRepository s3FileRepository;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
// 파일(이미지) 저장 서비스
@Transactional
public void saveItem(testDto request) throws IOException {
// 메인 이미지 처리
if(request.getMainImg() != null){
S3DataSave(request.getMainImgList());
}
// 서브 이미지 처리
if(request.getSubImgList() != null && !request.getSubImgList().isEmpty()){
S3DataListSave(request.getSubImgList());
}
}
//----------------------------------------------------------------------
// 파일 추출 & S3 업로드 & S3에 저장된 파일 정보를 반환
public S3Data S3Upload(MultipartFile multipartFile) throws IOException {
// 해당 파일 이름 추출 (ex : acb.jpg)
String fileName = multipartFile.getOriginalFilename();
// 해당 파일 확장자 추출 (ex : .jpg)
String ext = fileName.substring(fileName.indexOf("."));
// 이미지 파일명 변경하기 (중복을 피하기 위해서)
String uuidFileName = UUID.randomUUID() + ext;
// 해당 파일에 정보를 추가하는 메타데이터 작성
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(multipartFile.getSize());
metadata.setContentType(multipartFile.getContentType());
// S3에 파일 업로드하기 [putObject(버킷, 파일명, 서버에 저장할 파일, 메타데이터)]
amazonS3Client.putObject(bucket, uuidFileName, multipartFile.getInputStream(), metadata);
// S3에 저장된 파일 주소 가져오기
String s3Url = amazonS3Client.getUrl(bucket, uuidFileName).toString();
// S3Data DTO에 파일명과 링크 담아서 반환 (엔티티에 저장용)
S3Data data = new S3Data(uuidFileName, s3Url);
return data;
}
// S3에 저장된 파일 정보를 가지고 DB에 저장하기 (리스트용)
public void S3DataListSave(List<MultipartFile> multipartFileList) throws IOException {
// 이미지를 한 번에 처리(save)를 위한 리스트 초기화
List<S3File> s3FileList = new ArrayList<>();
// 여러 개인 서브 이미지 처리
for (MultipartFile multipartFile : multipartFileList){
// 이미지 추출 & S3업로드 & 엔티티에 저장할 데이터 반환
ItemDto.S3Data imgData = S3Upload(multipartFile);
// 엔티티에 담기
S3File s3FileServe = new S3File(imgData.getUuidFileName(), imgData.getS3Url());
s3FileList.add(s3FileServe);
}
// 한 번에 저장
s3FileRepository.saveAll(s3FileList);
}
// S3에 저장된 파일 정보를 가지고 DB에 저장하기 (단일용)
public void S3DataSave(MultipartFile multipartFile) throws IOException {
// 파일 추출 및 처리 / S3에 업로드 / 파일 명 & 주소 객체 반환
ItemDto.S3Data imgData = S3Upload(multipartFile);
// 엔티티에 담기
S3File s3File = new S3File(imgData.getUuidFileName(), imgData.getS3Url());
// 한 번에 저장
itemFileRepository.save(itemFile);
}
AWS S3에 업로드된 파일(이미지) 삭제하는 코드
amazonS3Client.deleteObject(bucket, uuidFileName);
S3에 이미지를 업로드한 뒤에 다시 이미지를 프론트 서버로 반환할 때에는
엔티티에 저장한 fileUrl을 반환하면 된다.
브라우저에 해당 이미지를 띄우기 위한 코드 (HTML)
<img alt=이미지명 src=fileUrl />
--
'AWS' 카테고리의 다른 글
[S3] S3 버킷 생성하기 (2) | 2024.11.14 |
---|---|
[S3] S3 버킷에 정책 설정하기 (0) | 2024.11.13 |
[S3] S3란? (3) | 2024.11.13 |
EC2 인스턴스 상태검사 "1/2개 검사 통과" (EC2 인스턴스 서버 다운) (1) | 2024.10.08 |
[ELB] ACM(SSL/TLS 인증서)를 통해 HTTPS 설정하기 (+ HTTP요청시 HTTPS로 자동 리다렉트) (0) | 2024.09.06 |