Spring Batch解析上传XML需先将MultipartFile转为临时文件或ByteArrayResource,再通过FileSystemResource或ByteArrayResource注入XmlItemReader;Jaxb2Marshaller须正确配置类绑定与命名空间支持;并发场景下需用UUID生成唯一临时文件并在afterStep中显式清理。
Spring Batch 本身不直接支持“上传即处理”的HTTP请求流程,XmlItemReader 只能读取本地文件路径或 InputStream,不能自动绑定 Spring MVC 的 MultipartFile。必须手动把上传的 MultipartFile 转成 InputStream 或临时文件,再注入到 reader 中。
XmlItemReader 使用 MultipartFile.getInputStream()
XmlItemReader 的 setResource() 接收的是 Resource 类型,而 MultipartFile 的 getInputStream() 是一次性流,无法重复读取 —— 这会导致 job 启动时 reader 初始化失败(因为 Spring Batch 在启动阶段会预校验 resource 是否可访问)。
new InputStreamResource(multipartFile.getInputStream()),它不支持 isReadable() 或 getFile()
MultipartFile 写入临时 File,再用 FileSystemResource 包装ByteArrayResource(适合小文件),但需注意内存占用和 reader 初始化时机File tempFile = File.createTempFile("batch-", ".xml");
multipartFile.transferTo(tempFile);
XmlItemReader reader = new XmlItemReader<>();
reader.setResource(new FileSystemResource(tempFile));
reader.setUnmarshaller(jaxb2Marshaller());
// ⚠️ 记得在 job 执行完后 deleteOnExit() 或显式清理
Jaxb2Marshaller 配置要注意什么XML 解析依赖 JAXB,如果实体类没加正确注解,或包路径未注册,UnmarshallingFailureException 会静默吞掉原始错误(只报 “Unable to unmarshal”),调试困难。
@XmlRootElement(或 @XmlType + @XmlAccessorType)Jaxb2Marshaller 必须设置 setClassesToBeBound(MyRecord.class),不能只靠包扫描setSupportJaxbElementClass(true) 并处理 QName
jakarta.xml.bind:jakarta.xml.bind-api 和 org.glassfish.jaxb:jaxb-runtime
上传接口被并发调用时,多个 job 实例若共用同一临时文件名,或未及时删除,会导致读取失败或磁盘爆满。
File.createTempFile("batch-" + UUID.randomUUID(), ".xml")
tempFile.deleteOnExit() —— 它只在 JVM 退出时触发,batch job 可能长期运行StepExecutionListener.afterStep() 中显式 tempFile.delete(),并 try-catch 防止中断遗漏org.springframework.util.StreamUtils.copy() 把 MultipartFile 读进 ByteArrayInputStream,再用 ByteArrayResource,绕过文件系统(仅限 MB 级以下)