知识目标
-
熟悉JasperReports的用法,能够使用JasperReports实现PDF文件导出
-
掌握Excel方式导出运营数据报表的方法,能够使用Apache POI以Excel方式导出运营数据报表
-
掌握PDF方式导出运营数据报表的方法,能够使用JasperReports以PDF方式导出运营数据报表
在有网络的环境下,传智健康的管理员可以随时随地浏览线上的运营数据报表,但有时候,管理员也希望能将线上的数据导出,独立保存在本地计算机中进行归档,以及做一些其他的数据加工等工作。对此,传智健康提供了两种运营数据报表导出功能,分别是 Excel 方式导出运营数据报表和 PDF 方式导出运营数据报表。接下来,本模块将对管理端的运营数据报表导出进行详细讲解。
10-1 Excel方式导出运营数据报表
运营数据报表的内容是以表格的形式展示的,为了使报表导出之后的数据格式与运营数据报表本身的数据格式保持一致,可以将页面中的报表数据写入 Excel 文件,再通过浏览器进行下载。
在浏览器中访问report_business.html 页面。
在report_business.html页面中,单击“导出Excel”按钮,导出完成后,页面底部显示下载了一个 Excel 格式的文件。
(1)提供Excel模板文件
在backend的template目录下,创建一个名称为report_template的XLSX文件作为模板文件,在该模板文件中创建一个名称为运营数据统计的sheet工作表,工作表中包含会员数据、预约与到诊数据和热门套餐。
(2)提交导出Excel文件的请求
在report_business.html页面中,为“导出 Excel”按钮绑定单击事件,并设置单击时要调用的方法,在该方法中提交导出 Excel 文件的请求。
<div class="excelTitle" >
<el-button @click="exportExcel()">导出Excel</el-button>
......
</div>
在页面中定义exportExcel()方法用于导出 Excel 文件。
<script>
var vue = new Vue({
......
methods:{
//导出Excel报表
exportExcel(){
window.location.href = '/report/exportBusinessReport.do';
}
}
})
</script>
(3)实现Excel报表下载控制器
在 ReportController 类中定义 exportBusinessReport( )方法,用于接收并处理导出 Excel 文件的请求。 通过调用ReportService接口的getBusinessReportData()方法获取运营数据,并读取数据写入与模板对应的变量或对象中;向模板中写入数据;进行文件下载。
//导出运营数据到Excel并提供客户端下载
@RequestMapping("/exportBusinessReport")
public Result exportBusinessReport(HttpServletRequest request, HttpServletResponse response){
try{
//1.获取运营数据,并读取数据写入与模板对应的变量或对象中
Map<String,Object> result = reportService.getBusinessReportData();
//取出返回结果数据,准备将报表数据写入到Excel文件中
String reportDate = (String) result.get("reportDate");
Integer todayNewMember = (Integer) result.get("todayNewMember");
Integer totalMember = (Integer) result.get("totalMember");
Integer thisWeekNewMember = (Integer) result
.get("thisWeekNewMember");
Integer thisMonthNewMember = (Integer) result
.get("thisMonthNewMember");
Integer todayOrderNumber = (Integer) result.get("todayOrderNumber");
Integer thisWeekOrderNumber = (Integer) result
.get("thisWeekOrderNumber");
Integer thisMonthOrderNumber = (Integer) result
.get("thisMonthOrderNumber");
Integer todayVisitsNumber = (Integer) result
.get("todayVisitsNumber");
Integer thisWeekVisitsNumber = (Integer) result
.get("thisWeekVisitsNumber");
Integer thisMonthVisitsNumber = (Integer) result
.get("thisMonthVisitsNumber");
List<Map> hotSetmeal = (List<Map>) result.get("hotSetmeal");
//2.向模板中写入数据
//动态获取Excel模板文件绝对磁盘路径
String filePath = request.getSession().getServletContext()
.getRealPath("template").split("out")[0]+"/web/backend/template"+ File.separator+"report_template.xlsx";
//基于POI在内存中创建一个Excel文件
XSSFWorkbook excel = new XSSFWorkbook(
new FileInputStream(new File(filePath)));
XSSFSheet sheet = excel.getSheetAt(0);
XSSFRow row = sheet.getRow(2);
row.getCell(5).setCellValue(reportDate);//日期
row = sheet.getRow(4);
row.getCell(5).setCellValue(todayNewMember);//新增会员数(本日)
row.getCell(7).setCellValue(totalMember);//总会员数
row = sheet.getRow(5);
row.getCell(5).setCellValue(thisWeekNewMember);//本周新增会员数
row.getCell(7).setCellValue(thisMonthNewMember);//本月新增会员数
row = sheet.getRow(7);
row.getCell(5).setCellValue(todayOrderNumber);//今日预约数
row.getCell(7).setCellValue(todayVisitsNumber);//今日到诊数
row = sheet.getRow(8);
row.getCell(5).setCellValue(thisWeekOrderNumber);//本周预约数
row.getCell(7).setCellValue(thisWeekVisitsNumber);//本周到诊数
row = sheet.getRow(9);
row.getCell(5).setCellValue(thisMonthOrderNumber);//本月预约数
row.getCell(7).setCellValue(thisMonthVisitsNumber);//本月到诊数
int rowNum = 12;
for(Map map : hotSetmeal){//热门套餐
String name = (String) map.get("name");
Long setmeal_count = (Long) map.get("setmeal_count");
BigDecimal proportion = (BigDecimal) map.get("proportion");
row = sheet.getRow(rowNum ++);
row.getCell(4).setCellValue(name);//套餐名称
row.getCell(5).setCellValue(setmeal_count);//预约数量
row.getCell(6).setCellValue(proportion.doubleValue());//占比
}
//3.文件下载
ServletOutputStream out = response.getOutputStream();//创建输出流
response.setContentType("application/vnd.ms-excel");//指定响应类型
//指定以附件形式下载
response.setHeader("content-Disposition","attachment;filename=report.xlsx");
excel.write(out);//写入流文件
out.flush();//关闭缓冲区的数据流
out.close();//关闭流对象
excel.close();
return null;
}catch (Exception e){
e.printStackTrace();
return new Result(false, MessageConstant.GET_BUSINESS_REPORT_FAIL);
}
}
(4)查询运营数据
在ReportController类的exportBusinessReport()方法中,调用了ReportService接口的getBusinessReportData()方法,该方法之前已经实现,这里不再重复,直接调用即可。
(5)测试 Excel 方式导出运营数据报表
启动服务,在浏览器中访http://localhost:8080/backend/pages/report_business.html。单击“导出Excel”按钮。
10-2 PDF方式导出运营数据报表
PDF 文件在企业办公中很常用,它不仅适合阅读,而且可以防止他人修改文件内容。传智健康管理端提供 PDF 方式导出运营数据报表的功能。
在浏览器中访问 report_business.html 页面。
在 report_business.html 页面单击“导出PDF”按钮,导出完成后,页面底部显示下载了一个PDF 文件。
使用 PDF 方式导出运营数据报表时,需要按照运营数据统计页面的内容分布创建PDF文件,然后将数据填充到 PDF 文件中。在实际企业项目开发中,有两种常见的PDF文件生成方式,具体如下。 iText生成PDF。 JasperReports生成PDF。 由于 iText 的原生 API 编程比较烦琐,为了简化编程过程,在实际项目开发时,大多数情况下使用JasperReports 生成 PDF 文件。对此本任务采用JasperReports结合模板设计器Jaspersoft Studio生成PDF文件。
JasperReports简介
JasperReports是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF、HTML或者XML格式。JasperReports完全由Java语言编写而成,可以用在 J2EE、Web等 Java应用程序中生成动态内容。使用 JasperReports 时,需要导入 JasperReports 的依赖具体如下所示。
JasperReports的工作流程
第1步,创建 JRXML 文件,该文件包含报表布局定义的 XML 文档,可以通过手动编码完成,也可以使用报表设计工具 Jaspersoft Studio 完成。 第2步,使用JasperReports 提供的JasperCompileManager工具将报表模板编译为.jasper 文件; 第3步,使用 JasperReports 提供的 JasperFillManager工具填充编译后的.jasper文件,填充后生成一个.jrprint文件; 第4步,使用文件导出器 JasperExportManager 将.jrprint 文件导出成各种格式的报表文件。
JasperReports入门案例
(1)设计PDF报表模板文件
先使用模板设计器 Jaspersoft Studio 设计入门案例的报表模板文件 demo.jrxml。 将设计好的 demo.jrxml 文件复制到backend 中的template 目录下。
(2)引入JasperReports的依赖
(3)编写单元测试方法
在controller包下创建测试类TestExport,在类中定义testJasperReports( )方法,用于测试导出 PDF 文件。
/**
* 测试类
*/
public class TestExport {
//单元测试方法,测试PDF报表导出
@Test
public void testJasperReports() throws Exception{
//获取pdf模板文件绝对磁盘路径
String jrxmlPath ="D:\\health\\10\\health_parent\\" +
"health_backend\\src\\main\\webapp\\template\\demo.jrxml";
String jasperPath="D:\\health\\10\\health_parent\\" +
"health_backend\\src\\main\\webapp\\template\\demo.jasper";
//编译模板
JasperCompileManager.compileReportToFile(jrxmlPath,jasperPath);
//构造数据
Map paramters = new HashMap();
paramters.put("reportDate","2022-03-01");
paramters.put("company","itcast");
List<Map> list = new ArrayList();
Map map1 = new HashMap();
map1.put("name","小明");
map1.put("address","beijing");
map1.put("email","xiaoming@itcast.cn");
Map map2 = new HashMap();
map2.put("name","xiaoli");
map2.put("address","nanjing");
map2.put("email","xiaoli@itcast.cn");
list.add(map1);
list.add(map2);
//填充数据
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperPath, paramters, new JRBeanCollectionDataSource(list));
//输出文件
String pdfPath = "D:\\test.pdf";
JasperExportManager.exportReportToPdfFile(jasperPrint,pdfPath);
}
}
(4)测试导出PDF文件
name为中文“小明”的数据没有显示出来,由于JasperReports的jar包中不包含中文的字体库,导致默认情况下中文无法正常显示,对此,可以在程序中导入中文字体库以解决中文无法显示的问题。
(5)导入中文字体库
导入的字体库文件包括fonts.xml和stsong.ttf,其中,fonts.xml用于配置字体信息,stsong.ttf表示华文宋体的字体文件。
在resources 目录下创建 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
(6)修改demo.jrxml
打开demo.jrxml模板文件查看内容,找到模板中需要显示中文的元素,统一将字体设置为华文宋体。
......
<textField>
<reportElement x="60" y="4" width="100" height="30"
uuid="9fd8ea6a-722d-4c35-a4dc-74f3ed490709"/>
<textElement>
<font fontName="华文宋体" size="14"/>
</textElement>
<textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
</textField>
......
(7)运行testJasperReports()方法
功能实现
(1)提供PDF模板文件
使用模板设计器 Jaspersoft Studio 设计运营数据报表的模板文件 health_business3.jrxml。 将设计好的模板文件复制到 backend 的 template 目录下。
(2)提交导出PDF文件的请求
在report_business.html 页面,为“导出 PDF”按钮绑定单击事件,并设置单击时要调用的方法,在方法中提交导出 PDF 文件的请求。
<div class="excelTitle" >
<el-button @click="exportPDF()">导出PDF</el-button>
......
</div>
在report_business.html 页面中定义exportPDF()方法用于导出 PDF 文件。
<script>
var vue = new Vue({
......
methods:{
//导出PDF报表
exportPDF(){
window.location.href = '/report/exportBusinessReport4PDF.do';
}
}
})
</script>
(3)实现PDF报表下载控制器
在ReportController 类中定义exportBusinessReport4PDF( )方法,用于接收并处理导出 PDF 文件的请求。 通过调用ReportService接口的getBusinessReportData( )方法查询运营数据,并将数据存储到集合中返回。 获取PDF模板文件绝对路径,编译模板并向模板中写入数据。 设置响应头信息中的响应类型和文件下载类型,并输出对应的文件。
//导出运营数据到PDF文件并提供下载
@RequestMapping("/exportBusinessReport4PDF")
public Result exportBusinessReport4PDF(HttpServletRequest request, HttpServletResponse response){
try{
Map<String,Object> result = reportService.getBusinessReportData();
//取出返回结果数据,准备将报表数据写入到Excel文件中
List<Map> hotSetmeal = (List<Map>) result.get("hotSetmeal");
//动态获取pdf模板文件绝对磁盘路径
String jrxmlPath = request.getSession().getServletContext()
.getRealPath("template") .split("out")[0]+"/web/backend/template"+ File.separator +
"health_business3.jrxml";
String jasperPath = request.getSession().getServletContext()
.getRealPath("template") .split("out")[0]+"/web/backend/template"+ File.separator + "health_business3.jasper";
//编译模板
JasperCompileManager.compileReportToFile(jrxmlPath, jasperPath);
//填充数据---使用JavaBean数据源方式填充
JasperPrint jasperPrint =
JasperFillManager.fillReport(jasperPath,result,
new JRBeanCollectionDataSource(hotSetmeal));
//创建输出流,用于从服务器写数据到浏览器
ServletOutputStream out = response.getOutputStream();
response.setContentType("application/pdf");
response.setHeader("content-Disposition","attachment;filename=report.pdf");
//输出文件
JasperExportManager.exportReportToPdfStream(jasperPrint,out);
out.flush();
out.close();
return null;
}catch (Exception e){
e.printStackTrace();
return new Result(false, MessageConstant.GET_BUSINESS_REPORT_FAIL);
}
}
(4)查询运营数据
在 ReportController 类的 exportBusinessReport4PDF( )方法中,调用了 ReportService 接口的 getBusinessReportData( )方法查询运营数据,由于在统计分析模块的运营数据统计功能中已经实现了运营数据的查询,这里可以直接调用查询运营数据的相关方法。
(5)测试 PDF 方式导出运营数据报表
启动服务。在浏览器中访问 http://localhost:8080/backend/pages/report_business.html,单击“导出PDF”按钮,以PDF方式导出运营数据。
在report_business.html页面中,单击“导出 PDF”按钮后,浏览器下载了一个名称为 report 的 PDF 文件。
模块小结
本模块主要对管理端的运营数据报表导出进行了讲解。首先讲解了 Excel 方式导出运营数据报表;其次讲解了 JasperReports 的使用并实现了 PDF 方式导出运营数据报表。希望通过本模块的学习,可以熟悉JasperReports 的使用,掌握 Excel 方式和 PDF 方式导出运营数据报表的功能。