【问题标题】:Apache Camel CSV with Header带有标题的 Apache Camel CSV
【发布时间】:2019-05-24 15:23:02
【问题描述】:

我编写了一个简单的测试应用程序,它从数据库中读取记录并将结果放入 csv 文件中。到目前为止它工作正常,但列名,即标题没有放在 csv 文件中。根据文档,它应该放在那里。我也试过不带/带流和拆分,但情况是一样的。

在第 182 行的骆驼单元测试中,标题被明确地放在那里:https://github.com/apache/camel/blob/master/components/camel-csv/src/test/java/org/apache/camel/dataformat/csv/CsvDataFormatTest.java

如何在不遍历标题的情况下解决这个非常简单的问题?我还尝试了不同的设置,但都一样。例如,我已经设置了分隔符,但没有设置标题。也提前感谢您的回复。

我像这样使用 Camel 2.16.1:

final CsvDataFormat csvDataFormat = new CsvDataFormat();
csvDataFormat.setHeaderDisabled(false);
[...]
from("direct:TEST").routeId("TEST")
        .setBody(constant("SELECT * FROM MYTABLE"))
        .to("jdbc:myDataSource?readSize=100") // max 100 records
//      .split(simple("${body}"))             // split the list
//      .streaming()                          // not to keep all messages in memory
        .marshal(csvDataFormat)
        .to("file:extract?fileName=TEST.csv");
[...]

编辑 1

我还尝试从 exchange.in 添加标题。它们在 HashSet 中的名称为“CamelJdbcColumnNames”。我像这样将它添加到 csvDataFormat 中:

    final CsvDataFormat csvDataFormat = new CsvDataFormat();
    csvDataFormat.setHeaderDisabled(false);
    [...]
    from("direct:TEST").routeId("TEST")
            .setBody(constant("SELECT * FROM MYTABLE"))
            .to("jdbc:myDataSource?readSize=100") // max 100 records
            .process(new Processor() {
                public void process(Exchange exchange) throws Exception {
                    headerNames =                       (HashSet)exchange.getIn().getHeader("CamelJdbcColumnNames");
                    System.out.println("#### Process headernames = " + new ArrayList<String>(headerNames).toString());
                     csvDataFormat.setHeader(new ArrayList<String>(headerNames));
                         }
                })
                .marshal(csvDataFormat)//.tracing()
                .to("file:extract?fileName=TEST.csv");

println() 打印列名,但生成的 cvs 文件不打印。

EDIT2 我按照评论 1 中的建议将标题名称添加到正文中,如下所示:

.process(new Processor() {
    public void process(Exchange exchange) throws Exception {

        Set<String> headerNames = (HashSet)exchange.getIn().getHeader("CamelJdbcColumnNames");
        Map<String, String> nameMap = new LinkedHashMap<String, String>();
        for (String name: headerNames){
            nameMap.put(name, name);
        }
        List<Map> listWithHeaders = new ArrayList<Map>();
        listWithHeaders.add(nameMap);

        List<Map> records = exchange.getIn().getBody(List.class);
        listWithHeaders.addAll(records);
        exchange.getIn().setBody(listWithHeaders, List.class);


        System.out.println("#### Process headernames = " + new ArrayList<String>(headerNames).toString());
        csvDataFormat.setHeader(new ArrayList<String>(headerNames));
     }
})

该提案解决了问题并感谢您,但这意味着 CsvDataFormat 并不是真正可用的。 JDBC 查询之后的交换主体包含来自 HashMaps 的 ArrayList,其中包含表的一条记录。 HashMap 的键是列名,值是值。因此,在 CsvDataFormat 中设置标头输出的配置值应该足以生成标头。您知道更简单的解决方案还是我错过了配置中的某些内容?

【问题讨论】:

    标签: csv apache-camel


    【解决方案1】:

    您使用 JDBC 从数据库中获取数据,因此您需要先自己将标头添加到消息正文中,使其成为第一行。 jdbc 的结果集只是数据,不包括标题。

    【讨论】:

    • 谢谢。我将标头明确添加到 CsvDataFormat 对象,但它们像以前一样被忽略。请参阅编辑 1。您的意思是转换正文并在那里插入标题吗?你能提供一个代码sn-p吗?
    • 我会按照您的建议解决,但如果您知道其他答案,请回复我的最后一个问题,谢谢。
    【解决方案2】:

    我已经通过覆盖 BindyCsvDataFormat 和 BindyCsvFactory 来做到这一点

    public class BindySplittedCsvDataFormat extends BindyCsvDataFormat {
    
        private boolean marshallingfirslLot = false;
    
        public BindySplittedCsvDataFormat() {
            super();
        }
    
        public BindySplittedCsvDataFormat(Class<?> type) {
            super(type);
        }
    
        @Override
        public void marshal(Exchange exchange, Object body, OutputStream outputStream) throws Exception {
            marshallingfirslLot = new Integer(0).equals(exchange.getProperty("CamelSplitIndex"));
            super.marshal(exchange, body, outputStream);
        }
    
        @Override
        protected BindyAbstractFactory createModelFactory(FormatFactory formatFactory) throws Exception {
            BindySplittedCsvFactory bindyCsvFactory = new BindySplittedCsvFactory(getClassType(), this);
            bindyCsvFactory.setFormatFactory(formatFactory);
            return bindyCsvFactory;
        }
    
        protected boolean isMarshallingFirslLot() {
            return marshallingfirslLot;
        }
    }
    
    
    public class BindySplittedCsvFactory extends BindyCsvFactory {
    
        private BindySplittedCsvDataFormat bindySplittedCsvDataFormat;
    
        public BindySplittedCsvFactory(Class<?> type, BindySplittedCsvDataFormat bindySplittedCsvDataFormat) throws Exception {
            super(type);
            this.bindySplittedCsvDataFormat = bindySplittedCsvDataFormat;
        }
    
        @Override
        public boolean getGenerateHeaderColumnNames() {
            return super.getGenerateHeaderColumnNames() && bindySplittedCsvDataFormat.isMarshallingFirslLot();
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      我的 spring xml 解决方案(但我想有一个选项来提取顶部的标题:

      使用spring xml

      <multicast stopOnException="true">
          <pipeline>
            <log message="saving table ${headers.tablename} header to ${headers.CamelFileName}..."/>
            <setBody>     
      <groovy>request.headers.get('CamelJdbcColumnNames').join(";") + "\n"</groovy>
            </setBody>
            <to uri="file:output"/>
          </pipeline>
      
          <pipeline>
            <log message="saving table ${headers.tablename} rows to ${headers.CamelFileName}..."/>
            <marshal>
              <csv delimiter=";" headerDisabled="false" useMaps="true"/>
            </marshal>
            <to uri="file:output?fileExist=Append"/>
          </pipeline>
        </multicast>
      

      http://www.redaelli.org/matteo-blog/2019/05/24/exporting-database-tables-to-csv-files-with-apache-camel/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-05
        • 2016-05-07
        • 2016-04-20
        • 1970-01-01
        • 2011-01-14
        • 2017-02-26
        相关资源
        最近更新 更多