Ireport制作JASPER子报表

1,123 阅读4分钟

前不久做项目的时候遇到了一个报表问题。数据源如下图所示

Snipaste_2022-08-19_11-15-24.png

左上表格为主数据,点击行数据,加载右上和下方表格数据。同时下方表格拆分成两个列表展示。要求结果如下图所示

Snipaste_2022-08-19_11-18-33.png

结合公司报表生成工具为Ireport5.6.0,决定使用主报表+子报表的形式实现报表

首先新建一个A4的默认报表

Snipaste_2022-08-19_11-22-32.png 后续一直点击下一步,直至生成一个空白的报表文件

Snipaste_2022-08-19_11-23-39.png

接下来需要添加静态文本域和参数接收 Snipaste_2022-08-19_11-26-53.png Snipaste_2022-08-19_11-27-53.png

在添加文本域之前,先调整好页面,删掉不需要的页面区域 Snipaste_2022-08-19_11-30-00.png

左侧列表区可以删除不需要的页面区域,也可以新增页面区域。因为我有三个子报表,需要建立三个detail区域 Snipaste_2022-08-19_11-32-10.png 建立三个detail区的原因是:如果将三个子报表放入同一个detail区后,数据会显示异常,部分列表数据无法正确加载。具体原因我也不清楚,在网上找了一圈也没找到。

接下来就是对报表的非列表展示信息进行调整 Snipaste_2022-08-19_11-36-03.png

新增参数 Snipaste_2022-08-19_11-37-39.png 此处的参数应该和非列表展示区参数名称一一对应,且参数名一致,否则在生成报表时会提示异常。

新增子报表 Snipaste_2022-08-19_11-40-03.png

Snipaste_2022-08-19_11-40-18.png

子报表的生成步骤与主报表一致,生成之后,调整一下子报表的大小,使子报表充满detail区域 Snipaste_2022-08-19_11-43-05.png

子报表生成之后,左侧的Parameters区域会自动新增一个SUBREPORT_DIR参数,这个参数的属性是子报表的绝对地址。 Snipaste_2022-08-19_11-46-23.png

这里调整好之后,开始编辑子报表属性。编辑方式与主报表一致,删除不需要的区域,新增静态文本域以及参数文本域 因为我的子报表是列表,故具体设置如下 Snipaste_2022-08-19_11-48-38.png

注意:此处参数文本域的写法是与之前的主报表的参数文本域写法不相同。 原因是二者的数据源不同,主报表的参数文本域是固定值,子报表的参数文本域是列表循环。对应的右侧的属性也不相同。可以简单的理解为Parameters对应的是不循环的数据,例如报表名称;Fields对应的是列表循环的数据,例如图中的不符合项目。

表格内容样式处理好之后,设置子报表的参数。在主报表中,新建fields参数 Snipaste_2022-08-19_11-58-03.png 三个参数分别对应三个不同的子报表。关联方式是:选中子报表后,打开属性界面。

Snipaste_2022-08-19_12-01-07.png 如果右侧没有属性界面,可以到上方的窗口中找到属性界面。组件面板也在此处 Snipaste_2022-08-19_12-02-47.png

报表文件基本就制作完成了。但是打印的时候会出现页面空白的情况或子报表内容不展示,原因是主报表的字体设置不正确,子报表没有做正确的属性设置。报表涉及到汉字的,一般将字体设置成宋体。 Snipaste_2022-08-19_12-06-26.png 除此之外,子报表的属性也要进行调整 我的子报表内容较少,选中所有控件之后,设置属性

Snipaste_2022-08-19_12-08-03.png

接下来是后台数据封装 简单来说,Parameters区域用Map来存储,Fields区域用List来存储。 由于我是有子报表,故List需要嵌套一层map<String,List> 具体如下

Map<String, Object> map = Maps.newHashMap();//主表的Parameters
	    map.put("oldToolName", "1");
	    map.put("aeestNo", "1");
	    map.put("accuracyClass", "1");
	    map.put("measuringRange", "1");
	    map.put("expiryDate","1");
	    map.put("buildingUser", "1");
	    map.put("handlingSuggestion", "1");
            
	    List<DeviationTask> taskList = DeviationTask.me.find(qp);
	    
	    List<Map> mapList1 = new ArrayList<Map>();
	    for (DeviationTask task : taskList) {
	    	mapList1.add(task.toMap());
	    }
	    if (mapList1.isEmpty()) {
	    	mapList1.add(new HashMap<>());
	    }
	    List<Map> lists = Lists.newArrayList();//主表的Fields
	    Map<String,Object> taskMap = Maps.newHashMap();
            
            List<DeviationItem> itemList = DeviationItem.me.find(qp2);
	    List<Map> maps = Lists.newArrayList();
	    List<Map> maps2 = Lists.newArrayList();
	    for(DeviationItem item : itemList) {
	        Map itemMap = Maps.newHashMap();
	        Map itemMap2 = Maps.newHashMap();
	        itemMap.put("PART_NAME",item.getPartName());
	        itemMap.put("PART_NO", item.getPartNo());
	        itemMap.put("LOT_NO", item.getLotNo());
	        itemMap.put("DIMENSIONAL_TOLERANCE", item.getDimensionalTolerance());
	        itemMap.put("QUANTITY",item.getQuantity());
	        itemMap.put("OPERATOR", item.getOperator());
	        maps.add(itemMap);
	        
	        
	        itemMap2.put("NEW_TOOL_NAME", item.getNewToolName());
	        itemMap2.put("REINSPECTION_DESCRIPTION",item.getReinspectionDescription());
	        itemMap2.put("NEW_TOOL_NO", item.getNewToolNo());
	        itemMap2.put("RETEST_CONCLUSION", item.getRetestConclusion());
	        itemMap2.put("RETEST_TIME", item.getRetestTime());
	        itemMap2.put("RETEST_INSPECTOR", item.getRetestInspector());
	        maps2.add(itemMap2);
	    }
            taskMap.put("taskList", new JRBeanCollectionDataSource(mapList1));//此处是格式化数据,否则后台会报错
            taskMap.put("itemList", new JRBeanCollectionDataSource(maps));
	    taskMap.put("resultList",  new JRBeanCollectionDataSource(maps2));
	    lists.add(taskMap);
	    String path="/jasper/qrcode/report5.jasper";//主报表文件的相对地址
        String fileName="偏离校准报告";
        downloadpdf(path, map, lists, fileName);
        
        public void downloadpdf(String path,Map<String, Object> root,List<? extends Object> list,String fileName){
        try {
            JasperReport departJasperReport = (JasperReport) JRLoader
                    .loadObject(this.getClass().getResourceAsStream(path));
            JasperPrint jasperPrint = JasperFillManager.fillReport(departJasperReport, root,
                    new JRBeanCollectionDataSource(list));

            super.previewPdf(fileName);
            JRPdfExporter exporter = new JRPdfExporter();
            exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
            SimpleOutputStreamExporterOutput simpleOs = new SimpleOutputStreamExporterOutput(
                    super.getResponse().getOutputStream());
            exporter.setExporterOutput(simpleOs);
            exporter.exportReport();
            super.getResponse().getOutputStream().close();
            super.renderNull();
        } catch (ServiceException e) {
            renderJson(new Result(false, e.getMessage()));
            return;
        } catch (Exception e) {
            log.error("打印失败", e);
            super.renderJson(new Result(false, "打印失败"));
        }
    }