【Spring Batch学习笔记】3:自定义Reader,Processor,Writer使用iReport批量生成报表

使用Spring Batch结合iReport批量生成xlspdfxlsxdocxpptx文件。数据源来自之前的MySQL数据库。

报表样式

从数据库生成.jasper文件见这篇。
【Spring Batch学习笔记】3:自定义Reader,Processor,Writer使用iReport批量生成报表_第1张图片

程序

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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>org.lzhgroupId>
    <artifactId>testSpringBatchartifactId>
    <version>1.0-SNAPSHOTversion>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <configuration>
                    <source>8source>
                    <target>8target>
                configuration>
            plugin>
        plugins>
    build>

    <dependencies>

        
        
        <dependency>
            <groupId>org.springframework.batchgroupId>
            <artifactId>spring-batch-coreartifactId>
            <version>3.0.7.RELEASEversion>
        dependency>

        
        
        <dependency>
            <groupId>org.codehaus.groovygroupId>
            <artifactId>groovy-allartifactId>
            <version>2.4.7version>
        dependency>
        
        <dependency>
            <groupId>com.lowagiegroupId>
            <artifactId>itextartifactId>
            <version>2.1.7version>
        dependency>
        
        <dependency>
            <groupId>com.itextpdfgroupId>
            <artifactId>itext-asianartifactId>
            <version>5.2.0version>
        dependency>
        
        <dependency>
            <groupId>net.sf.jasperreportsgroupId>
            <artifactId>jasperreportsartifactId>
            <version>5.6.0version>
        dependency>

        
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.11version>
        dependency>

        
        
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poiartifactId>
            <version>3.9version>
        dependency>

        

    dependencies>

project>

applicationContext.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">
    
    <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        
        <property name="jobRepository" ref="jobRepository"/>
    bean>
    
    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"/>
    
    <bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
beans>

batch.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:batch="http://www.springframework.org/schema/batch"
       xmlns:http="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/batch
        http://www.springframework.org/schema/batch/spring-batch.xsd">

    
    <import resource="applicationContext.xml"/>

    

    <batch:job id="iReportJob">
        <batch:step id="step-xls" next="step-pdf">
            <batch:tasklet transaction-manager="transactionManager">
                <batch:chunk reader="myJasperReader" processor="myJasperPrintProcessor-xls" writer="myBAOSWriter-xls" commit-interval="1"/>
            batch:tasklet>
        batch:step>
        <batch:step id="step-pdf" next="step-xlsx">
            <batch:tasklet transaction-manager="transactionManager">
                <batch:chunk reader="myJasperReader" processor="myJasperPrintProcessor-pdf" writer="myBAOSWriter-pdf" commit-interval="1"/>
            batch:tasklet>
        batch:step>
        <batch:step id="step-xlsx" next="step-docx">
            <batch:tasklet transaction-manager="transactionManager">
                <batch:chunk reader="myJasperReader" processor="myJasperPrintProcessor-xlsx" writer="myBAOSWriter-xlsx" commit-interval="1"/>
            batch:tasklet>
        batch:step>
        <batch:step id="step-docx" next="step-pptx">
            <batch:tasklet transaction-manager="transactionManager">
                <batch:chunk reader="myJasperReader" processor="myJasperPrintProcessor-docx" writer="myBAOSWriter-docx" commit-interval="1"/>
            batch:tasklet>
        batch:step>
        <batch:step id="step-pptx">
            <batch:tasklet transaction-manager="transactionManager">
                <batch:chunk reader="myJasperReader" processor="myJasperPrintProcessor-pptx" writer="myBAOSWriter-pptx" commit-interval="1"/>
            batch:tasklet>
        batch:step>
    batch:job>

    

    <bean id="myJasperReader" class="org.lzh.reader.MyJasperReader" scope="step">
        <property name="driven" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url">
            <list>
                <value>jdbc:mysql://localhost:3306/testdb?useSSL=falsevalue>
                <value>serverTimezone=GMT%2B8value>
            list>
        property>
        <property name="usr" value="lzh"/>
        <property name="pwd" value="3838438"/>
        <property name="jasperFilePath" value="D:/WorkSpace/iReport/fromMySQL.jasper"/>
        <property name="parameters">
            <map>
                <entry key="author" value="刘知昊"/>
            map>
        property>
    bean>

    

    <bean id="myJasperPrintProcessor-xls" class="org.lzh.processor.MyJasperPrintProcessor" scope="step">
        <property name="type" value="xls"/>
    bean>

    <bean id="myJasperPrintProcessor-pdf" class="org.lzh.processor.MyJasperPrintProcessor" scope="step">
        <property name="type" value="pdf"/>
    bean>

    <bean id="myJasperPrintProcessor-xlsx" class="org.lzh.processor.MyJasperPrintProcessor" scope="step">
        <property name="type" value="xlsx"/>
    bean>

    <bean id="myJasperPrintProcessor-docx" class="org.lzh.processor.MyJasperPrintProcessor" scope="step">
        <property name="type" value="docx"/>
    bean>

    <bean id="myJasperPrintProcessor-pptx" class="org.lzh.processor.MyJasperPrintProcessor" scope="step">
        <property name="type" value="pptx"/>
    bean>

    

    <bean id="myBAOSWriter-xls" class="org.lzh.writer.MyBAOSWriter" scope="step">
        <property name="suffix" value=".xls"/>
    bean>

    <bean id="myBAOSWriter-pdf" class="org.lzh.writer.MyBAOSWriter" scope="step">
        <property name="suffix" value=".pdf"/>
    bean>

    <bean id="myBAOSWriter-xlsx" class="org.lzh.writer.MyBAOSWriter" scope="step">
        <property name="suffix" value=".xlsx"/>
    bean>

    <bean id="myBAOSWriter-docx" class="org.lzh.writer.MyBAOSWriter" scope="step">
        <property name="suffix" value=".docx"/>
    bean>

    <bean id="myBAOSWriter-pptx" class="org.lzh.writer.MyBAOSWriter" scope="step">
        <property name="suffix" value=".pptx"/>
    bean>

beans>

JdbcConnector类

package org.lzh.connector;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

//对JDBC做简单封装
public class JdbcConnector {
    private static Connection connection = null;

    public static Connection link(String driven,String url, String usr, String pwd) {
        try {
            Class.forName(driven);
            connection = DriverManager.getConnection(url, usr, pwd);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

    public static void close() {
        if (null != connection) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

MyJasperReader类

package org.lzh.reader;

import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import org.lzh.connector.JdbcConnector;
import org.springframework.batch.item.ItemReader;

import java.sql.Connection;
import java.util.Map;

//读取jasper文件,与参数、数据源对象一并封装成JasperPrint总资源对象
public class MyJasperReader implements ItemReader<JasperPrint> {
    //由Spring注入
    private String driven;//驱动字符串
    private String[] url;//连接字符串
    private String usr;//连接账户
    private String pwd;//密码
    private String jasperFilePath;//编译后的jasper文件位置
    private Map parameters;//用来设置参数的Map
    //用来指示是否应当结束,不知道为什么一直重复执行step,只能用此下策
    private boolean isEnd = false;

    //用&来连接url
    private String linkUrl() {
        return String.join("&", url);
    }

    @Override
    public JasperPrint read() throws Exception {
        System.out.println("---Reader开始了---");
        //建立连接,即作为数据源对象(这里写死了,可以考虑加个List字段,然后可以选择从POJO的列表建立数据源)
        Connection connection = JdbcConnector.link(driven, linkUrl(), usr, pwd);
        //将jasper资源、参数Map、数据源对象整合到一起,形成JasperPrint总资源对象
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperFilePath, parameters, connection);
        //如果还没结束,即第一次跑,设置下次结束并正常返回(这时Connection等到Processor中断开)
        if (!isEnd){
            isEnd=true;
            return jasperPrint;
        }
        //如果已经结束,返回null停止执行
        System.out.println("[!]是时候结束step了");
        JdbcConnector.close();
        return null;
    }

    public void setDriven(String driven) {
        this.driven = driven;
    }

    public void setUrl(String[] url) {
        this.url = url;
    }

    public void setUsr(String usr) {
        this.usr = usr;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public void setJasperFilePath(String jasperFilePath) {
        this.jasperFilePath = jasperFilePath;
    }

    public void setParameters(Map parameters) {
        this.parameters = parameters;
    }
}

MyJasperPrintProcessor类

package org.lzh.processor;

import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperPrint;

import net.sf.jasperreports.engine.export.*;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRPptxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.export.*;
import org.lzh.connector.JdbcConnector;
import org.springframework.batch.item.ItemProcessor;

import java.io.ByteArrayOutputStream;

//拿到JasperPrint总资源对象,做相应的处理,生成ByteArrayOutputStream用于输出
public class MyJasperPrintProcessor implements ItemProcessor<JasperPrint, ByteArrayOutputStream> {
    //由Spring来注入
    private String type;//要生成的文件类型
    //字节数组输出流,用于返回
    private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

    @Override
    public ByteArrayOutputStream process(JasperPrint jasperPrint) throws Exception {
        //类型缺失
        if (null == type) {
            System.out.println("[x]没有为Processor注入要生成的文件类型");
            //注意关闭连接
            JdbcConnector.close();
            return null;//null则告诉Writer不需再处理
        }
        //这个try-finally用于在真正执行return前关闭连接
        try {
            //对于不同的类型做不同的处理
            if (type.equals("pdf")) {
                /**演示旧的实现方式*/
                //PDF输出工具
                JRPdfExporter jrPdfExporter = new JRPdfExporter();
                //为输出工具组合插件
                jrPdfExporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);//总资源对象
                jrPdfExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, byteArrayOutputStream);//输出字节数组流
                jrPdfExporter.setParameter(JRExporterParameter.CHARACTER_ENCODING, "UTF-8");//编码
                //导出,导出结束后会按照参数将结果放在输出字节数组流中
                jrPdfExporter.exportReport();
                return byteArrayOutputStream;
            } else if (type.equals("xls")) {
                /**演示新的实现方式,后面一概采用新的实现方式,旧的已经被@deprecate了*/
                //Xls输出工具
                JRXlsExporter jrXlsExporter = new JRXlsExporter();
                //为输出工具组合插件,不再使用被@deprecated的setParameter方法
                jrXlsExporter.setExporterInput(new SimpleExporterInput(jasperPrint));//总资源对象
                jrXlsExporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));//输出字节流数组
                //XLS配置对象
                SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration();
                configuration.setOnePagePerSheet(true);//每个工作表仅一页
                configuration.setDetectCellType(true);
                configuration.setCollapseRowSpan(false);
                //把配好的配置对象装载到输出工具上
                jrXlsExporter.setConfiguration(configuration);
                //导出,导出结束后会按照参数将结果放在输出字节数组流中
                jrXlsExporter.exportReport();
                return byteArrayOutputStream;
            } else if (type.equals("docx")) {
                JRDocxExporter jrDocxExporter = new JRDocxExporter();
                jrDocxExporter.setExporterInput(new SimpleExporterInput(jasperPrint));
                jrDocxExporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));
                SimpleDocxReportConfiguration configuration = new SimpleDocxReportConfiguration();
                configuration.setFlexibleRowHeight(true);//随便设置个配置
                jrDocxExporter.setConfiguration(configuration);
                jrDocxExporter.exportReport();
                return byteArrayOutputStream;
            } else if (type.equals("pptx")) {
                JRPptxExporter jrPptxExporter = new JRPptxExporter();
                jrPptxExporter.setExporterInput(new SimpleExporterInput(jasperPrint));
                jrPptxExporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));
                //SimplePptxReportConfiguration configuration=new SimplePptxReportConfiguration();
                //也可以像这样不设置配置,那就不需要装配这个设置对象到输出工具上,直接输出就好了
                jrPptxExporter.exportReport();
                return byteArrayOutputStream;
            } else if (type.equals("xlsx")) {
                JRXlsxExporter jrXlsxExporter = new JRXlsxExporter();
                jrXlsxExporter.setExporterInput(new SimpleExporterInput(jasperPrint));
                jrXlsxExporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));
                SimpleXlsxExporterConfiguration configuration = new SimpleXlsxExporterConfiguration();
                configuration.setKeepWorkbookTemplateSheets(true);
                jrXlsxExporter.setConfiguration(configuration);
                jrXlsxExporter.exportReport();
                return byteArrayOutputStream;
            }// FIXME 继续添加其它输出文件类型
            //至此是未识别的类型
            System.out.println("[x]未能被Processor识别的类型");
            return null;
        } finally {
            System.out.println("[v]关闭连接...");
            JdbcConnector.close();
        }
    }

    public void setType(String type) {
        this.type = type;
    }
}

MyBAOSWriter类

package org.lzh.writer;

import org.springframework.batch.item.ItemWriter;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;

//用于输出,可以注入文件后缀使其变成不同功能的Writer
public class MyBAOSWriter implements ItemWriter<ByteArrayOutputStream> {

    //由Spring注入
    private String suffix;//文件后缀,如".xls"

    @Override
    public void write(List list) throws Exception {
        if (null == list) {
            System.out.println("[x]无可输出");
            return;
        }
        //遍历要输出的每个BAOS
        for (ByteArrayOutputStream baos : list) {
            //跳过无可输出
            if(null==baos)
                continue;
            //将其变成字节数组
            byte[] bytes=baos.toByteArray();
            //写出到文件,携带后缀
            File file=new File("D:/WorkSpace/iReport/test/lzh"+suffix);
            FileOutputStream fileOutputStream=new FileOutputStream(file);
            fileOutputStream.write(bytes);
            System.out.println("[v]写入"+suffix);
            fileOutputStream.close();
        }
        System.out.println("---本次Writer已工作结束---");
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}

Main类

package org.lzh;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        //batch.xml导入了applicationConext.xml,所以只写batch.xml就可以一并加入上下文
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("batch.xml");
        //Spring Batch的作业启动器,在applicationContext.xml中配置为了bean
        JobLauncher jobLauncher = (JobLauncher) applicationContext.getBean("jobLauncher");
        //在batch.xml中配置的一个作业
        Job job = (Job) applicationContext.getBean("iReportJob");


        try {
            //开始执行这个作业,获得处理结果(要运行的job,job参数对象)
            JobExecution result = jobLauncher.run(job, new JobParameters());
            //输出处理结果看一下
            System.out.println("处理结果:" + result.toString());
        } catch (JobExecutionAlreadyRunningException | JobInstanceAlreadyCompleteException | JobRestartException | JobParametersInvalidException e) {
            e.printStackTrace();
        }
    }
}

运行

输出

【Spring Batch学习笔记】3:自定义Reader,Processor,Writer使用iReport批量生成报表_第2张图片

生成

【Spring Batch学习笔记】3:自定义Reader,Processor,Writer使用iReport批量生成报表_第3张图片

你可能感兴趣的:(#,Spring,Batch)