如何在JasperReports中每页显示一张Base64图片列表
实现JasperReports多图片分页显示(单图单页)
要让JSONPath返回的Base64图片列表在PDF中每张单独占一页,核心是把图片列表作为遍历数据源,让每个图片对应一个报表条目并强制分页。以下是两种可靠实现方式:
方式一:使用List组件(推荐)
这种方式不影响报表其他部分的结构,适合在现有Band中嵌入图片列表:
1. 定义参数
先确保传入的图片列表被声明为java.util.List<String>类型参数:
<parameter name="IMAGE_LIST" class="java.util.List<String>"/>
2. 替换原有Image为List组件
在你的目标Band中,用List组件包裹图片元素,并配置分页:
<band height="500" splitType="Stretch"> <property name="com.jaspersoft.studio.unit.height" value="px"/> <!-- 保留原有线条元素 --> <line> <reportElement x="467" y="31" width="75" height="1" uuid="8b2650b8-8df9-423e-8c41-ec5e2fd0d41f"/> </line> <!-- List组件:循环渲染每个图片 --> <componentElement> <reportElement x="25" y="50" width="516" height="440" uuid="a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6"/> <jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd"> <datasetRun subDataset="ImageDataset"> <!-- 将图片列表转为Jasper可遍历的数据源 --> <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{IMAGE_LIST})]]></dataSourceExpression> </datasetRun> <jr:listContents height="440" width="516"> <!-- 单张图片的渲染配置 --> <image hAlign="Center" vAlign="Middle"> <reportElement x="0" y="0" width="516" height="440" uuid="q7r8s9t0-u1v2-w3x4-y5z6-a7b8c9d0e1f2"/> <!-- 解析当前循环的Base64字符串为图片 --> <imageExpression><![CDATA[javax.imageio.ImageIO.read(new java.io.ByteArrayInputStream(java.util.Base64.getDecoder().decode($F{_THIS})))]]></imageExpression> <!-- 保持图片原始比例,避免拉伸变形 --> <scaleImage>RetainShape</scaleImage> </image> <!-- 强制每个图片后分页 --> <break> <reportElement x="0" y="440" width="1" height="1" uuid="d3e4f5a6-b7c8-d9e0-f1a2-b3c4d5e6f7a8"/> <type>Page</type> </break> </jr:listContents> </jr:list> </componentElement> </band>
3. 添加子数据集
在报表根节点<jasperReport>内定义List需要的子数据集:
<subDataset name="ImageDataset" uuid="x9y8w7v6-u5t4-s3r2-q1p0-o9n8m7l6k5j4"> <!-- 字符串列表的默认字段名为"_THIS" --> <field name="_THIS" class="java.lang.String"/> </subDataset>
方式二:直接用Detail带渲染
如果报表仅用于显示图片列表,可以直接将Detail带作为图片容器,设置报表数据源为图片列表:
1. 配置报表数据源和字段
在<jasperReport>标签内添加数据源和字段定义:
<jasperReport ...> <!-- 把图片列表设为报表数据源 --> <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{IMAGE_LIST})]]></dataSourceExpression> <!-- 定义字段获取当前图片的Base64字符串 --> <field name="_THIS" class="java.lang.String"/>
2. 在Detail带中放置图片和分页
<detail> <band height="500" splitType="Stretch"> <property name="com.jaspersoft.studio.unit.height" value="px"/> <line> <reportElement x="467" y="31" width="75" height="1" uuid="8b2650b8-8df9-423e-8c41-ec5e2fd0d41f"/> </line> <image hAlign="Center" vAlign="Middle"> <reportElement x="25" y="50" width="516" height="440" uuid="29e0f3ec-c9e4-4c79-87ad-db538ae9db7b"/> <imageExpression><![CDATA[javax.imageio.ImageIO.read(new java.io.ByteArrayInputStream(java.util.Base64.getDecoder().decode($F{_THIS})))]]></imageExpression> <scaleImage>RetainShape</scaleImage> </image> <!-- 强制分页 --> <break> <reportElement x="0" y="499" width="1" height="1" uuid="f8e7d6c5-b4a3-2109-8765-43210fedcba"/> <type>Page</type> </break> </band> </detail>
关键注意点
$F{_THIS}:JRBeanCollectionDataSource遍历字符串列表时,每个元素的默认字段名是_THIS,用于获取当前循环的Base64值。<break>标签:设置type="Page"确保每张图片渲染后自动分页。scaleImage:设为RetainShape可避免图片因容器尺寸被拉伸变形,若需要填充容器可改为FillFrame。
内容的提问来源于stack exchange,提问作者Amir Naby




