엘리스트랙
최종 프로젝트 개발5
Zmann
2024. 5. 5. 22:40
728x90
유저, 모임, 챌린지에서 이미지 업로드를 해주어야 돼서 이미지 업로드 기능을 구현하였다.
https://innovation123.tistory.com/197
[Spring / S3] SpringBoot 프로젝트 - S3 이미지 업로드
이전 글에서 S3 bucket과 IAM을 생성하고 SpringBoot project에서 S3 접근에 사용할 accessKey와 secretKey를 얻는 것까지 다뤘다. 2024.01.21 - [DevOps] - [AWS/S3] Spring boot project 이미지 업로드를 위해 S3 버켓 만들기 [
innovation123.tistory.com
이 블로그를 참고했는데 큰 도움이 되었다.
@Slf4j
@RequiredArgsConstructor
@Component
public class S3ImageService {
private final AmazonS3 amazonS3;
@Value("${cloud.aws.s3.bucketName}")
private String bucketName;
public String upload(MultipartFile image) {
if(image.isEmpty() || Objects.isNull(image.getOriginalFilename())){
throw new ServiceLogicException(ExceptionCode.EMPTY_FILE);
}
return this.uploadImage(image);
}
private String uploadImage(MultipartFile image) {
this.validateImageFileExtention(image.getOriginalFilename());
try {
return this.uploadImageToS3(image);
} catch (IOException e) {
throw new ServiceLogicException(ExceptionCode.IO_EXCEPTION_ON_IMAGE_UPLOAD);
}
}
private void validateImageFileExtention(String filename) {
int lastDotIndex = filename.lastIndexOf(".");
if (lastDotIndex == -1) {
throw new ServiceLogicException(ExceptionCode.NO_FILE_EXTENTION);
}
String extention = filename.substring(lastDotIndex + 1).toLowerCase();
List<String> allowedExtentionList = Arrays.asList("jpg", "jpeg", "png", "gif");
if (!allowedExtentionList.contains(extention)) {
throw new ServiceLogicException(ExceptionCode.INVALID_FILE_EXTENTION);
}
}
private String uploadImageToS3(MultipartFile image) throws IOException {
String originalFilename = image.getOriginalFilename(); //원본 파일 명
String extention = originalFilename.substring(originalFilename.lastIndexOf(".")); //확장자 명
String s3FileName = UUID.randomUUID().toString().substring(0, 10) + originalFilename; //변경된 파일 명
InputStream is = image.getInputStream();
byte[] bytes = IOUtils.toByteArray(is);
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("image/" + extention);
metadata.setContentLength(bytes.length);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
try{
PutObjectRequest putObjectRequest =
new PutObjectRequest(bucketName, s3FileName, byteArrayInputStream, metadata);
//.withCannedAcl(CannedAccessControlList.PublicRead);
amazonS3.putObject(putObjectRequest); // put image to S3
}catch (Exception e){
log.error("S3 이미지 업로드 중 에러 발생", e);
throw new ServiceLogicException(ExceptionCode.PUT_OBJECT_EXCEPTION);
}finally {
byteArrayInputStream.close();
is.close();
}
return amazonS3.getUrl(bucketName, s3FileName).toString();
}
public void deleteImageFromS3(String imageAddress){
String key = getKeyFromImageAddress(imageAddress);
try{
amazonS3.deleteObject(new DeleteObjectRequest(bucketName, key));
}catch (Exception e){
throw new ServiceLogicException(ExceptionCode.IO_EXCEPTION_ON_IMAGE_DELETE);
}
}
private String getKeyFromImageAddress(String imageAddress){
try{
URL url = new URL(imageAddress);
String decodingKey = URLDecoder.decode(url.getPath(), "UTF-8");
return decodingKey.substring(1); // 맨 앞의 '/' 제거
}catch (MalformedURLException | UnsupportedEncodingException e){
throw new ServiceLogicException(ExceptionCode.IO_EXCEPTION_ON_IMAGE_DELETE);
}
}
}
이미지를 업로드하는 서비스를 구현하고 기존 컨트롤러와 서비스에 적용을 해주었다.
@Operation(summary = "모임 생성 기능", description = "모임 생성")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공", content = @Content(schema = @Schema(implementation = MeetingResponseDto.class)))
})
@PostMapping
public ResponseEntity<MeetingResponseDto> createMeeting(@AuthenticationPrincipal String email, @ModelAttribute @Valid MeetingDto meetingDto){
meetingDto.setUserEmail(email);
return ResponseEntity.ok(meetingService.createMeeting(meetingDto));
}
@RequestBody로 프론트에서 받아오던 부분을 @ModelAttribute로 받아왔다. 프론트는 JSON에서 form-data로 넘겨주는 차이가 있다.
MultipartFile imageFile = meetingDto.getImageFile();
String imageUrl = Constants.DEFAULT_URL + "meeting_default_image.png";
if (imageFile != null && !imageFile.isEmpty()) {
imageUrl = s3ImageService.upload(imageFile);
}
그리고 서비스에서 이미지 업로드를 하는 기능을 넣어주었다. S3에 이미지를 넣어주면 해당 이미지의 url을 반환해 주어 그걸 저장해 주었다.
db에 이미지 url이 잘 저장되었다.
728x90