How to Create CSV File from POJO with Custom Column Headers and Positions – 如何使用自定义列标题和位置从 POJO 创建 CSV 文件

最后修改: 2023年 10月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

CSV is one of the common data exchange formats between systems and applications. A common use case is building Java applications that deal with these CSV files. While writing data to a CSV file, we need to map our Plain Old Java Object ( POJO ) to a CSV format.

CSV 是系统和应用程序之间常用的数据交换格式之一。常见的用例是构建Java 应用程序来处理这些 CSV 文件。在将数据写入 CSV 文件时,我们需要将普通旧 Java 对象(POJO)映射为 CSV 格式。

In this tutorial, we’ll learn how to map POJO to CSV format with a custom position and header name.

在本教程中,我们将学习如何使用自定义位置和标题名称将 POJO 映射为 CSV 格式。

2. OpenCSV Library

2.OpenCSV 库

OpenCSV is a very popular library for working with CSV files. We first need to add a Maven dependency to our project:

OpenCSV 是一个非常流行的用于处理 CSV 文件的库。首先,我们需要在项目中添加一个 Maven 依赖项:

<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>5.9</version>
</dependency>

3. Generating Input Records

3.生成输入记录

For this article, we’ll generate sample input records that we will map to CSV records.

在本文中,我们将生成样本输入记录,并将其映射为 CSV 记录。

3.1. Application Record

3.1.申请记录

Application record is a simple POJO that contains id, name, age, and created_at fields:

应用程序 record 是一个简单的 POJO,包含 id、name、age、created_at 字段:

public record Application(String id, String name, Integer age, String created_at) {}

3.2. List of Applications

3.2.应用程序列表

We’ll generate a list of applications that will be later converted to CSV format:

我们将生成一个应用程序列表,随后将其转换为 CSV 格式:

List<Application> applications = List.of(
  new Application("123", "Sam", 34, "2023-08-11"),
  new Application("456", "Tam", 44, "2023-02-11"),
  new Application("890", "Jam", 54, "2023-03-11")
);

4. POJO to CSV

4.将 POJO 转换为 CSV

The default mapping of POJO to CSV is straightforward. We can use StatefulBeanToCsvBuilder with a defined separator and other configs, and then we can write it with FilerWriter:

POJO 到 CSV 的默认映射非常简单。我们可以使用 StatefulBeanToCsvBuilder 并定义分隔符和其他配置,然后使用 FilerWriter 编写:

public static void beanToCSVWithDefault(List<Application> applications) throws Exception {
    try (FileWriter writer = new FileWriter("application.csv")) {
      var builder = new StatefulBeanToCsvBuilder<Application>(writer)
        .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
        .withSeparator(',')
        .build();
      
      builder.write(applications);
    }
}

The default mapping converts POJO to CSV with an ascending field name, but it’s not helpful if we want the header in a custom format.

默认映射将 POJO 转换为字段名以升序排列的 CSV,但如果我们想要自定义格式的标头,这并没有什么帮助。

4.1. Custom Header Strategy

4.1.自定义标题策略

If we want our output CSV file with a custom header, we can define and use a custom header strategy when writing to a CSV file.

如果我们希望输出的 CSV 文件带有自定义页眉,可以在写入 CSV 文件时定义并使用自定义页眉策略。

For example, if we want our header with the lowercase name, we can override generateHeader:

例如,如果我们希望标题使用小写名称,可以覆盖 generateHeader: GenerateHeader: GenerateHeader:

public class CustomCSVWriterStrategy<T> extends HeaderColumnNameMappingStrategy<T> {
    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
        String[] header = super.generateHeader(bean);
        return Arrays.stream(header)
          .map(String::toLowerCase)
          .toArray(String[]::new);
    }
}

Once we have a custom header mapping strategy, we can build StatefulBeanToCsvBuilder and then write POJO to CSV file in CSV format:

有了自定义头映射策略后,我们就可以构建 StatefulBeanToCsvBuilder,然后将 POJO 以 CSV 格式写入 CSV 文件:

public static void beanToCSVWithCustomHeaderStrategy(List<Application> applications)
  throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException {
    try (FileWriter writer = new FileWriter("application.csv")){
      var mappingStrategy = new CustomCSVWriterStrategy<Application>();
      mappingStrategy.setType(Application.class);

      var builder = new StatefulBeanToCsvBuilder<Application>(writer)
        .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
        .withMappingStrategy(mappingStrategy)
        .build();
      builder.write(applications);
    }
}

4.2. Custom Position Strategy

4.2.自定义位置策略

Writing a CSV file with a CSV field having a certain defined position is also possible. All we’ve to do is annotate the application record property with the required field position:

我们只需在应用程序记录属性中注释所需的字段位置即可:

public record Application(
    @CsvBindByPosition(position = 0)
    String id,
    @CsvBindByPosition(position = 1)
    String name,
    @CsvBindByPosition(position = 2)
    Integer age,
    @CsvBindByPosition(position = 3)
    String created_at) {}

Now, we can write POJO to CSV format using annotated Application records:

现在,我们可以使用带注释的 Application 记录将 POJO 写成 CSV 格式:

public static void beanToCSVWithCustomPositionStrategy(List<Application> applications) throws Exception {
    try (FileWriter writer = new FileWriter("application3.csv")) {
      var builder = new StatefulBeanToCsvBuilder<Application1>(writer)
        .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
        .build();
     
      builder.write(applications);
   }
}

4.3. Custom Position Strategy and Header Name

4.3.自定义位置策略和标题名称

If we want the CSV field along with the header at a certain position, we can do that using the custom column positioning strategy.

如果我们希望 CSV 字段和页眉位于某个位置,可以使用自定义列定位策略来实现。

First, we’ll need to annotate the application record class properties with position and header name:

首先,我们需要为应用程序记录类属性注释位置和标题名称:

public record Application1(
    @CsvBindByName(column = "id", required = true)
    @CsvBindByPosition(position = 1)
    String id,
    @CsvBindByName(column = "name", required = true)
    @CsvBindByPosition(position = 0)
    String name,
    @CsvBindByName(column = "age", required = true)
    @CsvBindByPosition(position = 2)
    Integer age,
    @CsvBindByName(column = "position", required = true)
    @CsvBindByPosition(position = 3)
    String created_at) {}

Once the record class is ready, we need to write a custom column positioning strategy.

记录类准备就绪后,我们需要编写自定义列定位策略。

This strategy will include logic to generate header and field positions:

该策略将包括生成标题和字段位置的逻辑:

public class CustomColumnPositionStrategy<T> extends ColumnPositionMappingStrategy<T> {
    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
        super.generateHeader(bean);
        return super.getColumnMapping();
    }
}

Now that we’re done with the record and column positioning strategy, we’re ready to use them inside client logic and generate a CSV file:

现在,我们已经完成了记录和列定位策略,可以在客户端逻辑中使用它们并生成 CSV 文件了:

public static void beanToCSVWithCustomHeaderAndPositionStrategy(List<Application1> applications)
  throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException {
    try (FileWriter writer = new FileWriter("application4.csv")){
        var mappingStrategy = new CustomColumnPositionStrategy<Application1>();
        mappingStrategy.setType(Application1.class);

        var builder = new StatefulBeanToCsvBuilder<Application1>(writer)
          .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
          .withMappingStrategy(mappingStrategy)
          .build();
        builder.write(applications);
    }
}

5. Conclusion

5.结论

In this tutorial, we learned how to convert POJO to CSV format and write to the CSV file. We discussed and wrote examples for including the header along with CSV fields. Additionally, we wrote custom header and positioning strategies as well.

在本教程中,我们学习了如何将 POJO 转换为 CSV 格式并写入 CSV 文件。我们讨论并编写了包含标题和 CSV 字段的示例。此外,我们还编写了自定义标题和定位策略。

OpenCSV doesn’t provide an out-of-the-box solution for having custom positioning and header for CSV files, but it’s easy to write a custom strategy to include a field and header at the required position.

OpenCSV 并没有为 CSV 文件提供自定义定位和页眉的开箱即用解决方案,但编写自定义策略在所需位置包含字段和页眉还是很容易的。

As always, the example code is available over on GitHub.

在 GitHub 上提供了示例代码。