复杂html动态页面高还原批量导出方案

复杂html动态页面高还原批量导出方案

方案一

  • thymeleaf

thymeleaf 负责服务端渲染,输出html静态页面。

  • wkhtmltopdf

wkhtmltopdf 是一个基于 WebKit 的命令行工具,能够将 HTML 转换为 PDF。

支持复杂的 HTML 和 CSS。
缺点

  1. wkhtmltopdf软件需要提前安装,增加系统部署复杂度。
  2. WebKit引擎的渲染结果和浏览器有差异,可能需要调整html的兼容性。
  • 其它

服务端缓存导出记录,下次导出同一份数据,直接命中对象存储中的文件。

xml 复制代码
        <!-- Thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
java 复制代码
    public void generatePdf() throws Exception {
        // Create the Thymeleaf context and set variables
        Context context = new Context();
        MyData data = myService.queryData(100L);
        context.setVariable("data", data);

        // Process the Thymeleaf template
        String htmlContent = templateEngine.process("report", context);

        FileUtil.writeUtf8String(htmlContent, "D:/data/tmp/input.html");

        // 调用 wkhtmltopdf 命令行工具
        Process process = Runtime.getRuntime().exec("D:/Program Files/wkhtmltopdf/bin/wkhtmltopdf D:/data/tmp/input.html D:/data/tmp/output.pdf");
        process.waitFor();
    }

针对缺点2,可以使用Cursor AI辅助编码工具,一键改写。

  • prompt
json 复制代码
[任务背景]
需要将HTML文档通过wkhtmltopdf(v0.12.6+)转换为PDF。由于该工具基于Qt WebKit引擎,请确保生成的HTML/CSS严格遵循其兼容性要求。

[核心要求]
1. 代码必须完全兼容wkhtmltopdf的渲染限制
2. 保持原有布局的视觉一致性
3. 优先使用经wkhtmltopdf验证的替代方案
4. 输出可维护的简洁代码

[技术限制清单]
## 布局系统
- 禁用:Flexbox/Gap属性、CSS Grid、Multi-column布局
- 替代方案:表格布局(table-layout)/浮动定位(float)/绝对定位
- 间距控制:使用margin/padding代替gap属性

## CSS特性
- 禁用:CSS变量(var())、position:sticky、clip-path等新特性
- 选择器:仅支持CSS2.1基础选择器,避免:nth-child等伪类
- 盒模型:明确指定width/height,避免calc()等动态计算

## 渲染特性
- 禁用:所有CSS动画/过渡效果、3D变换
- 伪元素:限制::before/::after的使用,避免复杂内容生成
- 字体:必须嵌入base64字体,禁用woff2格式

[优化策略]
1. 布局重构:使用基于浮动的布局系统(table布局作为备选方案)
2. 样式降级:将CSS变量替换为静态值,合并重复样式
3. 渐进增强:为关键元素添加兼容层(如通过JS计算布局)
4. 输出规范:生成带版本注释的代码,标注兼容性处理点

方案二

selenium-java
优点: 使用真实的Chrome浏览器渲染,高还原度。
缺点

  1. 需要安装Chrome浏览器Chrome驱动,并要保证两者的兼容性,增加系统部署复杂度。
xml 复制代码
    <!-- Selenium 主库 -->
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>4.15.0</version>
    </dependency>
    
    <!-- 强制指定 Guava 版本 -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>32.1.2-jre</version>
    </dependency>
</dependencies>
java 复制代码
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v114.page.Page;
import org.openqa.selenium.devtools.v114.page.model.PrintToPDFTransferMode;
import java.util.Base64;
import java.util.Optional;
import java.nio.file.Files;
import java.nio.file.Paths;

public class PdfExporter {

    public static void main(String[] args) {
        System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
        
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--headless=new");
        options.addArguments("--disable-gpu");
        options.addArguments("--force-device-scale-factor=1"); // 防止缩放
        
        WebDriver driver = new ChromeDriver(options);
        DevTools devTools = ((ChromeDriver) driver).getDevTools();

        try {
            devTools.createSession();
            devTools.send(Page.enable());

            driver.get("https://example.com");
            Thread.sleep(2000);

            // 完整参数配置(按方法定义顺序)
            String pdfData = devTools.send(
                Page.printToPDF(
                    Optional.of(false),               // landscape
                    Optional.of(false),              // displayHeaderFooter
                    Optional.of(true),               // printBackground
                    Optional.of(1.0),                // scale
                    Optional.of(8.5),                // paperWidth (inches)
                    Optional.of(11.0),               // paperHeight (inches)
                    Optional.of(0.4),                // marginTop
                    Optional.of(0.4),                // marginBottom
                    Optional.of(0.4),                // marginLeft
                    Optional.of(0.4),                // marginRight
                    Optional.empty(),                // pageRanges (默认全部)
                    Optional.empty(),                // headerTemplate
                    Optional.empty(),                // footerTemplate
                    Optional.of(true),               // preferCSSPageSize
                    Optional.of(PrintToPDFTransferMode.RETURNASBASE64) // transferMode
                )
            ).getData();

            Files.write(Paths.get("output.pdf"), Base64.getDecoder().decode(pdfData));
            System.out.println("PDF生成成功");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            driver.quit();
        }
    }
}
相关推荐
D_aniel_13 分钟前
排序算法-归并排序
java·排序算法·归并排序
可儿·四系桜1 小时前
WebSocket:实时通信的新时代
java·网络·websocket·网络协议
forestsea1 小时前
Maven 插件机制与生命周期管理
java·maven
七月在野,八月在宇,九月在户1 小时前
maven 依赖冲突异常分析
java·maven
金融数据出海1 小时前
黄金、碳排放期货市场API接口文档
java·开发语言·spring boot·后端·金融·区块链
胡斌附体1 小时前
微服务中 本地启动 springboot 无法找到nacos配置 启动报错
java·spring boot·微服务·yml·naocs yml
薯条不要番茄酱2 小时前
【JVM】从零开始深度解析JVM
java·jvm
夏季疯2 小时前
学习笔记:黑马程序员JavaWeb开发教程(2025.3.31)
java·笔记·学习
D_aniel_2 小时前
排序算法-快速排序
java·排序算法·快速排序
长安城没有风2 小时前
数据结构 集合类与复杂度
java·数据结构