Spring Batch XML到MySQL

在本章中,我們將創建一個使用XML Reader和MySQL Writer的Spring Batch應用程序。

讀取器 - 在應用程序中使用的讀取器是StaxEventItemReader,用於從XML文檔讀取數據。

以下是應用程序中使用的輸入XML文檔。 此文檔包含指定詳細信息的數據記錄,如教程ID,教程作者,教程標題,提交日期,教程圖標和教程說明。

完整的項目目錄結構如下所示 -
Spring

文件:tutorials.xml -

<?xml version="1.0" encoding="UTF-8"?> 
<tutorials> 
   <tutorial>      
      <tutorial_id>1001</tutorial_id> 
      <tutorial_author>Sansu</tutorial_author> 
      <tutorial_title>Learn Java</tutorial_title> 
      <submission_date>06-05-2007</submission_date> 
      <tutorial_icon>https://www.yiibai.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>Maxsu</tutorial_author> 
      <tutorial_title>MySQL學習</tutorial_title> 
      <submission_date>19-04-2007</submission_date> 
      <tutorial_icon>https://www.yiibai.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>Kobe</tutorial_author> 
      <tutorial_title>Learn JavaFX</tutorial_title> 
      <submission_date>06-07-2017</submission_date> 
      <tutorial_icon>https://www.yiibai.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 - 在應用程序中使用的寫入器是JdbcBatchItemWriter,用於將數據寫入MySQL數據庫。 假設在testdb的數據庫中創建了一個tutorials表。使用以下SQL語句創建創建表:

CREATE TABLE testdb.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) 
);

處理器 - 在應用程序中使用的處理器是一個自定義處理器,它將每個記錄的數據寫入PDF文檔。

在批處理過程中,如果讀取了「n」個記錄或數據元素,那麼對於每個記錄,它將讀取數據,處理數據並將數據寫入Writer。要處理數據,它在通過的處理器上進行中繼。 在這種情況下,在自定義處理器類中,我們編寫代碼來加載特定的PDF文檔,創建新頁面,並以表格格式將數據項寫入PDF。

最後,如果您執行此應用程序,它將讀取XML文檔中的所有數據項,將它們存儲在MySQL數據庫中,並將它們打印到單個頁面中給定的PDF文檔中。

jobconfig.xml

以下是示例Spring Batch應用程序的配置文件。 在這個文件中,我們將定義Job和step。 除此之外,還爲ItemReaderItemProcessorItemWriter定義了bean。 (在這裏,我們將它們與它們各自的類相關聯,並傳遞所需屬性的值來配置它們。)

<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 = "context.xml" /> 

   <bean id = "itemProcessor" class = "com.yiibai.CustomItemProcessor" /> 
   <batch:job id = "helloWorldJob"> 
      <batch:step id = "step1"> 
         <batch:tasklet>           
            <batch:chunk reader = "xmlItemReader" writer = "mysqlItemWriter" processor = "itemProcessor" commit-interval="10000">
            </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:tutorials.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 ="com.yiibai.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 testdb.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,如作業存儲庫,作業啓動器和事務管理器。

<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.ResourcelessTransactionManager" />
    <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/testdb" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </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

以下是處理器類。 在這個類中,在應用程序中編寫處理代碼。 在這裏,我們正在加載一個PDF文檔,創建一個新頁面,創建一個表格,併爲每條記錄插入以下值:教程ID,教程名稱,作者,表格中的提交日期。

package com.yiibai;

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("D:/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("D:/test.pdf");
        System.out.println("Hello");
        return item;
    }
}

文件:TutorialFieldSetMapper.java

以下是將數據設置爲Tutorial類的ReportFieldSetMapper類的代碼實現。

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方法的簡單類。

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來啓動批處理應用程序。

package com.yiibai;

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());
    }
}

在執行這個應用程序時,它將產生以下輸出 -

信息: Executed SQL script from class path resource [org/springframework/batch/core/schema-mysql.sql] in 5074 ms.
四月 28, 2018 10:15:26 上午 org.springframework.batch.core.launch.support.SimpleJobLauncher run
信息: Job: [FlowJob: [name=helloWorldJob]] launched with the following parameters: [{}]
四月 28, 2018 10:15:27 上午 org.springframework.batch.core.job.SimpleStepHandler handleStep
信息: Executing step: [step1]
Processing... [id=1001, author=Sansu, title=Learn Java, date=06-05-2007, icon =https://www.yiibai.com/java/images/java-minilogo.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=Maxsu, title=MySQL學習, date=19-04-2007, icon =https://www.yiibai.com/mysql/images/mysql-minilogo.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=Kobe, title=Learn JavaFX, date=06-07-2017, icon =https://www.yiibai.com/javafx/images/javafx-minilogo.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
四月 28, 2018 10:15:30 上午 org.springframework.batch.core.launch.support.SimpleJobLauncher run
信息: Job: [FlowJob: [name=helloWorldJob]] completed with the following parameters: [{}] and the following status: [COMPLETED]
Exit Status : COMPLETED

如果打開數據庫中的test.tutorial表,應該會看到以下內容 -

Spring

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.yiibai</groupId>
    <artifactId>SpringBatchSample</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SpringBatchExample</name>
    <url>http://maven.apache.org</url>

    <properties>
        <jdk.version>1.8</jdk.version>
        <spring.version>4.3.8.RELEASE</spring.version>
        <spring.batch.version>3.0.7.RELEASE</spring.batch.version>
        <mysql.driver.version>5.1.25</mysql.driver.version>
        <junit.version>4.11</junit.version>
    </properties>

    <dependencies>
        <!-- Spring Core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/pdfbox/pdfbox -->
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.0</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>mysql</groupId>
            <artifactId>mysql-connector-java</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>
    </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>
        <defaultGoal>compile</defaultGoal>
    </build>
</project>