Appearance
Spring Batch FlatFileItemWriter 详解教程
📌 本文将通过生动易懂的方式,全面讲解 Spring Batch 中的
FlatFileItemWriter
组件,帮助初学者掌握文件写入的核心技术
🧩 一、FlatFileItemWriter 概述
1.1 文件写入的挑战
写入平面文件面临的核心问题与文件读取类似:
- 需要支持分隔符格式和固定宽度格式
- 必须确保事务性写入(在批处理失败时能回滚)
- 需要处理文件创建、覆盖等文件系统操作
1.2 核心组件关系
🔧 二、核心组件解析
2.1 LineAggregator 接口
LineAggregator
负责将单个对象转换为可写入文件的字符串:
kotlin
interface LineAggregator<T> {
fun aggregate(item: T): String
}
TIP
LineAggregator
是 LineTokenizer
的逻辑逆操作:
LineTokenizer
: 字符串 → FieldSetLineAggregator
: 对象 → 字符串
PassThroughLineAggregator
最简单的实现,直接调用对象的 toString()
方法:
kotlin
class PassThroughLineAggregator<T> : LineAggregator<T> {
override fun aggregate(item: T): String {
return item.toString()
}
}
NOTE
当您需要直接控制字符串生成但仍需事务支持时,此实现非常有用
2.2 FieldExtractor 接口
负责将对象转换为字段数组,供 LineAggregator
使用:
kotlin
interface FieldExtractor<T> {
fun extract(item: T): Array<Any>
}
BeanWrapperFieldExtractor
最常用的实现,通过反射获取对象属性:
kotlin
val extractor = BeanWrapperFieldExtractor<Name>().apply {
names = arrayOf("firstName", "lastName", "age")
}
val name = Name("张", "三", 30)
val values = extractor.extract(name)
// 结果:["张", "三", 30]
IMPORTANT
names
属性顺序决定了字段在输出文件中的排列顺序
🚀 三、文件写入实战
3.1 基础文件写入
最简单的配置示例:
kotlin
@Bean
fun simpleItemWriter(): FlatFileItemWriter<Any> {
return FlatFileItemWriterBuilder<Any>()
.name("simpleItemWriter")
.resource(FileSystemResource("output/data.txt"))
.lineAggregator(PassThroughLineAggregator())
.build()
}
TIP
此配置适合直接写入字符串或简单对象
3.2 分隔符文件写入
写入 CSV 等分隔符格式文件:
kotlin
@Bean
fun csvItemWriter(): FlatFileItemWriter<Customer> {
val extractor = BeanWrapperFieldExtractor<Customer>().apply {
names = arrayOf("name", "email", "joinDate")
}
return FlatFileItemWriterBuilder<Customer>()
.name("customerWriter")
.resource(FileSystemResource("output/customers.csv"))
.delimited()
.delimiter(",")
.names("name", "email", "joinDate")
.build()
}
kotlin
@Bean
fun csvItemWriterShort(): FlatFileItemWriter<Customer> {
return FlatFileItemWriterBuilder<Customer>()
.name("customerWriter")
.resource(FileSystemResource("output/customers.csv"))
.delimited()
.delimiter("|")
.names("id", "name", "creditScore")
.build()
}
3.3 固定宽度文件写入
适用于银行对账单等需要严格对齐的场景:
kotlin
@Bean
fun fixedWidthWriter(): FlatFileItemWriter<Transaction> {
val extractor = BeanWrapperFieldExtractor<Transaction>().apply {
names = arrayOf("account", "amount", "date")
}
val aggregator = FormatterLineAggregator<Transaction>().apply {
fieldExtractor = extractor
format = "%-15s%10.2f%8td/%<tm/%<tY"
}
return FlatFileItemWriterBuilder<Transaction>()
.name("transactionWriter")
.resource(FileSystemResource("output/transactions.txt"))
.lineAggregator(aggregator)
.build()
}
kotlin
@Bean
fun fixedWidthWriterShort(): FlatFileItemWriter<Transaction> {
return FlatFileItemWriterBuilder<Transaction>()
.name("transactionWriter")
.resource(FileSystemResource("output/transactions.txt"))
.formatted()
.format("%-15s%10.2f%8td/%<tm/%<tY")
.names("account", "amount", "date")
.build()
}
NOTE
格式化字符串说明:
%-15s
:左对齐字符串,宽度15字符%10.2f
:10位宽浮点数,保留2位小数%8td/%<tm/%<tY
:日期格式(日/月/年)
⚙️ 四、高级配置技巧
4.1 文件创建处理
控制文件创建行为:
kotlin
@Bean
fun smartFileWriter(): FlatFileItemWriter<Any> {
return FlatFileItemWriterBuilder<Any>()
.name("smartWriter")
.resource(FileSystemResource("output/smart.txt"))
.lineAggregator(PassThroughLineAggregator())
.append(true) // [!code highlight] // 追加模式
.shouldDeleteIfEmpty(true) // [!code highlight] // 空文件时删除
.shouldDeleteIfExists(false) // [!code highlight] // 不覆盖现有文件
.build()
}
WARNING
重启作业时的文件处理策略:
- 默认:文件存在时追加写入
- 设置
shouldDeleteIfExists=true
:重启时删除并重建文件
4.2 自定义格式转换
实现自定义字段转换逻辑:
kotlin
class StatusFormatter : FieldExtractor<Order> {
override fun extract(item: Order): Array<Any> {
return arrayOf(
item.orderId,
item.amount,
when (item.status) {
"PENDING" -> "待处理"
"SHIPPED" -> "已发货"
else -> "未知状态"
}
)
}
}
@Bean
fun customFormatWriter(): FlatFileItemWriter<Order> {
return FlatFileItemWriterBuilder<Order>()
.name("orderWriter")
.resource(FileSystemResource("output/orders.csv"))
.delimited()
.delimiter(",")
.fieldExtractor(StatusFormatter())
.build()
}
🏁 五、总结与最佳实践
组件 | 适用场景 | 推荐实现 |
---|---|---|
LineAggregator | 对象→字符串转换 | FormatterLineAggregator |
FieldExtractor | 对象→字段数组 | BeanWrapperFieldExtractor |
文件格式 | 数据特点 | 配置方式 |
分隔符 | 变长字段 | .delimited().delimiter(",") |
固定宽度 | 严格对齐 | .formatted().format(...) |
IMPORTANT
最佳实践建议:
- 优先使用
FlatFileItemWriterBuilder
的流畅API - 复杂格式使用
FormatterLineAggregator
- 生产环境务必设置
shouldDeleteIfExists
策略 - 大文件写入启用缓冲(默认开启)
kotlin
// 完整最佳实践示例
@Bean
fun optimalFileWriter(): FlatFileItemWriter<Customer> {
return FlatFileItemWriterBuilder<Customer>()
.name("optimalWriter")
.resource(FileSystemResource("output/optimal.csv"))
.delimited()
.delimiter("|")
.names("id", "name", "email", "joinDate")
.headerCallback { writer -> // [!code highlight] // 写文件头
writer.write("ID|姓名|邮箱|注册日期")
}
.footerCallback { writer -> // [!code highlight] // 写文件尾
writer.write("生成时间:${LocalDateTime.now()}")
}
.shouldDeleteIfExists(true)
.transactional(false) // [!code highlight] // 禁用事务获得更高性能
.build()
}
通过本教程,您已掌握 Spring Batch 文件写入的核心技术。接下来可以尝试:
- 实现多格式文件导出
- 结合 Spring Cloud Task 创建文件导出微服务
- 添加文件加密功能增强安全性
⚡️ 行动建议:立即在您的项目中添加一个文件导出功能,实践本教程中的技术!