SpringBatch导出文数据到XML文件基本流程也是由三部分组成:itemReader,itemProcess,itemWriter;需要特殊注意的地方主要由两点:
- XML文件是由一组节点构成,所以批处itemReader查询出来的对象需要同XML文件的结点构造成一一对应的映射关系;
- SpringBatch提供了itemWriter的子类StaxEventItemWriter专门进行XML文件的输出。
首先介绍功能开发;
<users>
<user>
<name>tomname>
<address>Lu Jia Zui roadaddress>
user>
<user>
<name>tomname>
<address>Lu Jia Zui roadaddress>
user>
users>
这里我们写入XML文件,使用的是Jaxb2Marshaller组件,支持XML文件节点名称同bean的属性无需完全一致,使用@XmlElement令两者形成一一对应的关系即可。
这里使用了@XmlRootElement和@XmlElement:
这里Bean的属性名称不必同XML节点名称保持一致。
Bean object如下:
@XmlRootElement(name="user")
public class User{
private String name;
private String address;
@XmlElement(name = "name")
public String getName() {
return name;
}
public void setRName(String name) {
this.name= name;
}
@XmlElement(name = "address")
public String getMarketingProgram() {
return address;
}
public void setAddress(String address) {
this.address= address;
}
同一般的BatchJob相比较,导入XML文件主要由两处需要注意。其一,SpringBatch提供了StaxEventItemWriter写组件。其二,读取数据源需要配置item与java bean的映射关系。
StaxEventItemWriter:负责将Java对象转换为XML记录,有若干属性,必须要设置的有Marshaller,RootTagName,Resource。 他们各自的作用如下图所示。
下图中RootTagName是XML文件中的最大级别的根节点,如本文开头XML文件的==
,而Bean中@XmlRootTag注解则是表征最小对象的标签,如 ==
下图展示了StaxEventItemWriter写入XML文件的逻辑架构图,Marshaller负责将Item对象序列化为XML格式,然后由XMLEventWriter负责将XML字符串以STAX方式写入到文件。
除此之外,StaxEventItemWriter组件还提供了headerCallBack和footerCallBack两个回调函数,能够完成更为复杂的功能。
RowMapper:SpringBatch提供了接口,负责提供Item同Java bean之间的映射。实际开发中只需要自定义映射类,继承该接口即可;
public class UserFieldMapper implements RowMapper<User> {
@Override
public User mapRow(ResultSet rs, int i) throws SQLException {
User regUser = new User();
regUser.setName(rs.getString("name"));
regUser.setAddress(rs.getString("address"));
return regUser;
}
}
以上就是文件导出之前需要准备的配置文件,下面我们进行BatchJob的配置:以从数据库查询数据导入XML文件为例。
//配置BatchJob
@Bean
Job exportUserJob(JobBuilderFactory jobBuilderFactory,Step userToXmlStep) {
return jobBuilderFactory.get("exportuserJob").incrementer(new RunIdIncrementer())
.start(userToXmlStep).build();
}
//配置Step,导出XML文件使用StaxEventItemWriter组件
@Bean
Step userToXmlStep(ItemReader<User> userToXmlItemReader,
StaxEventItemWriter<User> xmlFileItemWriter,
StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("userToXmlStep")
.<User, User>chunk(10)
.reader(userToXmlItemReader)
.writer(xmlFileItemWriter)
.build();
}
//配置ItemReader,
@Bean
@StepScope
ItemReader<User> userToXmlItemReader(DataSource dataSource) {
JdbcPagingItemReader<User> databaseReader = new JdbcPagingItemReader<>();
databaseReader.setDataSource(dataSource);
databaseReader.setPageSize(10);
//!重要:配置数据库到DTO的映射关系
userFieldMapper userFieldMapper = new UserFieldMapper();
databaseReader.setRowMapper(userFieldMapper);
PagingQueryProvider queryProvider = createQueryProvider(jobParameters);
databaseReader.setQueryProvider(queryProvider);
return databaseReader;
}
private PagingQueryProvider createQueryProvider(Map jobParameters) {
MySqlPagingQueryProvider queryProvider = new MySqlPagingQueryProvider();
queryProvider.setSelectClause("SELECT name, address");
queryProvider.setFromClause("FROM user");
queryProvider.setSortKeys(sortByLastActivityDateDesc());
return queryProvider;
}
//Config result order
private Map<String, Order> sortByLastActivityDateDesc() {
Map<String, Order> sortConfiguration = new LinkedHashMap<>();
sortConfiguration.put("name", Order.ASCENDING);
return sortConfiguration;
}
//TODO,这里省略了ItemProcss
//配置ItemWriter
StaxEventItemWriter<User> toXmlItemWriter() {
StaxEventItemWriter<User> writer = new StaxEventItemWriter<>();
//配置文件写入的编码方式
writer.setEncoding("UTF-16");
//配置XML文件的根节点
writer.setRootTagName("Users");
//writer.setHeaderCallback(new HeaderCallback());
//writer.setFooterCallback(new FooterCallback());
writer.setMarshaller(marshaller());
return writer;
}
//配置Marshaller
private Jaxb2Marshaller marshaller() {
Jaxb2Marshaller xml = new Jaxb2Marshaller();
//Item映射到的绑定的Bean
xml.setClassesToBeBound(User.class);
return xml;
}
以上是SpringBatch导出数据到XML文件的基本开发技术。
在实际的开发过程中,也会遇到各种各样的问题,在这里仅介绍文件的XML文件的缩进的问题。
问题描述:项目开发中,导出的XML文件都写在了一行,并没有实现分行与格式缩进,试了设置Jaxb2Marshaller 的格式Marshaller.JAXB_FORMATTED_OUTPUT属性,都不生效。最终找到了如下的解决方案。
解决方案:自定义StaxEventItemWriter,借助带有缩进功能的IndentingXMLEventWriter改写XML文件的写组件。
核心代码如下:
//自定义带有缩进功能的StaxEventItemWriter XML文件写组件;
public class IndentingStaxEventItemWriter<T> extends StaxEventItemWriter<T> {
private boolean indent = true;
@Override
protected XMLEventWriter createXmlEventWriter(XMLOutputFactory outputFactory, Writer writer) throws XMLStreamException {
if (indent) {
return new IndentingXMLEventWriter( super.createXmlEventWriter( outputFactory, writer ) );
} else {
return super.createXmlEventWriter( outputFactory, writer );
}
}
public boolean isIndent() {
return indent;
}
public void setIndent(boolean indent) {
this.indent = indent;
}
}
//改写上面的ItemWriter,将StaxEventItemWriter替换成带有缩进的写 IndentingStaxEventItemWriter
@Bean
@StepScope
IndentingStaxEventItemWriter<User> userToXmlItemWriter() {
IndentingStaxEventItemWriter<Registration> writer = new IndentingStaxEventItemWriter<>();
writer.setEncoding("UTF-16");
writer.setRootTagName("Users");
writer.setMarshaller(marshaller());
String exportFilePath = sftpBiz.getOutTempDir();
writer.setResource("D://exportData.xml"));
return writer;
}
值得注意的是,上面的功能改写,需要借助stax-utils.jar;pom.xml导入jar。
<dependency>
<groupId>net.java.dev.stax-utils</groupId>
<artifactId>stax-utils</artifactId>
<version>20070216</version>
</dependency>
有的时候,基于项目的需要,可能要写入的XML文档结构较为复杂,如多
- https://docs.spring.io/spring-batch/trunk/reference/htmlsingle/
https://www.consulting-bolte.de/index.php/java-se-ee/java-ee/31-spring/jaxb/169-pretty-print-xml-using-spring-and-jaxb-2-0
https://www.tutorialspoint.com/spring_batch/spring_batch_mysql_to_xml.htm
http://websystique.com/springbatch/spring-batch-read-a-csv-file-and-write-to-an-xml-file/
本文中涉及的代码都是核心功能的介绍,不是完整的项目代码,本文示例代码都托管在GitHub;若有需要,可以在评论区留言,或联系作者QQ370731702.。
基于以上的分享技术点,欢迎同行的评论,留言和扶正。