使用Spring Batch结合iReport批量生成xls
、pdf
、xlsx
、docx
、pptx
文件。数据源来自之前的MySQL数据库。
<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>
<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>
<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>
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();
}
}
}
}
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;
}
}
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;
}
}
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 extends ByteArrayOutputStream> 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;
}
}
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();
}
}
}