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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349608.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NOIP模拟测试28「阴阳·虎·山洞」

写这几个题解我觉得我就像在按照官方题解抄一样 阴阳 题解 将题目中给的阴阳看作黑色和白色 首先我们观察到最后生成图中某种颜色必须是竖着单调递增或竖着单调递减 类似这样 否则不满足这个条件 但合法染色方案必须满足任意两个同颜色格子之间的格子也必须是该颜色。 然后我们…

linux设置环境变量_什么是linux环境变量

本来这篇文章好几天之前就写好了&#xff0c;但是媳妇儿跟我说工作日就不要发了&#xff0c;大家都在上班&#xff0c;哪有闲心思看你的文章。哎&#xff0c;可能大家用头条都是在放松刷娱乐&#xff0c;看小姐姐。所以就一直拖到现在。周末了&#xff0c;更是放松的好时候&…

理科卷math·english·chinese·biology·chemistry·physics

一套比一套炸,果然我只会做B卷,虽然我B也很差但没差到这种地步 $math$ 题解 看似没法做但总会有突破口 $70\%$ 发现和小凯的诱惑很像,于是看$gcd$是否为$1$只要为$1$可以凑齐所有数 $n^2$枚举两两$gcd$ $80\%$ 我考试时思路 找到每一个数和$mod$的$gcd$,发现只要是任一$gcd$倍数…

cad卸载_怎么把CAD卸载干净,老司机来教你

CAD经常出现文件丢失啊、这样那样的提示&#xff0c;要是身边有个大神级朋友还好&#xff0c;没有的小盆友只能乖乖的卸载&#xff0c;重新安装了&#xff0c;那么又有个问题拦住我们了——怎么把CAD卸载干净呢&#xff1f;由于卸载不干净&#xff0c;再次安装CAD时&#xff0c…

什么是JavaServer Faces(JSF)–(第2部分)

Facelets声明语言 在第1部分中&#xff0c;我介绍了JavaServer Pages&#xff08;JSF&#xff09;背后的基本思想 。 在本文中&#xff0c;我想介绍Facelets声明语言 。 HTML标签 我们遇到的第一个标签是代表HTML元素HTML标签。 这些实际上只是HTML标记&#xff08;例如输入&a…

问题 1076: 内部收益率

问题 1076: 内部收益率 时间限制: 1Sec 内存限制: 128MB 提交: 418 解决: 169 题目描述在金融中&#xff0c;我们有时会用内部收益率IRR来评价项目的投资财务效益&#xff0c;它等于使得投资净现值NPV等于0的贴现率。换句话说&#xff0c;给定项目的期数T、初始现金流CF0和项目…

路由器上的usb接口有什么用_路由器的USB接口,非常强大的功能,教您轻轻松松玩转,太实用了...

新一代出来的路由器后面基本上都会有一个或者是两个以上的有USB接口。居然还有很多人都不知道这些&#xff0c;要是比接口的用处。只是把它当做普通的无线路由器用。这样子太可惜了。其实路由器后面的usb接口呀&#xff0c;它有非常强大的功能&#xff0c;好处多多。接下来就请…

关于全局缓存的一种简单实现方法

缓存&#xff0c;在.Net系统开发中&#xff0c;经常使用到。如果&#xff0c;让你自己去实现&#xff0c;你会怎么做呢。 开始编码前思考&#xff1a; 1、肯定 是要 根据 key 去查询对应value&#xff0c;so 应该是List<KeyValuePair> 这类集合做缓存载体&#xff1b; 2、…

Lombok–您绝对应该尝试一下

Lombok在Java生态系统中并不是什么新鲜事物&#xff0c;但是我必须承认&#xff0c;直到我尝试使用它或被“确信”尝试它之前&#xff0c;我总是低估了它的价值。 我发现添加一个库来生成代码的价值并不高&#xff0c;这些库可以被当今的任何现代IDE轻松生成。 因此&#xff0c…

苹果手机透明桌面_原来苹果手机辨别真假这么简单!查看桌面1个图标,就能轻松分辨...

要说哪个品牌的手机贵&#xff0c;大家想到的肯定是苹果手机啦&#xff0c;所以说很多朋友都害怕自己买到假货。其实分辨苹果手机是不是正品很简单&#xff0c;只需学会这两个方法&#xff0c;就能辨别出手机的真假哦。一、从细节入手1.桌面时钟不知道大家发现没&#xff0c;iP…

NOIP模拟测试34「次芝麻·呵呵呵·长寿花」

次芝麻 题解 大力打表,发现快速幂, 例如初始$5$ $6$,那么第一次就是$5*2\%1110$,$6*2\%111$. 代码 #include<bits/stdc.h> using namespace std; #define ll long long ll n,m,k,d; ll g(ll x,ll k,ll s1){for(;k;k>>1,xx*x%d)if(k&1) ss*x%d;return s; } int …

Java Bean验证基础

这篇文章总结了一些简单易用的示例&#xff0c;这些示例说明了您想使用Java Beans Validation API&#xff08;JSR 349&#xff0c;JSR 303&#xff09;进行的最常见操作。 记住&#xff0c;Beans Validation独立于Java EE。 尽管它是作为Java EE兼容服务器的一部分内置的&…

NOIP模拟测试「简单的区间·简单的玄学·简单的填数·简单的序列」

简单的区间 $update$ 终于$AC$了 找到$(sum[r]sum[l](sum表示以中间点为基准的sum)-mx)\%k0$的点 注意这里$sum$表示是以$mid$为基准点,(即$sum[l]$为后缀和,$sum[r]$为前缀和) 回忆$(sum[r]-sum[l])\%k0$这个经典问题做法(入阵曲简化版),开桶,桶里维护$sum[l]\%k$,那么$r$贡献…

苹果手机变卡了怎么解决_iOS 变卡怎么解决?一招搞定!无需刷机

iOSiOS 因为其优秀的底层交互逻辑&#xff0c;能让一部 iPhone 在不跨版本更新系统的前提下&#xff0c;至少保证 2 年内如新机般流畅。两年之后呢&#xff1f;你是否为手中的老将渐衰而苦恼过&#xff1f;本人对手机的流畅度十分敏感&#xff0c;可以说到了极致。付款时&#…

NOIP模拟测试38「金·斯诺·赤」

金 辗转相减见祖宗 高精 #include<bits/stdc.h> using namespace std; #define A 2000 #define P 1 #define N 10 #define ll long long ll n,T; char sjdfj[A]; struct bignum {ll n[A],l;bignum(){l1,memset(n,0,sizeof(n));}void clear(){while(l>1&&!n[l-…

什么是JSON处理(JSON-P API)?

Java EE中的JSON-P简介 JSON处理1.0&#xff08; JSR 353 &#xff09;的Java API是一个低级&#xff0c;轻量级的JSON解析器和生成器&#xff0c;它提供了在属性和值级别上操作JSON数据的能力。 JSR 353提供了两种JSON处理模型&#xff1a; 对象模型和流模型。 两种模型都可以…

电视机原理图_电工电气,如何看电气原理图和接线图,如何设计图纸?

电气图纸一般可分为两大类&#xff0c;一类为电力电气图&#xff0c;它主要是表述电能的传输、分配和转换&#xff0c;如电网电气图、电厂电气控制图等。另一类为电子电气图&#xff0c;它主要表述电子信息的传递、处理&#xff1b;如电视机电气原理图。本文主要谈电力电气图的…

NOIP模拟测试39,思维禁锢专场「工业题·玄学题·卡常题」

工业题 题解 抱歉,题解没时间写了 代码 #include<bits/stdc.h> using namespace std; #define ll long long #define A 6666666 #define mod 998244353 ll jie[A],ni[A],acnt[A],bcnt[A]; ll fheng[A],fshu[A]; ll n,m,a,b; ll meng(ll x,ll k){ll ans1;for(;k;k>>…

ubuntu 如何登录远程服务器_VSCode远程登录云服务器、树莓派实现在线调试代码...

在PyCon2019大会上&#xff0c;微软发布了VSCode Remote&#xff0c;开启了远程开发的新时代&#xff01;Remote可以帮助开发者在容器、物理机器或虚拟机&#xff0c;以及WSL上实现无缝的远程开发。通过安装Remote Development Extension Pack&#xff0c;开发者可以快速上手远…

macosx jdk_MacOSX环境上的多个Java JDK

macosx jdk同样&#xff0c;这是在Mac&#xff08;OSX 10.8.x &#xff09;上配置Java开发环境的一个小技巧。 如果您现在真的开始&#xff0c;我建议您阅读我以前的文章之一 &#xff0c;这是一种快速干净的方法&#xff08;我想&#xff09;来设置环境变量并开始Java编码。 今…