OpenCSV: How to create CSV file from POJO with custom column headers and custom column positions?

后端 未结 19 1463
温柔的废话
温柔的废话 2020-12-08 04:14

I have created a MappingsBean class where all the columns of the CSV file are specified. Next I parse XML files and create a list of mappingbeans. Then I write that data int

19条回答
  •  春和景丽
    2020-12-08 04:59

    I wanted to achieve bi-directional import/export - to be able to import generated CSV back to POJO and visa versa.

    I was not able to use @CsvBindByPosition for this, because in this case - ColumnPositionMappingStrategy was selected automatically. Per documents: this strategy requires that the file does NOT have a header.

    What I've used to achieve the goal:

    HeaderColumnNameMappingStrategy
    mappingStrategy.setColumnOrderOnWrite(Comparator writeOrder)
    

    CsvUtils to read/write csv

    import com.opencsv.CSVWriter;
    import com.opencsv.bean.*;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.*;
    import java.util.List;
    
    public class CsvUtils {
        private CsvUtils() {
        }
    
        public static  String convertToCsv(List entitiesList, MappingStrategy mappingStrategy) throws Exception {
            try (Writer writer = new StringWriter()) {
                StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer)
                        .withMappingStrategy(mappingStrategy)
                        .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                        .build();
                beanToCsv.write(entitiesList);
                return writer.toString();
            }
        }
    
        @SuppressWarnings("unchecked")
        public static  List convertFromCsv(MultipartFile file, Class clazz) throws IOException {
            try (Reader reader = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
                CsvToBean csvToBean = new CsvToBeanBuilder(reader).withType(clazz).build();
                return csvToBean.parse();
            }
        }
    }
    

    POJO for import/export

    public class LocalBusinessTrainingPairDTO {
        //this is used for CSV columns ordering on exporting LocalBusinessTrainingPairs
        public static final String[] FIELDS_ORDER = {"leftId", "leftName", "rightId", "rightName"};
    
        @CsvBindByName(column = "leftId")
        private int leftId;
    
        @CsvBindByName(column = "leftName")
        private String leftName;
    
        @CsvBindByName(column = "rightId")
        private int rightId;
    
        @CsvBindByName(column = "rightName")
        private String rightName;
        // getters/setters omitted, do not forget to add them
    }
    

    Custom comparator for predefined String ordering:

    public class OrderedComparatorIgnoringCase implements Comparator {
        private List predefinedOrder;
    
        public OrderedComparatorIgnoringCase(String[] predefinedOrder) {
            this.predefinedOrder = new ArrayList<>();
            for (String item : predefinedOrder) {
                this.predefinedOrder.add(item.toLowerCase());
            }
        }
    
        @Override
        public int compare(String o1, String o2) {
            return predefinedOrder.indexOf(o1.toLowerCase()) - predefinedOrder.indexOf(o2.toLowerCase());
        }
    }
    

    Ordered writing for POJO (answer to initial question)

    public static void main(String[] args) throws Exception {
         List localBusinessTrainingPairsDTO = new ArrayList<>();
         LocalBusinessTrainingPairDTO localBusinessTrainingPairDTO = new LocalBusinessTrainingPairDTO();
         localBusinessTrainingPairDTO.setLeftId(1);
         localBusinessTrainingPairDTO.setLeftName("leftName");
         localBusinessTrainingPairDTO.setRightId(2);
         localBusinessTrainingPairDTO.setRightName("rightName");
    
         localBusinessTrainingPairsDTO.add(localBusinessTrainingPairDTO);
    
         //Creating HeaderColumnNameMappingStrategy
         HeaderColumnNameMappingStrategy mappingStrategy = new HeaderColumnNameMappingStrategy<>();
         mappingStrategy.setType(LocalBusinessTrainingPairDTO.class);
         //Setting predefined order using String comparator
         mappingStrategy.setColumnOrderOnWrite(new OrderedComparatorIgnoringCase(LocalBusinessTrainingPairDTO.FIELDS_ORDER));
         String csv = convertToCsv(localBusinessTrainingPairsDTO, mappingStrategy);
         System.out.println(csv);
    }
    

    Read exported CSV back to POJO (addition to original answer)

    Important: CSV can be unordered, as we are still using binding by name:

    public static void main(String[] args) throws Exception {
        //omitted code from writing
        String csv = convertToCsv(localBusinessTrainingPairsDTO, mappingStrategy);
    
        //Exported CSV should be compatible for further import
        File temp = File.createTempFile("tempTrainingPairs", ".csv");
        temp.deleteOnExit();
        BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
        bw.write(csv);
        bw.close();
        MultipartFile multipartFile = new MockMultipartFile("tempTrainingPairs.csv", new FileInputStream(temp));
    
        List localBusinessTrainingPairDTOList = convertFromCsv(multipartFile, LocalBusinessTrainingPairDTO.class);
    }
    

    To conclude:

    1. We can read CSV to POJO, regardless of column order - because we are using @CsvBindByName
    2. We can control columns order on write using custom comparator

提交回复
热议问题