How to read ini file in spring batch (key=value)

北战南征 提交于 2019-12-08 04:14:06

问题


I want to create a batch using Spring batch to read from an ini file and save the data in database but when I chekced the org.springframework.batch.item.file.FlatFileItemReader class I didn't find a way to parse my data from the ini file , I tried to combine the ini4j API with the spring batch but no result

my ini file :

 [Cat]
    a=1
    b= 2
    c= 3
    d= 4
    e= 5
    f= 6
    [Cat2]
     a=11
    b= 21
    c= 31
    d= 41
    e= 51
    f= 61

回答1:


What you can do is define your own ItemStreamReader that wraps a delegate ItemStreamReader, which is just a FlatFileItemReader that uses a PatternMatchingCompositeLineMapper as the line mapper. In your ItemStreamReader, loop to read lines from your delegate and if the line is an instance of a Property domain object then add it to a list in a Section domain object. What the PatternMatchingCompositeLineMapper allows you do do is check the line for a pattern match, and pass it to the right tokenizer and fieldSetMapper for the job.

Doing it this way will allow you to read multiple lines into one Section domain object that holds a List<Property>.

public class Section {

    private String name;
    private List<Property> properties;
    // getters and setters

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(name);
        for (Property prop: properties) {
            sb.append("," + prop.getKey() + "=" + prop.getValue());
        }
        return sb.toString();
    }
}

public class Property {

    private String key;
    private String value;
    // getters and setters
}

For you custom ItemStreamReader you would do this. You can see that the reading is delegated to another reader, which you will define later

import java.util.ArrayList;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemStreamReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;

public class IniFileItemReader implements ItemStreamReader<Object> {

    private Object curItem = null;
    private ItemStreamReader<Object> delegate;

    @Override
    public Object read() throws Exception, UnexpectedInputException,
            ParseException, NonTransientResourceException {
        if (curItem == null) {
            curItem = (Section) delegate.read();
        }

        Section section = (Section) curItem;
        curItem = null;

        if (section != null) {
            section.setProperties(new ArrayList<Property>());

            while (peek() instanceof Property) {
                section.getProperties().add((Property) curItem);
                curItem = null;
            }
        }
        return section;
    }

    private Object peek() throws Exception {
        if (curItem == null) {
            curItem = delegate.read();
        }
        return curItem;
    }

    public void setDelegate(ItemStreamReader<Object> delegate) {
        this.delegate = delegate;
    }

    @Override
    public void close() throws ItemStreamException {
        delegate.close();
    }

    @Override
    public void open(ExecutionContext arg0) throws ItemStreamException {
        delegate.open(arg0);
    }

    @Override
    public void update(ExecutionContext arg0) throws ItemStreamException {
        delegate.update(arg0);
    }
}

Then in your config you define the deleagte reader with the PatternMatchingCompositeLineMapper

<bean id="inputFile" class="org.springframework.core.io.FileSystemResource"
    scope="step">
    <constructor-arg value="#{jobParameters[inputFile]}"></constructor-arg>
</bean>

<bean id="sectionFileReader"
    class="com.underdogdevs.springbatch.reader.IniFileItemReader">
    <property name="delegate" ref="trueSectionFileReader"></property>
</bean>
<bean id="trueSectionFileReader"
    class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="lineMapper">
        <bean
            class="org.springframework.batch.item.file.mapping.PatternMatchingCompositeLineMapper">
            <property name="tokenizers">
                <map>
                    <entry key="[*" value-ref="sectionLineTokenizer">
                    </entry>
                    <entry key="*" value-ref="propertyLineTokenizer"></entry>
                </map>
            </property>
            <property name="fieldSetMappers">
                <map>
                    <entry key="[*" value-ref="sectionFieldSetMapper">
                    </entry>
                    <entry key="*" value-ref="propertyFieldSetMapper">
                    </entry>
                </map>
            </property>
        </bean>
    </property>
    <property name="resource" ref="inputFile"></property>
</bean>

<bean id="sectionLineTokenizer"
    class="com.underdogdevs.springbatch.tokenizer.SectionLineTokenizer">
</bean>

<bean id="sectionFieldSetMapper"
    class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
    <property name="prototypeBeanName" value="section"></property>
</bean>

<bean id="section" class="com.underdogdevs.springbatch.domain.Section"
    scope="prototype">
</bean>

<bean id="propertyLineTokenizer"
    class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
    <property name="delimiter" value="="></property>
    <property name="names" value="key,value"></property>
</bean>

<bean id="propertyFieldSetMapper"
    class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
    <property name="prototypeBeanName" value="property"></property>
</bean>

<bean id="property" class="com.underdogdevs.springbatch.domain.Property"
    scope="prototype">
</bean>

You see that I also used a custom LineTozenizer. I probably could've just used a DelimitedLineTokenizer, but by the time I realized it, I had already defined the class

import org.springframework.batch.item.file.transform.DefaultFieldSetFactory;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.batch.item.file.transform.FieldSetFactory;
import org.springframework.batch.item.file.transform.LineTokenizer;

public class SectionLineTokenizer implements LineTokenizer {

    private final String nameField = "name";
    private final FieldSetFactory fieldSetFactory = new DefaultFieldSetFactory();

    @Override
    public FieldSet tokenize(String line) {
        String name = line.replaceAll("\\[", "").replaceAll("\\]", "").trim();

        return fieldSetFactory.create(new String[] { name },
                new String[] { nameField });
    }
}

Using the following writer and job

<bean id="outputFile"
    class="org.springframework.core.io.FileSystemResource" scope="step">
    <constructor-arg value="#{jobParameters[outputFile]}"></constructor-arg>
</bean>

<bean id="outputFileWriter"
    class="org.springframework.batch.item.file.FlatFileItemWriter">
    <property name="resource" ref="outputFile"></property>
    <property name="lineAggregator">
        <bean
            class="org.springframework.batch.item.file.transform.PassThroughLineAggregator">
        </bean>
    </property>
</bean>

<batch:step id="outputStep">
    <batch:tasklet>
        <batch:chunk commit-interval="10" reader="sectionFileReader"
            writer="outputFileWriter">
        <batch:streams>
            <batch:stream ref="sectionFileReader" />
            <batch:stream ref="trueSectionFileReader" />
        </batch:streams>
        </batch:chunk>
    </batch:tasklet>
</batch:step>

<batch:job id="iniJob">
    <batch:step id="step1" parent="outputStep"></batch:step>
</batch:job>

And using this ini file

[Cat]
a=1
b=2
c=3
d=4
e=5
f=6
[Cat2]
a=11
b=21
c=31
d=41
e=51
f=61

I get the following output, which is the format in my toString() of the Section class

Cat,a=1,b=2,c=3,d=4,e=5,f=6
Cat2,a=11,b=21,c=31,d=41,e=51,f=61


来源:https://stackoverflow.com/questions/24243596/how-to-read-ini-file-in-spring-batch-key-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!