我想实现双向导入/导出-能够将生成的CSV导入回POJO,反之亦然。
我无法为此使用@CsvBindByPosition,因为在这种情况下-ColumnPositionMappingStrategy是自动选择的。
我用来实现目标的方法是:
HeaderColumnNameMappingStrategy
mappingStrategy.setColumnOrderOnWrite(Comparator writeOrder)
csvUtils读取/写入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导入/导出
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
}
用于预定义字符串排序的自定义比较器:
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());
}
}
POJO的有序写作(最初问题的答案)
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);
}
将导出的CSV读回POJO(原始答案的补充)
重要提示:CSV可以是无序的,因为我们仍在使用按名称绑定:
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);
}
结论:
无论列顺序如何,我们都可以将CSV读取为POJO-因为我们正在使用@CsvBindByName
我们可以使用自定义比较器在写入时控制列顺序