随笔 - 6  文章 - 129  trackbacks - 0
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(14)

随笔档案(6)

文章分类(467)

文章档案(423)

相册

收藏夹(18)

JAVA

搜索

  •  

积分与排名

  • 积分 - 815449
  • 排名 - 49

最新评论

阅读排行榜

评论排行榜

JFreeReport是由JFree组织开发的一个基于java的报表组件。利用JFreeReport组件可以完成大多数样式的报表,并且能够将其输出
 为pdf、xls、cvs、html等不同格式的文件和打印,为程序开发人员解决报表问题提供了很大的方便。
JFreeReport组件包括一个核心包以及几个扩展包,可以到www.jfree.org网站下载。由于是开源的,所以可以直接得到其源代码。
 (后面关于PDF输出中文方面就需要修改其源代码)
现在JFreeReport加入到了Pentaho,所以JFreeReport的最新版本只到jfreereport-0.8.7-9.jar,之后就以Pentaho Report Designer命名了。
 
二、JFreeReport组件的结构
JFreeReport组件的核心对象就是JFreeReport对象,我将其视两部分:一部分是报表格式定义,另一部分是数据存储。
JFreeReport组件的数据使用的是java.swing.table.TableModel类,我们对它都非常熟悉了,用JTable做表格时都会用到,所以在此不再累述。
 我主要讲讲JFreeReport的报表格式定义以及输出方法。
JFreeReport将报表分为以下几个部分:
 报头(ReportHeader)、
 报尾(ReportFooter)、
 页头(PageHeader)、
 页尾(PageFooter)、
 分组头(GroupHeader)、
 分组尾(GroupFooter)和数据域。
l     表头(ReportHeader)——内容显示在整个报表的开头,可以包括报表名称等内容。
l     表尾(ReportFooter)——内容显示在整个报表的末尾。
l     页首(PageHeader)——内容显示在每一页的首部,第一页则显示在ReportHeader下面,可以包括报表日期、填表人等内容。
l     页尾(PageFooter)——内容显示在每一页的末尾,可以包括页号等信息。
l     分组头(GroupHeader)——如果将数据分组,则GroupHeadar内容会显示在每一组分组的头部。
l     分组尾(GroupFooter)——如果将数据分组,则GroupHeadar内容会显示在每一组分组的头部。
l     数据域——报表数据,一般位于每页的中间部分。
 
三、报表格式定义
知道了JFreeReport组件的报表结构,下面该介绍如何定义了。有两种方法:一种是使用java代码实现,另一种是使用xml定义。
1、代码方式实现报表格式定义
使用代码方式实现步骤很简单,就是分别构造报头(ReportHeader)、报尾(ReportFooter)、页头(PageHeader)、页尾(PageFooter)、
 分组头(GroupHeader)和分组尾(GroupFooter)对象,然后使用set方法加入JFreeReport对象就可以了。
上面这几个对象我们一般只会用到其addElement(Element element)方法,即将一个元素(Element)加入到指定部分。在这里,元素的意义
就是显示在报表中的内容,包括文本、表格、图形、图片等等。Element是一个抽象类,他有几个子类,但我们不必直接使用这些子类,
而是通过org.jfree.report.elementfactory包中的工厂类来构建。:
l     LabelElementFactory——标签元素工厂类,定义报表中显示的固定文本内容。
l     TextElementFactory——文本元素工厂类,根据定义的域名,显示其域名下的内容。比如:tableModel中的“编号”字段下的内容。
l     StaticShapeElementFactory——图形元素类,可以绘制直线、矩形等图形。
其他的元素我没用过,大家可以查看JFreeReport的API文档。他们的用法请看下面的例子。
  public static final int ROW_HEIGHT = 20;    //报告:行高度
        public static final int HEADER_HEIGHT = 40;    //报告:报头高度
       JFreeReport report = new JFreeReport();    //构造JFreeReport对象
       report.setName("Report Name");
       PageDefinition pd = report.getPageDefinition();    //取得报告页面定义
       float pageWidth = pd.getWidth();    //取得打印材质的页宽
 
       //定义页头
       PageHeader header = new PageHeader();
       LabelElementFactory title = new LabelElementFactory();    //标题元素
       title.setText("统计报表");    //设置文本内容
       title.setColor(Color.BLACK);    //设置颜色
       title.setAbsolutePosition(new Point2D.Float(0, HEADER_HEIGHT));    //设置显示位置
       title.setMinimumSize(new FloatDimension(pageWidth, 36));    //设置尺寸
       title.setHorizontalAlignment(ElementAlignment.LEFT);
       title.setVerticalAlignment(ElementAlignment.MIDDLE);
       title.setDynamicHeight(true);    //设置是否动态调整高度(如果为true,当文本内容超出显示范围时高度自动加长)
       header.addElement(title.createElement());
       report.setPageHeader(header);
 
       String[] columnNames = getColumnNames();    //取得报表数据域的所有列名
 
    if (columnNames != null && columnNames.length > 0) ...{
          report.getItemBand().addElement(StaticShapeElementFactory.createHorizontalLine(null, Color.BLACK, new BasicStroke(1), 0));    //绘制表格的横线
           //定义报表头
           ReportHeader reportHeader = new ReportHeader();
        for (int i = 0; i < columnNames.length; i++) ...{
              //字段名元素
              LabelElementFactory col = new LabelElementFactory();
              col.setName(columnNames[i]);
              col.setColor(Color.BLACK);
              col.setHorizontalAlignment(ElementAlignment.CENTER);
              col.setVerticalAlignment(ElementAlignment.MIDDLE);
              col.setDynamicHeight(true);
              col.setAbsolutePosition(new Point2D.Float((pageWidth
                     / (columnNames.length))
                     * i, 0));
              col.setMinimumSize(new FloatDimension(pageWidth
                     / (columnNames.length), ROW_HEIGHT));    //设置最小尺寸
              col.setBold(true);    //设置是否粗体显示
              col.setText(columnNames[i]);
              reportHeader.addElement(col.createElement());
              reportHeader.addElement(StaticShapeElementFactory.createVerticalLine(null, Color.BLACK, new BasicStroke(1), col.getAbsolutePosition().getX()));    //元素左侧竖线
              reportHeader.addElement(StaticShapeElementFactory.createHorizontalLine(null, Color.BLACK, new BasicStroke(1), 0));    //元素上方横线
              reportHeader.addElement(StaticShapeElementFactory.createVerticalLine(null, Color.BLACK, new BasicStroke(1), pageWidth));    //元素右侧竖线
              report.setReportHeader(reportHeader);
             
              //字段内容元素
              TextFieldElementFactory data = new TextFieldElementFactory();
              data.setName(columnNames[i]);
 
              data.setColor(Color.BLACK);
              data.setAbsolutePosition(new Point2D.Float((pageWidth
                     / (columnNames.length))
                     * i, 0));
              data.setMinimumSize(new FloatDimension(pageWidth
                     / (columnNames.length), ROW_HEIGHT));
              data.setHorizontalAlignment(ElementAlignment.CENTER);
 
              data.setVerticalAlignment(ElementAlignment.MIDDLE);
              data.setDynamicHeight(true);
              data.setWrapText(new Boolean(true));
              data.setNullString("-");    //如果字段内容为空,显示的文本
              data.setFieldname(columnNames[i]);
               report.getItemBand().addElement(StaticShapeElementFactory.createHorizontalLine(null, Color.BLACK, new BasicStroke(1), 0));
              report.getItemBand().addElement(data.createElement());
               report.getItemBand().addElement(StaticShapeElementFactory.createHorizontalLine(null, Color.BLACK, new BasicStroke(1), -100));
               report.getItemBand().addElement(StaticShapeElementFactory.createVerticalLine(null, Color.BLACK, new BasicStroke(1), data.getAbsolutePosition().getX()));
               report.getItemBand().addElement(StaticShapeElementFactory.createHorizontalLine(null, Color.BLACK, new BasicStroke(1), 0));
           }// end for(int i=0;i<columnNames.length;i++)
          
           //最后的竖线
           report.getItemBand().addElement(StaticShapeElementFactory.createVerticalLine(null, Color.BLACK, new BasicStroke(1), pageWidth));
          
           PageFooter footer = new PageFooter();
          
           //设置页号
           PageOfPagesFunction pageFunction = new PageOfPagesFunction("PAGE_NUMBER");    //构造一个页号函数对象
           pageFunction.setFormat("{0} / {1}页");    //设置页号显示格式(此处显示的格式为“1/5页”)
           report.addExpression(pageFunction);
          
           TextFieldElementFactory pageCount = new TextFieldElementFactory();
           pageCount.setFieldname("PAGE_NUMBER");
           pageCount.setColor(Color.black);
           pageCount.setAbsolutePosition(new Point2D.Float(0, 0));
           pageCount.setMinimumSize(new FloatDimension(pageWidth, 0));
           pageCount.setHorizontalAlignment(ElementAlignment.RIGHT);
           pageCount.setVerticalAlignment(ElementAlignment.MIDDLE);
           pageCount.setDynamicHeight(true);
           footer.addElement(pageCount.createElement());
           report.setPageFooter(footer);
          
           ReportFooter reportFooter = new ReportFooter();
           reportFooter.addElement(StaticShapeElementFactory.createHorizontalLine(null, Color.BLACK, new BasicStroke(1), 0));
           report.setReportFooter(reportFooter);
 
2、XML方式实现报表格式定义
对于简单的报表,我们可以使用代码来实现,但对于复杂的报表,代码可能就无能为力了
 (虽然也可以实现,但对于读代码的人来说可能将是场灾难),那么我们就可以通过定义XML来实现报表格式的定义。
 这种方法非常方便而且清晰。
JFreeReport定义了两种XML实现方法。这里我只介绍一种,因为另一种我没有用过。我直接通过例子来解释如何实现:
<?xml version="1.0" encoding="GB2312"?>
<report name="My Report" pageformat="A4" leftmargin="40" rightmargin="40">
  <configuration>
    <property name="com.jrefinery.report.preview.PreferredWidth">1024</property>
    <property name="com.jrefinery.report.preview.PreferredHeight">768</property>
  </configuration>
   
  <!-- 报头  -->
  <reportfooter height="20" fontname="宋体" fontsize="12">
  </reportfooter>
   
  <!-- 页首  -->
  <pageheader fontname="宋体" fontsize="12">
    <!-- 文本域,用于显示表数据中某列的内容  -->
    <!-- x,y: 为坐标点(以页首区域的左上角为(0, 0)点)  -->
    <!-- width, height: 为文本域的宽度和高度,如果为数值则表示为绝对尺寸,如果为百分数,则自动以百分比方式调整尺寸大小  -->
    <!-- alignment: 排列方式 -->
    <!-- fieldname: 域名,即数据域的列名 -->
    <!-- nullstring: 当数据域内容为空时显示的字符串内容 -->
    <!-- alignment: 水平排列方式center,left或right -->
    <!-- vertical-alignment: 竖直排列方式top、middle或bottom -->
    <!-- dynamic: 是否动态调整单元格高度,如果为true,当文本内容不足以在当前尺寸中显示时将自动增加单元格高度 -->
    <string-field x="0" y="0" width="100%" height="30" alignment="center" fontname="黑体" fontsize="15" fieldname="report.title" nullstring=""></string-field>
   
    <!-- 标签域,用于在报表中显示固定文本内容  -->
    <label x="0" y="20" width="100%" height="20" alignment="center" fontname="黑体" fontsize="15">报表</label>
        
    <label x="5%" y="80" width="100%" height="20" alignment="left">统计时间:</label>
    <string-field x="90" y="80" width="30%" height="18" alignment="left" fieldname="report.time" nullstring=""/>
    
    <label x="70%" y="80" width="100%" height="20">统计日期:</label>
   
    <!-- 时间域,用于显示时间  -->
    <!-- report.date: 下面<function>中定义的函数,显示当前时间 -->
    <!-- format: 日期格式 -->
    <date-field fieldname="report.date" format="yyyy/M/d" x="0%" y="80" width="95%" height="20" alignment="right"></date-field>
  </pageheader>
   
  <!-- 页尾  -->
  <pagefooter height="20" fontname="宋体" fontsize="12">
    <string-field fieldname="pageXofY" x="0" y="4" width="100%" height="18" alignment="right"/>
  </pagefooter>
   
  <!-- 分组  -->
  <groups>
    <group name="group1">
      <!-- 分组头 -->
      <groupheader fontname="宋体" fontsize="10.5">
        <label x="0%" y="5" width="20%" height="40" alignment="center" vertical-alignment="middle"> 结  论 </label>
        <rectangle x="0%" y="0" width="20%" height="50" color="#000000" draw="true" fill="false"/>
               
        <label x="20%" y="5" width="40%" height="20" alignment="center" vertical-alignment="middle">上 年 度</label>
       
        <!-- 图形:矩形 -->
        <!-- color: 颜色 -->
        <!-- fill: 是否填充 -->
        <rectangle x="20%" y="0" width="40%" height="25" color="#000000" draw="true" fill="false"/>       
        <label x="20%" y="30" width="20%" height="20" alignment="center" vertical-alignment="middle">人 数</label>
        <rectangle x="20%" y="25" width="20%" height="25" color="#000000" draw="true" fill="false"/>
        <label x="40%" y="30" width="20%" height="20" alignment="center" vertical-alignment="middle">占比(%)</label>
        <rectangle x="40%" y="25" width="20%" height="25" color="#000000" draw="true" fill="false"/>
        <label x="60%" y="5" width="40%" height="20" alignment="center" vertical-alignment="middle">本 年 度</label>
        <rectangle x="60%" y="0" width="40%" height="25" color="#000000" draw="true" fill="false"/>
        <label x="60%" y="30" width="20%" height="20" alignment="center" vertical-alignment="middle">人 数</label>
        <rectangle x="60%" y="25" width="20%" height="25" color="#000000" draw="true" fill="false"/>
        <label x="80%" y="30" width="20%" height="20" alignment="center" vertical-alignment="middle">占比(%)</label>
        <rectangle x="80%" y="25" width="20%" height="25" color="#000000" draw="true" fill="false"/>
      </groupheader>
      <!-- 可以还有分组尾<groupfooter> -->
    </group>
  </groups>
   
  <!-- 数据域  -->
  <items fontname="宋体" fontsize="12"> 
   
    <!-- 图形:直线 -->
    <line x1="0" y1="0" x2="0" y2="100%"/>
       
    <string-field fieldname="年度体检结论" x="0%" y="5" width="20%" height="20" alignment="center" vertical-alignment="middle" nullstring="" dynamic="true"/>
    <line x1="20%" y1="0" x2="20%" y2="100%"/><!-- 结论 -->
    <string-field fieldname="上年度" x="20%" y="5" width="20%" height="20" alignment="center" vertical-alignment="middle" nullstring="" dynamic="true"/>
    <line x1="40%" y1="0" x2="40%" y2="100%"/><!-- 上年度人数 -->
    <string-field fieldname="上年度(%)" x="40%" y="5" width="20%" height="20" alignment="center" vertical-alignment="middle" nullstring="" dynamic="true"/>
    <line x1="60%" y1="0" x2="60%" y2="100%"/><!-- 上年度占比 -->
    <string-field fieldname="本年度" x="60%" y="5" width="20%" height="20" alignment="center" vertical-alignment="middle" nullstring="" dynamic="true"/>
    <line x1="80%" y1="0" x2="80%" y2="100%"/><!-- 本年度人数 -->
    <string-field fieldname="本年度(%)" x="80%" y="5" width="20%" height="20" alignment="center" vertical-alignment="middle" nullstring="" dynamic="true"/>
    <line x1="100%" y1="0" x2="100%" y2="100%"/><!-- 本年度占比 -->
       
    <line x1="0" y1="100%" x2="100%" y2="100%"/>       
  </items>
   
  <!-- 函数定义  -->
  <functions>
     <!-- 显示当前时间的函数用法  -->
    <property-ref name="report.date"/>

    <!-- 显示当前页码的函数用法 -->
    <function name="PageNumber" class="org.jfree.report.function.PageFunction" deplevel="1"/>

    <!-- 显示总页数的函数用法 -->
    <function name="PageTotal" class="org.jfree.report.function.PageTotalFunction" deplevel="1"/>
   
    <!-- 表达式,次表达式定义一个显示页码格式的用法 -->
    <expression name="pageXofY" class="org.jfree.report.function.TextFormatExpression">
      <properties>
        <property name="pattern">{0}/{1}页</property>
        <property name="field[0]">PageNumber</property>
        <property name="field[1]">PageTotal</property>
      </properties>
    </expression>
  </functions>
</report>
 另一种方法我没有用过,以后了解了再补充。
四、输出
定义完JFreeReport对象,就可以进行输出了。下面介绍几种输出方法。
1、通过预览窗口对象输出
该方式只能在Application环境中使用。通过预览窗口,用户可以自行选择打印、排版或生成各种格式的文件,这也是我们在Application中常用的方式。代码示例如下:
PreviewDialog preview = null;    //预览窗口对象
  try ...{
           // 将生成的报表放到预览窗口中
           preview = new PreviewDialog(report);
       } catch (ReportProcessingException e) ...{
           e.printStackTrace();
       }
 
   if (preview != null) ...{
           preview.pack();
           preview.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
           // 设置报表起始点及长宽
           preview.setLocation(new Point(0, 0));
           Dimension screen = getToolkit().getScreenSize();
           int width = (int) (screen.getWidth() - 2 * preview.getLocation().x);
           int height = (int) (screen.getHeight());
           preview.setSize(new Dimension(width, height));
 
           // 显示报表预览窗口
           preview.setVisible(true);
           preview.requestFocus();
           // preview.addWindowListener(new CloseHandler());
       }

2、输出HTML文本。
这种方法可以将报表输出为HTML语言形成的文本,这种方式适用于在浏览器中显示报表内容。示例代码如下:
ByteArrayOutputStream bo = null;
      StreamHtmlFilesystem filesystem = null;
       try ...{
           // 生成Html
           bo = new ByteArrayOutputStream();
           final HtmlProcessor processor = new HtmlProcessor(report);
           processor.setGenerateBodyFragment(true);
           processor.setEncoding ("UTF-8");
           filesystem = new StreamHtmlFilesystem(bo);
           processor.setFilesystem(filesystem);
           processor.processReport();
           String htmlCode = new String(bo.toByteArray(), "UTF-8");
           bo.close();
           bo = null;
           filesystem.close();
           filesystem = null;
       } catch(FileNotFoundException e) ...{
           e.printStackTrace();
       } catch(SecurityException e) ...{
           e.printStackTrace();
       } catch (ReportProcessingException e) ...{
           e.printStackTrace();
       } catch (IOException e) ...{
           e.printStackTrace();
       }
3、输出PDF文件
PDF的输出方式跟HTML的差不多,但有一点,JFreeReport本身无法输出中文字符,如果想要输出中文,我没有找到更好的方法,所以更改了JFreeReport包中org.jfree.report.modules.output.support.itext.BaseFontSupport类的源码,将
final BaseFont f = BaseFont.createFont(BaseFont.HELVETICA, stringEncoding, embedded,
false, null, null)中的BaseFont.HELVETICA改为“STSong-Light”,另外需要到www.lowagie.com/iText网站下载iText.jar包以支持STSong-Light字体编码,这样,就可以输出中文了。示例代码如下所示:
这里注意,必须将target的字体编码设为“UniGB-UCS2-H”而且使用Java1.5进行编译
       PDFOutputTarget target = null;
   try ...{
           //生成pdf
           FileOutputStream fos = new FileOutputStream("PDF.pdf");
           target = new PDFOutputTarget(fos);
           target.configure(report.getReportConfiguration());
           target.setFontEncoding("UniGB-UCS2-H");
           target.open();
   
           final PageableReportProcessor proc = new PageableReportProcessor(report);
           proc.setOutputTarget(target);
           proc.processReport();
           target.close();  
           target = null;
       } catch(FileNotFoundException e) ...{
           e.printStackTrace();
       } catch(SecurityException e) ...{
           e.printStackTrace();
       } catch (OutputTargetException e) ...{
           e.printStackTrace();
       } catch (ReportProcessingException e) ...{
           e.printStackTrace();
       }

以上就是我对JFreeReport组件的总结,写的不好希望对大家有所
 


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=2056738



posted on 2008-04-02 19:33 Ke 阅读(2187) 评论(0)  编辑  收藏 所属分类: JFreereport

只有注册用户登录后才能发表评论。


网站导航: