在 Spring Batch 4 中,StaxEventItemWriter 是一个用于将数据项写入 XML 文件的 ItemWriter 实现,它基于 STAX(Streaming API for XML)技术,适合处理大型 XML 文件,具有内存效率高的特点。
StaxEventItemWriter 类的核心特性:
流式 XML 处理:基于 STAX 的 XMLStreamWriter 进行写入,不会将整个 XML 文档加载到内存,而是逐元素生成,适合处理大数据量场景,避免内存溢出。
灵活的 XML 结构配置:可自定义根元素、记录元素(每个数据项对应的 XML 标签)等结构,支持自定义编码和 XML 格式。例如:
StaxEventItemWriter<User> writer = new StaxEventItemWriter<>(); try { XStreamMarshaller marshaller = new XStreamMarshaller(); Map<String, Class> aliases = new HashMap<>(); aliases.put("my-user", User.class); marshaller.setAliases(aliases); // 5.2 启用格式化输出(需XStream配置) XStream xstream = marshaller.getXStream(); xstream.autodetectAnnotations(true); xstream.setMode(XStream.NO_REFERENCES); writer.setMarshaller(marshaller); writer.setRootTagName("users"); // 自定义根元素名 writer.setEncoding("GBK"); // 配置XML编码(默认UTF-8),支持中文编码 writer.setResource(new FileSystemResource("f://users.xml")); // 设置文件路径 writer.afterPropertiesSet(); } catch (Exception e) { e.printStackTrace(); }
对象 → XML 转换:依赖 Marshaller(如 JAXB、XStream 等)将 Java 对象转换为 XML 元素,无需手动拼接 XML 字符串。
事务支持:遵循 Spring Batch 的事务管理机制,确保在批处理过程中出现异常时,能正确回滚未完成的写入操作。
该示例将从 resource 目录下名为 users.csv 文件读取数据,然后使用 StaxEventItemWriter 类将数据写入到 F:\users.xml 文件。
由于我们需要使用 XStreamMarshaller 序列化器,因此需要引入 spring-oxm 和 xstream 依赖,如下:
<!-- 从XML读取数据,StaxEventItemReader 需要依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.7</version> </dependency>
其中:
spring-oxm 定义了 Marshaller(对象 → XML)和 Unmarshaller(XML → 对象)标准接口,屏蔽底层实现差异(如 JAXB、XStream 等)。
xstream 提供高效的序列化/反序列化实现,无需 XML Schema 或注解配置。支持自定义字段别名、集合映射,轻量级且性能较好。
在项目的 resources 目录下面创建名为 users.csv 的文件,内容如下:
"id","username","password" 1,张三,"13BC03AC29FAC7B29736EC3BE5C2F55A" 2,李四,"5E5994FBCFA922D804DF45295AE98604" 3,王五,"6C14DA109E294D1E8155BE8AA4B1CE8E" 4,赵六,"03774AD7979A5909E78F9C9DB3A2F0B2"
创建一个简单的 POJO 用于映射 csv 读取的每一行数据,如下:
package com.hxstrive.spring_batch.staxItemWriterDemo.dto; import lombok.Data; import lombok.ToString; /** * 用户DTO * @author hxstrive.com */ @Data @ToString public class User { private int id; private String username; private String password; }
使用 @Configuration 注解创建配置类,配置 Spring Batch 的 Job、Step、ItemReader 和 ItemWriter,代码如下:
package com.hxstrive.spring_batch.staxItemWriterDemo.config; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.hxstrive.spring_batch.staxItemWriterDemo.dto.User; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.FlatFileItemWriter; import org.springframework.batch.item.file.mapping.DefaultLineMapper; import org.springframework.batch.item.file.mapping.FieldSetMapper; import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; import org.springframework.batch.item.file.transform.FieldSet; import org.springframework.batch.item.file.transform.LineAggregator; import org.springframework.batch.item.xml.StaxEventItemWriter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.oxm.xstream.XStreamMarshaller; import org.springframework.validation.BindException; import java.util.HashMap; import java.util.Map; /** * Spring Batch 配置类 * @author hxstrive.com */ @Configuration public class BatchConfig { // 用于创建和配置 Job 对象的工厂类 @Autowired private JobBuilderFactory jobBuilderFactory; // 用于创建和配置 Step 对象的工厂类 @Autowired private StepBuilderFactory stepBuilderFactory; // 创建Job对象 @Bean public Job staxEventItemWriterDemoJob() { return jobBuilderFactory.get("staxEventItemWriterDemoJob-" + System.currentTimeMillis()) .start(staxEventItemWriterDemoStep()) .build(); } // 创建Step对象 @Bean public Step staxEventItemWriterDemoStep() { return stepBuilderFactory.get("staxEventItemWriterDemoStep") .<User, User>chunk(2) .reader(flatFileItemReader()) .writer(xmlItemWriter()) .build(); } // 创建ItemReader对象 @Bean @StepScope //将 Bean 的生命周期与 Step 执行上下文 绑定 public FlatFileItemReader<? extends User> flatFileItemReader() { FlatFileItemReader<User> reader = new FlatFileItemReader<>(); reader.setResource(new ClassPathResource("users.csv")); reader.setLinesToSkip(1); // 跳过文件第一行,因为第一行是字段名 // 解析数据 DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(); tokenizer.setNames("id", "username", "password"); // 把解析出的数据映射到 User 对象中 DefaultLineMapper<User> lineMapper = new DefaultLineMapper<>(); lineMapper.setLineTokenizer(tokenizer); lineMapper.setFieldSetMapper(new FieldSetMapper<User>(){ @Override public User mapFieldSet(FieldSet fieldSet) throws BindException { // 将读取的每行数据,转换成一个个 User 对象 User user = new User(); user.setId(fieldSet.readInt("id")); user.setUsername(fieldSet.readString("username")); user.setPassword(fieldSet.readString("password")); System.out.println("reading user: " + user); return user; } }); lineMapper.afterPropertiesSet(); reader.setLineMapper(lineMapper); return reader; } // 创建ItemWriter对象【关键方法】 @Bean public StaxEventItemWriter<? super User> xmlItemWriter() { System.out.println("xmlItemWriter()"); StaxEventItemWriter<User> writer = new StaxEventItemWriter<>(); try { XStreamMarshaller marshaller = new XStreamMarshaller(); Map<String, Class> aliases = new HashMap<>(); aliases.put("user", User.class); marshaller.setAliases(aliases); writer.setMarshaller(marshaller); writer.setRootTagName("users"); writer.setResource(new FileSystemResource("f://users.xml")); writer.afterPropertiesSet(); } catch (Exception e) { e.printStackTrace(); } return writer; } }
上述配置,我们重点查看 xmlItemWriter() 方法,该方法创建并配置了一个 StaxEventItemWriter,用于将数据以 XML 格式写入文件。代码详细说明:
(1)方法定义,返回一个 StaxEventItemWriter 实例,泛型指定为 ? super User,表示它可以处理 User 类型及其父类的对象。
public StaxEventItemWriter<? super User> xmlItemWriter()
(2)实例化 StaxEventItemWriter,并指定处理 User 类型的对象。
StaxEventItemWriter<User> writer = new StaxEventItemWriter<>();
(3)使用 XStream 库进行对象到 XML 的转换(XStream 是一个简单的 XML 序列化工具)。通过别名映射,将 User 类在 XML 中显示为 <user> 标签(而非全类名),如下:
// 配置XML元素别名映射 // key: XML元素名, value: 对应的Java类 Map<String, Class> aliases = new HashMap<>(); aliases.put("user", User.class); // 将 <User> 对象映射为 <user> XML元素 marshaller.setAliases(aliases);
(4)配置写入器核心参数:
writer.setMarshaller(marshaller); // 设置XML序列化器 writer.setRootTagName("users"); // 设置XML根标签名为<users> writer.setResource( // 设置输出文件路径 new FileSystemResource("f://users.xml") // 写入F盘users.xml文件 ); // 初始化检查(Spring生命周期回调) writer.afterPropertiesSet(); // 验证必要属性是否已设置
老样子,仅在 Spring Boot 启动类上多添加 @EnableBatchProcessing 注解,开启批处理功能。代码如下:
package com.hxstrive.spring_batch.staxItemWriterDemo; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing // 开启批处理 public class SpringBatchDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchDemoApplication.class, args); } }
运行项目,输出日志如下图:
上图中,成功读取了四行数据。
再到 F 盘看看是否创建了 users.xml 文件,查看其内容,如下图:
到这里,你已经学会如何将数据写入到 XML 文件。
更多关于 StaxEventItemWriter 类的用法,请参考官方文档。