【问题标题】:Spring Batch Json custom ItemWriterSpring Batch Json 自定义 ItemWriter
【发布时间】:2016-05-25 16:36:09
【问题描述】:

我想从数据库中写入 json 格式的文件。 我有这个ItemWriter实现的原型,很简单。

import java.util.ArrayList;
import java.util.List;

import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.item.ItemWriter;
import org.springframework.core.io.Resource;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class CustomItemWriter<T> implements ItemWriter<T>, StepExecutionListener {
    private Gson gson;
    private Resource resource;
    private boolean shouldDeleteIfExists = true;
    private List<T> allItems = new ArrayList<T>();

    @Override
    public void write(List<? extends T> items) throws Exception {
        System.out.println("this is the begin " + items.size());
        allItems.addAll(items);
    }

    public Resource getResource() {
        return resource;
    }

    public void setResource(Resource resource) {
        this.resource = resource;
    }

    public boolean isShouldDeleteIfExists() {
        return shouldDeleteIfExists;
    }

    public void setShouldDeleteIfExists(boolean shouldDeleteIfExists) {
        this.shouldDeleteIfExists = shouldDeleteIfExists;
    }

    @Override
    public ExitStatus afterStep(StepExecution arg0) {
        //write ALL to the output file
        System.out.println(gson.toJson(allItems)); 
        return null;
    }

    @Override
    public void beforeStep(StepExecution arg0) {
        gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").disableHtmlEscaping().create();
    }
}

这里解决的问题是,write 方法向输出文件中的每个commitInterval 发送一个 JSON 数组,我只想在我的文件中有一个唯一的 JSON 数组。

在步骤运行后实现StepExecutionListener;我可以将整个数组发送到输出文件并将其转换为 JSON,然后将其写入输出文件(很好!)。

我的问题是,这是正确的方法吗?我认为每个commitInterval 都写入文件有好处,但我不确定我的解决方案。它有效,但我不想解决这个问题并激怒另一个问题。

【问题讨论】:

    标签: java json spring-batch


    【解决方案1】:

    您希望实际使用每个块刷新对文件的写入,否则您将失去可重新启动性。

    假设您对每行一个 JSON 对象没问题,我可能只会使用 FlatFileItemWriter 与自定义 LineAggregator 组合,将每个对象转换为 JSON 字符串。大致如下:

    public class JsonLineAggregator<T> implements LineAggregator<T>, StepExecutionListener {
    
        private Gson gson = new Gson();
        private boolean isFirstObject = true;
    
        @Override
        public String aggregate(final T item) {
            if (isFirstObject) {
                isFirstObject = false;
                return "[" + gson.toJson(item);
            }
            return "," + gson.toJson(item);
        }
    
        public void setGson(final Gson gson) {
            this.gson = gson;
        }
    
        @Override
        public void beforeStep(final StepExecution stepExecution) {
            if (stepExecution.getExecutionContext().containsKey("isFirstObject")) {
                isFirstObject = Boolean.parseBoolean(stepExecution.getExecutionContext().getString("isFirstObject"));
            }
        }
    
        @Override
        public ExitStatus afterStep(final StepExecution stepExecution) {
            stepExecution.getExecutionContext().putString("isFirstObject", Boolean.toString(isFirstObject));
            return null;
        }
    }
    

    编辑:更新了上面的 LineAggregator 实现,以演示如何让它输出看起来像 JSON 列表的东西。

    请注意,您还需要将FlatFileFooterCallback 注册到您的FlatFileItemWriter,并添加最后的“]”。

    public class JsonFlatFileFooterCallback implements FlatFileFooterCallback {
    
        @Override
        public void writeFooter(final Writer writer) throws IOException {
            writer.write("]");
        }
    }
    

    【讨论】:

    • 每行有很多 JSON 对象,我需要始终将数组写入文件,这样可以吗?
    • 不确定我是否理解您的问题...在write(List&lt;T&gt; items) 方法中传递给作者的每个通用类型T 的“项目”都将使用此设置在您的文件中获得自己的行跨度>
    • 在上面的答案中添加了详细信息,向您展示如何使最终输出看起来像 JSON 列表(我认为这就是您所要求的)
    • 好的,生成的文件有 n 个对象行,我的实现将所有对象写在一行中,但我喜欢你的解决方案,因为 commitInterval 不会失去它的原因。
    • 如果希望全部在一行,可以将FlatFileItemWriter上的lineSeparator设置为空字符串。
    【解决方案2】:

    感谢您的解决方案。

    在 Xml 中你可以这样添加。

        <property name="resource" value="file:opt/output.json" />  <!--  #{jobParameters['input.file.name']} -->
        <property name="shouldDeleteIfExists" value="true" />
    
        <property name="lineAggregator">
            <bean
                class="com.package.JsonLineAggregator">
            </bean>
        </property>
    
    </bean> 
    

    【讨论】:

      猜你喜欢
      • 2021-07-15
      • 2014-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-18
      相关资源
      最近更新 更多