使用Spring Batch读取XML并写入数据库

时间:2016-07-17 14:36:16

标签: java spring jdbc spring-batch

我想阅读XML并将其写入MySql数据库

<?xml version="1.0" encoding="UTF-8"?>
<parentNode id="001" name="p1" type="t1">
    <line>message1</line>
    <line>message2</line>
    <line>message3</line>
    <line>message4</line>
</parentNode>

我有以下读者

@XmlRootElement(name = "parentNode")
public class ParentNode {
    private String id;
    private String name;
    private String type;
    private List<String> lineNode;

    @XmlAttribute(name = "id")
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @XmlAttribute(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlAttribute(name = "type")
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @XmlElement(name = "line")
    public List<String> getLineNode() {
        return lineNode;
    }

    public void setLineNode(List<String> lineNode) {
        this.lineNode = lineNode;
    }
}

我有一位作家如下

public class ParentNodeItemPreparedStatementSetter implements ItemPreparedStatementSetter<ParentNode> {

@Override
public void setValues(ParentNode parentNode, PreparedStatement ps) throws SQLException {
    ps.setString(1, parentNode.getId());
    ps.setString(1, parentNode.getLineNode()); //HOW DO I WRITE EACH LINE INSTEAD OF ONLY THE LAST ONE

}

问题是如何将所有三个line写入数据库。此代码仅将<line>message4</line> message4写入数据库。我希望数据库有

ID | LINE
001 | message1
001 | message2
001 | message3
001 | message4

我的配置如下

    <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-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.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>

    <bean id="xmlItemReaderStep" class="org.springframework.batch.item.xml.StaxEventItemReader">
        <property name="resource" value="classpath:test.xml" />
        <property name="fragmentRootElementName" value="parentNode" />
        <property name="unmarshaller">
            <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                <property name="classesToBeBound">
                    <list>
                        <value>com.results.model.ParentNode</value>
                    </list>
                </property>
            </bean>
        </property>
    </bean>

    <bean id="resultsWriter"
        class="org.springframework.batch.item.database.JdbcBatchItemWriter">
        <property name="dataSource" ref="dataSource" />
        <property name="sql">
            <value>
                <![CDATA[        
                    insert into playground.LINE(id, line) values (?, ?);
                ]]>
            </value>
        </property>
        <property name="ItemPreparedStatementSetter">
            <bean
                class="com.results.preparedstatement.ParentNodeItemPreparedStatementSetter" />
        </property>
    </bean>

    <bean id="itemProcessor"
        class="com.results.itemprocessors.ParentNodeItemProcessor" />


    <bean id="transactionManager"
        class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />


    <batch:job id="resultJob">
        <batch:step id="step1">
            <batch:tasklet transaction-manager="transactionManager">
                <batch:chunk reader="xmlItemReaderStep" writer="resultsWriter"
                    processor="itemProcessor" commit-interval="100" />
            </batch:tasklet>
        </batch:step>
    </batch:job>

</beans> 

编辑: 通过修改ParentNodeItemPreparedStatementSetter,我可以得到我需要的东西。但看起来这不是正确的做法。

public class ParentNodeItemPreparedStatementSetter implements ItemPreparedStatementSetter<ParentNode> {
@Override
public void setValues(ParentNode parentNode, PreparedStatement ps) throws SQLException {
    for (int i = 0; i < parentNode.getLineNode().size(); i++) {
        ps.setString(1, parentNode.getId());
        ps.setString(2, parentNode.getLineNode().get(i));
        if (!(i == parentNode.getLineNode().size()-1))
            ps.addBatch();
    }
}

}

1 个答案:

答案 0 :(得分:1)

您希望它们之间似乎没有匹配:

ID | LINE
001 | message1
001 | message2
001 | message3
001 | message4

你有两个输入结构:

<?xml version="1.0" encoding="UTF-8"?>
<parentNode id="001" name="p1" type="t1">
  <line>message1</line>
  <line>message2</line>
  <line>message3</line>
  <line>message4</line>
</parentNode>


@XmlRootElement(name = "parentNode")
public class ParentNode {
  private String id;
  private String name;
  private String type;
  private List<String> lineNode;
  ...

在输入中,xml中有1行,因此当读者完成其工作时,只有一个ParentNode实例,但在写入之后,您希望在行表中拥有与lineNode列表中的元素一样多的行,所以4线。 它不是对称的。

如果您需要实际的输入xml结构,请在编写过程中不做任何更改并进行一种自定义映射。

在某种程度上,你可以通过添加与lineNode列表中的元素一样多的行来使用ParentNodeItemPreparedStatementSetter:

 for (int i = 0; i < parentNode.getLineNode().size(); i++) {
    ps.setString(1, parentNode.getId());
    ps.setString(2, parentNode.getLineNode().get(i));
    if (!(i == parentNode.getLineNode().size()-1))
        ps.addBatch();
}

这是一个技巧,但根据文档,它似乎并不坏:

  

public interface ItemPreparedStatementSetter

     

一种方便的SQL更新策略,有效地作为RowMapper的反转。

修改:回答您的评论。 如果您的实际输入xml结构可以修改,因为它是例如生成的,您可以设计xml结构,使其与您的预期匹配。 在输入中,您应该添加parent-id值:

<?xml version="1.0" encoding="UTF-8"?>
<parentNode id="001" name="p1" type="t1">
   <line parent-id="001">message1</line>
   <line parent-id="001">message2</line>
   <line parent-id="001">message3</line>
   <line parent-id="001">message4</line>
</parentNode>

在你的读者conf xml中,你会替换

<property name="fragmentRootElementName" value="parentNode" />

<property name="fragmentRootElementName" value="line" />

您还应该修改xml对象的结构。将您的行列表从String类型更改为自己的类,该类拥有两个必需字段:id和line。 通过这种方式,您可以在输入和输出中获得预期的数据,而无需进行任何处理。