无尽欢乐 JasperReport

上个月很磕了一下 JasperReport,再次亲身印证了 80/20 法则。。。今天抽空列出几个“看上去”都用不了多少时间就可以搞定的问题。

空白 pdf 报表

我用的是 Spring 中的 JasperReportsPdfView 来帮助整合生成 pdf,这本来应该是一个非常简单的过程:Controller 返回一个标识 JasperReportsPdfView 的 ModelAndView,然后 Spring 自动生成报表。我最开始尝试的时候这样写的 Controller:

1
2
3
4
5
protected ModelAndView handleRequestInternal(HttpServletRequest request,
            HttpServletResponse response) throws Exception
{
    return new ModelAndView("pdfReport");
}

pdfReport 对应一个 JasperReportsPdfView,并配置指向了一个不需要任何动态数据的 report.jrxml 模板。 打开浏览器访问 controller ,会返回生成后的 pdf,不过内容是空的。。。改来改去,折腾了半天,最后发现原来 即使模板不需要任何动态数据,还是要传递一个 dummy 过去,才可以 render 出结果

1
2
3
4
5
6
7
8
protected ModelAndView handleRequestInternal(HttpServletRequest request,
            HttpServletResponse response) throws Exception
{
    Map<Object> model = new HashMap<Object>();
    // Spring 配置的默认 jasper datasource 在 map 中的名称是 'datasource',这个名字可以配置。
    model.put("datasource", new JRBeanCollectionDataSource(new ArrayList<Object>()));
    return new ModelAndView("pdfReport",model);
}

文字消失

开始在 dev 环境下生成好好的 pdf,放到 product 环境下变得无法完全显示所有文字。推测是嵌入字体问题,换来换去都不行。最后想起 product 环境是 windows,而 dev 环境是 linux,digg 了许久文档,终于找出原因。原来 JasperReport 在生成 pdf 的时候 text 的 layout 是以 fontName 这个属性为基准,用 Java 的 AWT 里算出字的高度,而最终显示在 Adobe Reader 中的事根据 pdfFontName 这个属性。很显然, Linux 和 Windows 下面算出的文字高度不同。Linux下面可以显示,但是 Windows 下面高度就不够了,所以出现了缺字的现象。解决办法就是把 TextField 的高度加 4 px 左右。后来还想出一个方法是设置 stretch with overflow 那个属性,不过没有具体测试。

isStretchWithOverflow 失灵

用户输入的多行文字不能完全显示,只显示了在 iReport 里面设计时候的那部分,仿佛 isStretchWithOverflow 设置了跟没设置一样。又是昏天黑地的 digg,最后发现原因在客户端录入,Flex 的文本域 line separator 竟然是 \r 。Java 这边则是 \n,JasperReport 的文本 stretch 很可能是数文本有多少个 line separator 然后算出总高度,结果当然是算不出实际的行数。解决的办法是在把文本发到 JasperReport 之前,先 correct line separator。

总结

是福不是祸,是祸躲不过。上面的问题每一个都耗掉 2 hours+ 的时间来 debug,记在这里,希望可以造福后人。另外有一点比较奇怪的是,JasperReport 的论坛好像完全没有被 google index,出了问题一定要到 这里这里 才可以啊。囧

我佛慈悲。。。