안녕하세요 이번시간에는 이미지 업로드를 만들어 보도록 하겠습니다.

전체 코드는 여기 에서 볼 수 있습니다.

 

sug5806/board-project-rest

Contribute to sug5806/board-project-rest development by creating an account on GitHub.

github.com

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여기에 자세히 나와있습니다.

 

+ Recent posts