前言
近期项目中的心需求是要通过教师提交的听课记录进行PDF打印预览功能,为了实现这个功能我采用jasper的PDF模板+java进行实现
主要工具:idea+studio
需求格式:
其中课堂图片与课堂点评可以多条存在,鉴于这种需求采用jasper的父子报表进行实现.
开始打算使用一个模板进行功能实现,后来发现图片与评论只能取一条,这才意识到图片与评论的话是一个list集合,要进行遍历,所以采用父子报表进行功能实现.下面介绍一下我的实现方法.
一、具体步骤
1.解决模板问题
使用studio进行模板制作
在自己的百度网盘中放了一个版本比较旧的studio,如果有需要的话可以进行下载
https://pan.baidu.com/s/1t9x6KqTxOVcPW2TqkJejQw
提取码: sohy
模板软件的结构如图:
创建新的project,取名为parentPdf,然后创建所需要的Paremeters,如图:
将各个参数拖拽至detail板块中并进行排版:如图
下面的文件为子报表,子报表就是sonPdf那个文件,如图:
注意一点:子报表中的属性不是partemeters,而是field属性.
难点
报表的难点在于父子报表传参问题:
主要解决步骤:
拖拽一个subreport组件进入父报表,然后对改组件进行设置,主要设置两个参数:
1:数据源
2:子报表路径
子报表路径表达式:$P{listPath}
子报表数据源构造:new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{commentList})
模板最终步骤
将parentPdf.jrxml文件与sonPdf.jrxml文件进行编译得到两个jasper文件.
2.服务端代码
这里主要是为父子报表进行数据构造与传参.
话不多说,直接上代码
@GetMapping("/downloadMyReport/{id}/myReport.pdf")
@IgnoreAuthenticated
public void myReport(HttpServletRequest request, HttpServletResponse response, @PathVariable("id") Integer id) throws Exception {
// 1.引入jasper文件
File file = ResourceUtils.getFile(path + "/parentPdf.jasper");
logger.info(file.getPath()+"====================================>>>>");
FileInputStream fis = new FileInputStream(file);
//2.创建JasperPrint,向jasper文件中填充数据
ServletOutputStream os = response.getOutputStream();
try {
/**
* fis: jasper 文件输入流
* new HashMap :向模板中输入的参数
* JasperDataSource:数据源(和数据库数据源不同)
* 填充模板的数据来源(connection,javaBean,Map)
* 填充空数据来源:JREmptyDataSource
*/
File listFile = ResourceUtils.getFile(path + "/sonPdf.jasper");
logger.info(listFile.getPath()+"====================================>>>>");
/*
* 构建父报表数据
*/
Map<String, Object> map = new HashMap<>();
map.put("listPath", listFile.getPath());//子报表1路径
CampusAttendanceNote campusAttendanceNote = campusAttendanceNoteService.getAttendanceNoteById(id);
map.put("teacherName", campusAttendanceNote.getTeacherName() == null ? "未填写" : campusAttendanceNote.getTeacherName());
map.put("submitDate", campusAttendanceNote.getCreateTime() == null ? "未填写" : campusAttendanceNote.getCreateTime());
map.put("schoolName", campusAttendanceNote.getSpeakSchool() == null ? "未填写" : campusAttendanceNote.getSpeakSchool());
map.put("courseName", campusAttendanceNote.getCourseName() == null ? "未填写" : campusAttendanceNote.getCourseName());
map.put("courseTeacher", campusAttendanceNote.getSpeakTeacherName() == null ? "未填写" : campusAttendanceNote.getSpeakTeacherName());
map.put("topic", campusAttendanceNote.getTopic() == null ? "未填写" : campusAttendanceNote.getTopic());
String listenDate = campusAttendanceNote.getListenDate();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
SimpleDateFormat sdfToDate = new SimpleDateFormat("yyyy-MM-dd");
Date _listenDate = sdfToDate.parse(listenDate);
String format = sdf.format(_listenDate);
System.err.println(format);
String dateStr = DateUtils.getDateStr(_listenDate);
String resultCourseDate = format + " 第" + campusAttendanceNote.getWeekCount() + "周 " + dateStr + campusAttendanceNote.getPeriod() + " 第" + campusAttendanceNote.getCourseCount() + "节";
map.put("courseDate", resultCourseDate);
map.put("advice", campusAttendanceNote.getAdvice() == null ? "未填写" : campusAttendanceNote.getAdvice());
List<CampusAttendanceCourseComment> list = campusAttendanceNoteService.getCourseNoteByAttendanceId(campusAttendanceNote.getId());
map.put("commentList", list);//填充子报表数据
JasperPrint print = JasperFillManager.fillReport(fis, map, new JREmptyDataSource());
//3.将JasperPrint已PDF的形式输出
JasperExportManager.exportReportToPdfStream(print, os);
} catch (Exception e) {
e.printStackTrace();
} finally {
os.flush();
}
}
需要在代码中构造出map,父子报表传参主要通过map中的子报表jasper路径,与子报表的list数据进行传参.
3.接口访问效果
二、总结
这次的技术记录也仅限于自身学习总结,需求来的比较急,以至于代码还有模板都比较粗糙,这次的分享也比较粗糙,还请见谅,至于PDF模板的开发肯定还有各式各样的,如果有其他的技术,还请大家多多的交流一下,文章对大家有所帮助的话,那也是荣幸之至.
还请大家批评指导.