2017-07-07 108 views
0

我正在使用FlatFileItemReader讀取文件。我插入DefaultLineMapper和我自己的自定義FieldSetMapper(myMapper)。Spring批處理:如何獲取所有行讀取的錯誤?

目前在myMapper中,當發生錯誤時,我只需記錄它。我想積累全部錯誤,對於文件中的所有行,然後將它們保存到文件中。

我正在考慮實施我自己的Tasklet。但是從我讀過的內容來看,建議只在你的步驟是而不是進行面向塊的處理時才這樣做。

另一種選擇是使用ItemListenerSupport或ItemReadListener並實現onReadError()方法。但如果我這樣做,我不知道我如何能夠訪問全局/共享對象,其中包含所有錯誤的列表,對於全部爲行。

我一直在這兩個選項之間來回試圖讓他們工作,沒有太大的成功。任何建議非常感謝。

*****編輯*****

我的代碼不是什麼非標準的我不認爲。我定義的錯誤日誌工作帕拉姆:

Map<String, JobParameter> jobParametersMap ... 
jobParametersMap.put("errorsFile", new JobParameter(errorsFileURI)); 

我的XML配置是這樣的:

<job ...> 
    <step ...> 
    <step id="import"> 
    <tasklet> 
     <chunk reader="importReader" writer="importWriter" .../> 
    </tasklet> 
    </step> 
</job> 

<bean id="importReader" class="MyImportReader" scope="step"> 
    <property name="resource" .../> 
    <property name="lineMapper"> 
    <bean class = "...DefaultLineMapper"> 
     ... 
     <property name="fieldSetMapper" ref="importMapper"/> 
    </bean> 
    </property> 
    <property name="errorsFile" value="#jobParameters['errorsFile']}"/> 
</bean> 

<bean id="importWriter" ...scope="step"> 
    ... 
    <property name="errorsFile" value="#jobParameters['errorsFile']}"/> 
</bean> 

Reader類擴展FlatFileItemReader並實現ItemReadListener。作者實現了BatchLoadableWriter和StepExecutionListener。

正如你所看到的,我將errorsFile傳遞給Reader和Writer。 Writer使用了錯誤文件一段時間,而我只是將它添加到Reader中。這兩個類都有一個getFile/setter用於errorsFile。

它們之間的區別是在Writer中,@Overridden write()方法進行驗證,然後將全部項寫入文件中。所以所有錯誤一次寫入errorsFile。另外,如果有錯誤,則設置一個標誌(hasErrors),並在@Overridden afterStep()方法中檢查該標誌的值。如果是,則返回ExitStatus.FAILED。

鑑於讀者,每個Item調用一次doRead()方法。如果出現錯誤,我可以將它寫入errorsFile,並且我可以設置一個像Writer那樣的標誌。但該標誌將設置爲,該行/ Item僅爲

讓我們說我輸入10行。前5個錯誤,最後5個錯誤。當調用afterRead()時,它將檢查最後處理的Item的標誌值,該標誌沒有錯誤,因此hasErrors將爲false。不好。或者重寫onReadError()會更好。但是什麼會導致該方法被調用,這是Mapper中的一個錯誤?

東西告訴我實現我自己的Reader,和/或讓它實現ItemReadListener可能不是這樣的方式。對我來說,我似乎需要將這些邏輯中的一部分或全部放在讀者的「父母」中......這將是...一個Tasklet?但是我已經閱讀過SO和其他網絡上的其他地方,不推薦使用自己的Tasklet來執行塊處理。它應該只適用於簡單的任務。

我不知所措...

+0

你可以發佈一些代碼,你正在配置你的彈簧批處理作業。它使答案更容易。 – emeraldjava

回答

0

我認爲你應該考慮使用步驟和工作範圍。從您的讀者,您可以將錯誤詳細信息保存到這些範圍,然後在稍後階段參考信息。我會在這裏記錄太多的信息。

http://docs.spring.io/spring-batch/reference/html/configureStep.html#step-scope

您在工作開始時,產生並命名錯誤文件並將其保存到工作/步範圍。如果您的Reader有錯誤,它可以將詳細信息寫入文件。在過程結束時,您仍然可以參考錯誤文件名稱和記錄的詳細信息。

+0

但是這是否需要實現我自己的讀者?或者我可以在FieldMapper中執行此操作嗎?我想我的問題是,我在哪裏堅持這段代碼? Reader(默認的FlatFileItemReader)針對文件中的每一行執行。如果讀取/驗證失敗,我想將錯誤添加到錯誤列表中。我在哪裏放置代碼將列表放在作業或步驟範圍內?在所有處理完成後,我將代碼放到哪裏,然後將錯誤信息打印到文件中? –

+0

其實,我知道如何將列表作爲工作參數。但是,我應該在哪裏把從列表中獲取List的代碼添加到它(對於每次讀取)以及2)打印其內容(在完成所有讀取/處理之後)。對於(1)我想我必須實現我自己的Reader來擴展FlatFileItemReader,並在doRead()中獲取List並添加到它。至於(2),我不知道該把它放在哪裏。或者,也許我可以做(1)在一個ItemReadListener?對於(2)我不確定使用哪個聽衆。無論如何,我不知道聽衆是否可以在示波器中使用參數... –

+0

好吧,來弄清楚,你不能通過List作爲JobParam!遊民。因此,我將不得不使用emeraldjava的錯誤文件idea.But,但我仍然需要知道是否有任何* entire * read的實際錯誤,如果是,則返回錯誤狀態和指向該文件的鏈接。我不想打開文件並檢查行,以便知道是否有錯誤。仍然不確定在哪裏做... StepListener?在Reader/Mapper中拋出異常?但如果我這樣做,執行就會停止。我想閱讀/驗證*所有*行,然後*然後*拋出一個異常,如果有錯誤... –

1

只要跟進這個問題,以防它可以幫助其他人在路上。

我到底能夠做什麼,我希望通過實現自定義LineMapper並在該類的mapLine(串線,詮釋LINENUMBER)方法,保存LINENUMBER到執行上下文:

public class MyLineMapper implements LineMapper<MyPojo>, 
    InitializingBean, StepExecutionListener { 

    private ExecutionContext _executionContext; 

    public MyPojo mapLine(String line, int lineNumber) 
    throws Exception { 

    _executionContext.put("lineNumber", lineNumber); 

    MyPojo myPojo = fieldSetMapper.mapFieldSet(tokenizer.tokenize(line)); 
    return myPojo; 
} 

由於我需要訪問ExecutionContext,我在類中也實現了StepExecutionListener。

然後在我的自定義FieldMapper,我也實現了StepExecutionListener,這樣我就可以抓住從ExecutionContext中的行號,並用它來記錄與行號錯誤:

public class MyFieldMapper implements LineMapper<MyPojo>, 
    InitializingBean, StepExecutionListener { 

    private ExecutionContext _executionContext; 

    @Override 
    public MyPojo mapFieldSet(final FieldSet fieldSet) 
    throws BindException { 

    String currentLineNumber = 
     (_executionContext.get("lineNumber") != null) ? String 
     .valueOf(_executionContext.get("lineNumber")) : "-"; 

    if (some kind of error) { 
     logError(currentLineNumber, errorMsg); 

我然後檢查錯誤文件的存在在我的Writer的beforeWrite()方法中。如果存在,這意味着讀/驗證時會發生某種錯誤,並且拋出異常。

這樣我可以登錄所有讀/驗證錯誤,所有行我的csv文件,並退出,當出現第一個錯誤停止處理。

希望這有助於別人!

相關問題