안녕하세요 이번시간에는 이미지 업로드를 만들어 보도록 하겠습니다.
전체 코드는 여기 에서 볼 수 있습니다.
build.gradle, application.yml 파일을 수정하고
FileUploadDTO, FileController, FileService 을 새로 만들어야 합니다.
- build.gradle
// 확장자 구하기용 라이브러리
compile group: 'commons-io', name: 'commons-io', version: '2.6'
// aws
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-aws', version: '2.2.1.RELEASE'
- application.yml
cloud:
aws:
s3:
bucket: hese-board
region:
static: ap-northeast-2
credentials:
accessKey: ${accessKey}
secretKey: ${secretKey}
use-default-aws-credentials-chain: false
instance-profile: true
stack:
auto: false
accessKey와 secretKey에 ${} 이렇게 되어있는데 노출을 피하고자 외부에서 주입하는 것입니다.
이것을 IDE에서 적용하기 위해선
Program arguments에 넣어주시면 읽어서 사용할 수 있습니다.
- FileUploadDTO
@Data
@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FileUploadDTO {
private String url;
}
- FileController
@RestController
@RequiredArgsConstructor
public class FileController {
private final FileService fileService;
@PostMapping("/image/upload")
@PreAuthorize("isAuthenticated()")
public SuccessResponse<FileUploadDTO> imageUpload(@RequestPart MultipartFile file, Principal principal) throws IOException {
FileUploadDTO fileUploadDTO = fileService.fileUpload(file, principal.getName());
return SuccessResponse.success(fileUploadDTO);
}
}
@RequestPart를 통해 Multipart를 받는것을 적용해주고 file이라는 키값으로 파일을 받습니다. 만약 이 이름이 file이 아니라 image라면 파일을 보낼때 키값을 image로 바꿔 보내주면 됩니다.
- FileService
@Service
@RequiredArgsConstructor
@Slf4j
public class FileService {
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
public FileUploadDTO fileUpload(MultipartFile file, String email) throws IOException {
File uploadFile = convert(file).orElseThrow(() -> new IllegalArgumentException("파일 업로드에 실패하였습니다."));
String dir = "static/images/".concat(email);
return upload(uploadFile, dir);
}
private FileUploadDTO upload(File uploadFile, String dir) {
String sourceName = uploadFile.getName();
String sourceExt = FilenameUtils.getExtension(sourceName).toLowerCase();
String fileName = dir + "/" + LocalDateTime.now().toString().concat(".").concat(sourceExt);
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile);
return FileUploadDTO.builder()
.url(uploadImageUrl)
.build();
}
private void removeNewFile(File targetFile) {
if (targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
} else {
log.info("파일이 삭제되지 못했습니다.");
}
}
private String putS3(File uploadFile, String fileName) {
try {
amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, uploadFile)
.withCannedAcl(CannedAccessControlList.PublicRead));
} catch (Exception e) {
log.error("이미지 s3 업로드 실패");
log.error(e.getMessage());
removeNewFile(uploadFile);
throw new RuntimeException();
}
return amazonS3Client.getUrl(bucket, fileName).toString();
}
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(Objects.requireNonNull(file.getOriginalFilename()));
if (convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
}
AWS S3에 이미지를 올릴때는 유저가 올린 이미지를 구분하기 위해 이메일로 경로를 만들어 하였습니다.
해당 코드의 자세한 내용은 https://jojoldu.tistory.com/300여기에 자세히 나와있습니다.
'스프링 부트' 카테고리의 다른 글
@Bean과 @Component의 차이점 (0) | 2021.05.13 |
---|---|
스프링부트 게시판 API 만들기 - 리팩토링 (if else 구문을 strategy 패턴으로 바꾸기) (0) | 2021.05.08 |
스프링부트 게시판 API 만들기 - 13 게시물 좋아요 기능 만들기 (1) | 2021.05.04 |
스프링부트 게시판 API 만들기 - 12 (게시물 검색기능 및 QueryDSL) - 2 (0) | 2021.05.03 |
스프링부트 게시판 API 만들기 - 11 (게시물 검색기능 및 QueryDSL) - 1 (0) | 2021.05.01 |