有时候我们在项目中需要生成pdf文件(详细可看我的另一篇文章),并且pdf中需要动态的显示需要的图片,使用JasperReport可以很便捷的完成我们的诉求。比如我们需要生成如下的pdf文件: 接下来演示怎么实现:
设计模板
按自己的需求将image元素拖到指定的位置,拖拽image元素到报表设计区域的时候会让选择图片的资源路径,按默认配置即可,如下图 调节图片大小,以及每行展示的数量(detail栏的元素会根据数据源去遍历展示),如下图: 然后最重要的就是配置上图中的Expression表达式,即告诉框架要从哪里获取图片资源,这里我是通过字节数组输入流创建图片的,完整的Expression表达式如下,可以直接粘贴使用。说明:$ F{reportDescImage}是图片的字节数组对应的Base64编码后的字符串,所以表达式中要对$F{reportDescImage}进行Base64解码,转换为图片原来的字节数组,这样框架就可以渲染出图片了
new ByteArrayInputStream(org.apache.commons.codec.binary.Base64.decodeBase64($F{reportDescImage}.getBytes()))
代码实现
核心代码如下:
public void exportReportOrder(Integer reportId, HttpServletResponse servletResponse) {
ReportOrderDetailVO detailVO = this.getReportOrderDetail(reportId);
OutputStream outputStream;
try {
outputStream = servletResponse.getOutputStream();
String fileName = reportOrderConverter.getPdfFileName(detailVO);
servletResponse.setContentType("application/pdf;charset=utf-8");
servletResponse.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
Map<String, String> reportTypeToNameMap = reportTypeEnumService.getCodeToNameMap();
ExportFraudReportOrderResponse response = reportOrderConverter.assembleFraudReportOrder(detailVO, reportTypeToNameMap);
Map<String, Object> params = reportOrderConverter.assembleReportParams(response);
List<FraudReportOrderEvidenceImage> imageList = reportOrderConverter.getImageResources(detailVO);
JsonDataSource jsonDataSource = new JsonDataSource(new ByteArrayInputStream(JSON.toJSONString(imageList).getBytes(StandardCharsets.UTF_8)));
boolean hasImage = reportOrderConverter.hasImage(detailVO);
if (hasImage) {
fileGenerateService.generates(EnumFileMeta.PDF_4_FRAUD_REPORT, outputStream, params, jsonDataSource);
} else {
fileGenerateService.generates(EnumFileMeta.PDF_4_FRAUD_REPORT_WITHOUT_IMAGE, outputStream, params, jsonDataSource);
}
} catch (IOException io) {
log.error("获取http输出流失败", io);
throw new ServiceResponseException("获取http输出流失败");
} catch (Exception e) {
log.error("生成报告单失败", e);
throw new ServiceResponseException("生成报告单失败");
}
}
public List<FraudReportOrderEvidenceImage> getImageResources(ReportOrderDetailVO detailVO) {
if (!this.hasImage(detailVO)) {
return this.buildEmptyImage();
}
List<String> imageUrls = detailVO.getResourceList().stream()
.filter(f -> EnumResourceType.图片.getCode().equals(f.getResourceType()))
.map(m -> {
if (!StringUtils.startsWith(m.getResourceUrl(), HTTPS)) {
return HTTPS + m.getResourceUrl();
}
return m.getResourceUrl();
}).collect(Collectors.toList());
log.info("image urls: {}", imageUrls);
List<FraudReportOrderEvidenceImage> images = new ArrayList<>();
Lists.partition(imageUrls, 4).forEach(items -> {
FraudReportOrderEvidenceImage image = new FraudReportOrderEvidenceImage();
for (int i = 0; i < items.size(); i++) {
byte[] imageBytes = restTemplate.getForObject(items.get(i), byte[].class);
if (i == 0) {
image.setReportDescImage(this.byte2String(imageBytes));
continue;
}
if (i == 1) {
image.setReportDescImage2(this.byte2String(imageBytes));
continue;
}
if (i == 2) {
image.setReportDescImage3(this.byte2String(imageBytes));
continue;
}
if (i == 3) {
image.setReportDescImage4(this.byte2String(imageBytes));
}
}
images.add(image);
});
return images;
}
public boolean hasImage(ReportOrderDetailVO detailVO) {
if (Objects.isNull(detailVO) || CollectionUtils.isEmpty(detailVO.getResourceList())) {
return false;
}
List<String> imageUrls = detailVO.getResourceList().stream()
.filter(f -> EnumResourceType.图片.getCode().equals(f.getResourceType()))
.map(m -> m.getResourceUrl())
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(imageUrls)) {
return false;
}
return true;
}
private List<FraudReportOrderEvidenceImage> buildEmptyImage() {
FraudReportOrderEvidenceImage image = new FraudReportOrderEvidenceImage();
byte[] empty = new byte[0];
String emptyImage = new String(org.apache.commons.codec.binary.Base64.encodeBase64(empty), StandardCharsets.UTF_8);
image.setReportDescImage(emptyImage);
image.setReportDescImage2(emptyImage);
image.setReportDescImage3(emptyImage);
image.setReportDescImage4(emptyImage);
return Collections.singletonList(image);
}
private String byte2String(byte[] imageBytes) {
imageBytes = Objects.isNull(imageBytes) ? new byte[0] : imageBytes;
String imageStr = new String(org.apache.commons.codec.binary.Base64.encodeBase64(imageBytes), StandardCharsets.UTF_8);
return imageStr;
}
至此生成含图片的pdf文件就搞定了,以上供大家参考
|