簡介
JasperReports是一個基于Java的開源報表工具,它可以在Java環(huán)境下像其它IDE報表工具一樣來制作報表。JasperReports 支持PDF钉寝、HTML、XLS、CSV和XML文件輸出格式。JasperReports是當前Java開發(fā)者最常用的報表工具伟众。
準備工作
官網(wǎng)
報表模板設(shè)計器下載
iReport報表制作參考
本例使用的JasperReports版本為6.3.0,通過其報表設(shè)計器(iReport是其前身)設(shè)計好打印模板召廷,使用核心包按照指定的模板.jasper文件生成用于打印的HTML文件凳厢。
集成方式
添加Maven依賴
<properties>
......
<!-- 報表核心包 -->
<jasperreports.version>6.3.0</jasperreports.version>
<!--如果打印模板用到條形碼需要依賴以下兩種條形碼生成的jar包-->
<barcode4j.version>2.1</barcode4j.version>
<barbecue.version>1.5-beta1</barbecue.version>
<!--將.jrxml打印模板定義編譯成.jasper文件-->
<groovy.version>2.4.5</groovy.version>
<!--解析.jrxml-->
<commons-digester3.version>3.2</commons-digester3.version>
<!--SVG文檔操作相關(guān)-->
<batik-bridge.version>1.8</batik-bridge.version>
<!--XML與圖形進行轉(zhuǎn)換-->
<xmlgraphics-commons.version>2.1</xmlgraphics-commons.version>
......
</properties>
<dependencyManagement>
<dependencies>
......
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>${jasperreports.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>${groovy.version}</version>
</dependency>
<dependency>
<groupId>net.sf.barcode4j</groupId>
<artifactId>barcode4j</artifactId>
<version>${barcode4j.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.barbecue</groupId>
<artifactId>barbecue</artifactId>
<version>${barbecue.version}</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-bridge</artifactId>
<version>${batik-bridge.version}</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>xmlgraphics-commons</artifactId>
<version>${xmlgraphics-commons.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-digester3</artifactId>
<version>${commons-digester3.version}</version>
</dependency>
</dependencies>
<!--此處只列出本人過程中會用到的相關(guān)功能的依賴包账胧,不代表JasperReports完整功能依賴,大家根據(jù)需要引入即可-->
......
</dependencyManagement>
修改配置
在web工程src/main/resources路徑下新建jasperreports.properties先紫,在此文件中配置覆蓋JasperReports的相關(guān)屬性的默認值找爱。
由于生成條形碼默認格式為svg,本人使用的web端打印插件不支持此圖片格式泡孩,因此只用到以下配置修改车摄。
# barcode4j 生成圖片格式默認為svg,改用普通圖片格式
net.sf.jasperreports.components.barcode4j.image.producer=image
# 圖片dpi仑鸥,默認值為72吮播,Lodop打印使用的是96px,因此需要覆蓋
net.sf.jasperreports.image.dpi=96
# HTML單位長度單位眼俊,默認為px意狠,由于jasperReports的像素是按照1dpi=72px設(shè)計,和Lodop打印插件沖突疮胖,此處改為1dpi=72pt即可和Lodop的單位換算一致
net.sf.jasperreports.export.html.size.unit=pt
覆蓋HtmlExporter
1环戈、HtmlExporter生成的html文件,最終內(nèi)容和實際設(shè)計器中的預覽結(jié)果有差異澎灸,左右兩邊多了一些間距院塞,通過修改代碼去除不必要的間距。
2性昭、由于本人使用的打印插件分頁是根據(jù)Html實際內(nèi)容高度進行的拦止,因此需要保證每個分頁頁面的寬度、高度和設(shè)計器指定的紙張寬高(此處使用pt作為單位)一致糜颠。
- 重寫HtmlExporter類汹族,類路徑自己定義。
- 修改內(nèi)容如下
# 增加以下方法
//獲取每個分頁的寬度
private String getPageWidth() {
List<ExporterInputItem> items = exporterInput.getItems();
if (items.isEmpty()) {
return "";
}
JasperPrint jasperPrint = items.get(0).getJasperPrint();
return jasperPrint.getPageWidth() + "pt";//此處單位保持一致使用pt
}
# 修改exportReportToWriter方法其兴,固定好寬度同時去除左右兩邊的間距顶瞒。
protected void exportReportToWriter() throws JRException, IOException {
HtmlExporterConfiguration configuration = getCurrentConfiguration();
String htmlHeader = configuration.getHtmlHeader();
String betweenPagesHtml = configuration.getBetweenPagesHtml();
String htmlFooter = configuration.getHtmlFooter();
boolean flushOutput = configuration.isFlushOutput();// FIXMEEXPORT maybe
// move flush flag to
// output
if (htmlHeader == null) {
String encoding = getExporterOutput().getEncoding();
writer
.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n");
writer.write("<html>\n");
writer.write("<head>\n");
writer.write(" <title></title>\n");
writer.write(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + encoding
+ "\"/>\n");
writer.write(" <style type=\"text/css\">\n");
writer.write(" a {text-decoration: none}\n");
writer.write(" </style>\n");
writer.write("</head>\n");
writer
.write("<body text=\"#000000\" link=\"#000000\" alink=\"#000000\" vlink=\"#000000\" style=\"margin:0;width:"
+ getPageWidth() + "\">\n"); //此處有修改,固定寬度
writer.write("<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n");
writer.write("<tr><td>\n");//此處有修改元旬,去除左邊占比50%的空td塊
writer.write("\n");
} else {
writer.write(htmlHeader);
}
List<ExporterInputItem> items = exporterInput.getItems();
for (reportIndex = 0; reportIndex < items.size(); reportIndex++) {
ExporterInputItem item = items.get(reportIndex);
setCurrentExporterInputItem(item);
List<JRPrintPage> pages = jasperPrint.getPages();
if (pages != null && pages.size() > 0) {
PageRange pageRange = getPageRange();
int startPageIndex = (pageRange == null || pageRange.getStartPageIndex() == null) ? 0
: pageRange.getStartPageIndex();
int endPageIndex = (pageRange == null || pageRange.getEndPageIndex() == null) ? (pages
.size() - 1) : pageRange.getEndPageIndex();
JRPrintPage page = null;
for (pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
if (Thread.interrupted()) {
throw new ExportInterruptedException();
}
page = pages.get(pageIndex);
writer.write("<a name=\"" + JR_PAGE_ANCHOR_PREFIX + reportIndex + "_" + (pageIndex + 1)
+ "\"></a>\n");
/* */
exportPage(page);
if (reportIndex < items.size() - 1 || pageIndex < endPageIndex) {
if (betweenPagesHtml == null) {
// writer.write("<br/>\n<br/>\n"); 此處有修改榴徐,去除多余的換行符
} else {
writer.write(betweenPagesHtml);
}
}
writer.write("\n");
}
}
}
ReportContext reportContext = getReportContext();
if (fontsToProcess != null && fontsToProcess.size() > 0)// when no
// resourceHandler,
// fonts are not
// processed
{
if (reportContext == null) {
@SuppressWarnings("deprecation")
HtmlResourceHandler resourceHandler = getExporterOutput().getResourceHandler() == null ? getResourceHandler()
: getExporterOutput().getResourceHandler();
for (HtmlFontFamily htmlFontFamily : fontsToProcess.values()) {
writer.write("<link class=\"jrWebFont\" rel=\"stylesheet\" href=\""
+ resourceHandler.getResourcePath(htmlFontFamily.getId()) + "\">\n");
}
// generate script tag on static export only
writer.write("<!--[if IE]>\n");
writer.write("<script>\n");
writer.write("var links = document.querySelectorAll('link.jrWebFont');\n");
writer
.write("setTimeout(function(){ if (links) { for (var i = 0; i < links.length; i++) { links.item(i).href = links.item(i).href; } } }, 0);\n");
writer.write("</script>\n");
writer.write("<![endif]-->\n");
} else {
reportContext.setParameterValue(JsonExporter.REPORT_CONTEXT_PARAMETER_WEB_FONTS,
fontsToProcess);
}
}
// place hyperlinksData on reportContext
if (hyperlinksData.size() > 0) {
// for sure reportContext is not null, because otherwise there would be no
// item in the hyperilnkData
reportContext.setParameterValue("net.sf.jasperreports.html.hyperlinks", hyperlinksData);
}
if (htmlFooter == null) {
writer.write("</td></tr>\n"); //此處有修改,去除右邊占比50%的空td塊
writer.write("</table>\n");
writer.write("</body>\n");
writer.write("</html>\n");
} else {
writer.write(htmlFooter);
}
if (flushOutput) {
writer.flush();
}
}
根據(jù)報表模板生成HTML文件
public PrintPageConfig genPrintHtmlFile(String tmplFileUrl, String targetUrl,
Map<String, String> params) throws DemoServiceException {
Connection connection = null;
try {
DruidDataSource ds = ApplicationContextUtils
.getBean(DemoConstants.DEFAULT_DATASOURCE_CONTEXT_ID, DruidDataSource.class);
connection = ds.getConnection();
//傳入模板.jasper文件內(nèi)容
InputStream inputFile = new FileInputStream(tmplFileUrl);
JasperReport jasperReport = (JasperReport) JRLoader.loadObject(inputFile);
//指定數(shù)據(jù)源法绵,并傳入對應(yīng)報表的執(zhí)行參數(shù)
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, (Map) params,
connection);
//生成最終結(jié)果的HTML文件箕速,注意此處引用自己重寫的HtmlExporter
HtmlExporter exporter = new HtmlExporter(DefaultJasperReportsContext.getInstance());
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(new SimpleHtmlExporterOutput(targetUrl));
exporter.exportReport();
return new PrintPageConfig().setWidth(jasperPrint.getPageWidth())
.setHeight(jasperPrint.getPageHeight());
} catch (Exception e) {
throw new DemoServiceException(e.getMessage());
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
throw new DemoServiceException(e.getMessage());
}
}
}
}
使用Lodop打印生成的html內(nèi)容
本例使用Lodop綜合版本:Lodop6.216_CLodop2.093。
具體集成方式見官網(wǎng)說明朋譬,此處只介紹如何配合JasperReports打印出來的html文件進行不失真打印盐茎。Lodop官網(wǎng)
/**
* 根據(jù)已有的html url進行打印
* @param type
* 是打印還是打印預覽:preview-打印預覽;其它值為打印徙赢。
* @param config
* 打印內(nèi)容配置:
* 1字柠、為字符串時探越,表示打印的html所在的遠程url地址。
* 2窑业、為對象時:{
* url:打印的html所在的遠程url地址,
* width:html內(nèi)容的實際寬度(單位像素)
* height:html內(nèi)容的實際高度(單位像素)
* }
*
* 說明:
* JasperReports設(shè)計模板的像素和實際紙張的尺寸之比為72pt=1英寸(in)钦幔。
* Lodop打印的內(nèi)容是按照一個dpi占96px=72pt=1in=2.54cm(厘米)=25.4mm(毫米)打印,JasperReports的html結(jié)果內(nèi)容是按照一個dpi占72pt生成常柄。
*
*/
function doPrintByHtml(type, config) {
if (!window.LODOP) {
alert('打印插件不可用鲤氢,請先到首頁進行下載安裝,然后刷新瀏覽器西潘!');
return;
}
if (window.top && window.top.waltz && window.top.waltz.app && window.top.waltz.app.globalOption) {
var globalOption = window.top.waltz.app.globalOption;
if (globalOption.lodopLicenseAuthor) {
LODOP.SET_LICENSES(globalOption.lodopLicenseAuthor, globalOption.lodopLicenseKey, "", "");
}
}
LODOP.PRINT_INIT("printTask");
var url;
if ((typeof config == 'string') && config.constructor == String) {
url = config;
} else {
url = config.url;
var width = Math.round((config.width / 72 ) * 25.4) * 10,//1 inch=25.4mm卷玉,Lodop默認單位為0.1mm
height = Math.round((config.height / 72) * 25.4) * 10;
//設(shè)置紙張大小,設(shè)置后不允許用戶手動修改紙張大小
LODOP.SET_PRINT_PAGESIZE(0, width, height, "");
}
// 指定按實際寬度縮放比例
LODOP.SET_PRINT_MODE('PRINT_PAGE_PERCENT', "Full-Width");
LODOP.ADD_PRINT_HTM(0, 0, '100%', '100%', 'URL:' + url);
LODOP.SET_PRINT_STYLE("Stretch", 2);
if (type == 'preview') {
LODOP.PREVIEW();
} else {
LODOP.PRINT();
}
};
注意事項
使用JasperReports根據(jù)打印模板生成打印結(jié)果文件時喷市,對應(yīng)服務(wù)器必須安裝打印模板中用到的字體相种,比如:打印內(nèi)容包含中文,linux服務(wù)器需要安裝中文的語言包品姓,否則執(zhí)行生成結(jié)果文件時報錯寝并。