`

动态表头

阅读更多
最近在我公司drp(运营分销系统)开发中,需要大量报表,由于本人有过jasperReport的开发经验,所以选用了它,jr确实不错,开源,可扩展性很好,缺点就是免费的文档很少,更可气的是,代码中的doc少的可怜,基本上没有参考价值.

       由于我们的产品是用于服装行业的,在服装行业有一个尺码组,非常的麻烦,在制作含有尺码组的报表时,表头的各种尺码不能写死,要从数据库查询出来.但是,一般的报表工具都是不支持表头动态化的(我理解,报表嘛,是呈现给特定人物如老板看的特定内容,表头应该是设计好的,不会经常性的更改),jasperReport也是一样,并不直接支持,细究它的实现过程,我们还是可以扩展从而解决这个问题的.

      先看jasperReport的流程图.

           从上图可看到,jrxml文件要通过JRXmlLoader解析为一个JasperDesign的对象,从源码中可以看出,此对象用java类去描述了报表的整个设计,比如,columnHeader,detail,columnFooter等等.然后由JasperCompileManager编译为一个JasperReport对象,其实,如果你用ireport(jasperReport报表的可视化设计器)制作报表,你完全可以不必理会怎样生成jaserReport对象.ireport对此有很好的支持.

       了解了以上过程,我们可以看出,如果要动态的加入设计元素,只能在JasperDesign对象中下手.加入需要的动态元素,我的需求是在columnHeader中加入一个尺码组的表头,代码实现如下.

java 代码
1.package com.webstone.drp.report.common.dynamicHeader;   
2.  
3.import java.io.File;   
4.import java.lang.reflect.InvocationTargetException;   
5.import java.util.Iterator;   
6.import org.apache.commons.beanutils.BeanUtils;   
7.import net.sf.jasperreports.engine.JRException;   
8.import net.sf.jasperreports.engine.JasperCompileManager;   
9.import net.sf.jasperreports.engine.JasperReport;   
10.import net.sf.jasperreports.engine.design.JRDesignBand;   
11.import net.sf.jasperreports.engine.design.JRDesignStaticText;   
12.import net.sf.jasperreports.engine.design.JasperDesign;   
13.import net.sf.jasperreports.engine.xml.JRXmlLoader;   
14.  
15./**  
16. * @author yaer  
17. */  
18.@SuppressWarnings("unchecked")   
19.public class ReportDesignProcess {   
20.    private static final String flagTextKey = "customFlagText";   
21.  
22.    public static JasperReport getJasperReport(String xmlFilePath,   
23.            String[][] sizeGroup) throws JRException {   
24.        JasperDesign design = getJasperDesign(xmlFilePath);   
25.        JRDesignBand columnHeader = (JRDesignBand) design.getColumnHeader();   
26.  
27.        reSetColumnHeaderHeight(columnHeader, sizeGroup);   
28.        reSetshapeAndPosition(columnHeader, sizeGroup);   
29.        addElementToColumnHeader(columnHeader, sizeGroup);   
30.        return JasperCompileManager.compileReport(design);   
31.    }   
32.    private static JasperDesign getJasperDesign(String filePath)   
33.            throws JRException {   
34.        return JRXmlLoader.load(new File(filePath));   
35.    }   
36.    private static void reSetColumnHeaderHeight(JRDesignBand columnHeader,   
37.            String[][] sizeGroup) {   
38.        columnHeader.setHeight(columnHeader.getHeight() * sizeGroup.length);   
39.    }   
40.    private static JRDesignStaticText getFlagTextInDesign(   
41.            JRDesignBand columnHeader) {   
42.        return (JRDesignStaticText) columnHeader.getElementByKey(flagTextKey);   
43.    }   
44.    private static void reSetshapeAndPosition(JRDesignBand columnHeader,   
45.            String[][] sizeGroup) {   
46.        JRDesignStaticText flagText = getFlagTextInDesign(columnHeader);   
47.        Iterator<jrdesignstatictext></jrdesignstatictext> children = columnHeader.getChildren()   
48.                .iterator();   
49.        JRDesignStaticText element;   
50.        while (children.hasNext()) {   
51.            element = children.next();   
52.            if (element.getX() > flagText.getX()) {   
53.                element.setX(flagText.getX() + flagText.getWidth()   
54.                        * sizeGroup[0].length);   
55.            }   
56.            if (!flagTextKey.equals(element.getKey())) {   
57.                element.setHeight(element.getHeight() * sizeGroup.length);   
58.            }   
59.        }   
60.    }   
61.    private static void addElementToColumnHeader(JRDesignBand columnHeader,   
62.            String[][] sizeGroup) {   
63.        JRDesignStaticText flagText = getFlagTextInDesign(columnHeader);   
64.        columnHeader.removeElement(flagText);   
65.        for (int i = 0; i < sizeGroup.length; i++) {   
66.            for (int j = 0; j < sizeGroup[i].length; j++) {   
67.                try {   
68.                    JRDesignStaticText newElement = (JRDesignStaticText) BeanUtils   
69.                            .cloneBean(flagText);   
70.                    newElement.setText(sizeGroup[i][j]);   
71.                    newElement.setX(flagText.getX() + flagText.getWidth() * j);   
72.                    newElement.setY(flagText.getY() + flagText.getHeight() * i);   
73.                    columnHeader.addElement(newElement);   
74.                } catch (IllegalAccessException e) {   
75.                    e.printStackTrace();   
76.                } catch (InstantiationException e) {   
77.                    e.printStackTrace();   
78.                } catch (InvocationTargetException e) {   
79.                    e.printStackTrace();   
80.                } catch (NoSuchMethodException e) {   
81.                    e.printStackTrace();   
82.                }   
83.            }   
84.        }   
85.    }   
86.}  
      很遗憾,没有写注解,原因是我看了一本书叫<<测试驱动开发>>,里面有一句话"意图导向编程",意思是说,用手段比如容易理解,贴切的类名,方法名,属性达到让读者轻易理解代码.从而少写注解,让代码更简捷.如果大家不大明白以上代码的意思,那就是我写的不够好,还要继续努力.

  此类只有一个方法,根据传来的报表文件路径和一个二维数组式的尺码组生成一个jaserReport的对象.有三个关键方法.重新设置columnHeader的height;重新设置静态内容的形状和大小,添加新的元素到columnHeader中,其实,这儿有一个不太容易理的东西:类中有一个flagTextKey的属性,它是标识报表设计中动态内容的一个样板元素,为什么要这个样板元素了,因为用它承载动态内容的样式,要比在用代码实现方便的多.请看BeanUtils.coloneBean()方法,实际上是克隆样板元素对象.

        这个类设计的太具体于应用,应该写成一个抽象方法,让子类来具体实现加入动态元素的过程,我相信大家的需求和我不太一样.由于时间关系,我没有仔细考究.毕竟这只是一个参考实现.

  最后,在用于ireport画报表时就要注意了,一呈不变的元素该怎么画就怎么画,但样板元素的位置一定要放好.动态内容起始的位置和样式就靠它来定义,大多数时候,它是一个标签.只不过它的"key"属性和上面类的"flagTextKey"要保持一致.

  这个话题就到这儿了,我这儿还有一个我包装的工具类,我们公司的同事都认为对开发报表有帮助.

java 代码
1.package com.webstone.drp.report.common;   
2.  
3.import java.util.ArrayList;   
4.import java.util.Collection;   
5.import java.util.HashMap;   
6.import java.util.Map;   
7.import javax.servlet.http.HttpServletRequest;   
8.import javax.servlet.http.HttpSession;   
9.import javax.faces.context.FacesContext;   
10.import org.apache.commons.lang.ArrayUtils;   
11.import com.webstone.drp.report.common.dataSource.JRArrayCollectionDataSource;   
12.import com.webstone.drp.report.common.dynamicHeader.ReportDesignProcess;   
13.import net.sf.jasperreports.engine.JRException;   
14.import net.sf.jasperreports.engine.JasperFillManager;   
15.import net.sf.jasperreports.engine.JasperPrint;   
16.import net.sf.jasperreports.engine.JasperReport;   
17.import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;   
18.import net.sf.jasperreports.engine.JRDataSource;   
19.import net.sf.jasperreports.engine.util.JRLoader;   
20.  
21./**  
22. * 使用jasperReport做报表时的工具支持类.有两个用途,生成jasperPrint对象,和设置导出时的session  
23. *   
24. * @author yaer  
25. * @date 2006-8-26   
26. * @modify date 2006-12-8  
27. */  
28.public class ReportUtils {   
29.    public static final String XLS = "xls";// 导出为xls文件;   
30.    public static final String PDF = "pdf";// 导出为pdf文件;   
31.    private static final String JASPER = "jasper";// 编译过后的报表文件;   
32.    private static final String JRXML = "jrxml";// 原始的报表文件(xml格式);   
33.    private HttpServletRequest request;   
34.    private HttpSession session;   
35.    private String rootPath;// 报表文件路径   
36.  
37.    /**  
38.     * 在jsf环境下时构造些工具类对象  
39.     *   
40.     * @param context  
41.     *            jsf的上下文对象  
42.     */  
43.  
44.    public ReportUtils(FacesContext context) {   
45.        request = (HttpServletRequest) context.getExternalContext()   
46.                .getRequest();   
47.        session = (HttpSession) context.getExternalContext().getSession(true);   
48.        this.createRootPath(request);// 生成报表文件的绝对路径   
49.    }   
50.    /**  
51.     * 在其它web环境下构造此工具类对象  
52.     *   
53.     * @param req  
54.     *            request请求对象  
55.     */  
56.    public ReportUtils(HttpServletRequest req) {   
57.        this.request = req;   
58.        this.session = req.getSession();   
59.        this.createRootPath(request);// 生成报表文件的绝对路径   
60.    }   
61.    /**  
62.     * 获得报表文件的绝对路径  
63.     *   
64.     * @return rootPath  
65.     */  
66.    public String getRootPath() {   
67.        return rootPath;   
68.    }   
69.    /**  
70.     * 获得JasperPrint对象; jasperPrint对象在jasperReport中是填充了报表数据后的一个实体,打印,导出,显示都要使用它.  
71.     * 此方法含有java5.0支持的'可变参数'特性.params其实质是一个对象数组.在调用些方法时要注意它可能的参数顺序.  
72.     * 此方法参数描述:  
73.     * 1、最多只有四个参数。  
74.     * 2、固定参数filePath表示报表文件的路径,为了支持drp系统中动态尺码组做表头的特性, filePath包括两类:  
75.     *    编译过后的文件扩展名为'.jasper'和未编译的原始xml文件'.jrxml';  
76.     *    若报表中有动态尺码组作表头,则filePath为扩展名是'.jrxml'的文件。  
77.     *    若报表中不涉及动态尺码组,则filePath为扩展名是'.jasper'的文件。  
78.     * 3、可变参数params的完整列表是(注意顺序):Object obj/Collection dataSource,String seprator,String[][] sizeGroup.  
79.     *    这三个参数中,有一个例外,Object obj/Collection dataSource必须有一个,此参数表示填充报表的数据,可以是一个Collection式的集合,  
80.     *    也可以是一个model对象(有且只有一个Collection的属性);  
81.     *    String seprator表示分隔符,如果数据源是一个Array的集合,则需此参数。String[][]sizeGroup表款尺码组的二维数组。  
82.     *   
83.     * @param filePath  
84.     * @param params  
85.     * @return jasperPrint  
86.     */  
87.    public JasperPrint getJasperPrint(String filePath, Object... params) {   
88.        JasperReport jasperReport = null;   
89.        try {   
90.            if (JASPER.equals(filePath.substring(filePath.indexOf(".") + 1,   
91.                    filePath.length()))) {// jasper式文件的处理   
92.                jasperReport = getReportTemplate(filePath);   
93.            }   
94.            if (JRXML.equals(filePath.substring(filePath.indexOf(".") + 1,   
95.                    filePath.length()))) {// jrxml式文件的处理   
96.                jasperReport = ReportDesignProcess.getJasperReport(filePath,   
97.                        (String[][]) params[params.length - 1]);// 重新设置表头,编译   
98.                params = ArrayUtils.remove(params, params.length - 1);// 删除参数中的sizeGroup   
99.            }   
100.            return fillReport(jasperReport, params);   
101.        } catch (JRException e) {   
102.            e.printStackTrace();   
103.        }   
104.        return null;   
105.    }   
106.    /**  
107.     * 获得JasperPrint对象;自定义填充报表时的parameter和dataSource. 参数说明和动态表头的用法参考上一方法  
108.     * @param filePath  
109.     * @param parameter  
110.     * @param dataSource  
111.     * @param sizeGroup  
112.     * @return  
113.     */  
114.    public JasperPrint getJasperPrint(String filePath, Map parameter,   
115.            JRDataSource dataSource, Object... sizeGroup) {   
116.        JasperReport jasperReport = null;   
117.        try {   
118.            if (sizeGroup.length == 0) {   
119.                jasperReport = getReportTemplate(filePath);   
120.            }   
121.            if (sizeGroup.length == 1) {   
122.                jasperReport = ReportDesignProcess.getJasperReport(filePath,   
123.                        (String[][]) sizeGroup[sizeGroup.length - 1]);// 重新设置表头,编译   
124.            }   
125.            return JasperFillManager.fillReport(jasperReport, parameter,   
126.                    dataSource);   
127.        } catch (JRException e) {   
128.            e.printStackTrace();   
129.        }   
130.        return null;   
131.    }   
132.    public void setAttrToPage(JasperPrint jasperPrint, String report_fileName,   
133.            String report_type) {   
134.        session.setAttribute("REPORT_JASPERPRINT", jasperPrint);   
135.        session.setAttribute("REPORT_FILENAME", report_fileName);   
136.        session.setAttribute("REPORT_TYPE", report_type);   
137.    }   
138.    private JasperPrint fillReport(JasperReport jasperReport, Object[] params)   
139.            throws JRException {   
140.        Map parameters = null;   
141.        JRDataSource ds = null;   
142.        if (params.length == 0) {   
143.            return null;   
144.        }   
145.        if (params.length == 1 && params[0].getClass() == ArrayList.class) {//其实质是要判断是否是集合   
146.            ds = new JRBeanCollectionDataSource((Collection) params[0]);   
147.        }   
148.        if (params.length == 1 && params[0].getClass() != ArrayList.class) {   
149.            ClassAnalysis ca = new ClassAnalysis(params[0]);   
150.            parameters = ca.getFields();   
151.            ds = new JRBeanCollectionDataSource(ca.getSet());   
152.        }   
153.        if (params.length == 2 && params[0].getClass() == ArrayList.class) {   
154.            ds = new JRArrayCollectionDataSource((Collection) params[0],   
155.                    params[1].toString());   
156.        }   
157.        if (params.length == 2 && params[0].getClass() != ArrayList.class) {   
158.            ClassAnalysis ca = new ClassAnalysis(params[0]);   
159.            parameters = ca.getFields();   
160.            ds = new JRArrayCollectionDataSource(ca.getSet(), params[1]   
161.                    .toString());   
162.        }   
163.        return JasperFillManager.fillReport(jasperReport,   
164.                parameters == null ? new HashMap() : parameters, ds);   
165.    }   
166.    private void createRootPath(HttpServletRequest request) {   
167.        rootPath = request.getSession().getServletContext().getRealPath("/")   
168.                + "WEB-INF\\classes\\com\\webstone\\drp\\report\\jaser\\";   
169.    }   
170.    private JasperReport getReportTemplate(String jasperPath)   
171.            throws JRException {   
172.        return (JasperReport) JRLoader.loadObject(rootPath + jasperPath);   
173.    }   
174.}   
   此类用于生成填充后报表对象jasperPrint.
分享到:
评论

相关推荐

    EasyExcel 动态表头 导出

    【EasyExcel 动态表头 导出】是一种在Java编程环境下,利用阿里巴巴开源的EasyExcel库实现的高效、灵活的Excel数据导出功能。EasyExcel不仅提供了简单易用的API,而且支持动态表头,使得在导出Excel时可以根据业务...

    extjs 实现动态表头

    动态表头是ExtJS中一个高级特性,它允许开发者根据需要在运行时动态地创建和修改表格的列结构。这在处理数据展示和操作时具有很大的灵活性,尤其在数据字段不确定或需要自定义的情况下非常实用。 标题“extjs 实现...

    使用jasperReport实现动态表头.pdf

    在本文中,我们将深入探讨如何使用JasperReport来实现动态表头,这是一个在报表生成过程中非常重要的特性,尤其是在处理如服装行业中需要灵活调整的尺码组数据时。JasperReport是一个开源的报表工具,具有良好的可...

    jasperreport动态表头

    本文将深入探讨如何使用JasperReport实现动态表头,这在处理复杂和多级分类的数据时尤为有用。 JasperReport允许开发者创建交互式、高质量的PDF、HTML、XLS、CSV等多种格式的报表。动态表头是指表头能够根据数据的...

    GridView动态表头合并,表头合并

    然而,在实际应用中,我们有时需要对GridView的表头进行复杂的布局,例如实现动态表头合并。这在处理具有层次结构的数据时尤为有用,可以清晰地展示出数据之间的关系。本篇文章将深入探讨如何实现GridView动态表头的...

    JasperReport动态表头及按组分页,去掉了subreport

    本主题聚焦于“JasperReport动态表头及按组分页,去掉了subreport”,这是一个高级用法,旨在提高报表的可读性和效率。以下是对这些知识点的详细解释: 1. **JasperReport动态表头**: 动态表头是指在报表中,表头...

    spring boot框架layui前端,table拓展,支持动态表头和数据展示,支持table表数据编辑

    本项目重点在于实现动态表头和数据展示,同时支持表格的编辑功能,这些特性大大增强了用户界面的交互性和灵活性。接下来,我们将详细讨论相关知识点。 首先,Spring Boot是基于Spring框架的一个微服务开发工具,它...

    JasperReport动态表头及按组分页,去掉了subreport ,做成Jar文件

    在这个特定的场景中,我们看到的是一个关于动态表头和按组分页实现的优化,其中去掉了传统的`subreport`方法,并且打包成了一个Jar文件,表明这是一个可直接运行的Java应用程序。 1. **动态表头**: JasperReport...

    datagridview的动态表头,合计,分组。分合计

    在标题为"datagridview的动态表头,合计,分组。分合计"的话题中,我们将深入探讨如何实现`DataGridView`的动态表头、计算合计以及分组功能。 首先,**动态表头**是指在运行时根据数据源的结构或用户需求自动生成...

    JasperReport动态表头及subreport实现多表

    本篇文章将详细讲解如何利用JasperReport实现动态表头和多表分页,并通过subreport来达到灵活的布局效果。 首先,让我们了解JasperReport的基础。JasperReport是一款基于Java的报表设计工具,它允许开发者创建复杂...

    easyui的动态表头

    文件主要是关于easyui的动态表头,代码主要是js部分,

    Asp.net动态表头生成类

    在ASP.NET开发中,动态表头生成是一项常用的技术,它允许开发者在运行时根据不同的数据源和需求构建灵活多变的表格布局。标题"ASP.NET动态表头生成类"指向了这一关键点,即如何在ASP.NET环境中创建一个类来实现这种...

    Siverlight DataGrid动态表头

    2. **动态表头**:动态表头意味着表头的结构不是静态固定的,而是可以根据数据源或者用户的交互行为进行改变。这可能涉及到添加、删除或重新排列列,以及调整列宽和显示的属性。在本项目中,开发人员可能通过数据...

    extjs动态表头,绝对的好东西啊

    动态表头是ExtJS中的一个高级特性,它允许用户在运行时自定义表格的列结构,提供了高度可配置和交互性的体验。这个"extjs动态表头"的资源很可能是一个插件或组件,名为`Ext.ux.grid.DynamicGridPanel.js`,它扩展了...

    Layui动态表头方法

    在本文中,我们将深入探讨如何使用Layui框架实现动态表头的方法,这对于构建具有高度灵活性和可定制性的数据展示界面至关重要。Layui是一款基于前端MVC模式的轻量级、模块化前端框架,其丰富的组件库为开发人员提供...

    spreadjs_动态添加表头及数据绑定-demo.zip

    总的来说,这个示例项目是关于如何利用SpreadJS创建一个具有动态表头和数据绑定功能的Web电子表格应用。开发者可以通过学习这个示例,掌握如何在自己的项目中实现类似的功能,提升用户界面的交互性和数据管理的灵活...

    SSRS: 动态表头的Matrix实现的源代码

    本话题主要探讨如何利用SSRS的Matrix来实现动态表头。 动态表头是指表头能够根据数据集中的内容自适应调整,以展示层次化或分组的数据。在SSRS中,Matrix提供了这样的功能,允许我们在列和行上进行多层次的分组,...

    Excel技巧 制作动态表头提高工作效率.docx

    因此,掌握制作动态表头的技巧,可以显著提高工作效率。 动态表头的制作主要依赖于Excel的基本功能——单元格引用和公式。通过在工作表中设置一些基础单元格作为参数,并引用这些参数到其他工作表的标题公式中,...

    使用jasperReport实现动态表头.docx

    在本文中,我们将深入探讨如何使用JasperReport实现动态表头,特别是针对尺码组这样的特殊需求。 1. **JasperReport流程**: JasperReport的工作流程包括XML解析、设计对象构建和编译。首先,JRXML文件被`...

    Extjs 自定义树结构实现以及动态表头实现

    在本文中,我们将深入探讨如何使用ExtJS框架来实现自定义树结构以及动态表头的功能。ExtJS是一款强大的JavaScript库,常用于构建富客户端应用程序,它提供了丰富的UI组件和强大的数据绑定机制。VS2015是Visual ...

Global site tag (gtag.js) - Google Analytics