Spring Batch如何处理输出项多于输入项的嵌套JSON批处理场景?
你现在用自定义ItemProcessor加复杂FlatFileItemWriter的路子是通的,但针对这种一对多的嵌套展开场景,Spring Batch有更简洁的玩法,不用自己硬扛复杂逻辑:
1. 让ItemProcessor直接返回集合拆分
Spring Batch支持ItemProcessor返回List<?>类型,框架会自动把集合里的元素拆成单个Item传递给Writer,不用你自己在Processor里做复杂的遍历处理。示例代码:
public class NestedJsonProcessor implements ItemProcessor<ParentDto, List<ChildDto>> { @Override public List<ChildDto> process(ParentDto parent) { // 直接返回嵌套的子对象列表,框架自动拆成单个ChildDto给后续Writer return parent.getChildren(); } }
这样Writer只需要处理单个子对象,配置会简化一大截,不用再在Writer里处理嵌套结构的解析。
2. 用CompositeItemProcessor拆分+转换分离职责
如果拆分后还需要对子对象做字段转换、格式处理,用CompositeItemProcessor把拆分和转换逻辑分开,代码更清晰:
CompositeItemProcessor<ParentDto, ChildDto> compositeProcessor = new CompositeItemProcessor<>(); compositeProcessor.setDelegates(Arrays.asList( // 第一个处理器负责拆分 parent -> parent.getChildren(), // 第二个处理器负责子对象的转换 child -> { child.setFormattedCreateTime(new SimpleDateFormat("yyyy-MM-dd").format(child.getCreateTime())); return child; } ));
这种拆分职责的写法,后续维护起来也更方便,不用在一个Processor里堆一堆逻辑。
3. 简化FlatFileItemWriter配置
之前Writer配置复杂,核心原因是要在Writer里处理拆分后的多元素输出。现在拆分逻辑移到Processor后,Writer只需要专注于单个Item的输出,配置会非常清爽:
new FlatFileItemWriterBuilder<ChildDto>() .name("childItemWriter") .resource(new FileSystemResource("output.csv")) .delimited() .names("id", "childName", "formattedCreateTime") .build();
进阶玩法:读取阶段直接拆分
如果你的输入是JSON文件,还可以用Spring Batch的JsonItemReader配合Jackson的自定义反序列化,在读取阶段就把嵌套结构拆成单个子对象,连Processor的拆分逻辑都省了。比如自定义Jackson反序列化器,把父对象里的子列表直接拆成多个子对象输出;或者如果JSON结构允许,用@JsonUnwrapped注解直接反序列化为子对象列表。示例配置:
new JsonItemReaderBuilder<ChildDto>() .resource(new FileSystemResource("input.json")) .jsonObjectReader(new JacksonJsonObjectReader<>(ChildDto.class)) .build();
这个方式适合输入JSON结构比较规整的场景,能进一步简化整个批处理流程。
内容的提问来源于stack exchange,提问作者Nathan Lively

