有没有办法获取失败的读取输入文件的位置,以便在SkipListener
中使用它?
例:
我的SkipListener
移动了每个无法处理或写入错误位置的文件:
@Override
public void onSkipInWrite(MyFileObject arg0, Throwable arg1) {
logger.error("onSkipInWrite ");
logToErrorDirectory(arg0.getPath(), arg1);
}
@Override
public void onSkipInProcess(MyFileObject arg0, Throwable arg1) {
logger.error("onSkipInProcess ");
logToErrorDirectory(arg0.getPath(), arg1);
}
@Override
public void onSkipInRead(Throwable arg1) {
// WHAT TO DO HERE
}
当一个Item(准确的.xml
文件)也无法读取时,我需要做同样的事情。
我的配置:
<bean id="ExportPatentReader"
class="org.springframework.batch.item.file.MultiResourceItemReader"
scope="step">
<property name="resources" value="file:SomeFolder/*.xml'</property>
<property name="delegate" ref="staxPatentReader"></property>
<property name="strict" value="true"></property>
</bean>
<bean id="staxPatentReader" class="org.springframework.batch.item.xml.StaxEventItemReader"
scope="step">
<property name="fragmentRootElementName" value="Root" />
<property name="unmarshaller" ref="patentMarshaller" />
</bean>
<bean id="patentMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.company.MyFileObject</value>
</list>
</property>
</bean>
在MyFileObject
我可以轻松获取资源并移动文件,但问题出在此之前。 典型的情况是格式错误的xml文件仍然需要移动到错误目录,但由于它仍未编组,我无法找到获取它的资源路径的方法。
--------------------- UPDATE --------------------- < /强>
根据@Michael Minella的建议,我使用排序的Resources[]
和MultiResourceItemReader.resourceIndex
来获取失败的文件。对于 commit-interval = 1 工作完美!但是对于更大的ci没有运气:(。
我调整后的听众部分:
@Override
public void onSkipInRead(Throwable arg0) {
logger.error("onSkipInRead ");
ExecutionContext stepContext = stepExecution.getExecutionContext();
logger.info("ExecutionContext: " + stepContext.toString());
logger.info("stepExecution: " + stepExecution.toString());
Arrays.sort(resources, comparator);
Resource errorResource = resources[stepContext.getInt("MultiResourceItemReader.resourceIndex")+1];
// NOT WORKING
Resource errorResource2 = resources[stepExecution.getReadCount()+1];
try {
// INCORRECT PATH FOR CI>1
logger.info("Path: " + errorResource.getFile().getCanonicalPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Comparator<Resource> comparator = new Comparator<Resource>() {
/**
* Compares resource filenames.
*/
@Override
public int compare(Resource r1, Resource r2) {
return r1.getFilename().compareTo(r2.getFilename());
}
};
@Override
public void beforeStep(StepExecution arg0) {
stepExecution = arg0;
}
问题可能是每次提交完成并且ExecutionContext
已更新但无法找到解决方法。
对于日志记录期间的更新事项,打印的stepExecution看起来像这样:StepExecution: id=6, version=2, name=partitionedStep:partition4, status=STARTED, exitStatus=EXECUTING, readCount=10, filterCount=0, writeCount=10 readSkipCount=2, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription=
所以我想也许正确的索引可以是Items per commit + MultiResourceReader.index
<的组合/ p>
另一件事......我在开始时忘了提到我使用partitioner
来阅读文件,虽然不确定这是否会影响结果。
我使用SkipListener
的次数越多,我认为更简单的解决方案是编写自定义阅读器以至少替换StaxEventReader
:D
答案 0 :(得分:1)
MultiResourceItemReader
通过索引跟踪ExecutionContext
中正在处理的文件。当Resource []
被注入阅读器时,我们按文件名对数组进行排序。之后,我们将每个更新的当前文件的索引存储在步骤ExecutionContext
中。我认为您可以在SkipListener
中实施相同的逻辑。将相同的资源数组注入侦听器,对其进行排序,然后将索引从ExecutionContext
中拉出。您可以在此处MultiResourceItemReader
的代码中看到此操作:https://github.com/spring-projects/spring-batch/blob/master/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java
答案 1 :(得分:0)
我放弃了提议的解决方案,因为我无法使用commit-interval&gt; 1
解决了我的问题的一个肮脏的解决方案:
Custom Reader
替换StaxEventItemReader
==&gt;
在onSkipInRead()
read()
==&gt;
Custom Reader
中添加了read()
的逻辑
为了解决this问题,我强制MultiResourceItemReader
仅在 @Override
public void setResource(Resource arg0) {
resource = arg0;
// true for new resource
ResourceState = true;
}
@Override
public MyFileObject read() throws Exception {
MyFileObject item = null;
/*
* Run only for a new Resource
*/
if (ResourceState == true) {
logger.debug("Reading: " + resource.getFileName());
try {
// Actual reading
item = (MyFileObject) unmarshaller.unmarshal(resource.getFile());
} catch (Exception e) {
logger.error("Error while reading: " + resource.getFilename());
logToErrorDirectory(resource, errorPath, e);
}
/*
* Finished reading, resourceState=false
*/
ResourceState = false;
}
return item;
}
读取新资源时才会运行:
{{1}}
并不是这个解决方案的粉丝,但解决了我的问题!