2017-07-24 361 views
0

我使用Spring Batch從CSV文件讀取數據,然後將其保存到數據庫中。到目前爲止,一切都很好,除了我的輸入文件包含混合數據(多個表格有多個列)。將單個參數而不是列表傳遞給ItemWriter接口的Write()方法

我創建了一個類CsvFileLine將包含文件的整條生產線,並實現了接口ItemReader<CsvFileLine>,然後實現的接口ItemProcessor<List<CsvFileLine>, ProcessorResult>給誰,我會通過的CsvFileLine列表並返回ProcessorResult類型,我創建的對象還包含ClassA,ClassBClassC的3 ArrayList<>。現在

我的問題是,當我需要實現接口ItemWriter<ProcessorResult>write(List<? extends T> items)需要被延伸一些其它類而我打算傳遞單個對象,它是含有4周的ArrayLists必要的數據ProcessorResult項的列表的方法。

任何人都可以建議我如何處理這種情況?有沒有辦法只傳遞一個參數?

+0

1.爲什麼不使用標準的Spring Batch組件讀取CSV('FlatFileItemReader'等)? 2.處理多個項目類型和'ItemWriter'抽象有幾個不同的選項。像'ClassifierCompositeItemWriter'中的構成是最常見的方法。 –

+0

CSV文件中的行如何與最終要寫入數據庫的內容相關聯?文件中的一行是否恰好對應於數據庫中的一個插入/更新,即「ClassA」,「ClassB」或「ClassC」中的某一行?一個文件行可以表示這些類之一的多個實例嗎?我認爲你在這裏反對Spring Batch框架,但是如果不知道實際的最終目標,我不能提供很多有用的建議。 – mymarkers

+0

@MichaelMinella我是Spring Batch的新手,我遵循一個常見的例子,我認爲這是房子的一個標準。你有沒有很好的例子說明如何在不使用XML註釋的情況下使用'FlatFileItemReader'? –

回答

0

既然你已經選擇使用SpringBatch及其ItemWriter,你需要有一個堅定的想法,你的域對象如何映射到「Items」。

假設你ProcessorResult構成一個「項目」,只需撥打ItemWriter.write()大小爲1

名單的標準Java API提供了你Collections.singletonList()方便地做到這一點。

itemWriter.write(Collections.singletonList(processorResult)); 
+0

其實我的'ProcessorResult'包含3個ArrayLists:'processorResult.ListClassA','processorResult.ListClassB'和'processorResult.ListClassC'。每個列表包含多個對象。 現在我正在考慮爲每個ArrayList製作一個專門的作家,比如'ItemWriter '...... –

+0

我不知道你的域,但是你應該讓'ClassA','ClassB','ClassC'實現一個通用接口所以你可以多態地對待它們。 – slim

+0

和'ItemProcessor'每次我返回一個'ClassX' List而不是返回一個封裝所有這些對象的對象? –

1

感謝您的澄清。如果我理解正確,則表示文件中的每行包含ClassA,ClassBClassC的一個實例。我假設對於這個例子,但即使有不同的關係,解決方案也是相似的。

設置Spring Batch作業的關鍵是要考慮什麼構成「項目」以及你想要發生什麼。您還需要了解框架如何將每個接口的輸出作爲下一個輸入的輸入。 (春天有好的documentation)。 ItemReader的退貨類型爲單身人士ItemProcessor。所以在你的情況下,ItemProcessor實際上應該是ItemProcessor<CsvFileLine, ProcessorResult>而不是你所擁有的ItemProcessor<List<CsvFileLine>, ProcessorResult>。從ItemProcessorItemWriter的切換有點棘手。 ItemWriter實現應採用ItemProcessor返回類型的ListItemWriter需要List,因爲Spring批次組ItemProcessor一起輸出到事務中。在你的情況下,你可以有ItemWriter<List<ProcessorResult>>

有了這個基礎,我們可以改變ProcessorResult的結構,然後作者很容易實現。相反包含數據的所有文件中的ProcessorResult的,它將從只有一行包含的數據:

public class ProcessorResult { 
    private ClassA classA; 
    private ClassB classB; 
    private ClassC classC; 
    // Constructor and getters omitted for brevity 
} 

ItemProcessor需要一個CsvFileLine並將其轉換成一個ProcessorResult

public class ExampleProcessor implements ItemProcessor<CsvFileLine, ProcessorResult> { 

    public ProcessorResult process(CsvFileLine line){ 
    // mapping into ProcessorResult goes here 
    } 

ItemWriter需要List這些,並需要將它們保存到數據庫。它可能是這個樣子:

public class ExampleItemWriter implements ItemWriter<List<ProcessorResult>{ 

    private ClassADao classADao; 
    private ClassBDao classBDao; 
    private ClassCDao classCDao; 

    public void write(List<? extends ProcessorResult> items){ 
    for(ProcessorResult result : items){ 
     classADao.save(result.getClassA()); 
     classBDao.save(result.getClassB()); 
     classCDao.save(result.getClassC()); 
    } 
    } 
} 

記住,在List每個元素傳遞給ItemWriter映射回在ItemReader的單個項目。通常,這也是文件中的一行。要使用Spring Batch,您必須確保ItemReader的返回類型是ItemProcessor的輸入類型。同時,ItemWriter的輸入是由ItemProcessor返回的類型的List。您在這裏的讀者,處理器和作者不遵循這種模式,並且框架將無法使用它們。一些小的改變應該允許你使用你在框架內編寫的代碼。

最後,我會注意到你可能完全沒有ItemProcessor。您可以只有ItemReader<ProcessorResult>ItemWriter<ProcessorResult>並在ItemReader中執行映射。因此,您將邏輯從當前的ItemProcessor改爲LineMapper<ProcessorResult>。然後在FlatFileItemReader中使用它,然後將所有內容直接從讀寫器傳遞給寫入器。這超出了你的問題的範圍,我更喜歡XML配置,所以我將放棄它。

+0

非常感謝你的幫助。我會重寫我的代碼,以遵循您告訴我的模式並嘗試應用業務邏輯。實際上,我正在考慮的一點是如何建立不同實體之間的鏈接,因爲例如'ClassA'具有'List listClassB'類型的屬性並且對於'classC'也是一樣的。 –