Winse Blog

走走停停都是风景, 熙熙攘攘都向最好, 忙忙碌碌都为明朝, 何畏之.

Jasperreports使用小结

最近接了一个报表的任务,原来也有接触过,但是仅限于了解没有真正的动手画过。这里把从选型到最后成型一路下来遇到的问题整理下。

主要两个大问题:环境的搭建,以及子报表(嵌套报表)的配置。

选择Jasperreports

知道的有Birts、Pentaho、FineReport感觉其实都差不多,大家各自都取长补当更多。由于一穷二白的,没有弄过。网上找了和SpringMVC结合的都是Jasperreport的文章,就这么草率的定下来了。

基本的操作都类似,报表HelloWorld还是比较简单的。下载jaspersoftstudio最新版,然后了解各个区域的作用。

一个完全的报表模板包括如下几个区域:title, pageHeader, columnHeader, groupHeader, detail, groupFooter, columnFoter, pageFooter, summary

整合SpringMVC

原来做报表的同时都是直接连数据库的,过程中遇到各种问题。很多没法维护的事情发生:改个字段,数据库测试/生产链接等等。我这里直接选择通过JavaBean来传递数据。

贴代码之前先说PDF报表字体的问题,本来报表是加粗的,但是服务器生成浏览的时刻没有效果。发现还需要单独添加字体的包:pdf - Bold not working in Jaspersoft Studio for fonts other than sans serif

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#maven
<properties>
      <spring.version>4.2.5.RELEASE</spring.version>
...
      <dependency>
          <groupId>net.sf.jasperreports</groupId>
          <artifactId>jasperreports</artifactId>
          <version>6.3.1</version>
      </dependency>
      <dependency>
          <groupId>net.sf.jasperreports</groupId>
          <artifactId>jasperreports-fonts</artifactId>
          <version>6.0.0</version>
      </dependency>
      <dependency>
          <groupId>com.itextpdf</groupId>
          <artifactId>itextpdf</artifactId>
          <version>5.5.10</version>
      </dependency>
      <dependency>
          <groupId>com.itextpdf</groupId>
          <artifactId>itext-asian</artifactId>
          <version>5.2.0</version>
      </dependency>
      <dependency>
          <groupId>org.codehaus.groovy</groupId>
          <artifactId>groovy-all</artifactId>
          <version>2.4.7</version>
      </dependency>

# spring mvc xml
  <bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
      <property name="order" value="0"></property>
      <property name="basename" value="views"></property>
  </bean>
  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="order" value="1"></property>
      <property name="viewClass">
          <value>org.springframework.web.servlet.view.JstlView</value>
      </property>
...

# views.properties
HELLO.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView 
HELLO.url=/WEB-INF/report/helloworld.jasper
HELLO.reportDataKey=datasource

# java Controller
@Controller
@RequestMapping("/report")
public class HelloReportController {

  @RequestMapping("/hello.pdf")
  public ModelAndView printExpress() {
      ModelAndView mv = new ModelAndView("HELLO");

      // 如果直接传对象bean不行,需要使用list传值
      List<HelloWorldData> list = new ArrayList<>();
      list.add(new HelloWorldData("jarperreport", "Hi"));

      mv.addObject("datasource", list);
      return mv;
  }

最后通过浏览器就能查看报表的PDF文件了。

前端所有的页面都是通过ajax来获取展示的,这里通过jquery-media.js来进行展示(生成内嵌的iframe),这也是上面的地址加上pdf后缀的原因。

1
2
3
4
5
6
7
# html
<div class="modal-body" style="max-height: 900px; padding: 10px;">
  <a class="media" href="${contextPath}${url}"></a>
</div>

# jquery
$('a.media', $modal).media({width:"100%", height:600});

子报表

有一个结账的报表,既要展示汇总信息,还得把详情列表也输出出来。一开始的JavaBean:

1
2
3
4
5
6
7
8
9
10
public class InvoiceData {
  private String roomNo;
  private List<InvoiceDetailData> details;
  ...
}
public class InvoiceDetailData {
  private String date;
  private String amount;
  ...
}

但是简单报表是一维的,不能展示list里面的内容。网上一堆资料都是简单的案例,涉及多维度的就Table、Crosstable、Subreport这几个控件。Table的样式调起来麻烦,数据也不知道怎么搞。子报表至少看起来合乎逻辑,操作起来也简单。画好图标以及把对应的字段对应好后,子报表的Datasource直接填 $F{details}

修改views.properties,写好controller后,启动竟然报找不到details子报表路径。根据文章修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 主报表
# 类型必须加哦!
  <parameter name="DetailSubReport" class="net.sf.jasperreports.engine.JasperReport"/>
  ...
  <subreport>
      <reportElement stretchType="RelativeToBandHeight" x="0" y="0" width="520" height="167" uuid="8d69d85b-4fcf-482a-836c-c1698ce42dcd"/>
      <dataSourceExpression><![CDATA[$F{details}]]></dataSourceExpression>
      <subreportExpression><![CDATA[$P{DetailSubReport}]]></subreportExpression>
  </subreport>
  
# views.properties
Invoice.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView 
Invoice.url=/WEB-INF/report/invoice.jasper
Invoice.reportDataKey=datasource
Invoice.subReportUrls=DetailSubReport=/WEB-INF/report/InvoiceDetail.jasper

罗马建成非一日之功,再次编译启动后,再次报错,这次的是类型错误。感觉正在慢慢向成功靠近。修改类型后最后启动展示搞定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# javabean
public class InvoiceData {
  private JRDataSource details;
  
  public void setDetails(JRDataSource details) {
      this.details = details;
  }

  public void setDetails(List<InvoiceDetailData> details) {
      this.details = new JRBeanCollectionDataSource(details);
  }

# 主报表
  <field name="details" class="net.sf.jasperreports.engine.JRDataSource">
      <fieldDescription><![CDATA[details]]></fieldDescription>
  </field>

–END

Comments