2017-07-07 25 views
0

私はFlatFileItemReaderを使用してファイルを読み取ります。私はDefaultLineMapperと自分のカスタムFieldSetMapper(myMapper)を接続します。バネバッチ:すべての行のエラーを取得する方法は?

現在、myMapperでは、エラーが発生したときに簡単にログに記録します。ファイル内のすべての行についてすべてのエラーを累積し、ファイルに保存したいと考えています。

私自身のタスクレットの実装を検討していました。しかし、私が読んだところでは、あなたのステップがでなく、チャンク指向の処理を行うの場合にのみこれを行うことをお勧めします。

また、ItemListenerSupportまたはItemReadListenerのいずれかを使用して、onReadError()メソッドを実装することもできます。しかし、私がそれを行うと、どのようにすべてのエラーのリストを保持するグローバル/共有オブジェクトにアクセスできるか分かりません。すべて行です。

私はこれらの2つのオプションの間を行き来して、多くの成功を収めずに働かそうとしています。どんなアドバイスも感謝しています。

***** ***** EDIT

私のコードは、私は考えていない何も非標準ではありません。私はエラーが仕事のParamをログ定義:

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> 

リーダークラスはFlatFileItemReaderを拡張し、ItemReadListenerを実装しています。ライターは、BatchLoadableWriterおよびStepExecutionListenerを実装します。

私が見る通り、errorsFileはReaderとWriterの両方に渡します。 WriterはerrorsFileをしばらく使用していましたが、私はReaderにそれを追加しました。どちらのクラスもerrorsFileのgetter/setterを持っています。

これらの違いは、Writerで@Overridden write()メソッドが検証してからすべてアイテムをファイルに書き込むことです。したがってすべてエラーはerrorsFileに一度に書き込まれます。また、エラーがある場合はフラグが設定され(hasErrors)、そのフラグの値は@Overridden afterStep()メソッドでチェックされます。 trueの場合は、ExitStatus.FAILEDが返されます。

リーダーの場合、各アイテムに対してdoRead()メソッドが1回呼び出されます。エラーがあれば、errorsFileに書き込むことができます。は、にライターのようなフラグを設定できます。しかし、その旗はその行/項目に対してのみに設定されます。

私は10行をインポートするとしましょう。最初の5つにはエラーがあり、最後の5つにはエラーがありません。 afterRead()が呼び出されると、エラーのない最後に処理されたItemのフラグの値がチェックされるので、hasErrorsはfalseになります。良くない。または、おそらくonReadError()をオーバーライドする方がよいでしょう。しかし、そのメソッドが呼び出される原因は何か、Mapperのエラーですか?

私自身のReaderを実装しているか、ItemReadListenerを実装しているとか、この問題を解決する方法がないかもしれません。私にとっては、このロジックの一部または全部をReaderの "親"に置く必要があるようです。これは... Taskletですか?しかし、私はSOや他の場所でチャンク処理を実行する独自のタスクレットを実装することはお勧めしません。単純な作業の場合にのみ実行する必要があります。私は途方に暮れてよ

...

+0

現在、スプリングバッチジョブを設定している場所にコードを投稿できますか。それはより簡単な答えを与えることができます。 – emeraldjava

答えて

0

私はあなたがステップとジョブスコープを使用することを検討すべきだと思います。読者から、エラーの詳細をこれらのスコープに保存し、後でその情報を参照することができます。あまりにも多くの情報を記録することには注意が必要です。ジョブの開始時に

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

あなたは、生成し、名前を付けエラーファイルを、ジョブ/ステップスコープに保存します。リーダーにエラーがある場合は、詳細をファイルに書き込むことができます。プロセスの最後には、エラー・ファイル名への参照と、記録された詳細があります。

+0

しかし、これは自分のリーダーを実装する必要がありますか?あるいは、FieldMapperでこれを行うことはできますか?私は私の質問は、私はこのコードをどこに貼り付けるのですか? Reader(デフォルトのFlatFileItemReader)は、ファイル内の各行に対して実行されます。読み取り/検証に失敗した場合は、エラーのリストにエラーを追加します。 List in JobまたはStepスコープを入れるコードはどこに置くのですか?そして、すべての処理が完了したら、エラーをファイルに出力するコードをどこに置くのですか? –

+0

実際、Listをジョブパラメータとして渡す方法はわかっています。しかし、スコープからリストを取得するコードはどこに置くべきですか(1つの読み取りごとに)2)その内容を印刷します(すべての読み取り/処理が完了した後)。 (1)FlatFileItemReaderを拡張し、doRead()でListを取得して追加する独自のReaderを実装する必要があると思います。 (2)については、どこに置くべきかわからない。あるいは、私はItemReadListenerで(1)することができますか? (2)私はどのリスナーを使うべきかわからない。それにもかかわらず、リスナーがスコープ内のパラメータにアクセスできるかどうかはわかりません。 –

+0

まあ、リストをJobParamとして渡すことはできません。バマー。だから私はemeraldjavaのエラーファイルidea.Butを使用する必要がありますしかし、私はまだ*全体の*読み取りのための実際のエラーがあったかどうかを知る必要があり、そうであれば、エラーステータスとファイルへのリンクを返します。エラーがあるかどうかを知るために、ファイルを開いて行をチェックする必要はありません。まだどこでこれを行うかわからない... StepListener? Reader/Mapperに例外を投げる?しかし、もし私がそれを実行すると、実行が停止します。*すべての*行を読み込み/検証し、エラーがあれば*例外をスローしたい –

1

この問題は、他の誰かが道を辿るのを助ける場合に備えて、ちょうどこの問題に追いついています。私は、カスタムLineMapperと、そのクラスのmapLine(文字列のライン、INT LINENUMBER)メソッドを実装することで、私が望んでいた何のExecutionContextに行番号を保存することができました最後に

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からLINENUMBERをつかむと、行番号とエラーを記録するためにそれを使用することができます:

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); 

私はその後ERRORFILEの存在を確認します私のWriterのbeforeWrite()メソッドで。存在する場合、読み取り/検証中に何らかのエラーが発生したことを意味し、例外をスローします。

私はcsvファイルのすべてラインのために、すべて読み出し/検証エラーをログに記録し、ないの出口を第1回エラーが発生したときに処理を停止することができますこの方法では。

これはいつか他の人に役立つことを願っています!