JasperReport经验谈

转载 2006年05月17日 09:14:00

JasperReport和iReport是不错的Java报表工具. 在实际项目中, 本人用它们开发了20个Report, 涉及SubReport, Image, Graph, 积累了一些经验. 尤其是关于Export到Excel方面, 文档上也很少提及, 纯粹是摸索出来的, 有的问题还是通过读源代码才解决的. 此贴并非入门教程, 差不多算是笔记吧, 以问答形式记录. 

 

 

iReport

 

安装

 

 

下载,解压iReport 0.4.0 (推荐src版本)

 

确认JDK是1.4以上

 

把JDK /lib下的tools.jar拷贝到{ireport_home}/lib目录中

 

运行

 

 

对于下载的Binary版本,只能运行/bin/startup.bat

 

对于下载的Src版本,可以通过ant iReport运行(先安装ant)

 

如果运行startup.bat,出现java.lang.NoSuchMethodError错误,一般是JDK版本太低。如果确认已安装了1.4或以上,检查path系统变量,看看有1.3的JRE是不是排在前面(比如安装了Oracle的客户端,往往有1.3的JRE),如果出现Class Not Found,检查classpath。对于通过ant的方式运行,一般都没什么问题,所以推荐下载src版本

 

JasperReport 常见问题

 

 

.jrxml vs .jasper

 

 

如果在运行时载入.jrxml, 那么每次调用还得编译, 不如预先编译成.jasper.不过预先编译的jasper,必须用同样版本的JasperReport载入,而且灵活性差些. 不过对于大部分报表,还是预先编译成jasper方便

 

如果批量编译jrxml

 

 

用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方法

 

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);

 

如何保留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);

 

如何去掉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);

 

文档

 

 

哪里有文档 

 

 

JasperReport有份Ultimate Guide, 不过不是免费的, 和jFreeChart一个德行. 不过网上有流传, 写的还可以, 60多页, 不过也没详细到哪里去. 如果下载源代码版, 那么看看自带的Demo也不错. SF的论坛也是问问题的最好地方

 

源代码 仅供参考(reportProvider--一个Servlet, GraphProider, JRDataAdapter都是普通类)

 

/**
 *

 

Title: ReportProviderServlet


 *

 

Description: Servlet to generate Jasper reports


 *

 

Copyright: Copyright (c) 2004


 *

 

Company: *****


 * @author zephyr
 * @version 1.0
 */
package xyz;

 

 

 

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.base.*;
import net.sf.jasperreports.engine.export.*;
import net.sf.jasperreports.engine.util.*;

 

import org.apache.log4j.*;

 

import java.io.*;

 

import java.sql.*;

 

import java.util.*;

 

import javax.servlet.*;
import javax.servlet.http.*;

 


public class ReportProviderServlet extends HttpServlet
{
    private static Logger log = LogManager.getLogger(ReportProviderServlet.class);

 

    //Initialize: Setup DataSourceManager
    public void init() throws javax.servlet.ServletException
    {
        String prefix = getServletContext().getRealPath("/");
        String file = getInitParameter("data-source-file");

 

        DataSourceManager.configure(prefix + file);

 

        log.info("initialized successfully!");
    }

 

    //Process the HTTP request
    public void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        String reportClass = request.getParameter("reportClass");

 

        log.debug("Running Report:" + reportClass);

 

        boolean isExcelFormat = false;

 

        if (reportClass == null)
        {
            throw new IllegalArgumentException("Jasper Class Unspecified");
        }

 

        String reportFormat = request.getParameter("reportFormat");

 

        if (reportFormat == null)
        {
            reportFormat = "jasperPrint";
        }

 

        try
        {
            JasperReport myRpt = JasperManager.loadReport(this.getClass()
                                                              .getResourceAsStream("/jasperReports/" +
                        reportClass + ".jasper"));

 

            //set ReprintHeaderOnEachPage=false for Excel Format
            isExcelFormat = reportFormat.equalsIgnoreCase("excel");

 

            if (isExcelFormat)
            {
                //use reflect to set the private field of JRBaseReport
                //No margin for excel format, max pageHeight
                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);

 

                java.lang.reflect.Field pageHeight = JRBaseReport.class.getDeclaredField(
                        "pageHeight");
                pageHeight.setAccessible(true);
                pageHeight.setInt(myRpt, Integer.MAX_VALUE);

 

                //Don't print group header on each page
                if (null != myRpt.getGroups())
                {
                    for (int i = 0; i < myRpt.getGroups().length; i++)
                    {
                        myRpt.getGroups()[i].setReprintHeaderOnEachPage(false);
                    }
                }
            }

 

            Map params = new HashMap(10);
            Enumeration enu = request.getParameterNames();

 

            while (enu.hasMoreElements())
            {
                String key = (String) enu.nextElement();
                params.put(key,
                    request.getParameter(key).toUpperCase().replaceAll("'", "''"));
                log.debug(key + "=" + request.getParameter(key));
            }

 

            log.debug("Before Filling");

 

            OutputStream httpOut = response.getOutputStream();

 

            Connection conn = DataSourceManager.getConnection(request.getSession());

 

            JasperPrint rptPnt = JasperManager.fillReport(myRpt, params, conn);

 

            conn.close();

 

            if (reportFormat.equalsIgnoreCase("jasperPrint"))
            {
                response.setContentType("application/octet-stream");
                JRSaver.saveObject(rptPnt, httpOut);
            }
            else if (reportFormat.equalsIgnoreCase("pdf"))
            {
                response.setContentType("application/pdf");
                response.setHeader("Content-Disposition",
                    "attachment;filename=/"" + reportClass + ".PDF/"");
                JasperManager.printReportToPdfStream(rptPnt, httpOut);
            }
            else if (reportFormat.equalsIgnoreCase("excel"))
            {
                response.setContentType("application/vnd.ms-excel");
                response.setHeader("Content-Disposition",
                    "attachment;filename=/"" + reportClass + ".XLS/"");

 

                JRXlsExporter exporter = new JRXlsExporter();

 

                exporter.setParameter(JRExporterParameter.JASPER_PRINT, rptPnt);
                exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, httpOut);
                exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
                    Boolean.TRUE);
                exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET,
                    Boolean.FALSE);
                exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND,
                    Boolean.FALSE);
                exporter.exportReport();
            }
            else if (reportFormat.equalsIgnoreCase("html"))
            {
                JRHtmlExporter exporter = new JRHtmlExporter();
                response.setContentType("text/html");

 

                Map imagesMap = new HashMap();

 

                request.getSession().setAttribute("IMAGES_MAP", imagesMap);

 

                exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP,
                    imagesMap);
                exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI,
                    "image.jsp image=");
                exporter.setParameter(JRExporterParameter.JASPER_PRINT, rptPnt);
                exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, httpOut);

 

                exporter.exportReport();
            }

 

            log.debug("Report Exported");
        }
        catch (Exception ex)
        {
            log.error("Error Occured", ex);
        }
    }
}

 

 

 

 

 

/**
 *

 

Title: JRDataSourceAdapter


 *

 

Description: Converting JRDataSource to Mapped ArrayList


 *

 

Copyright: Copyright (c) 2004


 *

 

Company: *****


 * @author zephyr
 * @version 1.0
 */
package xyz;

 

 

 

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.design.*;

 

import java.util.*;

 


public class JRDataSourceAdapter
{
    public static Map JRDataSource2Map(JRDataSource dataSource, String[] fieldNames,
        Class[] fieldClasses) throws JRException
    {
        HashMap result;

 

        if (fieldNames.length != fieldClasses.length)
        {
            throw new JRException("Number of Field Name & Class unmatch");
        }

 

        JRDesignField[] fields = new JRDesignField[fieldNames.length];

 

        result = new HashMap(4);

 

        for (int i = 0; i < fieldNames.length; i++)
        {
            fields[i] = new JRDesignField();
            fields[i].setName(fieldNames[i]);
            fields[i].setValueClass(fieldClasses[i]);
            result.put(fieldNames[i], new ArrayList());
        }

 

        do
        {
            for (int i = 0; i < fields.length; i++)
            {
                Object value = dataSource.getFieldValue(fields[i]);
                ((ArrayList) result.get(fields[i].getName())).add(value);
            }
        }
        while (dataSource.next());

 

        return result;
    }
}

 

 

 

/**
 *

 

Title: GraphProvider


 *

 

Description: Generate JFreeChart Image


 *

 

Copyright: Copyright (c) 2004


 *

 

Company: ****


 * @author zephyr 
 * @version 1.0
 */
package xyz;

 

 

 

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.design.*;
import net.sf.jasperreports.engine.export.*;

 

import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.*;

 

import org.jfree.data.*;

 

import java.awt.*;
import java.awt.image.*;

 

import java.io.*;

 

import java.util.*;

 


public class GraphProvider
{
    public static Image getImage(Map dataSource, String fieldNameX, String fieldNameY,
        String chartName, String titleX, String titleY, boolean isBarChart, int imageWidth,
        int imageHeight) throws JRException
    {
        JRDesignField fieldX = new JRDesignField();
        fieldX.setName(fieldNameX);
        fieldX.setValueClass(java.lang.String.class);

 

        JRDesignField fieldY = new JRDesignField();
        fieldY.setName(fieldNameY);
        fieldY.setValueClass(java.lang.Double.class);

 

        ArrayList periods = (ArrayList) dataSource.get(fieldNameX);
        ArrayList values = (ArrayList) dataSource.get(fieldNameY);

 

        DefaultCategoryDataset categoryDs = new DefaultCategoryDataset();

 

        for (int i = 0; i < values.size(); i++)
        {
            Object obj = values.get(i);
            double dataValue = 0;

 

            if (obj != null)
            {
                dataValue = ((Double) obj).doubleValue();
            }

 

            categoryDs.addValue(dataValue, null, (String) periods.get(i));
        }

 

        JFreeChart c = null;

 

        if (isBarChart)
        {
            c = ChartFactory.createBarChart(chartName, titleX, titleY, categoryDs,
                    PlotOrientation.VERTICAL, false, false, false);
        }
        else
        {
            c = ChartFactory.createLineChart(chartName, titleX, titleY, categoryDs,
                    PlotOrientation.VERTICAL, false, false, false);
        }

 

        c.getTitle().setFont(new Font("Arial", Font.BOLD, 16));

 

        NumberAxis axis = (NumberAxis) c.getCategoryPlot().getRangeAxis();
        axis.setAutoRange(true);

 

        TickUnitSource tickUnits = NumberAxis.createIntegerTickUnits();
        axis.setStandardTickUnits(tickUnits);

 

        return (c.createBufferedImage(imageWidth, imageHeight));

 

       }
}

JasperReport经验谈

JasperReport和iReport是不错的Java报表工具. 在实际项目中, 本人用它们开发了20个Report, 涉及SubReport, Image, Graph, 积累了一些经验. 尤其是...
  • zephyr_zhao
  • zephyr_zhao
  • 2004年11月08日 20:54
  • 5337

打架经验谈

据我的观察总结,人一过个二十六岁就难得再有机会打架了。我个人认为没有打过架的男性人生是不完整的人生,想把看着不顺眼的人打倒在地然后踏上一万只脚这个冲动简直是胎里带来的。我上中学的时候虽然已经开化很多,...
  • h9s
  • h9s
  • 2004年07月16日 16:16
  • 760

如何实现复杂FPGA设计的时序收敛

“打鼹鼠”是一个古老(电子时代之前)的休闲游戏。在桌面上有许多洞,每个洞里都藏着鼹鼠。当有鼹鼠从洞里钻出来时,你就用锤子打它,让鼹鼠退回洞里,你因此而得分。当鼹鼠返回洞里时,又有一只鼹鼠会随机地从另外...
  • flyingforever_wl
  • flyingforever_wl
  • 2011年11月29日 08:46
  • 873

JasperReport简介

JasperReport是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF,HTML,XML,Excel(通过POI或JExcelAPI实现)和Rtf(通过POI实现)格式。该...
  • u013516966
  • u013516966
  • 2015年02月02日 15:46
  • 679

【iReport+JasperReport】1.iReport与JasperReport基础

1.什么是iReport与JasperReport 提到iReport,就不得不先说一下JasperReport。JasperReport是一个报表制作程序,用户按照它制定的规则编写一个XML文件,然...
  • u013517797
  • u013517797
  • 2016年07月03日 10:32
  • 7660

开发者使用JasperReport——不同数据源之自定义数据源

前言     前面讲解了一些JasperReport给我们提供的一些实现好的数据源,当然如果我们有自己的特殊需要,还可以自定义数据源。   正题 跟之前的一样,我们要生成报表需要以下几个步骤:...
  • zhaodandan19910306
  • zhaodandan19910306
  • 2013年04月24日 20:34
  • 1633

jasperreport 模板格式 及ireport 设计器

报表格式介绍 以下是图中提到的每个元件的描述。 元素 描述 title 标题包含该报告的标题。它只会出现一次,在报告的一开始,例如,“Yiibai教程报告”。 pag...
  • u013378306
  • u013378306
  • 2016年09月02日 12:01
  • 11488

利用jasperReport制作web报表

1)给出自己制作的jasperReport的视图效果,方便对报表工具初期学习的选择。 2)自己制作报表的测试源码和所有相关学习资料,对应所有jar包,jasperReport版本。 ...
  • leixingbang1989
  • leixingbang1989
  • 2015年03月30日 09:15
  • 1965

jasperReport 导出 excel 提供多种设置

 默认采用的是 JRXlsExporter 类, 在此类中的 createSheet 中                                 protected void createSh...
  • qiuyufeng
  • qiuyufeng
  • 2008年01月16日 12:36
  • 4023

Jasperreport利用子报表实现合并行

最近,在用做报表,其中有一部分报表中需要合并行,其实用分组解决起来没什么难度.但是客户给的Excel就是那样的,没办法.百度.google,搜了一天,确实搜到了.有人已经实现了.还提供了代码.谢谢这位...
  • benbengou008
  • benbengou008
  • 2011年04月21日 16:53
  • 2596
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JasperReport经验谈
举报原因:
原因补充:

(最多只允许输入30个字)