JasperReport 各种莫名奇妙问题的解决
也许你不曾遇到如题问题,那恭喜你,但你是否会疑惑为何我没有遇到而你们却遇到这种问题呢,我们可都是应用的struts2框架哦!!!是啊,为什么呢?有兴趣的不妨看看这篇博文http://peterliuye.javaeye.com/blog/418001以及http://www.blogjava.net/sterning/archive/2008/01/02/172317.html,也讲述了同样的问题,都给出了相应的解决方案,咱不说前者,因为前者给我的感觉是并没有使用struts2-jasperreport-plugin,在此说说后者吧,其核心思想是修改struts-jasperreport-plugin插件代码,原文内容如下:
继续吧!采用HTML格式预览时,莫名的出现一些图片的xx,但是我们并没有使用图片啊,关于这个为什么网上的资料很详细本人只是解读一下Struts2这个插件的源码最终解决图片显示问题 protected String imageServletUrl = "/images/";
exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, request.getContextPath() + imageServletUrl);现在明白为什么要新建一个images目录复制象素图片了吧!
对于HTML预览时右击查看源代码出现的是相对路径,但是大多数情况下根据生成的路径不能指定到px图片,不知道是不是这个插件包本身的问题还是其它的原因,总之先做出效果来、修改上句换成绝对路径吧!
exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, servletContext.getRealPath(File.separator) + imageServletUrl);这个图片xx问题自然就会解决了。
上面的方法真的可以吗?咋一看,再在本机一试,你将豁然惊喜,的确图片可以正常显示了,然若此时以你的机器作为server,到另一台机访问顿时傻眼了,因为问题依旧在,这是为什么呢?我们看一下修改前后的代码就一清二楚原因何在了:
修改前:exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, request.getContextPath() + imageServletUrl)
这是一个web的相对请求路径,将展示server端的相对资源,在server方、client均可正常工作
修改后:exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, servletContext.getRealPath(File.separator) + imageServletUrl)
这是一个web的绝对请求路径,将展示server端的绝对路径资源,也就是含有实际盘符信息的资源,以server作为client机访问完全正常,因为实际盘符信息存在client(serve)r方,然而到脱离server的client方访问就异常了,因为请求的实际资源并不在此时的client机(尽管依旧在server机)。
那究竟如何解决如题问题呢?治病需除根,问题的核心在于struts2拦截的太多了,他把我们jasperreport需要的图片资源请求<img src="/webserver/images/px"/>中的src内容作为action来处理了,后台server会报类似no aciont or result for namespace xxx action images/px这样的warning,这是为什么呢?为什么同样的struts2有人遇到如此烦恼的问题,而有人纳闷为何这傻瓜遇到而我没有遇到(偷着乐,嘻嘻),难道真的第三方插件出问题了?...,遇到不遇到取决于我们使用的struts2的版本,若你用的是struts2.0系列(如2.0.11,2.0.14),恭喜你,无此问题烦恼,若你像我一样用了struts2.1.6,那不好意思,我们有缘了,你肯定会搜到此篇博文。问题的答案为:
问题解决方案:在struts.xml中加入 <constant name="struts.action.extension" value="action"/>
如此解决的原因:sturts2默认的后缀扩展时action,是在struts2-core-xxxxx.jar的org.apache.struts2下的default.properties中定义的,正常情况下是
struts.action.extension=action
而在struts2.1.6中,却是struts.action.extension=action,,
多了两个逗号, 这便是问题的所在,如此的配置使得struts2的拦截器除了拦截后缀为action的url及uri外,还额外拦截任何没有后缀的url及uri,那些不期待被拦截的咚咚也被拦截去找相应的action了,致使产生了如题问题,怨啊~~~怎么会是~~~是tmd挺怨的,原来默认的咚咚里面冒出了"臭虫"。
然后创建一个images文件夹添加px到该文件:记住是px而不是px.jpg.
Servlet应用如下:
方案一隐藏:
- exporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, false);
方案二隐藏:
添加图片images目录和文件px
exporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, true);
exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, request.getContextPath() + "/images/px.");
struts2应用添加:
添加图片images目录和文件px
<constant name="struts.action.extension" value="action"/>
把jasperreport.jar包放到JDK/lib下,把JDK的Tools.jar和数据库驱动包放到iReport/lib下;如果iReport/lib下没有iTextAsian.jar包,要下载。
总结:
1.Report0.3.2及Jasperreport0.5.3以上都要求JDK1.4以上版本,所以要注意Oracle9装好会自动把java环境设为Oracle自带的JDK1.3.1,会导致无法运行iReport。这时候卸了JDK或者jbuilder,重装一下。如果项目用ORACLE的话,机器上至少装oracle客户端了,一般可能先装JDK,再装oracle什么的,就出麻烦了!
2. 安装完毕后第一次打开时可能菜单会出些乱码,在Options->选项->general->语言,择最上面的中文(中国),如果还不行的话就重启一下iReport一般都没问题了。
3.设计静态报表模板时,word输出格式问题,预览时总是空白页。
解决办法:可以通过设置报表属性中的“当没有数据时的显示方式”为:除detail外的所有地方。
4. net.sf.jasperreports.engine.JRRuntimeException: Could not load the following font :
pdfFontName : STSong-Light
pdfEncoding : Cp1252
isPdfEmbedded : false
ireport为了以PDF格式输出中文,需要在“PDF Font Name”选项中选择“STSong-Light”,在中文字体定义中勾选“Default”、“PDF Embedded”,“PDF Encoding”选择“UniGB-UCS2-H (Chinese Simplified)”。
5.Java.lang.IllegalStateException: getOutputStream() has already been called for this response
在写JSP程序的时候,如果程序中调用了response.getOutputStream()去向客户端输出文件等数据流,容器就会抛出这样的异常。
产生这样的异常原因:是web容器生成的servlet代码中有out.write(""),这个和JSP中调用的response.getOutputStream()产生冲突.即Servlet规范说明,不能既调用response.getOutputStream(),又调用response.getWriter(),无论先调用哪一个,在调用第二个时候应会抛出IllegalStateException,因为在jsp中,out变量实际上是通过response.getWriter得到的,你的程序中既用了response.getOutputStream,又用了out变量,故出现以上错误。
解决方案:在程序的最后添加:out.clear(); out = pageContext.pushBody(); 或者直接用servlet写
6.detai与ColumnFooter间有一大段空白,
从 iReprot 工具列社定 [编辑]>[报表属性] ,开启后的窗口选[More...] -> [Floating column footer] 打勾
7.在浏览器中显示JasperReports PDF文档
http://www.ensode.net/jasperreports_pdf_send_to_browser_pg2.html
把PDF直接“流向”浏览器。为此,我们必须首先通过调用ServletContext中的getResourceAsStream()方法以流形式得到编译的资源。这个方法返回一个java.io.InputStream的实例—我们可以把它作为一个参数传递给JasperRunManager类的runReportToPdfStream()方法。
8.分组时注意sql语句加上order by+分组字段,否则无法显示分组功能
9. jasperreports:pdf,ecxel都没出现乱码,html乱码
问题:
exporter.setParameter(JRExporterParameter.OUTPUT_WRITER, out);
我改成:OutputStream out = response.getOutputStream();
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
发现OutputStream还真好,不会出现乱码。
1 运行环境
1.1 JasperReport 3.5
JasperReports 是iReport的核心内容。它是一个强有力的开源报表产生工具,可以将内容输出到屏幕上、打印机或生成PDF, HTML, XLS, CSV和XML等文件。它完全用Java编写,并可在各种Java应用(包括J2EE或WEB应用)中用来产生动态报表内容。JasperReports 组织根据在一个XML文件中定义的报表设计通过JDBC访问关系数据库中的数据.填充报表数据之前必须先将报表设计被编译成一个jasper文件。
下载地址: http://jasperreports.sourceforge.net/
1.2 iReport3.5.2
iReport是一个制作Jasperreport XML文件的优秀可视化开发工具,通过它可以方便的设计报表模板。目前最高版本为iReport3.5.2
下载地址: http://ireport.sourceforge.net
1.3 iText 1.3.1
iText是一个开放源码的Java类库,是用来生成PDF文件的。
下载地址: http://itext.sourceforge.net
1.4 iTextAsian.jar
如果要在生成的pdf文件显示中文等亚洲字符,还必须下载itext的亚洲字符包。
下载地址: http://itextdocs.lowagie.com/downloads/iTextAsian.jar
以上四个包必须加到应用程序的构建路径中或加到CLASSPATH,若是Web应用放入相应的WEB-INF\lib\中。
2 设置中文支持
为了在报表中能够显示中文,加入以上四个包还不够(因为以上四个包仅对报表生成及中文显示提供了支持),必须设置报表上各显示对象的相关属性,各属性设置说明如下:
Font name: 宋体 (中文字体)
PDF font name: STSong-Light
PDF Encoding: UniGB-UCS2-H(Chinese Siplified)
PDF Embeded: √
注意:此三项的设置必须确保iTextAsian.jar亚洲语言包已经包含在项目中,否则出现编译错误.
若读者觉得对每一个对象设置比较麻烦,可通过iReport的”Format”?”Fonts”菜单进行统一设置,并设成报表的默认字体。如下图所示:
3可能出现的问题
经过以上的设置,报表中文的显示应该没什么问题了,笔者在报表的开发过程中遇到几个问题,现总结如下:
3.1 问题描述
在WinXp中运行iReport1.2.8,设计报表时将数据字段的字体设置成中文字体,调好格式后编译并运行,并使用JRViewer进行预览一切正常(中文显示正常),但使用PDF、Excel预览出现如下错误:
Could not load the following font :
pdfFontName : STSong-Light
pdfEncoding : UniGB-UCS2-H
isPdfEmbedded : true
产生原因:成成PDF的亚洲语言包没有包含到项目中
解决办法: 将亚洲语言包iTextAsian.jar包含到项中,可能过iReport的”Options”?”Classpath”将 iTextAsian.jar添加Classpath中或者直接将iTextAsian.jar复制到iReport安装目录下的lib中.若是Web项目则应该将iTextAsian.jar复制到此项目的WEB-INF\lib\中.
3.2 问题描述
在WinXp中运行iReport1.2.8,设计报表时将数据字段的字体设置成中文字体,调好格式后编译并运行,并使用JRViewer进行预览一切正常(中文显示正常),使用PDF、Excel预览时无任何错误,但中文无法显示(只显示空白).
产生原因:报表显示对象的PDF字体属性设置不正确
解决办法: 报表对象有关字体属性的设置如下:
Font name: 宋体 (中文字体)
PDF font name: STSong-Light
PDF Encoding: UniGB-UCS2-H(Chinese Siplified)
PDF Embeded: true
即如下图所法
3.3问题描述
生成PDF、Excel文件时,中文显示一切正常,但生成Html文件时显示乱码
产生原因:主要是网页编码问题
解决方法
在JSP页中生成Html时,设置 <%@ page contentType="text/html;charset=GB2312" %>
在Servlet中生成Html时,response.setContentType("text/html;charset=GB2312");
另外, 我们通过查看iReport生成的jrxml(<?xml version="1.0" encoding="UTF-8" ?>)文件可以发现, iReport保存的汉字都是UTF-8编码。了解它的编码可以有助于我们统一编码方式。
- JasperReport 常见问题
- .jrxml vs .jasper
- 如果在运行时载入.jrxml, 那么每次调用还得编译, 不如预先编译成.jasper.不过预先编译的jasper,必须用同样版本的JasperReport载入,而且灵活性差些. 不过对于大部分报表,还是预先编译成jasper方便
- 如果批量编译jrxml
- 用Ant很容易解决
.....
- 用Ant很容易解决
- 如何使用图片?
- 很容易,用Image控件就可以了. 在Image Express里面可以用String来表示图片的路径, 或者用InputStream, File对象.不过不管用File还是String对象, 都不得不用绝对路径, 这显然很不灵活. 解决办法是,穿入一个$P的参数,表示图片所在的目录,然后用$P和文件名拼接出完整的绝对路径. 更好的方法是用InputStream, 例如this.getClass().getResourceAsStream("logo.jpg") ,这时只要把图片放在当前.jasper所在的目录就可以了,不必考虑什么参数,什么路径了
- 显示非数据库字段变量
- 显示如运行日期等,可以直接在Text Field里面输入new java.util.Date(), 然后把Pattern设成如mm/dd/yyyy.
- 动态控制某些Field是否显示
- 每个Static Text, Text Field甚至整个Band的属性里面都有Print When Expression, 比如设成new Boolean(!$P{isDisplay}.equalsIgnoreCase("yes")), 那么只有当参数display的值为yes的时候才显示
- 使用Sub Report, 如何使用相对路径
- 见1.3, 和使用图片类似, 用InputStream或者传入参数
- Query里面如何使用参数
- $P!{xxx} 或者 $P{xxx} 后者只能用于类似PreparedStatement参数绑定, 而前者可替换Sql的任意部分. 在需要动态排序的时候, 前者特别有用. 比如 select a,b,c from t order by $P!{orderClause} 不管用$P还是$P!, SQL最终是以PreparedStatement方式执行的, 不必太担心性能问题 注意:参数是不能嵌套的, 比如$P{a} =‘‘$P{b}‘‘ , $P{b}=‘‘value‘‘, 不要指望$P{a}能被替换成‘‘value‘‘
- 如何使用图表(Graph)
- JasperReport本身没有图表功能, 只有显示Image的功能(见4.3). iReport里有个Graph向导, 其实质是通过jFreeChart生成Image. 更另外, 更直接的做法是放一个Image控件, Image Express Class设置成java.awt.Image, 在Image Expression里通过自定义的类返回java.awt.Image对象. 例如‘‘GraphProvider.getImage($P{REPORT_DATASOURCE},title, subtitle.....)‘‘. GraphProvider是自己的类, public static Image getImage(JRDataSource, ....)
- 如果显示多个图表
- 在一张报表上显示一个图表和显示多个图表是不同的. 假设Query是select name,price,qty from xxx, 第一张图显示name-price, 第二张图显示name-qty, 如果还是按3.8的方法, 第二张图根本显示不出来! 为什么 因为传入的是JRDataSource, 而JRDataSource仅仅是对ResultSet的简单封装, 在第一张图处理完后, 游标已经到了eof位置了, 在开始处理第二张图的时候,就必然抛出游标耗尽的异常! 怎么办 自己写个JRDataSourceAdapter, 把JRDataSource对象里面的值预先保存到一个Collection (相当于一个Offline的数据集), 然后把这个Collection传个getImage方法. 具体是, 建一个Variable mydate, 类型是java.util.Map, Calculation Type- System, Initial Value Expression是JRDataSourceAdapter.JRDataSource2Map($P{REPORT_DATA_SOURCE},new String[]{"NAME","PRICE","QTY"},new Class[]{java.lang.String.class,java.lang.Double.class,java.lang.Double.class}), JRDataSource2Map是自己写的一个Adapter. 然后在Image的Expression里面换成如‘‘GraphProvider.getImage(mydata,title, other params...), 当然得修改getImage方法
- .jrxml vs .jasper
- Export到Excel的问题
- 如何去掉报表头等
- 直接把不需要的Band删除(把其高度设为0). 如果仅仅是export到Excel的时候不需要报表头, 而输出到PDF等仍然需要保留, 那么使用print when expression, 见4.4
- 如果让Excel看起来整齐
- 不要有空白地方! 首先把所有的Field设成一样高, 对齐! 把所在Band的高度也设成和Field一样高, 让Field正好放入Band. 然后调整Field的宽度, 让每个Field都相邻,没有空隙. 最后,记得设置参数: exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
Boolean.TRUE);
- 不要有空白地方! 首先把所有的Field设成一样高, 对齐! 把所在Band的高度也设成和Field一样高, 让Field正好放入Band. 然后调整Field的宽度, 让每个Field都相邻,没有空隙. 最后,记得设置参数: exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
- 如何保留GridLine
- 首先, 设置参数exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE); 然后,把每个Field或者Static Text框的‘‘Transparent‘‘属性都勾上
- 如何使字段名只显示一次
- 如果把字段名放在ColumnHead区域, 那么输出到Excel, 会每个Page都显示一遍. 在设计Report时候, 一般会设定Page大小. 然而对于Excel, 这个Page设定仍然存在,而且往往很讨厌, 因为在Excel里, 通常希望得到连续的数据, 然而Jasper仍然会‘‘自作多情‘‘进行分页. 比如说, 设计JasperReport的时候, 设定page size为Letter, Portrait, 那么输出到Excel的时候每隔大约30行(具体取决于Field的高度), page header, column header, column foot, page foot 会被重复一次, 而且还附带一个高度为0的Excel Row, 表示Page Break的地方. 把字段名放在title band里, 可以解决字段名重复的问题, 当然page header也不要显示了. 如果需要, 可以把title band的print when expression设成只有输出Excel的时候才显示
- 为什么Excel里面的数据是从第二行,第B列开始显示的
- 因为第一行和第A列分别是用来表示page top margin 和 page left margin的. 对于Excel来说, 纯粹多余. 解决方法是把page margin 设成0. 不过如果这个report还需要以PDF等显示, 那么设成0就不好看了. 最好能动态的改变page margin. 当然,这个改变只能在外部(调用Report的地方) 进行, 在设计Report的时候是无能为力的. 不幸的是, JasperReport类居然没有setMargin的方法,只有getter. 折中的方法只能是reflect了. 代码示意如下: //use reflect to set the private field of JRBaseReport
java.lang.reflect.Field margin = JRBaseReport.class.getDeclaredField(
"leftMargin");
margin.setAccessible(true);
margin.setInt(myRpt, 0); margin = JRBaseReport.class.getDeclaredField("topMargin");
margin.setAccessible(true);
margin.setInt(myRpt, 0); margin = JRBaseReport.class.getDeclaredField("bottomMargin");
margin.setAccessible(true);
margin.setInt(myRpt, 0);
- 因为第一行和第A列分别是用来表示page top margin 和 page left margin的. 对于Excel来说, 纯粹多余. 解决方法是把page margin 设成0. 不过如果这个report还需要以PDF等显示, 那么设成0就不好看了. 最好能动态的改变page margin. 当然,这个改变只能在外部(调用Report的地方) 进行, 在设计Report的时候是无能为力的. 不幸的是, JasperReport类居然没有setMargin的方法,只有getter. 折中的方法只能是reflect了. 代码示意如下: //use reflect to set the private field of JRBaseReport
- 如何去掉Excel中隐藏的行
- 如前说述, 由于page break的关系, Excel中每隔几十行,就有一个高度为0的row, 即使把page botom margin设为0, 把page footer去掉都没有办法. 唯一的解决办法是把page height设为很大. 同5.5一样, 不得不使用reflect:
- java.lang.reflect.Field pageHeight = JRBaseReport.class.getDeclaredField(
"pageHeight");
pageHeight.setAccessible(true);
pageHeight.setInt(myRpt, Integer.MAX_VALUE);
- java.lang.reflect.Field pageHeight = JRBaseReport.class.getDeclaredField(
- 如前说述, 由于page break的关系, Excel中每隔几十行,就有一个高度为0的row, 即使把page botom margin设为0, 把page footer去掉都没有办法. 唯一的解决办法是把page height设为很大. 同5.5一样, 不得不使用reflect:
- 如何去掉报表头等
上一篇: 简单定义多线程!