OpenCSV:如何使用自定义列标题和自定义列位置从 POJO 创建 CSV 文件?

新手上路,请多包涵

我创建了一个 MappingsBean 类,其中指定了 CSV 文件的所有列。接下来我解析 XML 文件并创建一个 mappingbeans 列表。然后我将该数据作为报告写入 CSV 文件。

我正在使用以下注释:

 public class MappingsBean {

    @CsvBindByName(column = "TradeID")
    @CsvBindByPosition(position = 0)
    private String tradeId;

    @CsvBindByName(column = "GWML GUID", required = true)
    @CsvBindByPosition(position = 1)
    private String gwmlGUID;

    @CsvBindByName(column = "MXML GUID", required = true)
    @CsvBindByPosition(position = 2)
    private String mxmlGUID;

    @CsvBindByName(column = "GWML File")
    @CsvBindByPosition(position = 3)
    private String gwmlFile;

    @CsvBindByName(column = "MxML File")
    @CsvBindByPosition(position = 4)
    private String mxmlFile;

    @CsvBindByName(column = "MxML Counterparty")
    @CsvBindByPosition(position = 5)
    private String mxmlCounterParty;

    @CsvBindByName(column = "GWML Counterparty")
    @CsvBindByPosition(position = 6)
    private String gwmlCounterParty;
}

然后我使用 StatefulBeanToCsv 类写入 CSV 文件:

 File reportFile = new File(reportOutputDir + "/" + REPORT_FILENAME);
Writer writer = new PrintWriter(reportFile);
StatefulBeanToCsv<MappingsBean> beanToCsv = new
                              StatefulBeanToCsvBuilder(writer).build();
beanToCsv.write(makeFinalMappingBeanList());
writer.close();

这种方法的问题是,如果我使用 @CsvBindByPosition(position = 0) 来控制位置,那么我将无法生成列名。如果我使用 @CsvBindByName(column = "TradeID") 那么我无法设置列的位置。

有没有一种方法可以同时使用这两种注释,以便我可以创建带有列标题的 CSV 文件并控制列位置?

问候,维克拉姆帕塔尼亚

原文由 Vikram Pathania 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.6k
1 个回答

我遇到过类似的问题。据我所知,OpenCSV 中没有允许使用自定义列名 顺序将 bean 写入 CSV 的内置功能。

开箱即用的 OpenCSV 中有两个主要的 MappingStrategy 可用:

  • HeaderColumnNameMappingStrategy :允许根据自定义名称将 CVS 文件列映射到 bean 字段;将 bean 写入 CSV 时,这允许更改列标题名称,但我们无法控制列顺序
  • ColumnPositionMappingStrategy :允许根据列顺序将 CSV 文件列映射到 bean 字段;将 bean 写入 CSV 时,我们可以控制列顺序,但我们得到一个空标题(实现返回 new String[0] 作为标题)

我发现实现自定义列名和排序的唯一方法是编写您的自定义 MappingStrategy

第一个解决方案:快速简单但硬编码

创建自定义 MappingStrategy

 class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
    private static final String[] HEADER = new String[]{"TradeID", "GWML GUID", "MXML GUID", "GWML File", "MxML File", "MxML Counterparty", "GWML Counterparty"};

    @Override
    public String[] generateHeader() {
        return HEADER;
    }
}

并在 StatefulBeanToCsvBuilder 中使用它:

 final CustomMappingStrategy<MappingsBean> mappingStrategy = new CustomMappingStrategy<>();
mappingStrategy.setType(MappingsBean.class);

final StatefulBeanToCsv<MappingsBean> beanToCsv = new StatefulBeanToCsvBuilder<MappingsBean>(writer)
    .withMappingStrategy(mappingStrategy)
    .build();
beanToCsv.write(makeFinalMappingBeanList());
writer.close()

MappingsBean 我们离开的类 CsvBindByPosition 注释-控制排序(在这个解决方案 CsvBindByName 不需要注释)。由于自定义映射策略,标题列名称包含在生成的 CSV 文件中。

此解决方案的缺点是,当我们通过 CsvBindByPosition 注释更改列顺序时,我们还必须手动更改 HEADER 自定义映射策略中的常量。

第二种解决方案:更灵活

第一个解决方案有效,但对我不利。基于 MappingStrategy 的内置实现,我想出了另一个实现:

 class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
    @Override
    public String[] generateHeader() {
        final int numColumns = findMaxFieldIndex();
        if (!isAnnotationDriven() || numColumns == -1) {
            return super.generateHeader();
        }

        header = new String[numColumns + 1];

        BeanField beanField;
        for (int i = 0; i <= numColumns; i++) {
            beanField = findField(i);
            String columnHeaderName = extractHeaderName(beanField);
            header[i] = columnHeaderName;
        }
        return header;
    }

    private String extractHeaderName(final BeanField beanField) {
        if (beanField == null || beanField.getField() == null || beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class).length == 0) {
            return StringUtils.EMPTY;
        }

        final CsvBindByName bindByNameAnnotation = beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class)[0];
        return bindByNameAnnotation.column();
    }
}

您可以在 StatefulBeanToCsvBuilder 中使用此自定义策略,与第一个解决方案完全相同(请记住调用 mappingStrategy.setType(MappingsBean.class); ,否则此解决方案将不起作用)。

目前我们的 MappingsBean 必须同时包含 CsvBindByNameCsvBindByPosition 注释。第一个给出标题列名称,第二个在输出 CSV 标题中创建列的顺序。现在,如果我们更改(使用注释)列名称或 MappingsBean 类中的顺序 - 该更改将反映在输出 CSV 文件中。

原文由 sebast26 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏