Spring Batch4 教程

Spring Batch4 实现数据写入XML文件 StaxEventItemWriter

在 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-oxmxstream 依赖,如下:

<!-- 从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);
    }

}

运行项目,输出日志如下图:

image.png

上图中,成功读取了四行数据。

再到 F 盘看看是否创建了 users.xml 文件,查看其内容,如下图:

image.png

到这里,你已经学会如何将数据写入到 XML 文件。

更多关于 StaxEventItemWriter 类的用法,请参考官方文档。

 

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号