复杂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();
        }
    }
}
相关推荐
年老体衰按不动键盘8 分钟前
快速部署和启动Vue3项目
java·javascript·vue
咖啡啡不加糖13 分钟前
Redis大key产生、排查与优化实践
java·数据库·redis·后端·缓存
liuyang-neu17 分钟前
java内存模型JMM
java·开发语言
UFIT38 分钟前
NoSQL之redis哨兵
java·前端·算法
刘 大 望41 分钟前
数据库-联合查询(内连接外连接),子查询,合并查询
java·数据库·sql·mysql
怀旧,1 小时前
【数据结构】6. 时间与空间复杂度
java·数据结构·算法
大春儿的试验田1 小时前
Parameter ‘XXX‘ not found. Available parameters are [list, param1]
java
程序员JerrySUN2 小时前
[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制
java·linux·架构
2302_809798322 小时前
【JavaWeb】Docker项目部署
java·运维·后端·青少年编程·docker·容器
网安INF3 小时前
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
java·web安全·网络安全·flink·漏洞