전에 쓴 코드를 좀만 바꾸자
우리는 이미지와 오디오파일을 함께 저장해야하니까
그것이 약속이니까
application-db.yml (이것도 .gitignore에 추가하기)
# MySQL 설정
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://DB_IP:DB_PORT/DB_NAME?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
username: DB_USERNAME
password: DB_PASSWORD
jpa:
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
application.yml
spring:
profiles.include:
- s3
- db
build.gradle의 dependencies 에 추가
runtimeOnly 'com.mysql:mysql-connector-j'
// 테스트 의존성 추가
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
// P6Spy 쿼리 파라미터 로그 외부라이브러리 사용
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'
domain/Test.java
package s3test.fileupload.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity(name="test")
public class Test {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int idx;
private String image;
private String audio;
}
repository/TestRepository.java
package s3test.fileupload.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import s3test.fileupload.domain.Test;
@Repository
public interface TestRepository extends JpaRepository<Test, Integer> {
}
service/TestService.java
package s3test.fileupload.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import s3test.fileupload.domain.Test;
import s3test.fileupload.repository.TestRepository;
@Service
public class TestService {
@Autowired
private TestRepository testRepository;
public void save(String[] imageFileNames, String[] audioFileNames) {
for (int i = 0; i < imageFileNames.length; i++) {
testRepository.save(Test.builder()
.image(imageFileNames[i])
.audio(audioFileNames[i])
.build());
}
}
}
FileController.java
package s3test.fileupload;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import lombok.RequiredArgsConstructor;
import s3test.fileupload.service.TestService;
@RequiredArgsConstructor
@RestController
public class FileController {
private final AwsS3Uploader awsS3Uploader;
private final TestService testService;
@PostMapping("/upload")
public List<String[]> upload(@RequestParam("image") MultipartFile[] imageMultipartFile,
@RequestParam("audio") MultipartFile[] audioMultipartFile) throws IOException {
List<String[]> result = new ArrayList<>();
String[] imageFileNames = awsS3Uploader.upload(imageMultipartFile, "image");
String[] audioFileNames = awsS3Uploader.upload(audioMultipartFile, "audio");
testService.save(imageFileNames, audioFileNames);
result.add(imageFileNames);
result.add(audioFileNames);
return result;
}
}
AwsS3Uploader.java
package s3test.fileupload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@RequiredArgsConstructor
@Component
public class AwsS3Uploader {
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
public String bucket;
public String[] upload(MultipartFile[] multipartFile, String dirName) throws IOException {
File[] uploadFiles = new File[multipartFile.length];
for (int i = 0 ; i < multipartFile.length ; i++) {
uploadFiles[i] = convert(multipartFile[i])
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File convert fail")); // 파일 생성
}
return upload(uploadFiles, dirName);
}
private String[] upload(File[] uploadFiles, String dirName) {
String[] uploadUrls = new String[uploadFiles.length];
for (int i = 0 ; i < uploadFiles.length ; i++) {
String fileName = dirName + "/" + UUID.randomUUID() + uploadFiles[i].getName();
uploadUrls[i] = putS3(uploadFiles[i], fileName); // s3로 업로드
removeNewFile(uploadFiles[i]);
}
return uploadUrls;
}
// 1. 로컬에 파일생성
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(file.getOriginalFilename());
if (convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
// 2. S3에 파일업로드
private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, uploadFile).withCannedAcl(
CannedAccessControlList.PublicRead));
log.info("File Upload : " + fileName);
return amazonS3Client.getUrl(bucket, fileName).toString();
}
// 3. 로컬에 생성된 파일삭제
private void removeNewFile(File targetFile) {
if (targetFile.delete()) {
log.info("File delete success");
return;
}
log.info("File delete fail");
}
public void delete(String fileName) {
log.info("File Delete : " + fileName);
amazonS3Client.deleteObject(bucket, fileName);
}
}
AwsS3Config.java
package s3test.fileupload;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
@Configuration
public class AwsS3Config {
@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;
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
}
이러고 서버 킨 다음에, Postman 테스트 해보면,
S3 들어가서 확인해보면,
DB에도 S3 경로가 잘 저장되었다
이제 이걸 EC2에 올려보자..