前言
在上篇文章中,已经用iReport製作好报表的template,这篇文章就要介绍在Servlet中使用JasperReport的jar档产生报表。
import所需jar档
首先我们需要为我们之前建立的JasperReportExample专案import需要用到的jar档如下,我们可以去Maven的官网下载jar档,下列的版本仅供各位参考,不同的java版本会要不同的jar版本:
bcprov-jdk15on-1.46.jar
commons-beanutils-1.9.3.jar
commons-collections-3.2.1.jar
commons-digester-2.1.jar
commons-logging-1.2.jar
iText-2.1.7.js2.jar
jasperreports-5.6.1.jar
kaiu.jar (在第一篇中用iReport产出的字型jar档)
mysql-connector-java-5.1.38.jar
poi-3.10.1.jar
程式实作
Step 1.接着就是进入程式的部分,首先我们先製作前端的JSP页面,我们需要有两个DatePicker栏位让使用者选择要查询的生日起迄日,还有一个报表类型的Select让使用者可以选择要产生PDF或是Excel的报表,我们就在专案的/JasperReportExample/WebContent/html/pages路径下新增一个index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><script src="<%=request.getContextPath()%>/html/js/jquery-3.3.1.min.js" type="text/javascript"></script><script src="<%=request.getContextPath()%>/html/js/jquery-ui.min.js" type="text/javascript"></script><link rel="stylesheet" href="<%=request.getContextPath()%>/html/css/jquery-ui.min.css"><script>$( function() {$( "#startDate" ).datepicker({dateFormat : "yy-mm-dd"});$( "#endDate" ).datepicker({dateFormat : "yy-mm-dd"});} ); </script><title>ReportDownload</title></head><body><form method="Post" action="/JasperReportExample/ReportDownload"><p>起始时间:<input type="text" id="startDate" name="startDate" autocomplete="off"></p><p>结束时间:<input type="text" id="endDate" name="endDate" autocomplete="off"></p><p>报表类型:<select name="reportType"><option value="PDF">PDF</option><option value="Excel">Excel</option></select></p><input type="submit" value="下载"></form></body></html>
Step 2.接着我们要在路径/JasperReportExample/src/com/example/controller为这个JSP新增一个Home.java的controller,让request进来的时候可以导到我们的index.jsp去。
package com.example.controller;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@WebServlet("/Home")public class Home extends HttpServlet {private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.getRequestDispatcher("/html/pages/index.jsp").forward(request, response);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}}
Step 3.完成后我们就可以先run在tomcat上,并在浏览器打上网址http://localhost:8080/JasperReportExample/Home ,就可以看到我们刚刚做的JSP画面如下。
Step 4.接着我们要在路径/JasperReportExample/src/com/example/dao做一个PersonDao.java,让我们可以去DB查询Person的table,我们这边用的DB是MySQL,并事先为这个表格塞入一些假资料。
package com.example.dao;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;import com.example.model.Person;public class PersonDao {public List<Person> getPersonList(String startDate, String endDate){Connection conn = null;PreparedStatement ps = null;List<Person> personList = new ArrayList<Person>();try {Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/new_schema", "yourDBAccount", "yourDBPassword");String sql =" select * from Person where (Birthday Between ? AND ?) order by Id";ps = conn.prepareStatement(sql); ps.setString(1, startDate); ps.setString(2, endDate); ResultSet rs = ps.executeQuery(); while(rs.next()){ Person person = new Person(); person.setId(rs.getInt("Id")); person.setName(rs.getString("Name")); person.setAge(rs.getString("Age")); person.setPhone(rs.getString("Phone")); person.setEmail(rs.getString("Email")); person.setBirthday(rs.getString("Birthday").substring(0, 10)); personList.add(person); }} catch (SQLException | ClassNotFoundException e) {e.printStackTrace();} finally {try {conn.close();ps.close(); conn = null;} catch (SQLException e) {e.printStackTrace();}} return personList;}}
Step 5.最后在路径/JasperReportExample/src/com/example/controller新增一个ReportDownload.java的controller,并在这边接收前端JSP传过来的参数,然后用刚刚做的dao去DB查资料,然后再製作报表。
package com.example.controller;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.IOException;import java.io.OutputStream;import java.io.PrintWriter;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.example.dao.PersonDao;import com.example.model.Person;import net.sf.jasperreports.engine.JRAbstractExporter;import net.sf.jasperreports.engine.JRDataSource;import net.sf.jasperreports.engine.JREmptyDataSource;import net.sf.jasperreports.engine.JRException;import net.sf.jasperreports.engine.JRExporterParameter;import net.sf.jasperreports.engine.JasperFillManager;import net.sf.jasperreports.engine.JasperPrint;import net.sf.jasperreports.engine.JasperReport;import net.sf.jasperreports.engine.JasperRunManager;import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;import net.sf.jasperreports.engine.export.JRPdfExporter;import net.sf.jasperreports.engine.export.JRXlsExporter;import net.sf.jasperreports.engine.util.JRLoader;@WebServlet("/ReportDownload")public class ReportDownload extends HttpServlet {private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 前端传进来的参数String startDate = request.getParameter("startDate");String endDate = request.getParameter("endDate");String reportType = request.getParameter("reportType");File file = null;JasperReport jasperReport = null;JRDataSource dataSource = null;JRAbstractExporter exporter = null;byte[] bytes = null;try { // 用iReport产出来的jasper档案路径String path = "/Users/greg/Desktop/JasperReportExample.jasper";file = new File(path);jasperReport = (JasperReport) JRLoader.loadObject(file);} catch(JRException e) {System.err.println(e);}// 资料库查询资料PersonDao dao = new PersonDao();List<Person> personList = dao.getPersonList(startDate, endDate+" 23:59:59");int size = personList.size();if(size > 0) {dataSource = new JRBeanCollectionDataSource(personList);}else {dataSource = new JREmptyDataSource();}Map parameters=new HashMap();parameters.put ("searchDate", startDate + "~" + endDate);if("PDF".equals(reportType)) {exporter = new JRPdfExporter();}else if ("Excel".equals(reportType)) {exporter = new JRXlsExporter();}try {ByteArrayOutputStream oStream = new ByteArrayOutputStream();JasperPrint jasperPrint = JasperFillManager.fillReport("/Users/greg/Desktop/JasperReportExample.jasper", parameters, dataSource);exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, oStream);exporter.exportReport();bytes = oStream.toByteArray();oStream.close();} catch (JRException e) {e.printStackTrace();System.err.println(e);} if("PDF".equals(reportType)) { response.setHeader("Content-Disposition","attachment; filename=JasperReportExample.pdf"); response.setContentType("application/pdf"); response.setContentLength(bytes.length);}else if("Excel".equals(reportType)) {response.setHeader("Content-Disposition","attachment; filename=JasperReportExample.xls");response.setContentType("application/vnd.ms-excel");response.setContentLength(bytes.length);} ServletOutputStream ouputStream = response.getOutputStream();ouputStream.write(bytes, 0, bytes.length);ouputStream.flush();ouputStream.close(); }}
Step 6.到目前我们的程式部份都完成啰,专案的架构如下
Step 7.完成后我们就可以在刚刚的JSP网址选择日期跟报表类型进行下载,因为这只是个小Demo,所以并没有对前端的值进行检查,各位有兴趣的话可以自己在前端用JQuery或在后端新增检查的逻辑。
产出来的PDF报表:
产出来的Excel报表:
结论
这个小专案到这边就差不多完成啰,其实用iReport製作template还有很多功能可以操作,大家有兴趣的话可以製作更複杂的template,製作属于自己的客製化报表,若是对source code有兴趣的话可以参考我的GitHub。
对这篇主题有任何指教的部分也请各位在下方留言,互相交流~