SpingMVC IReport多数据源交叉报表示例

SpingMVC IReport多数据源交叉报表示例


Author: 许亮
Create: 2015-11-8 0:08:41

一、特别说明

  开始本示例之前,有必要先阅读我先前发布的《SpringMVC与iReport(JasperReports) 5.6整合开发实例》这篇博文,只有熟悉了SpringMVC与iReport的整合基础之后,才能更容易上手本示例教程,因为本示例的重点在于iReport报表模板的设计。
  开始之前,先来预览下最终的报表效果:

  

二、开发环境

  • 操作系统: Windows 7 x64
  • JDK: JDK 1.7.0_79 x64
  • 开发IDE: Eclipse Luna Service Release 2 (4.4.2) x64
  • Maven: Apache Maven 3.2.3
  • iReport: Jaspersoft iReport Designer 5.6.0

三、开发过程

3.1 主要依赖包(pom.xml中)

<!-- iReport JasperReports -->
<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>5.6.0</version>
</dependency>
<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.2.2</version>
</dependency>

<!-- JFreeChart -->
<dependency>
    <groupId>org.jfree</groupId>
    <artifactId>jfreechart</artifactId>
    <version>1.0.19</version>
</dependency>

3.2 数据建模

3.2.1 Person实体类

  此模型类主要实现报表中的数据清单展示。

package com.pes_soft.example.model;

import java.util.ArrayList;
import java.util.List;

/**
 * iReport subDataset测试bean: Person实体类
 * @Author 许亮
 * @Create 2015-1-15 20:32:27
 */
public class JavaBeanPerson {
    private String name;    // 姓名
    private String sex;     // 性别
    private int age;        // 年龄
    private String hometown;// 籍贯
    private String phone;   // 电话号码

    public JavaBeanPerson() {}

    public JavaBeanPerson(String name, String sex, int age, String hometown, String phone) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.hometown = hometown;
        this.phone = phone;
    }

    // 此处省略字段的getter和setter

    public static List<JavaBeanPerson> getList() {
        List<JavaBeanPerson> list = new ArrayList<JavaBeanPerson>();
        list.add(new JavaBeanPerson("Lily", "female", 22, "Hubei", "10086"));
        list.add(new JavaBeanPerson("Macro", "male", 33, "Beijing", "13800000000"));
        list.add(new JavaBeanPerson("Andy", "male", 44, "HongKong", "13812345678"));
        list.add(new JavaBeanPerson("Linder", "female", 28, "Guangxi", "18677778888"));
        list.add(new JavaBeanPerson("Jessie", "female", 26, "Gansu", "18219177720"));
        return list;
    }
}

3.2.2 颜色实体类

  此模型类主要实现报表中的柱状图展示。

package com.pes_soft.example.model;

import java.util.ArrayList;
import java.util.List;

/**
 * iReport subDataset测试bean: 颜色实体类
 * @Author 许亮
 * @Create 2015-1-15 20:13:27
 */
public class JavaBeanColor {
    private String color;   // 颜色名
    private int count;      // 计数

    public JavaBeanColor() {}

    public JavaBeanColor(String color, int count) {
        this.color = color;
        this.count = count;
    }

    // 此处省略字段的getter和setter

    public static List<JavaBeanColor> getList() {
        List<JavaBeanColor> list = new ArrayList<JavaBeanColor>();
        list.add(new JavaBeanColor("Red", 36));
        list.add(new JavaBeanColor("Green", 59));
        list.add(new JavaBeanColor("Blue", 27));
        list.add(new JavaBeanColor("Yellow", 8));
        list.add(new JavaBeanColor("Gray", 19));
        return list;
    }
}

3.2.3 颜色实体类

  此模型类主要实现报表中的柱状图展示。

package com.pes_soft.example.model;

import java.util.ArrayList;
import java.util.List;

/**
 * iReport subDataset测试bean: 水果实体类
 * @Author 许亮
 * @Create 2015-1-15 20:03:57
 */
public class JavaBeanFruit {
    private String name;    // 水果名称
    private int qty;        // 数量

    public JavaBeanFruit() {}

    public JavaBeanFruit(String name, int qty) {
        this.name = name;
        this.qty = qty;
    }

    // 此处省略字段的getter和setter

    public static List<JavaBeanFruit> getList() {
        List<JavaBeanFruit> list = new ArrayList<JavaBeanFruit>();
        list.add(new JavaBeanFruit("Apple", 40));
        list.add(new JavaBeanFruit("Banana", 28));
        list.add(new JavaBeanFruit("Orange", 37));
        list.add(new JavaBeanFruit("Grape", 15));
        list.add(new JavaBeanFruit("Pear", 21));
        return list;
    }
}

3.3 创建报表数据源封装类

package com.pes_soft.example.ds;

import java.util.List;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRAbstractBeanDataSourceProvider;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

/**
 * iReport数据源封装
 * @author 许亮
 * @Create 2015-1-15 15:42:52
 */
public class IReportDataSourceProvider extends JRAbstractBeanDataSourceProvider {   
    private List<?> dataList;

    public IReportDataSourceProvider(Class<?> beanClass) {
        super(beanClass);
    }

    public IReportDataSourceProvider(Class<?> beanClass, List<?> dataSourceList) {
        super(beanClass);
        this.dataList = dataSourceList;
    }

    public JRDataSource create(JasperReport report) throws JRException {
        return new JRBeanCollectionDataSource(this.dataList);
    }

    public void dispose(JRDataSource dataSource) throws JRException {
        this.dataList = null;
    }
}

3.4 编写报表访问的视图控制器方法

package com.pes_soft.example.ctrler;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.pes_soft.example.constant.IReportFormat;
import com.pes_soft.example.constant.IReportParam;
import com.pes_soft.example.ds.IReportDataSourceProvider;
import com.pes_soft.example.model.JavaBeanColor;
import com.pes_soft.example.model.JavaBeanFruit;
import com.pes_soft.example.model.JavaBeanPerson;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);

        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

        String formattedDate = dateFormat.format(date);
        model.addAttribute("serverTime", formattedDate );

        return "home";
    }

    /**
     * 返回iReport报表视图
     * @param model
     * @return
     */
    @RequestMapping(value = "/report", method = RequestMethod.GET)
    public String report(Model model) {
        // 报表数据源
        JRDataSource jrDataSourceMain_Person = null;
        JRDataSource jrDataSourceSub_Color = null;
        JRDataSource jrDataSourceSub_Fruit = null;

        try {
            IReportDataSourceProvider dataSourcePerson = new IReportDataSourceProvider(JavaBeanPerson.class, JavaBeanPerson.getList());
            jrDataSourceMain_Person = dataSourcePerson.create(null);

            IReportDataSourceProvider dataSourceColor = new IReportDataSourceProvider(JavaBeanColor.class, JavaBeanColor.getList());
            jrDataSourceSub_Color = dataSourceColor.create(null);

            IReportDataSourceProvider dataSourceFruit = new IReportDataSourceProvider(JavaBeanFruit.class, JavaBeanFruit.getList());
            jrDataSourceSub_Fruit = dataSourceFruit.create(null);
        } catch (JRException e) {
            e.printStackTrace();
        }

        model.addAttribute("url", "/WEB-INF/jasper/MvcMultiDsCrossReportExample.jasper");   // 报表模板
        model.addAttribute("format", IReportFormat.pdf.name());             // 报表输出格式
        model.addAttribute("jrMainDataSource", jrDataSourceMain_Person);    // 报表主数据源
        model.addAttribute("jrColorDataSource", jrDataSourceSub_Color);     // 报表子数据源1(柱状图[Bar Chart])
        model.addAttribute("jrFruitDataSource", jrDataSourceSub_Fruit);     // 报表子数据源2(饼图[Pie Chart])

        return IReportParam.IREPORT_VIEW; // 对应jasper-defs.xml中的bean id
    }
}

四、iReport报表模板的设计

4.1 创建主数据源字段(jrMainDataSource)

  注意字段的类型与模型JavaBeanPerson.java中的字段类型保持一致。创建字段的过程就不赘述了,直接上图。

  

4.2 创建报表参数(即报表的子数据源)

  为报表创建两个参数,jrColorDataSource和jrFruitDataSource,此两参数最终会转换为报表的两个子数据源,分别作为柱状图和饼图的数据源。创建报表参数的操作如下:

  

  然后将参数重命名为“jrColorDataSource”。
  接下来需要设置该报表参数的两个属性:
  ◆ Parameter Class(参数类):net.sf.jasperreports.engine.data.JRBeanCollectionDataSource
  ◆ Use as a prompt(是否弹出窗口以输入报表参数):去掉勾勾,即不弹出窗口

  

  至此,报表参数jrColorDataSource创建完成。另一个参数jrFruitDataSource的创建过程亦与此相同。

  

4.3 创建报表数据源

  为报表创建两个空的DataSet,分别重命名为subColorDataSet和subFruitDataSet。

  

  

  给DataSet创建字段,字段名分别对应Java实体模型JavaBeanColor.java、JavaBeanFruit.java中的字段,注意字段数据类型的一致性。

  

4.4 设计报表模板

  在报表iReport报表设计器中,可以删除一些不需要的Band。这里特别要注意的是,像柱状图、饼图这些图表对象,只能放在“Summary” Band里面。

  

  将组件面板中的“Chart”拖入到“Summary” Band里面,然后选择你想要的图表类型。这里先创建一个柱状图(Bar Chart)。

  

  指定柱状图所使用的DataSet。在4.3步骤里创建的两个空的DataSet就在这里派上用场了。这里就直接指定柱状图使用“subColorDataSet”这个DataSet,剩下的一个“subFruitDataSet”就留作饼图的数据集合。

  

  输入数据序列名称,这一步非必须,可以直接“下一步”跳过。

  

  指定报表的Category(分类)和Value(值)。这里的Category即Y轴,Value即X轴。

  

  同样的方法创建一个饼图。根据自己的需要,可以自由调整图表的尺寸。最终的报表模板效果如下:

  

4.5 数据关联转换

  回顾下报表模板的设计过程:
  ■ 创建了两个报表“Parameters(参数)”:jrColorDataSource和jrFruitDataSource,并且指定它们的“Parameter Class”为net.sf.jasperreports.engine.data.JRBeanCollectionDataSource。
  ■ 创建了两个空的“DataSet(数据集)”:subColorDataSet和subFruitDataSet,其中,
   subColorDataSet对应Java实体模型JavaBeanColor.java,两者字段保持一致;
   subFruitDataSet对应Java实体模型JavaBeanFruit.java,两者字段保持一致。
  ■ 创建了一个柱状图图表,指定使用的DataSet为“subColorDataSet”。
  ■ 创建了一个饼图图表,指定使用的DataSet为“subFruitDataSet”。

  至此,报表模板的设计似乎已经完成,非也!如果此时编译报表模板,将得到的.jasper文件放入/WEB-INF/jasper/目录中,并不能得到想要的报表,原因是:创建了两个空的“DataSet(数据集)”。

  我们一开始就创建了两个报表“Parameters(参数)”,那么接下来要做的就是:把报表“Parameters(参数)”赋值给两个空的“DataSet(数据集)”。

  选中一个图表对象,右键菜单中点击“Chart Data”。

  

  关键操作步骤为:
  ◆ 选择“Sub dataSet”为:subColorDataSet;
  ◆ 选择“Connection / DataSet Expression”为:Use datasource expression;
  ◆ 选择或设置上述表达式的值为:$P{jrColorDataSource},即其中一个报表“Parameters(参数)”。
  这样就完成了报表“Parameters(参数)”到报表“DataSet(数据集)”的数据关联转换。饼图同样要如此设置。

  

五、编译与运行

  编译报表模板,将得到的.jasper文件放入/WEB-INF/jasper/目录中,通过浏览器访问地址“http://localhost:8080/multids/report”查看报表(PDF格式)。如果能正常访问,说明你已经掌握了SpringMVC iReport多数据源交叉报表的的开发技术(至少本例中使用了三个不同的数据源,一个主数据源,两个子数据源)。

  Eclipse中导入本实例时,若访问时出现404错误,可能需要设置项目的ContextPath。在项目属性中找到“Web Project Settings”,然后修改即可。

  

  项目源码:mvc-ireport-multi-ds.rar

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
对于在Spring MVC中实现动态数据源的需求,你可以使用Spring框架提供的AbstractRoutingDataSource类来实现。 首先,你需要创建一个继承自AbstractRoutingDataSource的类,例如DynamicDataSource。在DynamicDataSource中,你可以重写determineCurrentLookupKey()方法,根据需要的数据源标识动态地选择对应的数据源。 下面是一个简单的示例: ```java public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { // 根据需要的数据源标识,返回对应的数据源名称 // 例如使用ThreadLocal来保存数据源标识 return DataSourceContextHolder.getDataSource(); } } ``` 然后,在Spring配置文件中,你需要配置DynamicDataSource作为数据源,并设置其目标数据源。 ```xml <bean id="dataSource" class="com.example.DynamicDataSource"> <property name="targetDataSources"> <map> <!-- 配置多个数据源 --> <entry key="dataSource1" value-ref="dataSource1"/> <entry key="dataSource2" value-ref="dataSource2"/> </map> </property> <property name="defaultTargetDataSource" ref="dataSource1"/> </bean> ``` 最后,你可以在代码中通过调用DataSourceContextHolder.setDataSource("dataSource1")来切换数据源。这里的"dataSource1"是你配置的数据源标识。 这样,当你在Spring MVC中进行数据库操作时,AbstractRoutingDataSource会根据当前线程中保存的数据源标识选择对应的数据源进行操作。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值