复杂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();
        }
    }
}
相关推荐
快乐非自愿4 分钟前
Java中使用FFmpeg拉取RTSP流
java·开发语言·ffmpeg
天天向上杰18 分钟前
地基简识Spring MVC 组件
java·spring·mvc·springmvc
武昌库里写JAVA20 分钟前
【Redis学习】Redis Docker安装,自定义config文件(包括RDB\AOF setup)以及与Spring Boot项目集成
java·开发语言·spring boot·学习·课程设计
是一只派大鑫25 分钟前
从头开始学SpringMVC—02获取请求参数&向域对象共享数据
java·后端·springmvc
大丈夫在世当日食一鲲40 分钟前
1JVM概念
java
虾球xz1 小时前
游戏引擎学习第128天
java·学习·游戏引擎
蟹至之1 小时前
类和对象(6)——Object类、内部类
java·开发语言·接口·深拷贝与浅拷贝·内部类·object类
野有蔓草W1 小时前
Android实现漂亮的波纹动画
android·java
A boy CDEF girl1 小时前
【JAVAEE】多线程
java·java-ee
m0_748257181 小时前
最新Java面试题,常见面试题及答案汇总
java·开发语言