Springbatch从两个数据库表读取数据并写入XML文件

问题描述 投票:0回答:1

我是春季批处理的新手,我想就我遇到的问题获得一些指导。我有两个数据库表Settlement_Header(具有文件的头信息)和Settlement_Detail(该头文件的所有事务的列表。)

目标是创建一个具有1个标头和多个详细信息的文件。

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

Current Output

期望的输出

Desired Output

这是我的Jdbc Itemreaeder

@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个回答
0
投票

您的行为绝对是正常的,因为对于您阅读的每个项目,您都有一个Settlement对象,其中包含一个Header和一个Detail。您的问题是批处理领域中的常见问题,在Spring Batch中它被称为“基于查询的驱动ItemReaders”,有关更多信息,请参见here

我按照这种模式解决问题的方式是,创建一个仅返回SettlementHeader个项目的读取器,并添加一个接受每个Item(SettlementHeader)并将其转换为Settlement通过查询数据库中的[[结算详细信息,找到对象。

这是我的解决方法:

步骤项

@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; }

}

希望对您有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.