프로젝트 중 AWS S3에서 특정 버킷의 파일을 읽어 DB에 저장해야 하는 상황이 생겨 기록을 한다.
build.gradle - 의존성 추가
dependencies {
...
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
...
}
spring boot와 aws를 연동시키기 위해 build.gradle에 spring-cloud-starter-aws를 추가한다.
application.yml - aws 자격 정보 입력
cloud:
aws:
credentials:
instance-profile: false
access-key: {IAM MY_ACCESS_KEY 입력}
secret-key: {IAM MY_SECERT_KEY 입력}
region:
auto: false
static: ap-northeast-2
stack:
auto: false
logging:
level:
com:
amazonaws:
util:
EC2MetadataUtils: error
aws:
s3:
bucket: {버킷 이름}
aws 계정에 해당하는 access-key, secret-key를 입력하고
접근을 원하는 버킷을 입력한다.
AWS 계정 연결
@Configuration
public class S3Config {
@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
@Primary
public BasicAWSCredentials awsCredentialsProvider(){
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(accessKey, secretKey);
return basicAWSCredentials;
}
@Bean
public AmazonS3 amazonS3() {
AmazonS3 s3Builder = AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentialsProvider()))
.build();
return s3Builder;
}
}
Amazon IAM계정과 연결하기 위한 Config클래스를 생성한다.
S3 버킷에 있는 파일 읽기
<Controller>
@Controller
@RequiredArgsConstructor
public class S3Controller {
private final S3Service s3Service;
@PostMapping("/csv_read")
public ResponseEntity<String> read(@PathVariable String fileName) throws IOException {
s3Service.readObject("food.csv");
return new ResponseEntity<>("success", HttpStatus.OK);
}
}
readObject(): 인자("food.csv")을 이름으로 갖는 파일을 읽어서 DB에 저장하는 메서드
만약 해당 파일이 버킷에 없으면 에러가 발생한다.
<food.csv 예시>
1,계란
2,라면
3,시금치
...
<Food>
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Food {
@Id
@Column(name = "food_id")
private String id;
//==생성자==//
public Food(String id, String name) {
this.id = id;
this.name = name;
}
}
food.csv의 데이터를 Food 엔티티 저장해 DB에 저장하는 것이 목적이다.
<Service>
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class S3Service {
private final AmazonS3 amazonS3;
private final EntityManager em;
@Value("${aws.s3.bucket}")
private String bucket;
/**
* S3 bucket 파일 읽어 DB에 저장
*/
@Transactional
public void readObject(String storedFileName) throws IOException {
S3Object o = amazonS3.getObject(new GetObjectRequest(bucket, storedFileName));
S3ObjectInputStream ois = null;
BufferedReader br = null;
// Read the CSV one line at a time and process it.
try {
ois = o.getObjectContent();
System.out.println ("ois = " + ois);
br = new BufferedReader (new InputStreamReader(ois, "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
// Store 1 record in an array separated by commas
String[] data = line.split(",", 0);
Food food = new Food(data[0], data[1]);
em.persist(food);
}
} finally {
if(ois != null){
ois.close();
}
if(br != null){
br.close();
}
}
}
}
컨트롤러에서 호출한 readObject()메서드가 있는 서비스 계층
부분적으로 간단히 살펴보자.
S3Object o = amazonS3.getObject(new GetObjectRequest(bucket, storedFileName));
aws s3의 버킷과 파일 이름(bucket, storedFileName)을 전달하고 매칭이 되면 S3Object를 반환한다.
br = new BufferedReader (new InputStreamReader(ois, "UTF-8"));
BufferedReader를 통해 csv파일을 한 줄 씩 읽는다.
String line;
while ((line = br.readLine()) != null) {
// Store 1 record in an array separated by commas
String[] data = line.split(",", 0);
Food food = new Food(data[0], data[1]);
em.persist(food);
}
1. 한 줄 씩 불러와 ","를 기준으로 문자열을 split 한뒤
2. Food 생성자 형식에 맞게 엔티티를 생성하고
3. 엔티티를 DB에 저장한다.
'java > spring' 카테고리의 다른 글
[Spring] Spring Jdbc - batchUpdate()를 사용한 bulk Insert 최적화 (0) | 2021.08.06 |
---|---|
[Spring] SpringBatch를 사용해 csv 파일 읽어 DB에 저장 (4) | 2021.08.06 |
[Spring] AWS S3에서 Spring Boot로 파일 다운로드 (0) | 2021.08.05 |
[Spring] Jasypt를 이용한 암호화 (2) | 2021.07.21 |
[Spring] 스프링 부트, 라이브러리 버전 맞추기 (0) | 2021.05.23 |