javascript
Spring批处理CSV处理
總覽
我們將討論的主題包括使用Spring Batch進行批處理的基本概念,以及如何將數據從CSV導入數據庫。
0 – Spring Batch CSV處理示例應用程序
我們正在構建一個應用程序,該應用程序演示Spring Batch處理CSV文件的基礎。 我們的演示應用程序將允許我們處理CSV文件,其中包含數百條日本動漫標題的記錄。
0.1 – CSV
我已經從這個Github存儲庫中下載了將要使用的CSV文件,它提供了相當全面的動漫列表。
這是在Microsoft Excel中打開的CSV的屏幕截圖
查看并從 Github 下載代碼
1 –項目結構
2 –項目依賴性
除了典型的Spring Boot依賴關系外,我們還包括spring-boot-starter-batch(這是對Spring Batch的依賴,顧名思義)和hsqldb(用于內存數據庫)。 我們還包括ToStringBuilder的commons-lang3。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.michaelcgood</groupId><artifactId>michaelcgood-spring-batch-csv</artifactId><version>0.0.1</version><packaging>jar</packaging><name>michaelcgood-spring-batch-csv</name><description>Michael C Good - Spring Batch CSV Example Application</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.7.RELEASE</version><relativePath /> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-batch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.hsqldb</groupId><artifactId>hsqldb</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.6</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>3 –模型
這是對動漫領域進行建模的POJO。 字段是:
- ID。 為了簡單起見,我們將ID視為字符串。 但是,可以將其更改為其他數據類型,例如Integer或Long。
- 標題。 這是動畫的標題,適合作為String。
- 描述。 這是動漫的描述,比標題長,也可以視為字符串。
需要注意的是我們的三個字段的類構造函數:public AnimeDTO(字符串id,字符串標題,字符串描述)。 這將在我們的應用程序中使用。 同樣,像往常一樣,我們需要創建一個沒有參數的默認構造函數,否則Java會拋出錯誤。
package com.michaelcgood;import org.apache.commons.lang3.builder.ToStringBuilder; /*** Contains the information of a single anime** @author Michael C Good michaelcgood.com*/public class AnimeDTO {public String getId() {return id;}public void setId(String id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}private String id;private String title;private String description;public AnimeDTO(){}public AnimeDTO(String id, String title, String description){this.id = id;this.title = title;this.description = title;}@Overridepublic String toString() {return new ToStringBuilder(this).append("id", this.id).append("title", this.title).append("description", this.description).toString();}}4 – CSV文件到數據庫配置
該類中發生了很多事情,并且不是一次編寫的,因此我們將逐步學習代碼。 訪問Github以查看完整的代碼。
4.1 –讀者
如Spring Batch文檔所述,FlatFileIteamReader將“從平面文件中讀取數據行,這些文件通常描述記錄的數據字段由文件中的固定位置定義或由某些特殊字符(例如,逗號)分隔”。
我們正在處理CSV,因此,當然用逗號分隔數據,這使其非常適合與我們的文件一起使用。
@Beanpublic FlatFileItemReader<AnimeDTO> csvAnimeReader(){FlatFileItemReader<AnimeDTO> reader = new FlatFileItemReader<AnimeDTO>();reader.setResource(new ClassPathResource("animescsv.csv"));reader.setLineMapper(new DefaultLineMapper<AnimeDTO>() {{setLineTokenizer(new DelimitedLineTokenizer() {{setNames(new String[] { "id", "title", "description" });}});setFieldSetMapper(new BeanWrapperFieldSetMapper<AnimeDTO>() {{setTargetType(AnimeDTO.class);}});}});return reader;}重要事項:
- FlatFileItemReader使用模型進行參數化。
4.2 –處理器
如果要在將數據寫入數據庫之前對其進行轉換,則需要一個ItemProcessor。 我們的代碼實際上并沒有應用任何業務邏輯來轉換數據,但是我們允許這種能力。
4.2.1 – CsvFileToDatabaseConfig.Java中的處理器
csvAnimeProcessor返回AnimeProcessor對象的新實例,我們將在下面進行檢查。
@BeanItemProcessor<AnimeDTO, AnimeDTO> csvAnimeProcessor() {return new AnimeProcessor();}4.2.2 – AnimeProcessor.Java
如果我們想在寫入數據庫之前應用業務邏輯,則可以在寫入數據庫之前操縱字符串。 例如,您可以在getTitle之后添加toUpperCase()以使標題大寫,然后再寫入數據庫。 但是,我決定不對此示例處理器執行此操作或不應用任何其他業務邏輯,因此未進行任何操作。 該處理器僅在此處進行演示。
package com.michaelcgood;import org.slf4j.Logger; import org.slf4j.LoggerFactory;import org.springframework.batch.item.ItemProcessor;public class AnimeProcessor implements ItemProcessor<AnimeDTO, AnimeDTO> {private static final Logger log = LoggerFactory.getLogger(AnimeProcessor.class);@Overridepublic AnimeDTO process(final AnimeDTO AnimeDTO) throws Exception {final String id = AnimeDTO.getId();final String title = AnimeDTO.getTitle();final String description = AnimeDTO.getDescription();final AnimeDTO transformedAnimeDTO = new AnimeDTO(id, title, description);log.info("Converting (" + AnimeDTO + ") into (" + transformedAnimeDTO + ")");return transformedAnimeDTO;}}4.3 –作家
csvAnimeWriter方法負責將值實際寫入我們的數據庫。 我們的數據庫是內存中的HSQLDB,但是此應用程序使我們可以輕松地將一個數據庫換成另一個數據庫。 dataSource是自動連線的。
@Beanpublic JdbcBatchItemWriter<AnimeDTO> csvAnimeWriter() {JdbcBatchItemWriter<AnimeDTO> excelAnimeWriter = new JdbcBatchItemWriter<AnimeDTO>();excelAnimeWriter.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<AnimeDTO>());excelAnimeWriter.setSql("INSERT INTO animes (id, title, description) VALUES (:id, :title, :description)");excelAnimeWriter.setDataSource(dataSource);return excelAnimeWriter;}4.4 –步驟
步驟是一個域對象,它包含批處理作業的獨立順序階段,并包含定義和控制實際批處理所需的所有信息。
現在,我們已經為數據創建了讀取器和處理器,我們需要編寫數據。 對于讀取,我們一直在使用面向塊的處理,這意味著我們一次讀取了一個數據。 面向塊的處理還包括在事務邊界內創建將被寫出的“塊”。 對于面向塊的處理,您可以設置提交間隔,一旦讀取的項目數等于已設置的提交間隔,就可以通過ItemWriter寫入整個塊,并提交事務。 我們將塊間隔大小設置為1。
我建議閱讀有關面向塊處理的Spring Batch文檔 。
然后,讀取器,處理器和寫入器調用我們編寫的方法。
@Beanpublic Step csvFileToDatabaseStep() {return stepBuilderFactory.get("csvFileToDatabaseStep").<AnimeDTO, AnimeDTO>chunk(1).reader(csvAnimeReader()).processor(csvAnimeProcessor()).writer(csvAnimeWriter()).build();}4.5 –工作
作業由步驟組成。 我們將參數傳遞到下面的Job中,因為我們想跟蹤Job的完成情況。
@BeanJob csvFileToDatabaseJob(JobCompletionNotificationListener listener) {return jobBuilderFactory.get("csvFileToDatabaseJob").incrementer(new RunIdIncrementer()).listener(listener).flow(csvFileToDatabaseStep()).end().build();}5 –作業完成通知監聽器
下面的類自動連接JdbcTemplate,因為我們已經設置了dataSource并且我們想輕松地進行查詢。 我們查詢的結果是AnimeDTO對象的列表。 對于返回的每個對象,我們將在控制臺中創建一條消息,以顯示該項目已被寫入數據庫。
package com.michaelcgood;import java.sql.ResultSet; import java.sql.SQLException; import java.util.List;import org.slf4j.Logger; import org.slf4j.LoggerFactory;import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.listener.JobExecutionListenerSupport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component;@Component public class JobCompletionNotificationListener extends JobExecutionListenerSupport {private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);private final JdbcTemplate jdbcTemplate;@Autowiredpublic JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic void afterJob(JobExecution jobExecution) {if(jobExecution.getStatus() == BatchStatus.COMPLETED) {log.info("============ JOB FINISHED ============ Verifying the results....\n");List<AnimeDTO> results = jdbcTemplate.query("SELECT id, title, description FROM animes", new RowMapper<AnimeDTO>() {@Overridepublic AnimeDTO mapRow(ResultSet rs, int row) throws SQLException {return new AnimeDTO(rs.getString(1), rs.getString(2), rs.getString(3));}});for (AnimeDTO AnimeDTO : results) {log.info("Discovered <" + AnimeDTO + "> in the database.");}}}}6 – SQL
我們需要為我們的數據庫創建一個模式。 如前所述,我們已將所有字段都設置為字符串,以便于使用,因此我們將其數據類型設置為VARCHAR。
DROP TABLE animes IF EXISTS; CREATE TABLE animes (id VARCHAR(10),title VARCHAR(400),description VARCHAR(999) );6 –主
這是帶有main()的標準類。 如Spring文檔所述, @SpringBootApplication是一個方便注釋,其中包括@ Configuration , @EnableAutoConfiguration , @ EnableWebMvc和@ComponentScan 。
package com.michaelcgood;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class SpringBatchCsvApplication {public static void main(String[] args) {SpringApplication.run(SpringBatchCsvApplication.class, args);} }7 –演示
7.1 –轉換
FieldSet通過處理器輸入,“ Converting”被打印到控制臺。
7.2 –在數據庫中發現新項目
當Spring Batch Job完成時,我們選擇所有記錄并將它們分別打印到控制臺。
7.3 –批處理完成
批處理完成后,這就是打印到控制臺的內容。
Job: [FlowJob: [name=csvFileToDatabaseJob]] completed with the following parameters: [{run.id=1, -spring.output.ansi.enabled=always}] and the following status: [COMPLETED] Started SpringBatchCsvApplication in 36.0 seconds (JVM running for 46.616)8 –結論
Spring Batch建立在基于POJO的開發方法和Spring Framework的用戶友好性的基礎上,使開發人員可以輕松地創建企業級批處理。
源代碼在 Github上
翻譯自: https://www.javacodegeeks.com/2017/10/spring-batch-csv-processing.html
總結
以上是生活随笔為你收集整理的Spring批处理CSV处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 游戏《星空》发布未来更新计划:正进行性能
- 下一篇: 粉笔公司董事长张小龙怒骂安信基金经理10