Spring 批处理 - compositeItemReader 和 compositeItemWritter 示例 - 无法在同一 XML/CSV 文件中打印两个表数据

Spring Batch - compositeItemReader and compositeItemWritter examples - Unable to print both tables data in same XML/CSV file

我正在开发 Composite Reader and Writter 示例。我能够成功开发代码,但是当尝试 运行 代码时,我只得到一个表数据,我没有看到其他表数据进入 CSV 文件。请指导。

Customer.java

public class Customer implements Serializable{
    private static final long serialVersionUID = 1L;

    private Integer customerNumber;
    private String customerName;
    private String contactLastName;
    private String contactFirstName;
    private String phone;
    private String addressLine1;
    private String addressLine2;
    private String city;
    private String state;
    private String postalCode;
    private String country;
    private Integer salesRepEmployeeNumber;
    private Double creditLimit;
    // setters and getters

    @Override
public String toString() {
    return employeeNumber + "|"+ lastName + "|" + firstName + "|"+ extension + 
            "|" + email + "|" + officeCode+ "|" + reportsTo + "|" + jobTitle;
}
}

Employee.java

public class Employee implements Serializable{
    private static final long serialVersionUID = 1L;

    private Integer employeeNumber;
    private String lastName;
    private String firstName;
    private String extension;
    private String email;
    private String officeCode;
    private Integer reportsTo;
    private String jobTitle;
    // setters and getters

    @Override
public String toString() {
    return customerNumber + "|" + customerName + "|" + contactLastName + "|" + contactFirstName + "|" + 
            phone+ "|" + addressLine1 + "|" + addressLine2 + "|" + city + "|" + state+ "|" + postalCode + "|" + 
            country+ "|" + salesRepEmployeeNumber + "|" + creditLimit;
}
}

jdbc-复合项-reader-job.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath:context-datasource.xml" />

    <!-- JobRepository and JobLauncher are configuration/setup classes -->
    <bean id="jobRepository"  class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />

    <bean id="jobLauncher"  class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository" />
    </bean>


    <!-- Step will need a transaction manager -->
    <bean id="transactionManager"
        class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

    <job id="compositeJdbcReaderJob" xmlns="http://www.springframework.org/schema/batch">
        <step id="compositeJdbcReaderStep">
            <tasklet>
                <chunk reader="compositeItemReader" writer="itemWriter" commit-interval="5"></chunk>
            </tasklet>
        </step>
    </job>


    <bean id="compositeItemReader" class="com.common.batch.reader.CompositeCursorItemReader">
        <property name="unifyingMapper">
            <bean class="com.common.batch.mapper.DefaultUnifyingStringItemsMapper" />
        </property>
        <property name="cursorItemReaders">
            <list>
                <ref bean="itemReader1" />
                <ref bean="itemReader2" />                 
            </list>
        </property>
    </bean>

    <bean id="itemReader1" class="org.springframework.batch.item.database.JdbcCursorItemReader">
        <property name="dataSource" ref="dataSource" />

        <property name="saveState" value="true" />

        <property name="sql">
            <value>
                <![CDATA[ SELECT * FROM customers ]]>
            </value>
        </property>
        <property name="rowMapper">
            <bean class="com.common.batch.mapper.CustomerMapper" />
        </property>
    </bean>



    <bean id="itemReader2" class="org.springframework.batch.item.database.JdbcCursorItemReader">
        <property name="dataSource" ref="dataSource" />

        <property name="saveState" value="true" />

        <property name="sql">
            <value>
                <![CDATA[ SELECT * FROM employees ]]>
            </value>
        </property>
        <property name="rowMapper">
            <bean class="com.common.batch.mapper.EmployeeMapper" />
        </property>
    </bean>


    <bean id="itemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
        <property name="resource" value="file:csv/employees.txt" />

        <property name="lineAggregator">
            <bean class="org.springframework.batch.item.file.transform.PassThroughLineAggregator"/>
        </property>
    </bean>
</beans>

EmployeeMapper.java

public class EmployeeMapper implements RowMapper<Employee>{

    @Override
    public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
        Employee employee = new Employee();
        employee.setEmployeeNumber(rs.getInt("employeeNumber"));
        employee.setLastName(rs.getString("lastName"));
        employee.setFirstName(rs.getString("firstName"));
        employee.setExtension(rs.getString("extension"));
        employee.setEmail(rs.getString("email"));
        employee.setOfficeCode(rs.getString("officeCode"));
        employee.setReportsTo(rs.getInt("reportsTo"));
        employee.setJobTitle(rs.getString("jobTitle"));

        return employee;
    }
}

CustomerMapper.java

public class CustomerMapper implements RowMapper<Customer>{

    @Override
    public Customer mapRow(ResultSet rs, int rowNum) throws SQLException {
        Customer customer = new Customer();
        customer.setCustomerNumber(rs.getInt("customerNumber"));
        customer.setCustomerName(rs.getString("customerName"));
        customer.setContactLastName(rs.getString("contactLastName"));
        customer.setContactFirstName(rs.getString("contactFirstName"));
        customer.setPhone(rs.getString("phone"));
        customer.setAddressLine1(rs.getString("addressLine1"));
        customer.setAddressLine2(rs.getString("addressLine2"));
        customer.setCity(rs.getString("city"));
        customer.setState(rs.getString("state"));
        customer.setPostalCode(rs.getString("postalCode"));
        customer.setCountry(rs.getString("country"));
        customer.setSalesRepEmployeeNumber(rs.getInt("salesRepEmployeeNumber"));
        customer.setCreditLimit(rs.getDouble("creditLimit"));

        return customer;
    }
}

CompositeMain.java

public class CompositeMain {
    @SuppressWarnings("resource")
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("composite/jdbc-composite-item-reader-job.xml");

        JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
        Job job = (Job) context.getBean("compositeJdbcReaderJob");

        JobExecution execution;
        try {
            execution = jobLauncher.run(job, new JobParameters());
            System.out.println("Job Exit Status : "+ execution.getStatus());

        } catch (JobExecutionAlreadyRunningException | JobRestartException
                | JobInstanceAlreadyCompleteException | JobParametersInvalidException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        System.out.println("Done !!");
    }
}

CompositeCursorItemReader.java

public class CompositeCursorItemReader<T> implements ItemStreamReader<T> {

    private List<AbstractCursorItemReader<?>> cursorItemReaders;

    private UnifyingItemsMapper<T> unifyingMapper;

    @Override
    public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        // read from all registered readers
        List items = new ArrayList();
        for (AbstractCursorItemReader<?> cursorItemReader : cursorItemReaders) {
            items.add(cursorItemReader.read());
        }
        // delegate to mapper
        return unifyingMapper.mapItems(items);
    }

    @Override
    public void update(ExecutionContext executionContext) {
        for (ItemStream itemStream : cursorItemReaders) {
            itemStream.update(executionContext);
        }
    }

    @Override
    public void close() throws ItemStreamException {
        for (ItemStream itemStream : cursorItemReaders) {
            itemStream.close();
        }
    }

    @Override
    public void open(ExecutionContext executionContext) throws ItemStreamException {
        for (ItemStream itemStream : cursorItemReaders) {
            itemStream.open(executionContext);
        }
    }

    public void setUnifyingMapper(UnifyingItemsMapper<T> mapper) {
        this.unifyingMapper = mapper;
    }

    public void setCursorItemReaders(List<AbstractCursorItemReader<?>> cursorItemReaders) {
        this.cursorItemReaders = cursorItemReaders;
    }
}

当我看到输出时,我只看到一个表数据:

121|Baane Mini Imports|Bergulfsen|Jonas |07-98 9555|Erling Skakkes gate 78|null|Stavern|null|4110|Norway|1504|81700.01102|Bondur|Gerard|x5408|gbondur@classicmodelcars.com|4|1056|Sale Manager (EMEA)
124|Mini Gifts Distributors Ltd.|Nelson|Susan|4155551450|5677 Strong St.|null|San Rafael|CA|97562|USA|1165|210500.01143|Bow|Anthony|x5428|abow@classicmodelcars.com|1|1056|Sales Manager (NA)
125|Havel & Zbyszek Co|Piestrzeniewicz|Zbyszek |(26) 642-7555|ul. Filtrowa 68|null|Warszawa|null|01-012|Poland|0|0.01165|Jennings|Leslie|x3291|ljennings@classicmodelcars.com|1|1143|Sales Rep
128|Blauer See Auto, Co.|Keitel|Roland|+49 69 66 90 2555|Lyonerstr. 34|null|Frankfurt|null|60528|Germany|1504|59700.01166|Thompson|Leslie|x4065|lthompson@classicmodelcars.com|1|1143|Sales Rep
129|Mini Wheels Co.|Murphy|Julie|6505555787|5557 North Pendale Street|null|San Francisco|CA|94217|USA|1165|64600.01188|Firrelli|Julie|x2173|jfirrelli@classicmodelcars.com|2|1143|Sales Rep
131|Land of Toys Inc.|Lee|Kwai|2125557818|897 Long Airport Avenue|null|NYC|NY|10022|USA|1323|114900.01216|Patterson|Steve|x4334|spatterson@classicmodelcars.com|2|1143|Sales Rep
141|Euro+ Shopping Channel|Freyre|Diego |(91) 555 94 44|C/ Moralzarzal, 86|null|Madrid|null|28034|Spain|1370|227600.01286|Tseng|Foon Yue|x2248|ftseng@classicmodelcars.com|3|1143|Sales Rep
144|Volvo Model Replicas, Co|Berglund|Christina |0921-12 3555|Berguvsvägen  8|null|Luleå|null|S-958 22|Sweden|1504|53100.01323|Vanauf|George|x4102|gvanauf@classicmodelcars.com|3|1143|Sales Rep
145|Danish Wholesale Imports|Petersen|Jytte |31 12 3555|Vinbæltet 34|null|Kobenhavn|null|1734|Denmark|1401|83400.01337|Bondur|Loui|x6493|lbondur@classicmodelcars.com|4|1102|Sales Rep
146|Saveley & Henriot, Co.|Saveley|Mary |78.32.5555|2, rue du Commerce|null|Lyon|null|69004|France|1337|123900.01370|Hernandez|Gerard|x2028|ghernande@classicmodelcars.com|4|1102|Sales Rep
148|Dragon Souveniers, Ltd.|Natividad|Eric|+65 221 7555|Bronz Sok.|Bronz Apt. 3/6 Tesvikiye|Singapore|null|079903|Singapore|1621|103800.01401|Castillo|Pamela|x2759|pcastillo@classicmodelcars.com|4|1102|Sales Rep
151|Muscle Machine Inc|Young|Jeff|2125557413|4092 Furth Circle|Suite 400|NYC|NY|10022|USA|1286|138500.01501|Bott|Larry|x2311|lbott@classicmodelcar

我现在有几个问题:

  1. 我们如何将两个表数据打印到一个文件中?
  2. 我们如何将两个表的数据打印到单独的文件中?
  3. 我们如何打印 lbott@classicmodelcar FK 关系表的实际值而不是参考值?

如果您需要任何其他信息来解决问题,请告诉我。期待专家的反馈。

实体关系..

Re #3,根据实体关系 (ER),我认为您需要为付款创建模型 class,如下所示:请确保为所有 [=42] 创建了模型 classes =] ER 图。

Payment.java

public class Payment implements Serializable{
    private static final long serialVersionUID = 1L;

    private Integer customerNumber;
    private String checkNumber;
    private Date paymentDate;
    private Double amount;
        // setters and getters

        @Override
    public String toString() {
        return customerNumber + "|"+ checkNumber + "|" + paymentDate + "|"+ amount ;
    }
}

发生这种情况是因为您没有为每个要写入文件的 table 创建单独的 ItemWritter。 您需要做以下事情:'

  1. 创建另一个 FlatFileItemWriter<bean id="itemWriter2" .... />
  2. 你还需要创建另一个 JdbcCursorItemReader 比如 <bean id="itemReader2" class="org.springframework.batch.item.database.JdbcCursorItemReader">
  3. 你还需要创建单独的 CompositeCursorItemReader 就像说 <bean id="compositeItemReader2" class="com.common.batch.reader.CompositeCursorItemReader">
  4. 您还需要像下面这样定义才能调用下一步

        <step id="compositeJdbcReaderStep2">
            <tasklet>
                <chunk reader="compositeItemReader2" writer="itemWriter2" commit-interval="5" />
            </tasklet>
        </step>
    </job>