Spring Batch - MySQL 到平面文件



在本章中,我们将创建一个 Spring Batch 应用,它使用 MySQL 读取器和一个**平面文件**写入器(.txt)。

**读取器** - 我们在应用中使用的读取器是**JdbcCursorItemReader**,用于从 MySQL 数据库读取数据。

假设我们在 MySQL 数据库中创建了一个如下所示的表。

CREATE TABLE details.tutorialsdata( 
   tutorial_id int NOT NULL, 
   tutorial_author VARCHAR(20), 
   tutorial_title VARCHAR(20), 
   submission_date VARCHAR(20) 
);

假设我们向其中插入了以下记录。

mysql> select * from tutorialsdata; 
+-------------+-----------------+----------------+-----------------+ 
| tutorial_id | tutorial_author | tutorial_title | submission_date | 
+-------------+-----------------+----------------+-----------------+ 
|         101 | Sanjay          | Learn Java     | 06-05-2007      | 
|         102 | Abdul S         | Learn MySQL    | 19-04-2007      | 
|         103 | Krishna Kasyap  | Learn JavaFX   | 06-07-2017      | 
+-------------+-----------------+----------------+-----------------+ 
3 rows in set (0.00 sec) 

**写入器** - 我们在应用中使用的写入器是**FlatFileItemWriter**,用于将数据写入**平面文件**(.txt)。

**处理器** - 我们在应用中使用的处理器是一个自定义处理器,它只打印从 CSV 文件读取的记录。

创建项目

创建一个新的 Maven 项目,如Spring Batch - 环境章节中所述。

pom.xml

以下是此 Maven 项目中使用的 pom.xml 文件的内容。

<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/maven-v4_0_0.xsd"> 
   <modelVersion>4.0.0</modelVersion> 
   <groupId>com.tutorialspoint</groupId> 
   <artifactId>SpringBatchSample</artifactId> 
   <packaging>jar</packaging> 
   <version>1.0-SNAPSHOT</version> 
   <name>SpringBatchExample</name>
   <url>http://maven.apache.org</url>  

   <properties> 
      <jdk.version>21</jdk.version> 
      <spring.version>5.3.14</spring.version> 
      <spring.batch.version>4.3.4</spring.batch.version> 
      <mysql.driver.version>8.4.0</mysql.driver.version> 
      <junit.version>4.11</junit.version> 
      <pdf.version>2.0.32</pdf.version>
      <xstream.version>1.4.17</xstream.version>
      <jaxb.version>2.3.1</jaxb.version> 
      <jaxb.impl.version>2.3.4</jaxb.impl.version> 
   </properties>  

   <dependencies> 
      <!-- Spring Core --> 
      <dependency> 
         <groupId>org.springframework</groupId> 
         <artifactId>spring-core</artifactId> 
         <version>${spring.version}</version> 
      </dependency>  

      <!-- Spring jdbc, for database --> 
      <dependency> 
         <groupId>org.springframework</groupId> 
         <artifactId>spring-jdbc</artifactId> 
         <version>${spring.version}</version> 
      </dependency>  

      <!-- Spring XML to/back object --> 
      <dependency> 
         <groupId>org.springframework</groupId> 
         <artifactId>spring-oxm</artifactId> 
         <version>${spring.version}</version> 
      </dependency>  

      <!-- MySQL database driver --> 
      <dependency>
         <groupId>com.mysql</groupId>
         <artifactId>mysql-connector-j</artifactId>
         <version>${mysql.driver.version}</version>
      </dependency>  

      <!-- Spring Batch dependencies --> 
      <dependency> 
         <groupId>org.springframework.batch</groupId> 
         <artifactId>spring-batch-core</artifactId> 
         <version>${spring.batch.version}</version> 
      </dependency> 

      <dependency> 
         <groupId>org.springframework.batch</groupId> 
         <artifactId>spring-batch-infrastructure</artifactId> 
         <version>${spring.batch.version}</version> 
      </dependency>  

      <!-- Spring Batch unit test --> 
      <dependency> 
         <groupId>org.springframework.batch</groupId> 
         <artifactId>spring-batch-test</artifactId> 
         <version>${spring.batch.version}</version> 
      </dependency>  

      <!-- Junit --> 
      <dependency> 
         <groupId>junit</groupId> 
         <artifactId>junit</artifactId> 
         <version>${junit.version}</version> 
         <scope>test</scope> 
      </dependency> 

      <!-- pdfbox -->
      <dependency>
         <groupId>org.apache.pdfbox</groupId>
         <artifactId>pdfbox</artifactId>
         <version>${pdf.version}</version>
      </dependency>
	  
      <!-- xstream -->
      <dependency>
         <groupId>com.thoughtworks.xstream</groupId>
         <artifactId>xstream</artifactId>
         <version>${xstream.version}</version>
      </dependency>
	  
      <!-- jaxb-api -->
      <dependency>
         <groupId>javax.xml.bind</groupId>
         <artifactId>jaxb-api</artifactId>
         <version>${jaxb.version}</version>
      </dependency>
	  
      <!-- JAXB RI -->
      <dependency>
         <groupId>com.sun.xml.bind</groupId>
         <artifactId>jaxb-impl</artifactId>
         <version>${jaxb.impl.version}</version>
      </dependency>

   </dependencies> 

   <build> 
      <finalName>spring-batch</finalName> 
      <plugins> 
         <plugin> 
            <groupId>org.apache.maven.plugins</groupId> 
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.9</version> 
            <configuration> 
               <downloadSources>true</downloadSources> 
               <downloadJavadocs>false</downloadJavadocs> 
            </configuration> 
         </plugin> 
   
         <plugin> 
            <groupId>org.apache.maven.plugins</groupId> 
            <artifactId>maven-compiler-plugin</artifactId> 
            <version>2.3.2</version> 
            <configuration> 
               <source>${jdk.version}</source> 
               <target>${jdk.version}</target> 
            </configuration> 
         </plugin> 
      </plugins> 
   </build> 
</project>    

jobConfig.xml

以下是我们示例 Spring Batch 应用的配置文件。在此文件中,我们将定义作业和步骤。此外,我们还为 ItemReader、ItemProcessor 和 ItemWriter 定义 Bean。(在这里,我们将它们与相应的类关联,并传递所需属性的值以配置它们。)

在 Maven 项目的**src > main > resources**文件夹中创建此文件。

<beans xmlns = "http://www.springframework.org/schema/beans" 
   xmlns:batch = "http://www.springframework.org/schema/batch" 
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:util = "http://www.springframework.org/schema/util" 
   xsi:schemaLocation = "http://www.springframework.org/schema/batch 
   
      http://www.springframework.org/schema/batch/spring-batch-2.2.xsd 
      http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
   
   <import resource = "context.xml" />  
   <bean id = "tutorial" class = "Tutorial" scope = "prototype" /> 
   <bean id = "itemProcessor" class = "CustomItemProcessor" />  
   
   <batch:job id = "helloWorldJob"> 
      <batch:step id = "step1"> 
         <batch:tasklet> 
            <batch:chunk reader = "mysqlItemReader" 
               writer = "flatFileItemWriter" processor = "itemProcessor" 
               commit-interval = "10"> 
            </batch:chunk> 
         </batch:tasklet> 
      </batch:step> 
   </batch:job> 
         
   <bean id = "mysqlItemReader" 
      class = "org.springframework.batch.item.database.JdbcCursorItemReader" > 
      <property name = "dataSource" ref = "dataSource" /> 
      <property name = "sql" value = "select * from details.tutorialsdata" /> 
      <property name = "rowMapper">  
         <bean class = "TutorialRowMapper" /> 
      </property> 
   </bean>
   
   <bean id = "flatFileItemWriter" 
      class = " org.springframework.batch.item.file.FlatFileItemWriter">      
      <property name = "resource" value = "file:tutorials.txt"/> 
      <property name = "lineAggregator"> 
         <bean class = " org.springframework.batch.item.file.transform.PassThroughLineAggregator"/> 
      </property> 
   </bean> 
</beans> 

Context.xml

以下是我们的 Spring Batch 应用的**context.xml**。在此文件中,我们将定义 Bean,如作业存储库、作业启动器和事务管理器。

在 Maven 项目的**src > main > resources**文件夹中创建此文件。

<beans xmlns = "http://www.springframework.org/schema/beans" 
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:jdbc = "http://www.springframework.org/schema/jdbc" 
   xsi:schemaLocation = "http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
      http://www.springframework.org/schema/jdbc 
      http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd "> 
   
   <!-- stored job-meta in database --> 
   <bean id = "jobRepository"  
      class = "org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"> 
      <property name = "dataSource" ref = "dataSource" /> 
      <property name = "transactionManager" ref = "transactionManager" /> 
      <property name = "databaseType" value = "mysql" /> 
   </bean>  
 
   <bean id = "transactionManager"  
      class = "org.springframework.batch.support.transaction.ResourcelessTransactionManager" />  
   
   <bean id = "dataSource" 
      class = "org.springframework.jdbc.datasource.DriverManagerDataSource"> 
      <property name = "url" value = "jdbc:mysql://127.0.0.1:3306/details" /> 
      <property name = "username" value = "myuser" /> 
      <property name = "password" value = "password" /> 
   </bean> 
    
   <bean id = "jobLauncher"  
      class = "org.springframework.batch.core.launch.support.SimpleJobLauncher"> 
      <property name = "jobRepository" ref = "jobRepository" /> 
   </bean> 
  
   <!-- create job-meta tables automatically --> 
   <jdbc:initialize-database data-source = "dataSource">   
      <jdbc:script location = "org/springframework/batch/core/schema-drop-mysql.sql" />   
      <jdbc:script location = "org/springframework/batch/core/schema-mysql.sql" /> 
   </jdbc:initialize-database> 
</beans> 

CustomItemProcessor.java

以下是处理器类。在此类中,我们编写应用中处理的代码。在这里,我们打印每条记录的内容。

在 Maven 项目的**src > main > java**文件夹中创建此类。

import org.springframework.batch.item.ItemProcessor;  

// Implementing the ItemProcessor interface 
public class CustomItemProcessor implements ItemProcessor<Tutorial, Tutorial> {  
 
   @Override 
   public Tutorial process(Tutorial item) throws Exception { 
      System.out.println("Processing..." + item); 
      return item; 
   } 
}

TutorialRowMapper.java

以下是**TutorialRowMapper**类,它将数据设置为**Tutorial**类。

在 Maven 项目的**src > main > java**文件夹中创建此类。

public class TutorialRowMapper implements RowMapper<Tutorial> {  
   
   @Override 
   public Tutorial mapRow(ResultSet rs, int rowNum) throws SQLException {  
  
      Tutorial tutorial = new Tutorial();  
  
      tutorial.setTutorial_id(rs.getInt("tutorial_id")); 
      tutorial.setTutorial_title(rs.getString("tutorial_title")); 
      tutorial.setTutorial_author(rs.getString("tutorial_author")); 
      tutorial.setSubmission_date(rs.getString("submission_date"));  
      return tutorial; 
   } 
}

Tutorial.java

以下是**Tutorial**类。它是一个简单的 Java 类,带有**setter**和**getter**方法。在此类中,我们使用注解将此类的方法与 XML 文件的标签关联。

在 Maven 项目的**src > main > java**文件夹中创建此类。

import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement(name = "tutorial") 
public class Tutorial {  
   private int tutorial_id; 
   private String tutorial_author; 
   private String tutorial_title;
   private String submission_date;  
 
   @XmlAttribute(name = "tutorial_id") 
   public int getTutorial_id() { 
      return tutorial_id; 
   }  
 
   public void setTutorial_id(int tutorial_id) { 
      this.tutorial_id = tutorial_id; 
   }  
 
   @XmlElement(name = "tutorial_author") 
   public String getTutorial_author() { 
      return tutorial_author; 
   }  
   public void setTutorial_author(String tutorial_author) { 
      this.tutorial_author = tutorial_author; 
   }  
      
   @XmlElement(name = "tutorial_title") 
   public String getTutorial_title() { 
      return tutorial_title; 
   }  
   
   public void setTutorial_title(String tutorial_title) { 
      this.tutorial_title = tutorial_title; 
   }  
   
   @XmlElement(name = "submission_date") 
   public String getSubmission_date() { 
      return submission_date; 
   }  
   
   public void setSubmission_date(String submission_date) { 
      this.submission_date = submission_date; 
   } 
   
   @Override 
   public String toString() { 
      return "  [Tutorial id=" + tutorial_id + 
         ",Tutorial Author=" + tutorial_author  + 
         ",Tutorial Title=" + tutorial_title + 
         ",Submission Date=" + submission_date + "]"; 
   } 
}  

App.java

以下是启动批处理过程的代码。在此类中,我们将通过运行 JobLauncher 来启动 Batch 应用。

在 Maven 项目的**src > main > java**文件夹中创建此类。

import org.springframework.batch.core.Job; 
import org.springframework.batch.core.JobExecution; 
import org.springframework.batch.core.JobParameters; 
import org.springframework.batch.core.launch.JobLauncher; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext;  

public class App {  
   
   public static void main(String[] args) throws Exception { 
     
      String[] springConfig  =  { "jobConfig.xml" };  
      
      // Creating the application context object  
      ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);  
      
      // Creating the job launcher 
      JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher"); 
    
      // Creating the job 
      Job job = (Job) context.getBean("helloWorldJob"); 
    
      // Executing the JOB 
      JobExecution execution = jobLauncher.run(job, new JobParameters()); 
      System.out.println("Exit Status : " + execution.getStatus()); 
   } 
}

输出

在 Eclipse 中右键单击项目,选择**以...方式运行 -> Maven 构建**。将目标设置为**clean package**并运行项目。您将看到以下输出。

[INFO] Scanning for projects...
[INFO] 
[INFO] [1m----------------< [0;36mcom.tutorialspoint:SpringBatchSample[0;1m >----------------[m
[INFO] [1mBuilding SpringBatchExample 1.0-SNAPSHOT[m
[INFO]   from pom.xml
[INFO] [1m--------------------------------[ jar ]---------------------------------[m
[INFO] 
[INFO] [1m--- [0;32mclean:3.2.0:clean[m [1m(default-clean)[m @ [36mSpringBatchSample[0;1m ---[m
[INFO] Deleting C:\Users\Tutorialspoint\eclipse-workspace\SpringBatchSample\target
[INFO] 
[INFO] [1m--- [0;32mresources:3.3.1:resources[m [1m(default-resources)[m @ [36mSpringBatchSample[0;1m ---[m
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 4 resources from src\main\resources to target\classes
[INFO] 
[INFO] [1m--- [0;32mcompiler:2.3.2:compile[m [1m(default-compile)[m @ [36mSpringBatchSample[0;1m ---[m
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 5 source files to C:\Users\Tutorialspoint\eclipse-workspace\SpringBatchSample\target\classes
[INFO] 
[INFO] [1m--- [0;32mresources:3.3.1:testResources[m [1m(default-testResources)[m @ [36mSpringBatchSample[0;1m ---[m
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource from src\test\resources to target\test-classes
[INFO] 
[INFO] [1m--- [0;32mcompiler:2.3.2:testCompile[m [1m(default-testCompile)[m @ [36mSpringBatchSample[0;1m ---[m
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] [1m--- [0;32msurefire:3.1.2:test[m [1m(default-test)[m @ [36mSpringBatchSample[0;1m ---[m
[INFO] 
[INFO] [1m--- [0;32mjar:3.3.0:jar[m [1m(default-jar)[m @ [36mSpringBatchSample[0;1m ---[m
[INFO] Building jar: C:\Users\Tutorialspoint\eclipse-workspace\SpringBatchSample\target\spring-batch.jar
[INFO] [1m------------------------------------------------------------------------[m
[INFO] [1;32mBUILD SUCCESS[m
[INFO] [1m------------------------------------------------------------------------[m
[INFO] Total time:  3.323 s
[INFO] Finished at: 2024-07-31T13:35:50+05:30
[INFO] [1m------------------------------------------------------------------------[m

要检查上述 SpringBatch 程序的输出,请右键单击 App.java 类并选择**以...方式运行 -> Java 应用**。它将产生以下输出 -

Jul 31, 2024 1:36:25 PM org.springframework.batch.core.launch.support.SimpleJobLauncher afterPropertiesSet
INFO: No TaskExecutor has been set, defaulting to synchronous executor.
Jul 31, 2024 1:36:28 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=helloWorldJob]] launched with the following parameters: [{}]
Jul 31, 2024 1:36:28 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [step1]
Processing...  [Tutorial id=101,Tutorial Author=Sanjay,Tutorial Title=Learn Java,Submission Date=06-05-2007]
Processing...  [Tutorial id=102,Tutorial Author=Abdul S,Tutorial Title=Learn MySQL,Submission Date=19-04-2007]
Processing...  [Tutorial id=103,Tutorial Author=Krishna Kasyap,Tutorial Title=Learn JavaFX,Submission Date=06-07-2017]
Jul 31, 2024 1:36:28 PM org.springframework.batch.core.step.AbstractStep execute
INFO: Step: [step1] executed in 191ms
Jul 31, 2024 1:36:28 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=helloWorldJob]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 515ms
Exit Status : COMPLETED

这将生成一个 TXT 文件(根文件夹中的 tutorials.txt),其内容如下。

  [Tutorial id=101,Tutorial Author=Sanjay,Tutorial Title=Learn Java,Submission Date=06-05-2007]
  [Tutorial id=102,Tutorial Author=Abdul S,Tutorial Title=Learn MySQL,Submission Date=19-04-2007]
  [Tutorial id=103,Tutorial Author=Krishna Kasyap,Tutorial Title=Learn JavaFX,Submission Date=06-07-2017]
广告