컬쥐네 다락방
AWS S3를 이용한 파일 업로드 본문
미니 프로젝트를 진행하면서부터 프로필 수정이나 게시글 업로드 과정에서 사진 파일 등록 기능이 필요해지면서 공부했던 파일 업로드 기능입니다.
AWS의 S3를 사용해서 입력받은 파일 데이터를 저장하고, 이미지 url을 반환하여 이 Url을 이용해 사진을 보여주는 방식을 주로 사용했습니다 :)
-FileUploadService
@RequiredArgsConstructor
@Service
public class FileUploadService {
private final S3Service s3Service;
public String uploadImage(MultipartFile file) {
String fileName = createFileName(file.getOriginalFilename());
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType(file.getContentType());
try (InputStream inputStream = file.getInputStream()) {
s3Service.uploadFile(inputStream, objectMetadata, fileName);
} catch (IOException e) {
throw new IllegalArgumentException(String.format("파일 변환 중 에러가 발생하였습니다 (%s)", file.getOriginalFilename()));
}
return s3Service.getFileUrl(fileName);
}
private String createFileName(String originalFileName) {
return UUID.randomUUID().toString().concat(getFileExtension(originalFileName));
}
private String getFileExtension(String fileName) {
try {
return fileName.substring(fileName.lastIndexOf("."));
} catch (StringIndexOutOfBoundsException e) {
throw new IllegalArgumentException(String.format("잘못된 형식의 파일 (%s) 입니다", fileName));
}
}
}
입력받은 파일에서 파일의 원래 이름, 메타 데이터, inputStream을 읽어오고 이 정보를 이용해서 S3에 저장을 요청합니다. 여기서 메타 데이터는 데이터를 설명해주는 데이터, inputStream은 바이트 단위의 데이터 라고 이해했습니다.
특히 파일을 저장할 땐 원래 파일 명을 사용하기 보다는 파일 명을 이용해 숫자와 영어로 구성된 랜덤 이름을 만들어 저장!
이 외에도 이런 작업이 매끄럽게 이어지도록 기능 별로 클래스를 만들어서 관리했습니다 .
-S3Service
//인터페이스인 S3Service를 FileUploadService에서 주입받아서 런타임 시점에 오브젝트 관계를 갖도록 해줌
public interface S3Service {
void uploadFile(InputStream inputStream, ObjectMetadata objectMetadata, String fileName);
String getFileUrl(String fileName);
}
-S3 Service Impl
@RequiredArgsConstructor
@Component
public class S3ServiceImpl implements S3Service {
private final AmazonS3Client amazonS3Client;
private final S3Component s3Component;
@Override
public void uploadFile(InputStream inputStream, ObjectMetadata objectMetadata, String fileName) {
amazonS3Client.putObject(new PutObjectRequest(s3Component.getBucket(), fileName, inputStream, objectMetadata).withCannedAcl(CannedAccessControlList.PublicRead));
}
//aws-cloud-starter-aws 라이브러리에서 제공하는 AmazonS3Client를 사용해서 다음과 같이 파일을 업로드 하고(uploadFile),
//아래 메소드는 업로드한 파일의 URI를 가져오는 메소드입니다.
@Override
public String getFileUrl(String fileName) {
return String.valueOf(amazonS3Client.getUrl(s3Component.getBucket(), fileName));
}
//S3Component를 주입받아서 프로퍼티에 추가한 버킷 정보를 가져와서 awsS3Client.putObject(...)를 통해 AWS S3로 파일을 업로드합니다.
//그리고 awsClient.getUrl(...)을 통해 업로드된 파일의 URI을 가져옵니다. 다음은 -> FileUploadService
}
-S3 Component
//ConfigurationProperties(prefix="cloud.aws.s3")을 통해 프로퍼티의 값을 불러오도록 합니다.
// @Setter 필요, 또한 S3ServiceImpl에서 빈 주입 받기 위해 빈으로 등록
@Getter
@Setter
@ConfigurationProperties(prefix = "cloud.aws.s3")
@Component
public class S3Component {
private String bucket;
}
Component에서는 prefix를 통해 properties에서 bucket의 값을 받도록 만들어져있다.
이 bucket의 이름을 가져다가 다른 클래스들에서 저장될 위치를 정해줬습니다.
-실제 Controller에서 사용된 모습
@RequestMapping("/api/profile")
public UserDto profileChange(@RequestPart String userData, @RequestParam(required = false) MultipartFile file, HttpServletRequest httpServletRequest) {
JSONObject userJson = new JSONObject(userData);
//토근에서 사용자 정보 추출
String token = jwtTokenProvider.resolveToken(httpServletRequest);
String email = jwtTokenProvider.getUserPk(token);
User member = userRepository.findByEmail(email)
.orElseThrow(() -> new IllegalArgumentException("일치하는 E-MAIL이 없습니다"));
if(file == null){
UserDto userDto = new UserDto(member,userJson);
userService.update(userDto);
return userDto;
} else{
String fileUrl = fileUploadService.uploadImage(file);
//해당 사용자의 프로필 업데이트
UserDto userDto = new UserDto(member,userJson,fileUrl);
userService.update(userDto);
return userDto;
}
}
프로필 수정에서는 사용자가 프로필을 수정하지 않을 수 있기 때문에 프로필 사진을 등록했을 때와 등록하지 않았을 때로 나눠서 이미지 데이터를 저장할 것인지, 아니면 현재 데이터를 그대로 사용할 것인지 나눠줬습니다 .
'공부방 > 항해 99' 카테고리의 다른 글
항해 99, 실전 프로젝트 - 오프라인 책 교환 서비스 개발 일지 -3- (feat. 책과 콩나무) (0) | 2021.05.16 |
---|---|
항해 99, 실전 프로젝트 - 오프라인 책 교환 서비스 개발 일지 -2- (0) | 2021.05.04 |
2021.04.19 ~ 04.25 항해 99 - 8주차 회고록 (0) | 2021.04.26 |
항해 99, 실전 프로젝트 - 오프라인 책 교환 서비스 개발 일지 -1- (0) | 2021.04.26 |
항해 99, 미니 프로젝트 - 항해 하우스 개발 보고서 (0) | 2021.04.26 |
Comments