java - SuperCSV,Dozer : Writing to a csv file. 对于具有多行列表的对象

标签 java csv dozer supercsv

我有一个 A 类,它的属性很少:

class A {

private String col1;
private String col2;
private List<B> bList;

// setters and getters
}

Class B {
private String b1;
private String b2;
//setters and getters
}

我正在尝试使用 supercsv 和 dozer 将其写入 csv 文件。

csv 的行数应与 A 类列表 bList 中的元素相同。 并且应该有四列 col1、col2(这对于所有行来说都是公共(public)的)和来自 A 类 B 类列表的 b1、b2。

目前在映射文件中我有:

<mapping type="one-way" wildcard="false" map-null="true">
                <class-a>package.a</class-a>
                <class-b>org.supercsv.io.dozer.CsvDozerBeanData</class-b>
.....
</mapping>

但它只将数据映射到一行。如果不将其映射到更扁平的类中,有什么更好的方法呢? 在映射中可以将其从类 A 映射到 CsvDozerBeanData 列表吗?这行得通吗?

谢谢。

最佳答案

您能否添加从 BA 的关系?然后,您可以使用以下 bean 映射迭代每个子列表:

new String[] { "a.col1", "a.col2", "b1", "b2" }

这是一个如何使用它的示例。请注意嵌套循环以迭代每个 A 内的每个 B

public class DozerTest {

    @Test
    public final void test() throws IOException {
        StringWriter out = new StringWriter();
        ICsvDozerBeanWriter writer = new CsvDozerBeanWriter(out, 
                CsvPreference.STANDARD_PREFERENCE);
        writer.configureBeanMapping(B.class, 
                new String[] { "a.col1", "a.col2", "b1", "b2" });

        for (A a : generateData()) {
            for (B b : a.getbList()) {
                writer.write(b);
            }
        }
        writer.flush();
        System.out.println(out.toString());
    }

    private List<A> generateData() {
        List<A> data = new ArrayList<A>();

        for (int i = 0; i < 3; i++) {
            A a = new A();
            a.setCol1("col1 for a" + i);
            a.setCol2("col2 for a" + i);

            B firstB = new B();
            firstB.setB1("first b1 for a" + i);
            firstB.setB2("first b2 for a" + i);
            firstB.setA(a);

            B secondB = new B();
            secondB.setB1("second b1 for a" + i);
            secondB.setB2("second b2 for a" + i);
            secondB.setA(a);

            a.setbList(Arrays.asList(firstB, secondB));
            data.add(a);
        }

        return data;
    }

}

打印:

col1 for a0,col2 for a0,first b1 for a0,first b2 for a0
col1 for a0,col2 for a0,second b1 for a0,second b2 for a0
col1 for a1,col2 for a1,first b1 for a1,first b2 for a1
col1 for a1,col2 for a1,second b1 for a1,second b2 for a1
col1 for a2,col2 for a2,first b1 for a2,first b2 for a2
col1 for a2,col2 for a2,second b1 for a2,second b2 for a2

更新以解决评论

如果您无法添加关系,那么您可以只使用 CellProcessors(甚至不需要使用 Dozer)。我刚刚创建了 3 个简单的单元处理器:

  • ElementAt - 仅抓取所需索引处的元素
  • GetB1 - 获取 Bb1 字段
  • GetB2 - 获取 Bb2 字段

他们正在行动:

@Test
public final void test2() throws IOException {
    StringWriter out = new StringWriter();
    ICsvDozerBeanWriter writer = new CsvDozerBeanWriter(out, 
        CsvPreference.STANDARD_PREFERENCE);
    writer.configureBeanMapping(A.class, 
        new String[] { "col1", "col2", "bList", "bList" });

    for (A a : generateData()) {
        for (int i = 0; i < a.getbList().size(); i++) {
            CellProcessor[] processors = new CellProcessor[] { null, null, 
                new ElementAt(i, new GetB1()),
                new ElementAt(i, new GetB2()) };
            writer.write(a, processors);
        }
    }
    writer.flush();
    System.out.println(out.toString());
}

class GetB1 extends CellProcessorAdaptor {
    public Object execute(Object value, CsvContext context) {
        validateInputNotNull(value, context);
        return ((B) value).getB1();
    }
}

class GetB2 extends CellProcessorAdaptor {
    public Object execute(Object value, CsvContext context) {
        validateInputNotNull(value, context);
        return ((B) value).getB2();
    }
}

class ElementAt extends CellProcessorAdaptor {

    private final int index;

    public ElementAt(int index) {
        this.index = index;
    }

    public ElementAt(int index, CellProcessor next) {
        super(next);
        this.index = index;
    }

    public Object execute(Object value, CsvContext context) {
        validateInputNotNull(value, context);
        Object element = ((List<?>) value).get(index);
        return next.execute(element, context);
    }

}

输出:

col1 for a0,col2 for a0,first b1 for a0,first b2 for a0
col1 for a0,col2 for a0,second b1 for a0,second b2 for a0
col1 for a1,col2 for a1,first b1 for a1,first b2 for a1
col1 for a1,col2 for a1,second b1 for a1,second b2 for a1
col1 for a2,col2 for a2,first b1 for a2,first b2 for a2
col1 for a2,col2 for a2,second b1 for a2,second b2 for a2

附:我不建议提供您自己的推土机映射 XML,除非您确实必须这样做(在本例中似乎没有必要)。

关于java - SuperCSV,Dozer : Writing to a csv file. 对于具有多行列表的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21862624/

相关文章:

asp.net - 如何让asp.net下载动态csv

php - readfile 下载空文件和错误的文件类型

java - 通过 Dozer 将字符串映射到映射

java - 如何按需生成属性的类实例?

java - Java中的线程安全队列

java - 在 tomcat 上部署 Spring Boot 应用程序时出现 404 错误

java - 如何跳过空记录 CSVFormat 解析器

java - 推土机映射类级别是可访问的

java - 如何从属于它的实例变量之一获取类的特定实例

用于 SQL Server 数据库的 Java Servlet 和 JDBC