[Spring Boot] AWS S3 적용하기

unhak·2022년 10월 20일

Spring Boot

목록 보기
1/3
post-thumbnail

S3란?

AWS가 제공하는 Simple Storage Service(S3)로 업계 최고의 확장성, 데이터 가용성, 보안 및 성능을 제공하는 객체 스토리지 서비스입니다.


S3 초기 설정

pom.xml 의존성 추가

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-aws</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

application.properties 추가

버킷 및 자격정보 입력

cloud.aws.credentials.access-key=S3 ACCESS-KEY
cloud.aws.credentials.secret-key=S3 SECRET-KEY
cloud.aws.region.static=ap-northeast-2 (S3 버킷 지역)
cloud.aws.s3.domain=S3 도메인 주소
cloud.aws.s3.bucket=S3 버킷 이름
cloud.aws.stack.auto=false

S3 설정 클래스 생성

Spring Boot S3 설정 정보 연결

S3Utils.java

@Service
public class S3Utils {

	private AmazonS3 amazonS3;

	@Value("${cloud.aws.credentials.access-key}")
	private String accesskey;

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

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

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

	// AWS S3 자격 증명 지정
	@PostConstruct
	public void setAmazonS3() {
		AWSCredentials awsCredentials = new BasicAWSCredentials(accesskey, secretKey);

		amazonS3 = AmazonS3ClientBuilder.standard()
				.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
				.withRegion(region)
				.build();
	}
}

S3 파일 업로드

S3Utils.java 클래스에 폴더 생성, 파일 업로드, 파일 삭제 기능 추가

// 폴더 생성
public void createFolder(String bucketName, String folderName) {
	amazonS3.putObject(bucketName, folderName + "/", new ByteArrayInputStream(new byte[0]), new ObjectMetadata());
}

// 다중 파일 업로드
public void fileUpload(List<MultipartFile> files, List<String> fileList) throws Exception {
	if(amazonS3 != null) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		Date date = new Date();
		String today = sdf.format(date);

		if(!files.isEmpty()) {
			createFolder(bucket + "/contact", today);
		}

		ObjectMetadata objectMetadata = new ObjectMetadata();
		for(int i=0; i<files.size(); i++) {
			objectMetadata.setContentType(files.get(i).getContentType());
			objectMetadata.setContentLength(files.get(i).getSize());
			objectMetadata.setHeader("filename", files.get(i).getOriginalFilename());
			amazonS3.putObject(new PutObjectRequest(bucket + "/contact/" + today, fileList.get(i), files.get(i).getInputStream(), objectMetadata));
		}
	} else {
		throw new AppException(ErrorType.aws_credentials_fail, null);
	}
}

// 다중 파일 삭제
public void fileDelete(String filePath, String fileName) {
	if(amazonS3 != null) {
		amazonS3.deleteObject(new DeleteObjectRequest(filePath, fileName));
	} else {
		throw new AppException(ErrorType.aws_credentials_fail, null);
	}
}

S3 구현

S3 Service

실제 DB에 경로를 저장함과 동시에 S3에 파일 업로드까지 하는 로직 구현

public int fileUpload(String auth, List<MultipartFile> files, String contactType, String contactTitle, String contactTxt) throws Exception {
    // 현재 날짜로 폴더 생성
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
	Date date = new Date();
	String today = sdf.format(date);
    String userId = jwtTokenUtil.getUserIdFromToken(auth); // 토큰을 이용해 사용자 ID 찾기
	List<String> fileList = Lists.newArrayList();
	FileModel fileModel = new FileModel();

    // AWS S3에 업로드 될 파일의 URL을 DB에 넣기 위해 URL 경로 생성
    List<String> urlList = Lists.newArrayList();

    if(files != null && files.size() > 0){
		for (MultipartFile file : files) {
			String fileRandomName = HashUtils.generateRandomKey(16);
			String fileOriginName = file.getOriginalFilename();
			String fileExtension = fileOriginName.substring(fileOriginName.lastIndexOf("."));
			String fileFullName = fileRandomName + "_" + userId + fileExtension;
			String fileFullPath = "/contact/" + today + "/" + fileFullName;
			urlList.add(fileFullPath);
		}

		// AWS S3 파일 업로드를 위해 DB에 들어갈 URL 경로에서 파일명만 추출
		if(urlList.size() > 0){
			for(int i = 0; i<urlList.size(); i++){
				fileList.add(urlList.get(i).substring(urlList.get(i).lastIndexOf("/")+1));
				if(i == 0){
					fileModel.setContact_pic_url_1(urlList.get(i));
				} else if(i == 1){
					fileModel.setContact_pic_url_2(urlList.get(i));
				}
			}
		}
	}

	fileModel.setContact_type(contactType);
	fileModel.setContact_title(contactTitle);
	fileModel.setContact_txt(contactTxt);
	fileModel.setContact_answer_status(0);
	fileModel.setUser_id(userId);

	int result = fileDao.fileUpload(fileModel);
	// AWS S3에 파일 업로드 하기 위해 파일 목록과 사용자 ID를 넘겨주면서 S3Utils의 fileUpload 호출
	if(fileList.size() > 0){
		s3Utils.fileUpload(files, fileList);
	}
    return result;
}

AWS S3에 업로드된 파일의 삭제는 경로, 폴더 날짜, 사진명을 기준으로 처리

s3Utils.fileDelete(bucket + "/contact/" + folderDt, picName);

S3 Controller

MultipartFile을 List 형태로 받아 다중 파일 업로드가 가능하도록 구현

@RequestMapping(value="/fileUpload", method=RequestMethod.POST)
public BaseModel fileUpload(@RequestHeader("Authorization") String auth,
							@RequestParam("files") List<MultipartFile> files,
							@RequestParam("contact_type") String contactType,
							@RequestParam("contact_title") String contactTitle,
							@RequestParam("contact_txt") String contactTxt) throws Exception {
                            
	BodyModel body = new BodyModel();
	body.setBody(fileService.fileUpload(auth, files, contactType, contactTitle, contactTxt));

	return ok(body);
}

참고 자료

profile
slowly but steadily🐢

0개의 댓글