[Spring] AWS S3 연동해 파일 업로드하기 (2 - 연동, 사진 업로드하기)

yuz·2023년 5월 17일
0

spring

목록 보기
2/3
post-thumbnail

의존성 추가

  • 프로젝트에 아래 의존성을 추가 (스프링 부트는 Spring Cloud AWS 추가)
    <!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
    <dependency>
    	<groupId>com.amazonaws</groupId>
    	<artifactId>aws-java-sdk-s3</artifactId>
    	<version>1.12.389</version>
    </dependency>

설정 및 연동

  • 연동에 필요한 정보들을 properties 파일에 작성
    리전은 생성된 버킷 페이지에서 확인할 수 있는데, 한국이면 보통 ap-northeast-2입니다 참고

    cloud.aws.credentials.accessKey=액세스 키
    cloud.aws.credentials.secretKey=시크릿 키
    cloud.aws.stack.auto=false
    
    cloud.aws.s3.bucket=버킷명
    cloud.aws.region=리전
    
    cloud.aws.s3.bucket.url=https://s3.리전.amazonaws.com/버킷명
  • 설정파일 작성

    @Configuration 
    @EnableWebMvc
    @PropertySource("classpath:props/fileUpload.properties")
    public class AWSConfiguration implements WebMvcConfigurer{
     	@Value("${cloud.aws.credentials.accessKey}")
    	private String accessKey;
    	
    	@Value("${cloud.aws.credentials.secretKey}")
    	private String secretKey;
    	
    	@Value("${cloud.aws.region}")
    	private String region;
    	
    	@Bean
    	public AmazonS3Client awsS3Client() {
    		BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
    		AmazonS3Client s3Builder = (AmazonS3Client)AmazonS3ClientBuilder.standard()
    									.withRegion(region)
    									.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
    									.build();
    		 
    		return s3Builder;
    	}
    }

    코드의 흐름은 다음과 같습니다

    1. @PropertySource 어노테이션으로 작성한 properties파일의 값을 가져옵니다
      액세스 키, 시크릿 키와 같은 중요 정보들을 환경변수로 다루기 위함입니다

      .withRegion(Regions.AP_NORTHEAST_2)

      region은 프로퍼티 파일에 입력하지 않고 위 형태처럼 Regions의 enum을 통해 값을 입력할 수도 있습니다 참고

    2. AWSCredentials의 구현체인 BasicAWSCredentials 클래스를 생성합니다
      생성자에 액세스 키, 시크릿 키를 전달합니다
      AWSCredentials 인터페이스는 액세스 키, 시크릿 키에 대한 액세스를 제공하는 역할을 합니다 (자격 증명 공급자)

    3. S3 서비스에 액세스하기 위한 AmazonS3Client 클래스를 AmazonS3ClientBuilder를 통해 구현합니다
      아마존에서는 AmazonS3Client클래스에 생성자를 사용하는 것보다 AmazonS3ClientBuilder를 사용하는 것을 권장하고 있습니다

      • standard()로 모든 기본값이 설정된 builder 인스턴스 생성
      • withRegion() 메소드의 매개변수로 리전 전달
      • withCredentials() 메소드의 매개변수로 AWSStaticCredentialsProvider 객체를 전달 (BasicAWSCredentials를 매개변수로 직접 사용하지 않고, AWSStaticCredentialsProvider 객체의 생성자에 전달해 BasicAWSCredentials를 래핑하기 위함)
      • build()로 S3 클라이언트 빌드


    4. 마지막으로 @Bean 어노테이션을 사용해 반환된 AmazonS3Client 객체를 빈으로 등록합니다


서비스 클래스 구현

@Service
@PropertySource("classpath:props/fileUpload.properties")
public class ProductFileService {
	private static final Logger logger = LoggerFactory.getLogger(ProductController.class);
	
	@Autowired
	private AmazonS3 s3Client;
	
	@Value("${cloud.aws.s3.bucket}")
	private String bucket;
	
	
	public String getPath() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");
		return sdf.format(new Date());
	}
	
	public String getUUID() {
		return UUID.randomUUID().toString(); 
	}
	
	public boolean delete(List<String> keyList) throws Exception{
		int rowCnt = 0;
		
		for(String key : keyList) {
			DeleteObjectRequest deleteObjectRequest = new DeleteObjectRequest(this.bucket, key);
			this.s3Client.deleteObject(deleteObjectRequest);
			logger.info("delete complete! {}", deleteObjectRequest.getKey());
			rowCnt++;
		}
		return rowCnt == keyList.size() ? true : false;
	}
	
	public List<ProductFileDto> upload(List<MultipartFile> file, String product_no) throws Exception{
		List<ProductFileDto> list = new ArrayList<>();
		int idx = 0;
        
		for(MultipartFile multipartFile : file) {				
			byte[] bytes = IOUtils.toByteArray(multipartFile.getInputStream());
			
			String originalName = multipartFile.getOriginalFilename();
			String uuid = getUUID();
			
			ObjectMetadata objectMetadata = new ObjectMetadata();
			objectMetadata.setContentLength(bytes.length);
			objectMetadata.setContentType(multipartFile.getContentType());
						
			// 요청 바디 작성
			PutObjectRequest putObjectRequest = new PutObjectRequest(this.bucket, getPath()+uuid, multipartFile.getInputStream(), objectMetadata)
					.withCannedAcl(CannedAccessControlList.PublicRead);
			
			// 업로드 요청
			this.s3Client.putObject(putObjectRequest);
			logger.info("upload complete! {}", putObjectRequest.getKey());
			
            // DB에 파일 정보 저장 (저장 경로, 파일명, 저장 순서 등)
			ProductFileDto productFileDto = new ProductFileDto(product_no, putObjectRequest.getKey(), originalName, uuid, idx);
			list.add(productFileDto);
			
			idx++;
		}
		return list;
	}	
}
  1. 업로드
  • 업로드할 파일의 정보를 바이트 배열로 얻습니다
  • ObjectMetadata 객체를 생성합니다. ObjectMetadata는 객체의 메타데이터 정보를 나타냅니다
    • setContentLength()로 파일의 바이트 배열 길이를 전달
    • setContentType()으로 파일 객체의 contentType을 전달
  • PutObjectRequest 객체를 생성, 요청 바디를 작성합니다
    • 매개변수에 순서대로 bucket명, 업로드할 파일의 경로+파일명, InputStream, ObjectMetadata를 전달
    • withCannedAcl() 메소드의 매개변수로 액세스 제어 정책을 전달합니다
  • 마지막으로 AmazonS3putObject() 메소드에 요청 바디를 전달, 호출하면 업로드 요청이 완료됩니다

  1. 삭제
  • DeleteObjectRequest 객체의 생성자에 bucket명, 삭제하고자 할 파일의 경로를 포함한 파일명을 전달해 객체를 생성합니다
  • AmazonS3deleteObject() 메소드에 요청 바디를 전달, 호출하면 삭제 요청이 완료됩니다

0개의 댓글