🌿SPRING/🌱연습[SPRING]

[SPRING] [AWS] 게시글 이미지 업로드 하기 (1) - S3 설정하기

디카페인라떼 2022. 9. 23. 00:18

이미지 업로드 부분을 계속 미뤄두다가 이젠 정말로 해야할 때가 왔다......
일단은 개인프로젝트에 먼저 해보고나서 팀과제에 차차 구현해보려고 하는데 

정말 어려웠다..........ㅠ


aws S3 설정하기

다른 블로그 글을 보면서 설정을 했는데 (나중에 대참사가 일어남)

대충 설정을 하면 안되었다... aws...권한 설정 ..

 

https://artiiicy.tistory.com/16

 

[AWS] S3 생성하기 + IAM 설정하기

AWS에서 제공하는 인터넷용 스토리지(strage) 서비스인 S3를 생성하고 IAM을 이용하여 리소스들을 안전하게 제어할 수 있도록 설정해보겠습니다. S3란? IAM이란? - S3 : (Simple Storage Service) 아마존에서

artiiicy.tistory.com

 

👉 S3에서 버킷을 생성하는 부분은 이 글을 참고해서 만들었다.(정책 생성은 안함)... +IAM 설정까지!

 

근데 여기에서 추가로 권한을 설정해 주어야 한다

 

S3 버킷 권한 확인 / 설정하기

 

 

👉 모든 퍼블릭 액세스 차단 을 해제하고 변경 사항 저장 !

 

 

 

👉 모든 사람 (퍼블릭 액세스) 의 객체와 객체 ACL 의 권한을 읽기(나열) /읽기를 모두 선택하고 저장해준다!!

 


Graddle build
//s3
implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.3.1'

 

properties 설정
#aws
cloud.aws.credentials.accessKey=${ACCESS_KEY}
cloud.aws.credentials.secretKey=${SECRET_KEY}
cloud.aws.s3.bucket=${BUCKET}
cloud.aws.region.static=ap-northeast-2
cloud.aws.stack.auto=false

👉 환경변수로 지정해 넣었다. 

# file upload max size (?? ??? ?? ??)
spring.servlet.multipart.max-file-size=20MB
spring.servlet.multipart.max-request-size=20MB

👉 추가로 파일 크기도 지정.

 


S3Config
@Configuration
public class S3Config {

  @Value("${cloud.aws.credentials.accessKey}")
  private String accessKey;

  @Value("${cloud.aws.credentials.secretKey}")
  private String secretKey;

  @Value("${cloud.aws.region.static}")
  private String region;

  @Autowired
  public AmazonS3 amazonS3() {
    AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
    return AmazonS3ClientBuilder.standard()
        .withRegion(region)
        .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
        .build();
  }
}

👉Config는 이대로만 설정해주면된다 !

🚨다만 @Autowired 부분이 원래는 @Bean 으로되어있었는데 자꾸 Bean 주입이 안되었다고 되어있어서 왜이럴까 ..했는데 @Autowired로 의존성을 주입해주니까 실행되었다!

   👉<에러로그>

Description:
Parameter 0 of constructor in ...S3Upload required a bean of type 'com.amazonaws.services.s3.AmazonS3Client' that could not be found.
Action:
Consider defining a bean of type 's3.AmazonS3Client' in your configuration.

 

S3Upload(Service)
@Slf4j
@RequiredArgsConstructor // final 멤버변수가 있으면 생성자 항목에 포함시킴
@Component
@Service
public class S3Upload {


  private final AmazonS3Client amazonS3Client;

  @Value("${cloud.aws.s3.bucket}")
  private String bucket;


  // MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
  public String uploadFiles(MultipartFile multipartFile, String dirName) throws IOException {
    File uploadFile = convert(multipartFile)
        .orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
    return upload(uploadFile, dirName);
  }

  private String upload(File uploadFile, String dirName) {
    String fileName = dirName + "/" + UUID.randomUUID() + "." + uploadFile.getName();
    String uploadImageUrl = putS3(uploadFile, fileName);

    removeNewFile(uploadFile);  // 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)

    return uploadImageUrl;      // 업로드된 파일의 S3 URL 주소 반환
  }

//S3 버킷에 이미지 업로드
  private String putS3(File uploadFile, String fileName) {
    amazonS3Client.putObject(
        new PutObjectRequest(bucket, fileName, uploadFile)
            .withCannedAcl(CannedAccessControlList.PublicRead)  // PublicRead 권한으로 업로드 됨
    );
    return amazonS3Client.getUrl(bucket, fileName).toString();
  }

  //로컬에 있는 이미지 삭제
  private void removeNewFile(File targetFile) {
    if (targetFile.delete()) {
      log.info("파일이 삭제되었습니다.");
    } else {
      log.info("파일이 삭제되지 못했습니다.");
    }
  }

  //변환
  private Optional<File> convert(MultipartFile file) throws IOException {
    //변환시 파일명에 또다른 독립성을 주기 위해 날짜+시간도 추가로 넣어줌
    String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
    File convertFile = new File(System.getProperty("user.dir") + "/" + now + ".jpg"); // 파일 변환

    if (convertFile.createNewFile()) {
      try (FileOutputStream fos = new FileOutputStream(convertFile)) {
        fos.write(file.getBytes());
      }
      return Optional.of(convertFile);
    }
    return Optional.empty();
  }
  }

👉 이부분만 있으면 업로드는 🙆‍♂️

 


S3 Controller
  • 실제로 S3에 파일이 잘 업로드 되는 지 확인하는 controller를 만들어서 확인해 본다.
@RequiredArgsConstructor
@RestController
public class S3Controller {

  private final S3Upload s3Upload;

  @PostMapping("/api/auth/image")
  public ResponseDto imageUpload(@RequestPart(required = false) MultipartFile multipartFile) {

    if (multipartFile.isEmpty()) {
      return new ResponseDto("파일이 유효하지 않습니다.");
    }
    try {
      return new ResponseDto(s3Upload.uploadFiles(multipartFile, "static"));
    } catch (Exception e) {
      e.printStackTrace();
      return new ResponseDto("파일이 유효하지 않습니다.");
    }
  }
}

👉 여기서 post를 날려주고 S3 버킷에서 파일이 들어온게 확인된다면 잘 설정한것!

 


Postman

👉 에러 없이 응답값이 잘들어왔고

 

👉S3에도 잘 들어왔다!!!!