常用PDF制作
- iText PDF:iText是著名的开放项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf 的文档,而且可以将XML、Html文件转化为PDF文件。
- Openoffice:openoffice是开源软件且能在windows和linux平台下运行,可以灵活的将word或者Excel转化 为PDF文档。
- Jasper Report:是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF
JasperReport
生命周期
- 设计阶段(Design):所谓的报表设计就是创建一些模板,模板包含了报表的布局与设计,包括执行计算的 复杂公式、可选的从数据源获取数据的查询语句、以及其它的一些信息。模板设计完成之后,我们将模板保 存为JRXML文件(JR代表JasperReports),其实就是一个XML文件。
- 执行阶段(Execution):使用以JRXML文件编译为可执行的二进制文件(即.Jasper文件)结合数据进行执 行,填充报表数据
- 输出阶段(Export):数据填充结束,可以指定输出为多种形式的报表
原理
- JRXML:报表填充模板,本质是一个XML. JasperReport已经封装了一个dtd,只要按照规定的格式写这个xml文件,那么jasperReport就可以将其解析 最终生成报表,但是jasperReport所解析的不是我们常见的.xml文件,而是.jrxml文件,其实跟xml是一样 的,只是后缀不一样。
- Jasper:由JRXML模板编译生成的二进制文件,用于代码填充数据。 解析完成后JasperReport就开始编译.jrxml文件,将其编译成.jasper文件,因为JasperReport只可以 对.jasper文件进行填充数据和转换,这步操作就跟我们java中将java文件编译成class文件是一样的
- Jrprint:当用数据填充完Jasper后生成的文件,用于输出报表。 这一步才是JasperReport的核心所在,它会根据你在xml里面写好的查询语句来查询指定是数据库,也可以控 制在后台编写查询语句,参数,数据库。在报表填充完后,会再生成一个.jrprint格式的文件(读取jasper文 件进行填充,然后生成一个jrprint文件)
- Exporter:决定要输出的报表为何种格式,报表输出的管理类。
- Jasperreport可以输出多种格式的报表文件,常见的有Html,PDF,xls等
模板制作工具:Jaspersoft Studio
.jrxml文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.5.0.final using JasperReports Library version 6.5.0 -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="test01" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="b7211d1c-a575-48f1-b253-9c63f5f41307">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
<queryString>
<![CDATA[]]>
</queryString>
<background>
<band splitType="Stretch"/>
</background>
<pageHeader>
<band height="96" splitType="Stretch">
<image>
<reportElement x="-20" y="-20" width="180" height="50" uuid="93b99d68-82d6-4d23-a6f8-6594b9c1af3e"/>
<imageExpression><![CDATA[" https://img0.bdstatic.com/img/image/wise/3%E8%B6%B3%E7%90%83%E5%AE%9D%E8%B4%9D.jpg"]]></imageExpression>
</image>
<line>
<reportElement x="-20" y="30" width="591" height="5" uuid="69ffb590-4919-481e-922e-577ae367e59e"/>
</line>
</band>
</pageHeader>
<detail>
<band height="80" splitType="Stretch">
<staticText>
<reportElement x="230" y="50" width="100" height="30" uuid="104d722d-99b1-44f5-b3fb-582f78411ab5"/>
<textElement>
<font fontName="华文宋体"/>
</textElement>
<text><![CDATA[Jaspersoft好强大]]></text>
</staticText>
</band>
</detail>
<pageFooter>
<band height="75" splitType="Stretch">
<staticText>
<reportElement x="230" y="20" width="100" height="30" uuid="6863d3c6-774e-4f7c-adda-5f1bc6148c78"/>
<textElement>
<font fontName="华文宋体"/>
</textElement>
<text><![CDATA[xxx出品]]></text>
</staticText>
</band>
</pageFooter>
</jasperReport>
生命周期:
package cn.itcast.jr;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.view.JasperViewer;
import java.util.HashMap;
public class PDFTest {
public static void main(String[] args) {
showPdf();
}
public static void createJasper(){
try{
String path = "C:\\Users\\资源\\test01.jrxml";
JasperCompileManager.compileReportToFile(path);
}catch(Exception e){
e.printStackTrace();
}
}
public static void createJrprint(){
try{
String path = "C:\\Users\\资源\\test01.jasper";
//通过空参数和空数据源进行填充
JasperFillManager.fillReportToFile(path,new HashMap(),new JREmptyDataSource());
}catch(Exception e){
e.printStackTrace();
}
}
public static void showPdf(){
try{
String path = "C:\\Users\\资源\\test01.jrprint";
JasperViewer.viewReport(path,false);
}catch(Exception e){
e.printStackTrace();
}
}
}
springboot工程使用
- 依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.5.0</version>
</dependency>
<dependency>
<groupId>org.olap4j</groupId>
<artifactId>olap4j</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
- 配置文件:application.yml
server:
port: 8181
spring:
application:
name: jasper-demo #指定服务名
resources:
static-locations: classpath:/templates/
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ihrm?useUnicode=true&characterEncoding=utf8
username: root
password: root
-
准备.jasper文件:test001.jasper
-
测试controller
@RestController
public class JasperController {
@GetMapping("/testJasper")
public void createHtml(HttpServletResponse response, HttpServletRequest
request)throws Exception{
//引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
Resource resource = new ClassPathResource("templates/test01.jasper");
//加载jasper文件创建inputStream
FileInputStream isRef = new FileInputStream(resource.getFile());
ServletOutputStream sosRef = response.getOutputStream();
try {
//创建JasperPrint对象
JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, new HashMap<>(),new JREmptyDataSource());
//写入pdf数据
JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
} finally {
sosRef.flush();
sosRef.close();
}
}
}
中文乱码问题:
- 配置文件:jasperreports_extension.properties
net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.lobstertwo=stsong/fonts.xml
- 指定中文配置文件fonts.xml
<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>
<!--<fontFamily name="Lobster Two">-->
<!--<normal>lobstertwo/LobsterTwo-Regular.otf</normal>-->
<!--<bold>lobstertwo/LobsterTwo-Bold.otf</bold>-->
<!--<italic>lobstertwo/LobsterTwo-Italic.otf</italic>-->
<!--<boldItalic>lobstertwo/LobsterTwo-BoldItalic.otf</boldItalic>-->
<!--<pdfEncoding>Identity-H</pdfEncoding>-->
<!--<pdfEmbedded>true</pdfEmbedded>-->
<!--<!–-->
<!--<exportFonts>-->
<!--<export key="net.sf.jasperreports.html">'Lobster Two', 'Times New Roman',
Times, serif</export>-->
<!--</exportFonts>-->
<!--–>-->
<!--</fontFamily>-->
<fontFamily name="华文宋体">
<normal>stsong/stsong.TTF</normal>
<bold>stsong/stsong.TTF</bold>
<italic>stsong/stsong.TTF</italic>
<boldItalic>stsong/stsong.TTF</boldItalic>
<pdfEncoding>Identity-H</pdfEncoding>
<pdfEmbedded>true</pdfEmbedded>
<exportFonts>
<export key="net.sf.jasperreports.html">'华文宋体', Arial, Helvetica, sansserif</export>
<export key="net.sf.jasperreports.xhtml">'华文宋体', Arial, Helvetica, sansserif</export>
</exportFonts>
<!--
<locales>
<locale>en_US</locale>
<locale>de_DE</locale>
</locales>
-->
</fontFamily>
</fontFamilies>
- 引入对应字体库:stsong.TTF
数据填充
进行数据填充需要在设计相应的.jasper模板时进行相关设置。
主要的就是.jasper模板的制作。
parameters(参数)数据填充
/**
* 基于parameters以Map的形式填充数据
*/
@GetMapping("/testJasper2")
public void createPdf(HttpServletRequest request, HttpServletResponse response) throws IOException {
//1.引入jasper文件
Resource resource = new ClassPathResource("templates/testParam.jasper");
FileInputStream fis = new FileInputStream(resource.getFile());
//2.创建JasperPrint,向jasper文件中填充数据
ServletOutputStream os = response.getOutputStream();
try {
Map parameters = new HashMap<>();
//设置参数 参数的key = 模板中使用的parameters参数的name
parameters.put("username","张三");
parameters.put("mobile","120");
parameters.put("dept","讲师");
parameters.put("company","传智播客");
JasperPrint print = JasperFillManager.fillReport(fis,parameters,new JREmptyDataSource());
JasperExportManager.exportReportToPdfStream(print,os);
} catch (JRException e) {
e.printStackTrace();
}finally {
os.flush();
}
}
数据源数据填充
- 模板制作:数据源填充设置
/**
* 基于JDBC数据源的形式填充数据
*/
//测试JDBC连接数据源
@GetMapping("/testJasper03")
public void createPdf(HttpServletRequest request, HttpServletResponse response)
throws Exception {
//1.引入jasper文件
Resource resource = new ClassPathResource("templates/testConn.jasper");
FileInputStream fis = new FileInputStream(resource.getFile());
//2.创建JasperPrint,向jasper文件中填充数据
ServletOutputStream os = response.getOutputStream();
try {
/**
* 1.jasper文件流
* 2.参数列表
* 3.数据库连接
*/
HashMap parameters = new HashMap();
JasperPrint print = JasperFillManager.fillReport(fis,parameters,getConnection());
//3.将JasperPrint已PDF的形式输出
JasperExportManager.exportReportToPdfStream(print,os);
response.setContentType("application/pdf");
} catch (JRException e) {
e.printStackTrace();
}finally {
os.flush();
}
}
//创建数据库Connection
public Connection getConnection() throws Exception {
String url = "jdbc:mysql://localhost/ihrm";
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, "root", "root");
return conn;
}
- 制作模板动态构造sql进行查询
- 创建参数
- sql动态传参
- 代码中:通过parameters传递参数进去。
javaBean数据源填充
- 模板中需手动创建field,然后进行排版。
/**
* 基于javaBean数据源的形式填充数据
*/
@GetMapping("/testJasper4")
public void createPdf(HttpServletRequest request, HttpServletResponse response) throws Exception {
//1.引入jasper文件
Resource resource = new ClassPathResource("templates/testBean.jasper");
FileInputStream fis = new FileInputStream(resource.getFile());
//2.创建JasperPrint,向jasper文件中填充数据
ServletOutputStream os = response.getOutputStream();
try {
Map parameters = new HashMap<>();
//构建javaBean的数据源
//1.获取到对象的list集合
List<User> userList = getUserList();
//2.通过list集合创建javaBean的数据源对象
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(userList);
JasperPrint print = JasperFillManager.fillReport(fis,parameters,ds);
JasperExportManager.exportReportToPdfStream(print,os);
} catch (JRException e) {
e.printStackTrace();
}finally {
os.flush();
}
}
public List<User> getUserList() {
List<User> list = new ArrayList<>();
for(int i=0;i<10;i++) {
User user = new User(i+"", "用户"+i, "test","讲师", "1380000000"+i);
list.add(user);
}
return list;
}
分组报表
- 制作模板时设置分组:选择根据某字段进行分组,后续会根据传入的数据进行分组展示
/**
* 分组报表
*/
@GetMapping("/testJasper5")
public void createPdf(HttpServletRequest request, HttpServletResponse response) throws Exception {
//1.引入jasper文件
Resource resource = new ClassPathResource("templates/testGroup.jasper");
FileInputStream fis = new FileInputStream(resource.getFile());
//2.创建JasperPrint,向jasper文件中填充数据
ServletOutputStream os = response.getOutputStream();
try {
Map parameters = new HashMap<>();
//构建javaBean的数据源
//1.获取到对象的list集合
List<User> userList = getUserList();
//2.通过list集合创建javaBean的数据源对象
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(userList);
JasperPrint print = JasperFillManager.fillReport(fis,parameters,ds);
JasperExportManager.exportReportToPdfStream(print,os);
} catch (JRException e) {
e.printStackTrace();
}finally {
os.flush();
}
}
public List<User> getUserList() {
List<User> list = new ArrayList<>();
for(int i=0;i<10;i++) {
User user = new User(i+"", "itcast"+i, "test1","讲师", "1380000000"+i);
list.add(user);
}
for(int i=0;i<5;i++) {
User user = new User(i+"", "itheima"+i, "test2","讲师", "1380000000"+i);
list.add(user);
}
return list;
}
- 计数、页面等可通过内置函数与内置field进行设置。主要还是模板的设计。
Chart图表
/**
* charts图形报表
*/
@GetMapping("/testJasper6")
public void createPdf(HttpServletRequest request, HttpServletResponse response) throws Exception {
//1.引入jasper文件
Resource resource = new ClassPathResource("templates/testCharts.jasper");
FileInputStream fis = new FileInputStream(resource.getFile());
//2.创建JasperPrint,向jasper文件中填充数据
ServletOutputStream os = response.getOutputStream();
try {
Map parameters = new HashMap<>();
//构建javaBean的数据源
//1.获取到对象的list集合
List<UserCount> userList = getUserCountList();
//2.通过list集合创建javaBean的数据源对象
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(userList);
JasperPrint print = JasperFillManager.fillReport(fis,parameters,ds);
JasperExportManager.exportReportToPdfStream(print,os);
} catch (JRException e) {
e.printStackTrace();
}finally {
os.flush();
}
}
public List<UserCount> getUserCountList() {
List<UserCount> list = new ArrayList<>();
UserCount uc1 = new UserCount("传智播客",1000l);
UserCount uc2 = new UserCount("黑马程序员",1000l);
UserCount uc3 = new UserCount("baidu",1000l);
list.add(uc1);
list.add(uc2);
list.add(uc3);
return list;
}