Spring Batch XML到MySQL


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

讀取器 - 在應用程式中使用的讀取器是StaxEventItemReader,用於從XML文件讀取資料。

以下是應用程式中使用的輸入XML文件。 此文件包含指定詳細資訊的資料記錄,如教學ID,教學作者,教學標題,提交日期,教學圖示和教學說明。

完整的專案目錄結構如下所示 -

檔案: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>/20/206/8011.htmlimages/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>/18/142/4124.htmlimages/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>/20/206/8011.htmlfximages/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 =/20/206/8011.htmlimages/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 =/18/142/4124.htmlimages/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 =/20/206/8011.htmlfximages/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表,應該會看到以下內容 -

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>