前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、工具类

1.1、CsvReaderUtils

package com.healerjean.proj.utils.excel.csv;

import com.opencsv.ICSVParser;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.List;

@Slf4j
public class CsvReaderUtils {

    /**
     * 构造函数
     */
    private CsvReaderUtils() {

    }

    /**
     * 获取实例
     *
     * @return 实例
     */
    public static CsvReaderUtils getInstance() {
        return new CsvReaderUtils();
    }

    /**
     * 读取CSV
     *
     * @param file 文件
     * @param type Class<E>
     * @param <E>  E
     * @return List<E>
     */
    public <E> List<E> readerCsv(File file, Class<E> type) throws FileNotFoundException {
        return readerCsv(file, 1, ICSVParser.DEFAULT_SEPARATOR, type);
    }

    /**
     * 读取CSV
     *
     * @param file      文件
     * @param separator 分隔符
     * @param type      Class<E>
     * @param <E>       E
     * @return List<E>
     */
    public <E> List<E> readerCsv(File file, char separator, Class<E> type) throws FileNotFoundException {
        return readerCsv(file, 1, separator, type);
    }

    /**
     * 读取CSV
     *
     * @param file      文件
     * @param skipLines 跳过前几行读取,默认第一行
     * @param separator 分隔符
     * @param type      Class<E>
     * @param <E>       E
     * @return List<E>
     */
    public <E> List<E> readerCsv(File file, int skipLines, char separator, Class<E> type) throws FileNotFoundException {
        ColumnPositionMappingStrategy<E> mappingStrategy = new ColumnPositionMappingStrategy<>();
        mappingStrategy.setType(type);
        CsvToBean<E> build = new CsvToBeanBuilder<E>(new FileReader(file))
                .withSkipLines(skipLines)
                .withMappingStrategy(mappingStrategy)
                .withSeparator(separator).build();
        return build.parse();
    }

    /**
     * 读取CSV
     *
     * @param inputStream 文件
     * @param type Class<E>
     * @param <E>  E
     * @return List<E>
     */
    public <E> List<E> readerCsvInputStream(InputStream inputStream, Class<E> type){
        return readerCsvInputStream(inputStream, 1, ICSVParser.DEFAULT_SEPARATOR, type);
    }

    /**
     * 读取CSV
     *
     * @param inputStream      文件
     * @param skipLines 跳过前几行读取,默认第一行
     * @param separator 分隔符
     * @param type      Class<E>
     * @param <E>       E
     * @return List<E>
     */
    public <E> List<E> readerCsvInputStream(InputStream inputStream, int skipLines, char separator, Class<E> type){
        ColumnPositionMappingStrategy<E> mappingStrategy = new ColumnPositionMappingStrategy<>();
        mappingStrategy.setType(type);
        CsvToBean<E> build = new CsvToBeanBuilder<E>(new InputStreamReader(inputStream))
                .withSkipLines(skipLines)
                .withMappingStrategy(mappingStrategy)
                .withSeparator(separator).build();
        return build.parse();
    }

}

1.2、CsvWriterUtils

package com.healerjean.proj.utils.excel.csv;

import com.opencsv.CSVWriter;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.List;

@Slf4j
public final class CsvWriterUtils {
    /**
     * CSV文件后缀
     */
    private static final String CSV_FILE_SUFFIX = ".csv";
    /**
     * 列顺序
     */
    public final String[] columnMapping;
    /**
     * 表头顺序
     */
    public final String[] headerMapping;

    /**
     * 构造函数
     *
     * @param columnMapping 列顺序
     * @param headerMapping 表头顺序
     */
    private CsvWriterUtils(String[] columnMapping, String[] headerMapping) {
        this.columnMapping = columnMapping;
        this.headerMapping = headerMapping;
    }

    /**
     * 获取实例
     *
     * @param columnMapping 列顺序
     * @param headerMapping 表头顺序
     * @return 实例
     */
    public static CsvWriterUtils getInstance(String[] columnMapping, String[] headerMapping) {
        return new CsvWriterUtils(columnMapping, headerMapping);
    }

    /**
     * 写入CSV
     *
     * @param dataList 数据列表
     * @param fileName 文件名称
     * @param filePath 文件路径
     * @return 生成后的路径
     */
    public <E> String writeCsv(List<E> dataList, String fileName, String filePath, Class<E> type) {
        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        // 服务器绝对路径
        File localDir = new File(filePath);
        if (!localDir.exists()) {
            boolean result = localDir.mkdirs();
            if (!result) {
                log.error("writeCsv 创建目录失败:{}", filePath);
                throw new RuntimeException("writeCsv 创建目录失败");
            }
        }
        log.info("CsvWriterUtils writeCsv begin,size:{}", dataList.size());
        CSVWriter csvWriter;
        // 写入文件的绝对路径
        String writeFilePath = filePath + fileName;
        if (!fileName.contains(CSV_FILE_SUFFIX)) {
            writeFilePath += CSV_FILE_SUFFIX;
        }
        try (Writer writer = new FileWriter(writeFilePath)) {
            // 手动增加BOM标识
            writer.write(new String(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}));
            // 映射策略
            ColumnPositionMappingStrategy<E> strategy = new ColumnPositionMappingStrategy<>();
            strategy.setType(type);
            strategy.setColumnMapping(columnMapping);
            csvWriter = new CSVWriter(writer,
                    CSVWriter.DEFAULT_SEPARATOR,
                    CSVWriter.NO_QUOTE_CHARACTER,
                    CSVWriter.DEFAULT_ESCAPE_CHARACTER,
                    CSVWriter.DEFAULT_LINE_END);
            // 写表头
            csvWriter.writeNext(headerMapping);
            StatefulBeanToCsv<E> beanToCsv = new StatefulBeanToCsvBuilder<E>(writer).
                    withMappingStrategy(strategy).
                    withQuotechar(CSVWriter.NO_QUOTE_CHARACTER).
                    withSeparator(CSVWriter.DEFAULT_SEPARATOR).
                    withEscapechar('\\').build();
            beanToCsv.write(dataList);
            csvWriter.close();
            log.info("CsvWriterUtils writeCsv end,size:{}", dataList.size());
            return writeFilePath;
        } catch (IOException e) {
            log.error("CsvWriterUtils writeCsv IOException", e);
        } catch (CsvRequiredFieldEmptyException e) {
            log.error("CsvWriterUtils writeCsv CsvRequiredFieldEmptyException", e);
        } catch (CsvDataTypeMismatchException e) {
            log.error("CsvWriterUtils writeCsv CsvDataTypeMismatchException", e);
        }
        return null;
    }
}

2、说明

2.1、@CsvBindByPosition

@CsvBindByPosition是根据文件中字段的位置来映射

@CsvBindByPosition(position = 1)
private String name;

2.1.1、@CsvCustomBindByPosition

@CsvCustomBindByPosition(position = 2, converter = StringToClaimMetaDate.class)
private Date dataTime;

2.1.1.1、converter

public class StringToClaimMetaDate extends AbstractBeanField<Date> {

    @SneakyThrows
    @Override
    protected Object convert(String value) {
        if (StringUtils.isBlank(value)) {
            return null;
        }
        return DateUtils.parseDate(value, "yyyyMMdd");
    }
}

2.2、@CsvBindByName

@ CsvBindByName根据表头的名称来映射;@CsvBindByPosition是根据文件中字段的位置来映射。当2个注解一起使用时则基于位置的方式有效。

@CsvBindByPosition(column = "name")
private String name;

ContactAuthor