Jasper Report中多次使用InputStream图片异常问题求助
解决Jasper Report页脚重复显示动态图片的问题
问题根源
InputStream是一次性读取流,第一次渲染页脚时会把流的指针读到末尾,后续再读取就没有数据了,导致图片只显示一次或完全无法渲染。
可行解决方案
1. 将InputStream转为byte[]存储到DTO(推荐)
把数据库获取的图片流转换成字节数组存在DTO里,字节数组可以重复读取,完美适配页脚多次渲染的场景。
步骤:
- 修改DTO,替换或新增byte[]类型的图片字段:
public class YourDTO { // 替换原来的InputStream字段 private byte[] imageBytes; // 从数据库Blob获取图片并转换为byte[] public void setImageFromBlob(Blob blob) throws IOException { try (InputStream is = blob.getBinaryStream()) { // 用Apache Commons IO的工具类快速转换,也可以自己实现流读取 this.imageBytes = org.apache.commons.io.IOUtils.toByteArray(is); } } // Getter方法 public byte[] getImageBytes() { return imageBytes; } }
- 在Jasper模板中配置图片元素:
- 添加图片组件,设置表达式为
$F{imageBytes} - 把表达式的Class设置为
java.lang.Byte[](部分版本可选byte[]) - 确保图片元素的Evaluation Time设置为
Band(页脚带区渲染时重新计算表达式)
- 添加图片组件,设置表达式为
2. 每次渲染时重新获取InputStream(适合无法修改DTO的场景)
如果不能修改DTO结构,每次渲染页脚时要重新从数据库获取新的InputStream,而不是复用同一个流对象。
示例思路:
// 在报表填充的数据源或参数中,提供一个获取新流的方法 public InputStream getFreshImageStream() throws SQLException { // 重新从数据库查询Blob并返回新的InputStream Blob blob = yourDao.getImageBlobById(imageId); return blob.getBinaryStream(); }
在模板的图片表达式中调用这个方法:$P{imageProvider}.getFreshImageStream(),注意要处理异常,同时确保数据库连接在报表渲染期间保持可用。
3. 尝试重置InputStream(局限性大)
如果你的InputStream支持mark()和reset()方法(并非所有流都支持,比如数据库Blob的流大多不支持),可以在每次使用前重置流指针:
// 在DTO中添加重置方法 public void resetImageStream() throws IOException { if (imageStream.markSupported()) { imageStream.reset(); } }
然后在报表的图片表达式中先调用重置再返回流,但这种方法兼容性差,不推荐。
关键注意点
- 避免在DTO中存储复用的InputStream对象,这是导致重复渲染失败的核心原因
- 确保模板中图片元素的Evaluation Time设置正确,不要提前计算表达式
内容的提问来源于stack exchange,提问作者Hosam
相关产品推荐
相关产品推荐

