网页如何转pdf并实现下载

需求场景:

       web界面已经生成了对应的报告信息模板和相关文件,现需要将网页文档转为pdf下载答应,同时网页中指标内容会应用户的修改而发生变化,现用户需要下载该网页版的报告。

方案一:html2pdf

前端使用html2pdf.js和pdf相关的组件JS,直接将网页转为pdf然后下载。

优点:1、网络上相关参考案例较多,纯前端,不用后台开发费力。

           2、转化时间段,效率高,几乎可以实现实时转化,服务器压力小;

缺点:1、对浏览器的兼容要求比较高,有些页面语法无法实现,浏览器分辨率对生成的文件清晰度影响较大,虽然可以通过设置像素处理,但是比较繁琐;按照官网案例很难实现清晰度较高的文档,且坑较多,笔者为后台开发选手,处理很难,放弃。

遇到的问题:

1、html2pdf使用canvas对页面进行截屏,然后转化为pdf,对网页中原有的echarts绘制的图像转canvas元素时出现空白,对跨域的网页图片转化也会出现问题;

相关案例可以在gitee或网页中搜索,有很多案例。

通过使用和测试,感觉改该插比较适用网页简单,对内容要求较低,实时性强的场景。

方案二:poi-tl

可参考:https://blog.csdn.net/weixin_41419401/article/details/113933121

且没有可用的word文档模板(文档模板可以自己定义修改,但工作量大),所以放弃了使用java poi 在服务端转化的方案。

官网文档较详细,生成word后转pdf很容易。

个人人为适用于文档内容格式固定,内容丰富但变化较小的场景。

方案三:frammark

     该方案在网上查过,但是要后台熟悉使用,有点类似poi,考虑开发周期,放弃。

方案四:nodejs文档转化服务

     选用该方案是考虑到项目中有很多网页转化场景,使用单一服务比较好扩展。

    安装nodejs过程如下:

1、下载安装nodejs对应版本,配置bin目录至环境变量 ,linux同样  

 参考地址 : https://www.runoob.com/nodejs/nodejs-install-setup.html

2、cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org

3、 安装结果验证:
			版本验证,命令为:node -v和npm -v
			查看位置:where node
			查看淘宝镜像设置,命令为:npm get registry
			查看npm全局路径设置情况,命令为:npm install webpack -g

4、执行命令:npm init 初始化生成package.json (执行命令回车即可)

5、 项目中安装mysql,执行命令为:
			npm install express mysql --save
6、 项目中安装puppeteer,执行命令为:
			cnpm install puppeteer --save
			cnpm install bufferutil --save
			cnpm install  utf-8-validate --save

7、启动服务 node app.js

linux 中以上命令也可执行。特别的,linux环境下生成的pdf可能会有部分中文乱码,出现方框,所以需要修改linux 字体配置等。

案例代码如下:

// 引入相关库文件
//var express = require('express');
const puppeteer = require('puppeteer');
const config = require('./config.js');
const mysqlUtils = require('./MysqlUtils.js');

//var app = express();
let intervalObj = null;

/**
 * 定义node服务对象
**/
var nodeServerObj = {
	/**
	 * 开启服务
	 */
	startServer: function () {
		try {
			mysqlUtils.start();
			console.log("node server start---------------------");
			// 定时获取任务
			this.getUnstartDatas();
			intervalObj = setInterval(nodeServerObj.getUnstartDatas, config.INTERVAL_TIME);
		} catch (e) {
			console.error(e);
		}
	},

	/**
	 * 停止服务
	 */
	stopServer: function () {
		if (intervalObj) {
			clearInterval(intervalObj);
			intervalObj = null;
		}
	},

	/**
	 * 获取未开始的数据内容
	 */
	getUnstartDatas: function () {
		if (config.ISSHOW_DEBUGINFO) {
			console.log("getUnstartDatas---------------------");
		}

		let sql = "select id, semester, class_id, child_id, report_file_name, report_file_save_name, status from rk_lb_dg_report_prisefile where status='0' order by id";
		mysqlUtils.executeSql(sql, function (err, result) {
			if (err) {
				console.error(err);
			} else {
				for (let i in result) {
					nodeServerObj.startWork(result[i]);
				}
			}
		});
	},

	/**
	 * 开始下载文件(先修改状态再进行转换)
	 * @param {*} reportItem 
	 */
	startWork: function (reportItem) {
		if (config.ISSHOW_DEBUGINFO) {
			console.log("startWork---------------------");
			console.log("操作文件:" + JSON.stringify(reportItem));
		}

		let sql = "update rk_lb_dg_report_prisefile set status='2', modify_time=now() where id=" + reportItem['id'];
		mysqlUtils.executeSql(sql, function (err, result) {
			if (err) {
				console.error(err);
			} else {
				nodeServerObj.createReportFile(reportItem);
			}
		});
	},

	/**
	 * 生成报告文件(通过puppeteer进行转换)
	 * @param {*} reportItem 
	 */
	createReportFile: function (reportItem) {	
		let url = config.REPORT_SERVER_PREVIEW_URL + "?childId=" + reportItem['child_id'] + "&semester=" + reportItem['semester'] + "&classId=" + reportItem['class_id'];
		if (config.ISSHOW_DEBUGINFO) {
			console.log("createReportFile---------------------url="+url);
		}

		var saveFile = config.DOWNLOAD_DIRECTORY + reportItem['report_file_save_name'];

		(async () => {
			try {
				const browser = await puppeteer.launch({
					headless: true,
					args: ['--no-sandbox', '--disable-setuid-sandbox']
				})
				let loadUiFlag = true;// 加载页面是否正常,默认为true
				const page = await browser.newPage();
				page.setUserAgent("Mozilla/5.0 (Linux; Android 8.1.0; MI 8 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36");
				// page.on('response',(res)=>{
				// 	let url = res.url();
				// 	if(res.status() == 404){
				// 		console.error("页面访问异常,url="+url);
				// 		loadUiFlag = false;
				// 		// 转换失败
				// 		nodeServerObj.stopWork(reportItem['id'], 1, saveFile);
				// 	}/*else{
				// 		console.log("监听事件中正常访问的地址信息,url="+url+", status: "+res.status());
				// 	}*/
				// });
			
				await page.goto(url, { waitUntil: 'networkidle0' });				
				await page.pdf({
					path: saveFile,
					format: 'A4'
				});

				await browser.close();
				// 转换成功
				if(loadUiFlag){
					nodeServerObj.stopWork(reportItem['id'], 3, saveFile);	
				}
				
			} catch (e) {
				console.error(e);
				// 转换失败
				nodeServerObj.stopWork(reportItem['id'], 1, saveFile);
			}
		})();
	},

	/**
	 * 结束转换文件工作
	 * @param {*} id 
	 * @param {*} status 转换结果,1:转换失败,3:转换完成
	 */
	stopWork: function (id, status, saveFile) {
		if (config.ISSHOW_DEBUGINFO) {
			console.log("stopWork---------------------");			
		}
		
		let sql = "update rk_lb_dg_report_prisefile set status='" + status + "', modify_time=now() where id=" + id;
		mysqlUtils.executeSql(sql, function (err, result) {
			if (err) {
				console.error(err);
			}else{
				console.log("id: " + id + ", status: " + status + ", saveFile: " + saveFile);
			}
		});
	}
	
	

	
	
};

// 初始化服务
nodeServerObj.startServer();

链接:

nodejs实现api接口:

https://www.jianshu.com/p/5f5050257f2e

https://www.cnblogs.com/tuspring/p/14340457.html

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JCEF(Java Chromium Embedded Framework)是一个基于CEF(Chromium Embedded Framework)的Java实现,它允许你在Java应用程序中嵌入Chrome浏览器。如果你想将网页换为PDF,JCEF本身并不会直接提供这种功能,因为它主要用于网页渲染而非PDF生成。不过,你可以结合JCEF与外部工具或库来实现这一需求,通常会涉及以下几个步骤: 1. **加载网页**:使用JCEF创建一个`CefWebViewController`并加载你要换的网页。 ```java CefWebViewController viewCtrl = new CefWebViewController(myBrowserContext); viewCtrl.setClient(new MyWebViewControllerClient()); viewCtrl.loadUrl("http://example.com"); ``` 2. **捕获网页内容**:获取网页的HTML源代码,这通常是通过监听`OnLoadingStateChange`或`OnRenderProcessTerminated`等事件并在浏览器关闭时实现。 ```java // 在MyWebViewControllerClient类中 @Override public void onRendererProcessTerminated(CefRefPtr<CefBrowser> browser, int exitCode) { String htmlContent = viewCtrl.getHtmlSource(); // 获取HTML内容 } ``` 3. **换为PDF**:有了HTML内容之后,可以使用外部库如Apache PDFBox、iText或者其他PDF生成库,将HTML换为PDF。 ```java import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.text.PDFTextStripper; PDDocument pdfDoc = new PDDocument(); try { PDFTextStripper pdfStripper = new PDFTextStripper(); pdfStripper.write(pdfDoc, new StringReader(htmlContent)); // 添加样式和其他处理... } finally { pdfDoc.save("output.pdf"); // 保存PDF文件 pdfDoc.close(); } ``` 4. **处理错误和异常**:确保在换过程中处理可能出现的错误和异常,比如换失败或资源不足等情况。 需要注意的是,JCEF并不能保证所有网页都能完美地化为PDF,特别是复杂的HTML结构或含有非标准CSS/JS的内容。此外,为了安全原因,某些网站可能会阻止抓取其内容,所以可能需要额外的权限处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值