Spring Batch技术问询:如何实现ItemWriter接收定制项、写入指定字段及ItemProcessor返回定制数据
Hey there! Let's break down your questions step by step—both are common scenarios in Spring Batch, and there are straightforward solutions for each.
1. How to Make ItemWriter Accept Customized Items Instead of Raw Objects
The core idea here is using an ItemProcessor to transform your original Record object into a customized type (like a lightweight DTO with only the fields you need). Spring Batch natively supports type transformation in processors, so the writer can directly consume this tailored output.
First, create a simplified DTO for the fields you care about:
public class RecordExportDTO { private String ordNo; private String ordDate; // Constructor, getters (use Lombok to reduce boilerplate if you want) public RecordExportDTO(String ordNo, String ordDate) { this.ordNo = ordNo; this.ordDate = ordDate; } public String getOrdNo() { return ordNo; } public String getOrdDate() { return ordDate; } }
Then modify your processor to return this DTO instead of the full Record:
public class RecordTableProcessor implements ItemProcessor<Record, RecordExportDTO> { @Override public RecordExportDTO process(Record item) throws Exception { // Add your existing business logic here, then map to the DTO return new RecordExportDTO(item.getOrdNo(), item.getOrdDate()); } }
Now your FlatFileItemWriter can be configured to work with RecordExportDTO directly, focusing only on the fields in the DTO.
2. Writing Only Specific Fields to Flat File (Two Practical Approaches)
You have two solid options here, depending on whether you want to keep using the full Record in your processor or switch to a simplified DTO.
Approach 1: Keep the Full Record, Configure Writer to Extract Target Fields
If you need to retain the full Record for other processing steps, you can configure the FlatFileItemWriter to ignore extra fields and only output ordNo and ordDate.
Use a BeanWrapperFieldExtractor to specify which fields to include, paired with a DelimitedLineAggregator for CSV-style output:
@Bean public FlatFileItemWriter<Record> recordWriter() { FlatFileItemWriter<Record> writer = new FlatFileItemWriter<>(); writer.setResource(new FileSystemResource("output/records.csv")); // Define which fields to extract from the Record object BeanWrapperFieldExtractor<Record> fieldExtractor = new BeanWrapperFieldExtractor<>(); fieldExtractor.setNames(new String[]{"ordNo", "ordDate"}); fieldExtractor.afterPropertiesSet(); // Required to initialize the extractor // Format extracted fields into a delimited line DelimitedLineAggregator<Record> lineAggregator = new DelimitedLineAggregator<>(); lineAggregator.setDelimiter(","); lineAggregator.setFieldExtractor(fieldExtractor); writer.setLineAggregator(lineAggregator); writer.setHeaderCallback(writer1 -> writer1.write("ordNo,ordDate")); // Optional header row return writer; }
This setup makes the writer ignore all other fields in Record and only write the two you specified.
Approach 2: Use the Simplified DTO from the First Question
If you already modified the processor to return RecordExportDTO, the writer configuration becomes cleaner because the DTO only contains the fields you need. You can use the same aggregator approach (with fewer fields) or even a PassThroughLineAggregator if you handle formatting in the DTO's toString():
Option A: Explicit Field Mapping
@Bean public FlatFileItemWriter<RecordExportDTO> recordWriter() { FlatFileItemWriter<RecordExportDTO> writer = new FlatFileItemWriter<>(); writer.setResource(new FileSystemResource("output/records.csv")); DelimitedLineAggregator<RecordExportDTO> lineAggregator = new DelimitedLineAggregator<>(); lineAggregator.setDelimiter(","); BeanWrapperFieldExtractor<RecordExportDTO> fieldExtractor = new BeanWrapperFieldExtractor<>(); fieldExtractor.setNames(new String[]{"ordNo", "ordDate"}); fieldExtractor.afterPropertiesSet(); lineAggregator.setFieldExtractor(fieldExtractor); writer.setLineAggregator(lineAggregator); writer.setHeaderCallback(writer1 -> writer1.write("ordNo,ordDate")); return writer; }
Option B: Use toString() for Formatting
Override toString() in RecordExportDTO:
// Inside RecordExportDTO @Override public String toString() { return ordNo + "," + ordDate; }
Then simplify the writer config:
writer.setLineAggregator(new PassThroughLineAggregator<>());
Which Approach to Pick?
- Go with Approach 1 if you need the full
Recordfor other parts of your batch job (e.g., additional processors or listeners) and only need to limit fields for writing. - Choose Approach 2 if you want cleaner, more maintainable code—using a DTO ensures only necessary fields are passed to the writer, reducing errors if the
Recordclass changes later.
内容的提问来源于stack exchange,提问作者Prathviraj Singh Chouhan

