Skip to content

CSV ‐ Object 매핑

Minjae An edited this page Jul 10, 2023 · 4 revisions

CSV - Object 매핑

OpenCSV를 사용하여 CSV 파일의 데이터를 자바 객체에 매핑하는 방법은 다음과 같습니다:

  1. 먼저, CSV 파일과 매핑할 자바 객체를 정의해야 합니다. 객체의 필드는 CSV 파일의 각 열과 일치해야 합니다.

예를 들어, CSV 파일에 이름, 나이, 이메일이 있는 경우 다음과 같은 자바 클래스를 정의할 수 있습니다:

public class Person {
    private String name;
    private int age;
    private String email;

    // 생성자, getter, setter 등의 필요한 메서드
}
  1. CSV 파일을 읽고 객체에 매핑하는 코드를 작성합니다. 다음은 OpenCSV를 사용하여 CSV 파일을 읽고 객체에 매핑하는 예시입니다:
import com.opencsv.CSVReader;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;

import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CSVToObjectMappingExample {
    public static void main(String[] args) {
        String csvFile = "path/to/your/file.csv"; // 읽을 CSV 파일 경로

        try (CSVReader reader = new CSVReader(new FileReader(csvFile))) {
            CsvToBean<Person> csvToBean = new CsvToBeanBuilder<Person>(reader)
                    .withType(Person.class) // 매핑할 클래스 지정
                    .withIgnoreLeadingWhiteSpace(true) // 앞뒤 공백 무시
                    .build();

            List<Person> persons = csvToBean.parse(); // CSV 데이터를 객체로 매핑

            for (Person person : persons) {
                System.out.println(person.getName() + ", " + person.getAge() + ", " + person.getEmail());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 위의 코드에서 "path/to/your/file.csv" 부분에는 실제로 읽을 CSV 파일의 경로를 제공해야 합니다. CsvToBeanBuilder를 사용하여 CSV 파일을 읽고

CsvToBean 객체를 생성합니다. withType() 메서드를 사용하여 매핑할 클래스를 지정하고, build() 메서드를 호출하여 CsvToBean 객체를 생성합니다.

그런 다음 parse() 메서드를 호출하여 CSV 데이터를 자바 객체로 매핑합니다.

CSV 파일의 각 열은 자동으로 매핑되며, 필드 이름과 CSV 파일의 열 이름이 일치해야 합니다.

필드 이름이 CSV 열 이름과 다른 경우 @CsvBindByName 어노테이션을 사용하여 필드와 CSV 열을 매핑할 수도 있습니다.

OpenCSV는 매핑할 객체의 필드 유형에 맞춰 자동 변환을 수행하므로, 매핑할 객체의 필드 유형을 CSV 열의 데이터 유형과 일치시켜야 합니다.

필요에 따라 데이터 유형 변환을 수행하는 커스텀 컨버터를 작성하여 사용할 수도 있습니다.

이렇게 작성된 코드는 CSV 파일의 데이터를 자바 객체로 매핑하여 필요한 작업에 활용할 수 있습니다.

Field Converting

csv 파일의 필드 값들을 적절한 타입으로 변환할 필요가 있을 때는 OpenCsv에서 제공하는 AbstractBeanField를 이용할 수 있다.

다음과 같이 AbstractBeanField를 상속받아 Converter 클래스를 정의한다.

CocktailRecipeGlassConverter

package Alchole_free.Cockpybara.converter;

import Alchole_free.Cockpybara.domain.Glass;
import com.opencsv.bean.AbstractBeanField;
import com.opencsv.exceptions.CsvConstraintViolationException;
import com.opencsv.exceptions.CsvDataTypeMismatchException;

import java.util.Map;

public class CocktailRecipeGlassConverter extends AbstractBeanField {
    private final Map<String, Glass> namesAndValues=Glass.getNameAndValues();

    @Override
    protected Object convert(String value) throws CsvDataTypeMismatchException, CsvConstraintViolationException {
        return namesAndValues.get(value);
    }
}

Glass

Glass enum 클래스에는 name 필드를 규정하여 csv 파일내 필드명과 enum 값을 바로 매핑할 수 있게 구성하였다.

getNameAndValues() 메서드를 통하여 받은 Map 으로 Converter 내에서 값을 바로 enum 값으로 변환하여 제공한다.

package Alchole_free.Cockpybara.domain;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public enum Glass {
    CHAMPAGNE_FLUTE("Champagne flute"),
    MARGARITA_COUPETTE_GLASS("Margarita/Coupette glass"),
    MASON_JAR("Mason jar"),
    OLD_FASHIONED_GLASS("Old-fashioned glass"),
    PUNCH_BOWL("Punch Bowl"),
    POUSSE_CAFE_GLASS("Pousse cafe glass"),
    COCKTAIL_GLASS("Cocktail Glass"),
    BEER_GLASS("Beer Glass"),
    WHISKEY_SOUR_GLASS("Whiskey sour glass"),
    BRANDY_SNIFTER("Brandy snifter"),
    COFFEE_MUG("Coffee mug"),
    HIGHBALL_GLASS("Highball Glass"),
    MARGARITA_GLASS("Margarita glass"),
    SHOT_GLASS("Shot Glass"),
    COLLINS_GLASS("Collins Glass"),
    WHITE_WINE_GLASS("White wine glass"),
    MARTINI_GLASS("Martini Glass"),
    CORDIAL_GLASS("Cordial glass"),
    BEER_PILSNER("Beer pilsner"),
    PINT_GLASS("Pint glass"),
    COPPER_MUG("Copper Mug"),
    PARFAIT_GLASS("Parfait glass"),
    IRISH_COFFEE_CUP("Irish coffee cup"),
    HURRICANE_GLASS("Hurricane glass"),
    WINE_GLASS("Wine Glass"),
    JAR("Jar"),
    BEER_MUG("Beer mug"),
    PITCHER("Pitcher");

    private final String name;

    Glass(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

   public static Map<String, Glass> getNameAndValues(){
       Glass[] values = Glass.values();
       Map<String, Glass> namesAndValues=new HashMap<>();
       Arrays.stream(values).forEach(v->namesAndValues.put(v.getName(), v));
       return namesAndValues;
   }
}

CocktailRecipe

Converter 는 아래와 같이 @CsvCustomBindByName 어노테이션을 이용하여 사용할 수 있다.

package Alchole_free.Cockpybara.domain;


import Alchole_free.Cockpybara.converter.CocktailRecipeBooleanConverter;
import Alchole_free.Cockpybara.converter.CocktailRecipeCategoryConverter;
import Alchole_free.Cockpybara.converter.CocktailRecipeGlassConverter;
import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.CsvCustomBindByName;
import lombok.Data;

@Data
public class CocktailRecipe {
    @CsvBindByName(column = "strDrink")
    private String name;

    @CsvCustomBindByName(column = "isAlcoholic", converter = CocktailRecipeBooleanConverter.class)
    private String isAlcoholic;

    @CsvCustomBindByName(column = "strCategory", converter = CocktailRecipeCategoryConverter.class)
    private Category category;

    @CsvBindByName(column = "strDrinkThumb")
    private String drinkImgPath;

    @CsvCustomBindByName(column = "strGlass", converter = CocktailRecipeGlassConverter.class)
    private Glass glass;

    @CsvBindByName(column = "strInstructions")
    private String instruction;

    private boolean isMemberRecipe;
}