如何使用Grails Rendering将HTML转换为PDF?
如何用Grails Rendering实现HTML到PDF的转换
我来帮你搞定用Grails Rendering插件把HTML转PDF的事儿,结合你提供的模板,一步步来操作:
1. 先安装Rendering插件
根据你的Grails版本选择对应的安装方式:
- Grails 3.x+:在项目根目录的
build.gradle中添加依赖:compile "org.grails.plugins:rendering:2.0.3" - Grails 2.x:在
grails-app/conf/BuildConfig.groovy的plugins块中添加:plugins { runtime ":rendering:1.0.0" }
添加后刷新依赖,确保插件安装成功。
2. 完善你的HTML模板
把你提供的模板补全后,放在grails-app/views/[你的控制器名]/seldata.gsp路径下(比如控制器叫InvoiceController,就放在grails-app/views/invoice/seldata.gsp)。这里给你补全并优化了模板内容,方便数据渲染:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>template seldata</title> <style> /* 解决中文显示问题,需提前把中文字体文件(比如simhei.ttf)放在web-app/fonts目录 */ @font-face { font-family: 'SimHei'; src: url('${resource(dir: "fonts", file: "simhei.ttf")}'); font-weight: normal; font-style: normal; } .invoice-box { max-width: 800px; margin: auto; padding: 30px; border: 1px solid #eee; box-shadow: 0 0 10px rgba(0, 0, 0, .15); font-size: 16px; line-height: 24px; font-family: 'SimHei', 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; color: #555; } .invoice-box table { width: 100%; line-height: inherit; text-align: left; border-collapse: collapse; } .invoice-box table td { padding: 8px; vertical-align: top; } .invoice-box table tr.top table td.title { font-size: 45px; line-height: 45px; color: #333; } .invoice-box table tr.information td { padding-bottom: 20px; } .invoice-box table tr.item td { border-bottom: 1px solid #eee; } .invoice-box table tr.total td:nth-child(2) { border-top: 2px solid #eee; font-weight: bold; } </style> </head> <body> <div class="invoice-box"> <table cellpadding="0" cellspacing="0"> <tr class="top"> <td colspan="2"> <table> <tr> <td class="title"> <!-- 可选:添加你的logo --> <img src="${resource(dir: 'images', file: 'logo.png')}" style="width:100%; max-width:300px;" /> </td> <td> 发票编号: ${invoiceNumber}<br> 生成日期: ${createDate.format("yyyy-MM-dd HH:mm")}<br> </td> </tr> </table> </td> </tr> <tr class="information"> <td colspan="2"> <table> <tr> <td> 客户名称: ${customer.name}<br> 联系地址: ${customer.address}<br> 联系电话: ${customer.phone} </td> <td> 开票方: 你的公司名称<br> 税号: 你的公司税号<br> 地址: 你的公司地址 </td> </tr> </table> </td> </tr> <tr class="heading"> <td>商品名称</td> <td>金额</td> </tr> <!-- 循环渲染商品数据 --> <g:each in="${items}" var="item"> <tr class="item"> <td>${item.name}</td> <td>¥${item.amount}</td> </tr> </g:each> <tr class="total"> <td></td> <td>总计: ¥${totalAmount}</td> </tr> </table> </div> </body> </html>
3. 编写控制器动作处理PDF生成
创建一个控制器(比如InvoiceController),注入PdfRenderingService,然后编写生成PDF的方法:
import grails.plugin.rendering.pdf.PdfRenderingService class InvoiceController { // 自动注入PDF渲染服务 PdfRenderingService pdfRenderingService def generatePdf() { // 1. 准备要传递给模板的业务数据(这里是示例,替换成你的真实数据) def model = [ invoiceNumber: "INV-2024-0001", createDate: new Date(), customer: [ name: "张三", address: "北京市朝阳区XX路XX号", phone: "138XXXXXXX" ], items: [ [name: "商品A", amount: 100.00], [name: "商品B", amount: 200.00] ], totalAmount: 300.00 ] // 2. 渲染指定模板为PDF字节数组 def pdfBytes = pdfRenderingService.render( template: "/invoice/seldata", // 对应你的模板路径 model: model, // 可选:设置PDF页面参数 pluginContextPath: servletContext.contextPath, encoding: "UTF-8" ) // 3. 设置响应头,让浏览器下载PDF文件 response.contentType = "application/pdf" response.setHeader("Content-disposition", "attachment; filename=invoice_${invoiceNumber}.pdf") response.outputStream << pdfBytes response.outputStream.flush() } }
4. 测试生成PDF
启动Grails应用,访问http://localhost:8080/invoice/generatePdf,浏览器就会自动下载生成好的PDF文件了。
常见注意事项
- 中文显示问题:Flying Saucer(Rendering插件底层依赖)默认不支持中文字体,需要添加中文字体文件并在CSS中通过
@font-face引入,模板中已经给出示例。 - 样式兼容性:尽量使用内联样式或简单的CSS选择器,复杂CSS可能无法被Flying Saucer完全解析。
- 图片路径:模板中的图片要使用Grails的
${resource()}标签生成正确的路径,避免图片无法加载。
内容的提问来源于stack exchange,提问作者reasonzila
相关产品推荐
相关产品推荐

