如何在spring批处理中读取ini文件(key = value) [英] How to read ini file in spring batch (key=value)
问题描述
我想创建一个使用Spring批处理从一个ini文件读取批处理,并保存在数据库中的数据,但当我chekced org.springframework.batch.item.file.FlatFileItemReader
类我没有找到一种方法来解析我的数据从ini文件,我试图将 ini4j
API与spring批处理,但没有结果
我的ini文件:
[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
你可以做的是定义你自己的 ItemStreamReader
来包装一个委托 ItemStreamReader
,它只是一个使用 PatternMatchingCompositeLineMapper
作为线映射器的 FlatFileItemReader
。在你的 ItemStreamReader
中,循环读取委托中的行,如果行是 Property
域对象的实例,将它添加到 Section
域对象的列表中。 PatternMatchingCompositeLineMapper
允许你做的是检查模式匹配的行,并把它传递给正确的标记器和fieldSetMapper作业。
通过这种方式,可以将多行读入一个 Section 域对象,该对象包含
List< Property> / code>。
public class Section {
private String name;
私人列表<属性>性能;
// getters和setters
$ b $ @覆盖
public String toString(){
StringBuilder sb = new StringBuilder(name);
for(Property prop:properties){
sb.append(,+ prop.getKey()+=+ prop.getValue());
}
return sb.toString();
$ b $ public class Property {
private String key;
私有字符串值;
// getters and setters
}
为您定制 ItemStreamReader
你可以这样做。你可以看到,阅读是委托给另一个读者,你将在稍后定义
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实现了ItemStreamReader< Object> {
private Object curItem = null;
private ItemStreamReader< Object>代表;
$ b $ @Override
public Object read()throws Exception,UnexpectedInputException,
ParseException,NonTransientResourceException {$ b $ if(curItem == null){
curItem = (Section)delegate.read();
}
Section section =(Section)curItem;
curItem = null;
if(section!= null){
section.setProperties(new ArrayList< Property>()); $($)
$ b while(peek()instanceof Property){
section.getProperties()。add((Property)curItem);
curItem = null;
}
}
return section;
$ b $ 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);
$ b @Override
public void update(ExecutionContext arg0)throws ItemStreamException {
delegate.update(arg0);
$ b然后在你的配置中定义了带有 PatternMatchingCompositeLineMapper
< bean id =inputFileclass =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 =delegateref =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 =resourceref =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 =prototypeBeanNamevalue =section>< / property>
< / bean>
< bean id =sectionclass =com.underdogdevs.springbatch.domain.Section$ b $ scope =prototype>
< / bean>
< bean id =propertyLineTokenizer
class =org.springframework.batch.item.file.transform.DelimitedLineTokenizer>
< property name =delimitervalue ==>< / property>
< property name =namesvalue =key,value>< / property>
< / bean>
< bean id =propertyFieldSetMapper
class =org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper>
< property name =prototypeBeanNamevalue =property>< / property>
< / bean>
< bean id =propertyclass =com.underdogdevs.springbatch.domain.Property$ b $ scope =prototype>
< / bean>
您看到我也使用了自定义 LineTozenizer
。我可能可以使用一个 DelimitedLineTokenizer
,但是当我意识到它的时候,我已经定义了类
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实现LineTokenizer {
private final String nameField =name;
private final FieldSetFactory fieldSetFactory = new DefaultFieldSetFactory();
$ b $ @Override
public FieldSet tokenize(String line){
String name = line.replaceAll(\\[,).replaceAll(\ \],).trim();
return fieldSetFactory.create(new String [] {name},
new String [] {nameField});
$ b $ p $使用下面的作者和作业
< bean id =outputFile
class =org.springframework.core.io.FileSystemResourcescope =step> ;
< constructor-arg value =#{jobParameters [outputFile]}>< / constructor-arg>
< / bean>
< bean id =outputFileWriter
class =org.springframework.batch.item.file.FlatFileItemWriter>
< property name =resourceref =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 =10reader =sectionFileReader
writer =outputFileWriter>
< batch:streams>
< batch:stream ref =sectionFileReader/>
< batch:stream ref =trueSectionFileReader/>
< / batch:streams>
< / batch:chunk>
< / batch:tasklet>
< batch:job id =iniJob>
< / batch:job>
并使用这个ini文件
[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
我得到下面的输出,这是我的 toString()
code> 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
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
解决方案 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
这篇关于如何在spring批处理中读取ini文件(key = value)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!