You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Vaadin元素转换为iText 7元素?解决Leaflet地图PDF导出无图形问题

解决方案:Vaadin集成Leaflet地图导出PDF(iText7)

核心问题分析

直接通过Vaadin元素的getOuterHTML()转换PDF无法显示地图,原因是:

  • Leaflet地图依赖前端JavaScript动态渲染瓦片和图形,后端获取的OuterHTML仅包含初始空容器DOM,不包含渲染后的地图像素数据。
  • iText7的HtmlConverter不会执行JavaScript,无法触发地图渲染,因此导出的PDF中地图区块为空。

正确实现步骤

1. 前端将Leaflet地图转为静态图片

在Vaadin组件中调用前端JavaScript,将渲染完成的地图转为Base64格式的图片,再传递给后端:

// Vaadin组件中添加前端交互方法
@ClientCallable
public void captureMap(String mapContainerId) {
    // 调用Leaflet的getImage方法捕获地图
    getElement().executeJs("""
        const mapContainer = document.getElementById($0);
        const map = L.DomUtil.get(mapContainer)._map;
        // 等待地图完全渲染
        map.whenReady(() => {
            map.getImage().then(imgElement => {
                const base64Img = imgElement.src;
                $server.receiveMapImage(base64Img);
            });
        });
    """, mapContainerId);
}

// 接收前端传来的地图图片Base64
@ClientCallable
public void receiveMapImage(String base64Image) {
    try {
        exportMapToPdf(base64Image);
    } catch (IOException e) {
        // 处理异常
        e.printStackTrace();
    }
}

2. 后端用iText7生成含地图的PDF

拿到Base64图片后,有两种方式生成PDF:

方式一:直接将图片嵌入PDF

适合只需要导出地图的场景:

private void exportMapToPdf(String base64Image) throws IOException {
    // 去除Base64前缀
    String imageData = base64Image.replaceFirst("^data:image/[^;]+;base64,", "");
    byte[] imageBytes = Base64.getDecoder().decode(imageData);

    // 初始化PDF文档
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter("map_export.pdf"));
    Document doc = new Document(pdfDoc);

    // 添加地图图片
    ImageData pdfImage = ImageDataFactory.create(imageBytes);
    Image mapImg = new Image(pdfImage);
    mapImg.setWidthPercent(100); // 自适应页面宽度
    doc.add(mapImg);

    doc.close();
}

方式二:替换HTML中的地图容器为图片后转换

需要保留Vaadin组件其他内容的场景:

private void exportFullContentToPdf(String base64Image) throws IOException {
    // 获取Vaadin组件的原始HTML
    String originalHtml = this.getElement().getOuterHTML();
    // 将地图容器替换为Base64图片标签(假设地图容器id为"leaflet-map")
    String modifiedHtml = originalHtml.replace(
        "<div id=\"leaflet-map\"></div>",
        String.format("<img src=\"%s\" style=\"width: 100%; height: auto;\"/>", base64Image)
    );

    // 初始化PDF文档
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter("full_content_export.pdf"));
    Document doc = new Document(pdfDoc);

    // 转换修改后的HTML为iText元素并添加到PDF
    List<IElement> elements = HtmlConverter.convertToElements(modifiedHtml);
    for (IElement element : elements) {
        if (element instanceof IBlockElement) {
            doc.add((IBlockElement) element);
        }
    }

    doc.close();
}

关键注意事项

  • 确保地图完全渲染:使用Leaflet的whenReady()事件触发捕获,避免导出空白图片。
  • 跨域处理:如果地图瓦片来自第三方域名,需要确保瓦片服务器允许跨域访问,否则getImage()可能失败。
  • 图片大小优化:如果地图尺寸较大,Base64数据会占用较多内存,可考虑将图片临时保存为文件后再嵌入PDF。

内容的提问来源于stack exchange,提问作者Алексей Жуков

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 21:45:01