Spring Batch 简明教程

Spring Batch - XML to MySQL

在本章中,我们将创建一个使用 XML 读取器和 MySQL 写入器的 Spring Batch 应用程序

In this chapter, we will create a Spring Batch application which uses an XML Reader and a MySQL Writer.

Reader − 我们在应用程序中使用的读取器是 StaxEventItemReader 以从 XML 文档读取数据

Reader − The reader we are using in the application is StaxEventItemReader to read data from XML documents.

以下为我们在本应用程序中使用的输入 XML 文档。此文档包含详细记录指定教程 ID、教程作者、教程标题、提交日期、教程图标和教程描述等详细信息的数据记录

Following is the input XML document we are using in this application. This document holds data records which specify details like tutorial id, tutorial author, tutorial title, submission date, tutorial icon, and tutorial description.

<?xml version="1.0" encoding="UTF-8"?>
<tutorials>
   <tutorial>
      <tutorial_id>1001</tutorial_id>
      <tutorial_author>Sanjay</tutorial_author>
      <tutorial_title>Learn Java</tutorial_title>
      <submission_date>06-05-2007</submission_date>
      <tutorial_icon>https://www.tutorialspoint.com/java/images/java-minilogo.jpg</tutorial_icon>
      <tutorial_description>Java is a high-level programming language originally
         developed by Sun Microsystems and released in 1995.
         Java runs on a variety of platforms.
         This tutorial gives a complete understanding of Java.');</tutorial_description>
   </tutorial>

   <tutorial>
      <tutorial_id>1002</tutorial_id>
      <tutorial_author>Abdul S</tutorial_author>
      <tutorial_title>Learn MySQL</tutorial_title>
      <submission_date>19-04-2007</submission_date>
      <tutorial_icon>https://www.tutorialspoint.com/mysql/images/mysql-minilogo.jpg</tutorial_icon>
      <tutorial_description>MySQL is the most popular
         Open Source Relational SQL database management system.
         MySQL is one of the best RDBMS being used for developing web-based software applications.
         This tutorial will give you quick start with MySQL
         and make you comfortable with MySQL programming.</tutorial_description>
   </tutorial>

   <tutorial>
      <tutorial_id>1003</tutorial_id>
      <tutorial_author>Krishna Kasyap</tutorial_author>
      <tutorial_title>Learn JavaFX</tutorial_title>
      <submission_date>06-07-2017</submission_date>
      <tutorial_icon>https://www.tutorialspoint.com/javafx/images/javafx-minilogo.jpg</tutorial_icon>
      <tutorial_description>JavaFX is a Java library used to build Rich Internet Applications.
         The applications developed using JavaFX can run on various devices
         such as Desktop Computers, Mobile Phones, TVs, Tablets, etc.
         This tutorial, discusses all the necessary elements of JavaFX that are required
         to develop effective Rich Internet Applications</tutorial_description>
   </tutorial>
</tutorials>

Writer − 我们在应用程序中使用的 writerJdbcBatchItemWriter 以将数据写入 MySQL 数据库。假设我们在名为 "details" 的数据库中创建了 MySQL 中的一个表

Writer − The writer we are using in the application is JdbcBatchItemWriter to write the data to MySQL database. Assume we have created a table in MySQL inside a database called "details".

CREATE TABLE details.TUTORIALS(
   tutorial_id int(10) NOT NULL,
   tutorial_author VARCHAR(20),
   tutorial_title VARCHAR(50),
   submission_date VARCHAR(20),
   tutorial_icon VARCHAR(200),
   tutorial_description VARCHAR(1000)
);

Processor − 我们在应用程序中使用的处理器是一个自定义处理器,它在 PDF 文档上输出每条记录的数据。

Processor − The processor we are using in the application is a custom processor which writes the data of each record on the PDF document.

在批处理中,如果读取 "n" 记录或数据元素,那么对于每条记录,它将读取数据,处理它,然后在写入器中写入数据。要处理数据,它会中继到已传递的处理器。在本例中,在自定义的处理器类中,我们编写的代码能够加载特定的 PDF 文档,创建一个新页面,将数据项以表格格式写入 PDF。

In batch process, if "n" records or data elements were read, then for each record, it will read the data, process it, and write the data in the Writer. To process the data, it relays on the processor passed. In this case, in the custom processor class, we have written code to load a particular PDF document, create a new page, write the data item onto the PDF in a tabular format.

最后,如果你执行此应用程序,它将从 XML 文档读取所有数据项,将它们存储在 MySQL 数据库中,并以单独的页面在给定的 PDF 文档中打印它们。

Finally, if you execute this application, it reads all the data items from the XML document, stores them in the MySQL database, and prints them in the given PDF document in individual pages.

jobConfig.xml

以下为我们示例 Spring Batch 应用程序的配置文件。在此文件中,我们将定义作业和步骤。除了这些之外,我们还将定义 ItemReader、ItemProcessor 和 ItemWriter 的 Bean。(在这里,我们将它们分别与其类关联起来,并传递必需的属性值来配置它们。)

Following is the configuration file of our sample Spring Batch application. In this file, we will define the Job and the steps. In addition to these, we also define the beans for ItemReader, ItemProcessor, and ItemWriter. (Here, we associate them with their respective classes and pass the values for the required properties to configure them.)

<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
      http://www.springframework.org/schema/util
      http://www.springframework.org/schema/util/spring-util-3.0.xsd ">

   <import resource = "../jobs/context.xml" />

   <bean id = "itemProcessor" class = "CustomItemProcessor" />
   <batch:job id = "helloWorldJob">
      <batch:step id = "step1">
         <batch:tasklet>
            <batch:chunk reader = "xmlItemReader" writer = "mysqlItemWriter" processor = "itemProcessor">
            </batch:chunk>
         </batch:tasklet>
      </batch:step>
   </batch:job>

   <bean id = "xmlItemReader"
      class = "org.springframework.batch.item.xml.StaxEventItemReader">
      <property name = "fragmentRootElementName" value = "tutorial" />
      <property name = "resource" value = "classpath:resources/tutorial.xml" />
      <property name = "unmarshaller" ref = "customUnMarshaller" />
   </bean>

   <bean id = "customUnMarshaller" class = "org.springframework.oxm.xstream.XStreamMarshaller">
      <property name = "aliases">
         <util:map id = "aliases">
            <entry key = "tutorial" value = "Tutorial" />
         </util:map>
      </property>
   </bean>
   <bean id = "mysqlItemWriter" class = "org.springframework.batch.item.database.JdbcBatchItemWriter">
      <property name = "dataSource" ref = "dataSource" />
      <property name = "sql">
         <value>
            <![CDATA[insert into details.tutorials (tutorial_id, tutorial_author, tutorial_title,
               submission_date, tutorial_icon, tutorial_description)
               values (:tutorial_id, :tutorial_author, :tutorial_title, :submission_date,
               :tutorial_icon, :tutorial_description);]]>
         </value>
      </property>

      <property name = "itemSqlParameterSourceProvider">
         <bean class = "org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider" />
      </property>
   </bean>
</beans>

Context.xml

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

Following is the context.xml of our Spring Batch application. In this file, we will define the beans like job repository, job launcher, and transaction manager.

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:jdbc = "http://www.springframework.org/schema/jdbc"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   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.ResourcelessTransactionMana ger" />
   <bean id = "jobLauncher"
      class = "org.springframework.batch.core.launch.support.SimpleJobLauncher">
      <property name = "jobRepository" ref = "jobRepository" />
   </bean>

   <!-- connect to MySQL database -->
   <bean id = "dataSource"
      class = "org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name = "driverClassName" value = "com.mysql.jdbc.Driver" />
      <property name = "url" value = "jdbc:mysql://localhost:3306/details" />
      <property name = "username" value = "myuser" />
      <property name = "password" value = "password" />
   </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

以下为 processor 类。在此类中,我们编写应用程序中的处理代码。在这里,我们加载 PDF 文档,创建一个新页面,创建一个表,并为表中的每条记录插入以下的值:教程 ID、教程名称、作者、提交日期。

Following is the processor class. In this class, we write the code of processing in the application. Here, we are loading a PDF document, creating a new page, creating a table, and inserting the following values for each record: tutorial id, tutorial name, author, date of submission in the table.

import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.springframework.batch.item.ItemProcessor;

public class CustomItemProcessor implements ItemProcessor<Tutorial, Tutorial> {

   public static void drawTable(PDPage page, PDPageContentStream contentStream,
      float y, float margin, String[][] content) throws IOException {
      final int rows = content.length;
      final int cols = content[0].length;
      final float rowHeight = 50;
      final float tableWidth = page.getMediaBox().getWidth()-(2*margin);
      final float tableHeight = rowHeight * rows;
      final float colWidth = tableWidth/(float)cols;
      final float cellMargin=5f;

      // draw the rows
      float nexty = y ;
      for (int i = 0; i <= rows; i++) {
         contentStream.drawLine(margin,nexty,margin+tableWidth,nexty);
         nexty-= rowHeight;
      }

      //draw the columns
      float nextx = margin;
      for (int i = 0; i <= cols; i++) {
         contentStream.drawLine(nextx,y,nextx,y-tableHeight);
         nextx += colWidth;
      }

      // now add the text
      contentStream.setFont(PDType1Font.HELVETICA_BOLD,12);

      float textx = margin+cellMargin;
      float texty = y-15;
      for(int i = 0; i < content.length; i++){
         for(int j = 0 ; j < content[i].length; j++){
            String text = content[i][j];
            contentStream.beginText();
            contentStream.moveTextPositionByAmount(textx,texty);
            contentStream.drawString(text);
            contentStream.endText();
            textx += colWidth;
         }

         texty-=rowHeight;
         textx = margin+cellMargin;
      }
   }

   @Override
   public Tutorial process(Tutorial item) throws Exception {
      System.out.println("Processing..." + item);

      // Creating PDF document object
      PDDocument doc = PDDocument.load(new File("C:/Examples/test.pdf"));

      // Creating a blank page
      PDPage page = new PDPage();
      doc.addPage( page );
      PDPageContentStream contentStream =  new PDPageContentStream(doc, page);

      String[][] content = {{"Id",""+item.getTutorial_id()},
      {"Title", item.getTutorial_title()},
      {"Authour", item.getTutorial_author()},
      {"Submission Date", item.getSubmission_date()}} ;
      drawTable(page, contentStream, 700, 100, content);

      contentStream.close();
      doc.save("C:/Examples/test.pdf" );
      System.out.println("Hello");
      return item;
   }
}

TutorialFieldSetMapper.java

以下是将数据设置为 Tutorial 类的 ReportFieldSetMapper 类。

Following is the ReportFieldSetMapper class which sets the data to the Tutorial class.

import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;

public class TutorialFieldSetMapper implements FieldSetMapper<Tutorial> {

   @Override
   public Tutorial mapFieldSet(FieldSet fieldSet) throws BindException {
      // instantiating the Tutorial class
      Tutorial tutorial = new Tutorial();

      // Setting the fields from XML
      tutorial.setTutorial_id(fieldSet.readInt(0));
      tutorial.setTutorial_title(fieldSet.readString(1));
      tutorial.setTutorial_author(fieldSet.readString(2));
      tutorial.setTutorial_icon(fieldSet.readString(3));
      tutorial.setTutorial_description(fieldSet.readString(4));
      return tutorial;
   }
}

Tutorial.java

以下是 Tutorial 类。它是一个具有 settergetter 方法的简单类。

Following is the Tutorial class. It is a simple class with setter and getter methods.

public class Tutorial {
   private int tutorial_id;
   private String tutorial_author;
   private String tutorial_title;
   private String submission_date;
   private String tutorial_icon;
   private String tutorial_description;

   @Override
   public String toString() {
      return " [id=" + tutorial_id + ", author=" + tutorial_author
         + ", title=" + tutorial_title + ", date=" + submission_date + ", icon ="
         +tutorial_icon +", description = "+tutorial_description+"]";
   }

   public int getTutorial_id() {
      return tutorial_id;
   }

   public void setTutorial_id(int tutorial_id) {
      this.tutorial_id = tutorial_id;
   }

   public String getTutorial_author() {
      return tutorial_author;
   }

   public void setTutorial_author(String tutorial_author) {
      this.tutorial_author = tutorial_author;
   }

   public String getTutorial_title() {
      return tutorial_title;
   }

   public void setTutorial_title(String tutorial_title) {
      this.tutorial_title = tutorial_title;
   }

   public String getSubmission_date() {
      return submission_date;
   }

   public void setSubmission_date(String submission_date) {
      this.submission_date = submission_date;
   }

   public String getTutorial_icon() {
      return tutorial_icon;
   }

   public void setTutorial_icon(String tutorial_icon) {
      this.tutorial_icon = tutorial_icon;
   }

   public String getTutorial_description() {
      return tutorial_description;
   }

   public void setTutorial_description(String tutorial_description) {
      this.tutorial_description = tutorial_description;
   }
}

App.java

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

Following is the code which launces the batch process. In this class, we will launch the Batch Application by running the JobLauncher.

public class App {
   public static void main(String[] args) throws Exception {
      String[] springConfig  = {    "jobs/job_hello_world.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());
   }
}

执行此应用程序后,它将生成以下输出。

On executing this application, it will produce the following output.

May 05, 2017 4:39:22 PM org.springframework.context.support.ClassPathXmlApplicationContext
prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@306a30c7:
startup date [Fri May 05 16:39:22 IST 2017]; root of context hierarchy
May 05, 2017 4:39:23 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
May 05, 2017 4:39:32 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [step1]
Processing... [id=1001, author=Sanjay, title=Learn Java, date=06-05-2007,
icon =https://www.tutorialspoint.com/java/images/java-mini-logo.jpg,
description = Java is a high-level programming language originally developed by Sun Microsystems
and released in 1995. Java runs on a variety of platforms.
This tutorial gives a complete understanding of Java.');]
Hello
Processing.. [id=1002, author=Abdul S, title=Learn MySQL, date=19-04-2007,
icon =https://www.tutorialspoint.com/mysql/images/mysql-mini-logo.jpg,
description = MySQL is the most popular Open Source Relational SQL database management system.
MySQL is one of the best RDBMS being used for developing web-based software applications.
This tutorial will give you quick start with MySQL and make you comfortable with MySQL programming.]
Hello
Processing... [id=1003, author=Krishna Kasyap, title=Learn JavaFX, date=06-072017,
icon =https://www.tutorialspoint.com/javafx/images/javafx-mini-logo.jpg,
description = JavaFX is a Java library used to build Rich Internet Applications.
The applications developed using JavaFX can run on various devices
such as Desktop Computers, Mobile Phones, TVs, Tablets, etc.
This tutorial, discusses all the necessary elements of JavaFX
that are required to develop effective Rich Internet Applications]
Hello
May 05, 2017 4:39:36 PM org.springframework.batch.core.launch.support.SimpleJobLauncher run
INFO: Job: [FlowJob: [name=helloWorldJob]] completed with the following parameters: [{}]
and the following status: [COMPLETED]
Exit Status : COMPLETED

如果您在数据库中验证 details.tutorial 表,它将显示以下输出 −

If you verify the details.tutorial table in the database, it will show you the following output −

tutorial _id

tutorial _author

tutorial _title

submission _date

tutorial _icon

tutorial _description

1001

Sanjay

Learn Java

06-05-2007

https://www.tutorials point.com /java/images/ java-mini-logo.jpg

Java is a high-level programming language originally developed by Sun Microsystems and released in 1995. Java runs on a variety of platforms. This tutorial gives a complete understanding of Java.

1002

Abdul S

Learn MySQL

19-04-2007

https://www. tutorialspoint.com /mysql/images /mysql-minilogo.jpg

MySQL is the most popular Open Source Relational SQL database management system. MySQL is one of the best RDBMS being used for developing web-based software applications. This tutorial will give you quick start with MySQL and make you comfortable with MySQL programming.

1003

Learn JavaFX

Krishna Kasyap

06-07-2017

https://www. tutorialspoint.com /javafx/images/ javafx-minilogo.jpg

MySQL is the most popular Open Source Relational SQL database management system. MySQL is one of the best RDBMS being used for developing web-based software applications. This tutorial will give you quick start with MySQL and make you comfortable with MySQL programming.

这将生成一个 PDF,其中每一页都有记录,如下所示。

This will generate a PDF with the records on each page as shown below.

page thumbnails