【问题标题】:Springbatch reading data from two DB tables and write to XML fileSpring Batch 从两个 DB 表中读取数据并写入 XML 文件
【发布时间】:2020-08-16 23:46:51
【问题描述】:

我是 Spring Batch 的新手,我想就我遇到的问题获得一些指导。我有两个数据库表 Settlement_Header(其中包含文件的头信息)和 Settlement_Detail(这是该头文件的所有事务的列表。)

目标是创建一个包含 1 个标题和多个详细信息的文件。

当前输出 - 标题出现在每条记录上,我希望它出现一次。我尝试在项目处理器中包含一个条件,但它没有解决我的问题。

Current Output

期望的输出

Desired Output

这是我的阅读器

@Bean(destroyMethod="")
public JdbcCursorItemReader<Settlement> settlementreader(){
    JdbcCursorItemReader<Settlement> ItemReader = new JdbcCursorItemReader<>();
    ItemReader.setDataSource(dataSource);
    ItemReader.setSql("SELECT DISTINCT A.PROCESS_DATE,A.FILE_NAME,A.SERVICE,A.SUB_SERVICE,A.SENDER,A.RUN_MODE,A.CURRENCY,A.PROCESS_WINDOW_NO,B.RECORD_SEQ_NO,"
            + "B.AGENT_FROM,B.AGENT_TO,B.SETTLE_VOLUME,B.AMOUNT_CURRENCY,B.SETTLE_AMOUNT "
            + "FROM SETTLEMENT_HEADER A,SETTLEMENT_DETAIL B WHERE A.FILE_ID=B.FILE_ID");
    ItemReader.setRowMapper(new SettlementRowMapper());
    return ItemReader;
}

作家

@Bean (destroyMethod="")
   public StaxEventItemWriter<Settlement> settlementwriter() throws Exception {
       StaxEventItemWriter<Settlement> ItemWriter = new StaxEventItemWriter<>();
       ItemWriter.setResource(new FileSystemResource(".../Settlement.xml")); 
       ItemWriter.setRootTagName("Settlement");
       ItemWriter.setMarshaller(marshaller);
       ItemWriter.afterPropertiesSet();
       return ItemWriter;
   }

行映射器

公共类 SettlementRowMapper 实现 RowMapper {

@Override
public Settlement mapRow(ResultSet rs, int rowNum) throws SQLException {

    Settlement Settlement = new Settlement ();
    List<SettlementHeader> settlementheader= new ArrayList<SettlementHeader>();
    List<SettlementDetail> settlementdetail = new ArrayList<SettlementDetail>();
    SettlementHeader header = new SettlementHeader();
    SettlementDetail detail = new SettlementDetail();
    SttlAmt sttlAmt = new SttlAmt();


    header.setPrcDte(rs.getDate("PROCESS_DATE").toLocalDate());
    header.setFilename(rs.getString("FILE_NAME"));
    header.setService(rs.getString("SERVICE"));
    header.setSubServ(rs.getString("SUB_SERVICE"));
    header.setSender(rs.getInt("SENDER"));
    header.setRunMode(rs.getString("RUN_MODE"));
    header.setCurrency(rs.getString("CURRENCY"));
    header.setPrcWndwNum(rs.getInt("PROCESS_WINDOW_NO"));
    detail.setSeqNumb(rs.getInt("RECORD_SEQ_NO"));
    detail.setAgntFrm(rs.getInt("AGENT_FROM"));
    detail.setAgntTo(rs.getInt("AGENT_TO"));
    detail.setSttlVol(rs.getInt("SETTLE_VOLUME"));
    sttlAmt.setCcy(rs.getString("AMOUNT_CURRENCY"));
    sttlAmt.setValue(rs.getDouble("SETTLE_AMOUNT"));
    detail.setSttlAmt(sttlAmt); 
    settlementheader.add(header);
    settlementdetail.add(detail);
    Settlement.setSettlementDetails(settlementdetail);
    Settlement.setSettlementHeader(settlementheader);
    return Settlement;
}

【问题讨论】:

    标签: java spring-batch spring-jdbc rowmapper


    【解决方案1】:

    您的行为是绝对正常的,因为对于您阅读的每个 Item,您都有一个包含一个 Header 和一个 Detail 的 Settlement 对象。

    您的问题是批处理领域的常见问题,使用 Spring Batch,它被称为“驱动基于查询的 ItemReaders”,您可以在 here.

    按照这种模式解决您的问题的方法是创建一个仅返回 SettlementHeader 项目的阅读器,并添加一个处理器,该处理器接收每个项目 (SettlementHeader) 并通过查询将其转换为 Settlement Object Settlement Details 的数据库。

    这是我的解决方案:

    步骤项目

    @Bean(destroyMethod = "")
    public JdbcCursorItemReader<SettlementHeader> settlementHeaderReader(DataSource dataSource) {
        JdbcCursorItemReader<SettlementHeader> ItemReader = new JdbcCursorItemReader<>();
        ItemReader.setDataSource(dataSource);
        ItemReader.setSql("SELECT DISTINCT A.FILE_ID, A.PROCESS_DATE, A.FILE_NAME, A.SERVICE, A.SUB_SERVICE, A.SENDER, A.RUN_MODE, A.CURRENCY, A.PROCESS_WINDOW_NO"
                            + "FROM SETTLEMENT_HEADER A");
        ItemReader.setRowMapper(new SettlementHeaderRowMapper());
        return ItemReader;
    }
    
    
    @Bean
    public ItemProcessor<SettlementHeader, Settlement> settlementHeaderProcessor(JdbcTemplate jdbcTemplate){
    
        return item -> {
            List<SettlementDetail> settlementDetails = jdbcTemplate.query("SELECT B.RECORD_SEQ_NO, B.AGENT_FROM,B.AGENT_TO,B.SETTLE_VOLUME,B.AMOUNT_CURRENCY,B.SETTLE_AMOUNT " +
                    "  FROM SETTLEMENT_DETAIL B WHERE ? = B.FILE_ID",
                    new Object[]{item.getFileId()},
                    new SettlementDetailRowMapper());
    
            Settlement settlement = new Settlement ();
    
            List<SettlementHeader> settlementheader= new ArrayList<SettlementHeader>();
            settlementheader.add(item);
    
            settlement.setSettlementDetails(settlementDetails);
            settlement.setSettlementHeader(settlementheader);
    
            return settlement;
        };
    }
    
    // Your writer should stay the same
    @Bean(destroyMethod = "")
    public StaxEventItemWriter<Settlement> settlementwriter() throws Exception {
        StaxEventItemWriter<Settlement> ItemWriter = new StaxEventItemWriter<>();
        ItemWriter.setResource(new FileSystemResource(".../Settlement.xml"));
        ItemWriter.setRootTagName("Settlement");
        ItemWriter.setMarshaller(marshaller);
        ItemWriter.afterPropertiesSet();
        return ItemWriter;
    }
    

    行映射器

    public class SettlementHeaderRowMapper implements RowMapper<SettlementHeader> {
    @Override
    public SettlementHeader mapRow(ResultSet rs, int i) throws SQLException {
        SettlementHeader header = new SettlementHeader();
    
        header.setFileId(rs.getInt("FILE_ID"));
        header.setPrcDte(rs.getDate("PROCESS_DATE").toLocalDate());
        header.setFilename(rs.getString("FILE_NAME"));
        header.setService(rs.getString("SERVICE"));
        header.setSubServ(rs.getString("SUB_SERVICE"));
        header.setSender(rs.getInt("SENDER"));
        header.setRunMode(rs.getString("RUN_MODE"));
        header.setCurrency(rs.getString("CURRENCY"));
        header.setPrcWndwNum(rs.getInt("PROCESS_WINDOW_NO"));
    
        return header;
    }
    

    }

    public class SettlementDetailRowMapper implements RowMapper<SettlementDetail> {
    @Override
    public SettlementDetail mapRow(ResultSet rs, int i) throws SQLException {
        SettlementDetail detail = new SettlementDetail();
        SttlAmt sttlAmt = new SttlAmt();
    
        detail.setSeqNumb(rs.getInt("RECORD_SEQ_NO"));
        detail.setAgntFrm(rs.getInt("AGENT_FROM"));
        detail.setAgntTo(rs.getInt("AGENT_TO"));
        detail.setSttlVol(rs.getInt("SETTLE_VOLUME"));
        sttlAmt.setCcy(rs.getString("AMOUNT_CURRENCY"));
        sttlAmt.setValue(rs.getDouble("SETTLE_AMOUNT"));
        detail.setSttlAmt(sttlAmt);
    
        return detail;
    }
    

    }

    希望对你有帮助。

    【讨论】:

    • 非常感谢。我试试看
    • 成功了,谢谢。我的根元素 Settlement 出现了两次。我的 Settlement 模型类上有 writer.setRootTagName ='Settlement' 和 XmlRootAnnotation。
    • 完美。 writer.setRootTagName 用于设置包含所有结算项目的根元素。默认情况下,如果您不设置它,它将被设置为“root”。我会这样做: writer.setRootTagName("Settlements")
    • 所以我无法删除 1 个注释,因为我有两个根元素标签。如果我删除模型类 Jaxb 上的 XMLRoot 会产生编译错误。
    • 如果这样做,您的 XML 文档将无效。但是有一个解决方法是覆盖 StaxEventItemWriter 的行为。检查这个 [stackoverflow.com/a/49324643/2831242] 。希望这是您正在寻找的。​​span>
    猜你喜欢
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多