개요
이 글에서는 Java와 OpenCSV 라이브러리를 사용하여 간단한 웹 크롤러를 구현하고, 수집한 데이터를 CSV 파일로 저장하거나 CSV 파일에서 읽어오는 방법을 다룹니다.
OpenCSV 의존성 추가
먼저, 프로젝트에 OpenCSV 라이브러리를 추가합니다. build.gradle 파일에 다음 의존성을 추가하세요.
implementation 'com.opencsv:opencsv:5.9'
Java POJO 구현
다음은 CSV 파일의 데이터를 매핑할 Java POJO 클래스입니다.
import com.opencsv.bean.CsvBindByName;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Objects;
public class News {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.KOREA);
@CsvBindByName(column = "headline", required = true)
private final String headline;
@CsvBindByName(column = "url", required = true)
private final String url;
@CsvBindByName(column = "collected_at", required = true)
private final String collectedAt;
public News(String headline, String url, String collectedAt) {
this.headline = headline;
this.url = url;
this.collectedAt = collectedAt;
}
public String getHeadline() {
return headline;
}
public String getUrl() {
return url;
}
public String getCollectedAt() {
return collectedAt;
}
public boolean isRangeInTime() {
return LocalDateTime.parse(collectedAt, FORMATTER).getHour() == LocalTime.now().getHour();
}
public String toJsonFormat() {
return """
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*%s* \\n %s"
}
}""".formatted(headline, url);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof News news)) {
return false;
}
return Objects.equals(getHeadline(), news.getHeadline()) && Objects.equals(getUrl(), news.getUrl());
}
@Override
public int hashCode() {
return Objects.hash(getHeadline(), getUrl());
}
@Override
public String toString() {
return "News{" +
"headline='" + headline + '\'' +
", url='" + url + '\'' +
", collectedAt='" + collectedAt + '\'' +
'}';
}
}
- CSV 파일에 읽기 / 쓰기 작업에 사용될 객체입니다.
@CsvBindByName
: CSV 파일의 실제 컬럼 이름을 지정합니다.- column 속성 : 멤버 변수 이름과 실제 컬럼 이름이 다를 때, 컬럼의 이름을 작성한다.
- required 속성 : 필수 필드로 지정하여, 값이 없을 경우 예외가 발생합니다. (default = false)
CSV 읽기
다음은 CSV 파일을 읽어오는 메서드입니다.
public List<News> readNewsListFromCsv() throws IOException {
return new CsvToBeanBuilder<News>(new FileReader(new File(FILE_LOCATION, FILE_NAME)))
.withType(News.class)
.withMappingStrategy(MAPPING_STRATEGY)
.build()
.parse();
}
CsvToBeanBuilder
: CSV 파일을 Java 객체로 변환합니다.withType(T)
: 변환할 Java 클래스 타입을 지정합니다.withMappingStrategy()
: 매핑 전략을 지정해서 컬럼 헤더에 해당하는 값을 불러올 수 있다.
MappingStrategy
ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy<>();
strategy.setType(T);
strategy.setColumnMapping(COLUMN_NAMES);
setType(T)
: 매핑할 Java 클래스 타입을 지정합니다.setColumnMapping
: CSV 파일의 컬럼 순서를 지정합니다.- Java POJO 필드에
@CsvBindByName
로 바인딩을 했다면, Writer 에 중복해서 적용하지 않도록 주의해야합니다!
- Java POJO 필드에
CSV 쓰기
CSV 파일에 데이터를 저장하는 방법은 다음과 같습니다.
구성
/* 설정 */
// Writer (FileWriter)
Writer writer = Files.newBufferedWriter(Paths.get(new File(FILE_LOCATION, FILE_NAME).toURI()));
// BeanToCsv
StatefulBeanToCsv<News> beanToCsv = new StatefulBeanToCsvBuilder<News>(writer).build();
사용
/* 사용 */
try {
beanToCsv.write(newsList);
writer.close();
log.info("[File Manager] csv 파일 저장에 성공했습니다.");
} catch (CsvRequiredFieldEmptyException | CsvDataTypeMismatchException | IOException e) {
log.error("[File Manager] csv 파일 저장 중에 예외가 발생했습니다.", e);
throw new RuntimeException(e);
}
StatefulBeanToCsv
: Java 객체를 CSV 파일로 변환합니다.write(List<T>)
: Java 객체 리스트를 CSV 파일에 저장합니다try-with-resources
을 사용하면 Writer를 자동으로 닫을 수 있도록 사용합니다.
참고
- https://gksdudrb922.tistory.com/191
- https://www.tutorialspoint.com/mapping-java-beans-to-csv-using-opencsv
'Java' 카테고리의 다른 글
Java Memory Model(JMM)과 동시성 규칙 (2) | 2025.01.22 |
---|---|
JVM 아키텍처 정리 (0) | 2025.01.22 |
[Java] Optional에서 map과 flatMap의 차이점 쉽고 빠르게 이해하기 (0) | 2024.02.28 |