改造jasperreports for struts2插件,增加多种数据源提供能力

来源:互联网 发布:岚锋创视网络 编辑:程序博客网 时间:2024/05/17 08:10

    jasperreports是个很好用的报表引擎,近期研究了一下与struts2的接合应用问题。目前从struts2网站上下载的插件支持的数据源很单一,只能够支持List<实体类>的数据形式,这样就对程序员开发报表的灵活性作了很大的限制。jasperreports支持的数据源有很多种,例如List<Map>形式的JRMapCollectionDataSource,或者与Hibernate配合应用的JRHibernateListDataSource等等,目前struts2中的插件即struts2-jasperreports-plugin让人很不爽,用了几分钟时间改造一下它,让它支持所有JasperReports能够使用的数据源。

   修改过程如下:

1.使用svn工具从struts2的代码仓库中获得struts2-jasperreports-plugin的源代码,打开JasperReportsResult.java文件,找到如下这段代码:

        // Handle IE special case: it sends a "contype" request first.
        // TODO Set content type to config settings?
        if ("contype".equals(request.getHeader("User-Agent"))) {
            try {
                response.setContentType("application/pdf");
                response.setContentLength(0);

                ServletOutputStream outputStream = response.getOutputStream();
                outputStream.close();
            } catch (IOException e) {
                LOG.error("Error writing report output", e);
                throw new ServletException(e.getMessage(), e);
            }
            return;
        }

        // Construct the data source for the report.
        ValueStack stack = invocation.getStack();

在这些代码以后进行修改,定义一个JRDataSource接口,然后判断action当中提供的数据源是否满足JRDataSource接口,修改的代码如下:

        // Construct the data source for the report.
        ValueStack stack = invocation.getStack();

        Object dataSourceObject=stack.findValue(dataSource);
        JRDataSource jrDataSource=null;
        //以下判断是否满足JRDataSource接口
        try{
         jrDataSource=(JRDataSource)dataSourceObject;
        }catch(Exception e){
         jrDataSource = new ValueStackDataSource(stack, dataSource);
        }

最后再修改一下生成报表时填充数据的参数,如下:

            jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, jrDataSource);

这样就可以了。

    另外这个struts2-jasperreports-plugin的代码好像和我对jasperreports的理解有点问题,居然提取字段数据时先按描述来进行提取的,我在使用其它的报表工具时都是先按fieldname去提取数据,所以顺便将ValueStackDataSource中的代码代码改一下,如下:

    public Object getFieldValue(JRField field) throws JRException {
        //TODO: move the code to return a ValueStackDataSource to a seperate
        //      method when and if the JRDataSource interface is updated to support
        //      this.
        String expression = field.getName();

        if (expression == null) {
            //Description is optional so use the field name as a default
            expression = field.getDescription();
        }

编译时还有一些小小的问题,log类找不到,随便改成Log4j的或者什么的都可以,经测试很爽。

例如与Spring当中的JdbcTemplate接合在一起应用时:
  String query_sql="select b.name,a.class_name,a.edu_start_year,d.student_name from class_info a " +
    "inner join teacher b on a.teacher_id=b.teacher_id inner join student_class c " +
    "on a.class_info_code=c.class_info_code inner join student d " +
    "on c.student_id=d.student_id  where a.class_info_code=? order by b.name,a.class_name";
  List<Map> tmp_dataList=this.jdbcTemplate.queryForList(query_sql,new Object[]{Integer.valueOf(this.class_info_code)},new int[]{Types.INTEGER});
  this.datalist = new JRMapCollectionDataSource(tmp_dataList);
  注意这里向struts2-jasperreports-plugin提供数据的是datalist对象,数据类型是JRMapCollectionDataSource,在struts2的配置参数中指定dataSource为datalist就行啦!