스프링부트를 사용하여 AWS S3 버킷 연동하여 파일 업로드 하기

 

IAM사용자 키 엑세스키 생성에 이어서 스프링 부트에서 S3에 파일을 업로드할 수 있도록 구현하였다.

또한 업로드된 파일의 이름과 주소를 DB에 저장한다.

 

1. 먼저 dependencies에 의존성을 추가한다

implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

 

 

2. application.yml 설정

spring:
  jackson:
    property-naming-strategy: SNAKE_CASE
  datasource:
    url: jdbc:mysql://localhost:3306/community?serverTimezone=Asia/Seoul
    username: root
    password: password
  redis:
    host: localhost
    port: 6379
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
    properties:
      hibernate:
        format_sql: true
  data: # spring data rest - 관련 설정
    rest:
      base-path: /api  #endpoint start path
      detection-strategy: annotated
  profiles:
    include: API-KEY   #key가 저장된 yml 연동


cloud: # AWS 계정연동 관련설정
  aws:
    region:
      static: ap-northeast-2
#    s3:
#      credentials:
#        access-key: access-key
#        secret-key: secret-key
    stack:
      auto: false

핵심은 spring.profies: 부터의 설정들이다

 

- spring.profiles.include : 깃에 올리지 않을 엑세스키와 시크릿키가 담긴 application-API-KEY.yml파일을 연결했다. 

환경변수를 통해 키를 관리해준다면 주석처리된 부분을 해제하여 환경변수를 통해 엑세스키와 시크릿키를 할당하면 된다.

 

- cloud설정에서 aws관련 내용들을 적어준다

 

- 마지막줄 stack.auto: false는 관련 내용을 사용하지 않음으로 반드시 적어준다.

 

 

3.  .gitignore 설정 (옵션)

### api key 관련 ###
/src/main/resources/application-API-KEY.yml

이렇게 추가해주면 키가담긴 yml파일이 깃에 올라가지 않는다.

 

 

4. 터미널에 git -rm -r -cached /src/main/resources/application-API-KEY.yml 입력

- 해당 명령어를 입력하면 기존 추적되던 캐시를 삭제한다.

 

 

5. Entity

@NoArgsConstructor
@Setter @Getter
@Entity
public class UploadFile{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long fileId;
    private String fileName;
    private String imagePath;
    @ManyToOne
    @JoinColumn(name = "board_id")
    private Board board;

    public UploadFile(String fileName, String imagePath) {
        this.fileName = fileName;
        this.imagePath = imagePath;
    }
}

- 추후 Board엔티티와 매핑을 위해 조인컬럼을 사용하였다.

 

 

6. service

@RequiredArgsConstructor
@Service
public class S3Service {

    private String S3Bucket = "kjs-project-upload"; // Bucket 이름
    private final AmazonS3Client amazonS3Client;
    private final UploadFileRepository uploadFileRepository;

    public List<String> uploadFiles(MultipartFile[] multipartFileList) throws Exception {
        List<String> imagePathList = new ArrayList<>();

        for (MultipartFile multipartFile : multipartFileList) {
            String fileName = multipartFile.getOriginalFilename(); // 파일 이름
            long size = multipartFile.getSize(); // 파일 크기

            ObjectMetadata objectMetaData = new ObjectMetadata();
            objectMetaData.setContentType(multipartFile.getContentType());
            objectMetaData.setContentLength(size);

            // S3에 업로드
            amazonS3Client.putObject(
                    new PutObjectRequest(S3Bucket, fileName, multipartFile.getInputStream(), objectMetaData)
                            .withCannedAcl(CannedAccessControlList.PublicRead)
            );

            String imagePath = amazonS3Client.getUrl(S3Bucket, fileName).toString(); // 접근가능한 URL 가져오기
            imagePathList.add(imagePath); //String Type URL주소

            //엔티티에 저장하는 로직

            UploadFile uploadFile = new UploadFile();
            uploadFile.setFileName(fileName);
            uploadFile.setImagePath(imagePath);
            uploadFileRepository.save(uploadFile);
        }
        return imagePathList;
    }
}

 

 

 

7. Repository

public interface UploadFileRepository extends JpaRepository<UploadFile, Long> {}

- @Repository 는 상속받는 JPARpository에 포함되어있기 때문에 적지 않아도 된다.

 

 

8. Contorller

@RestController
@RequiredArgsConstructor
public class BoardController {
    private final S3Service s3Service;

    @PostMapping("/upload")
    public ResponseEntity<Object> upload(@RequestParam MultipartFile[] files) throws Exception {
        List<String> imagePathList = s3Service.uploadFiles(files);

        return new ResponseEntity<>(imagePathList, HttpStatus.OK);
    }

 

 

9. Postman 테스트

- body에 기존 Json형식으로 데이터를 넣는것이 아닌 form-data형식으로 데이터를 넣어줘야한다.

 

 

결과값으로 사진파일을 확인할 수 있는 S3주소를 리턴한다.

 

또한 연결된 DB를 확인해보면 해당 파일명과 S3버킷 안에있는 파일URL이 저장된 것을 확인할 수 있다.

 

 

참고 : https://jforj.tistory.com/261

+ Recent posts