记一次导出pdf表单引发的问题
需求:点击按钮,将相关内容生成pdf下载下来
问题1:之前项目封装好的下载文件方法不携带token
我尝试新写了一个方法,携带token
问题2:此时出现了跨域问题
我分别尝试在controller类上和方法上加@CrossOrigin(origins = “*”)都无济于事。
我在拦截器里打了断点,发现浏览器发的请求头根本获取不到。
原因是跨域请求浏览器会先发起一个预检请求,此时我们应该拦截并允许跨域
跨域问题解决
==========================0
生成pdf需要引入这俩依赖
// https://mvnrepository.com/artifact/org.thymeleaf/thymeleafimplementation("org.thymeleaf:thymeleaf:3.1.3.RELEASE")
// https://mvnrepository.com/artifact/org.xhtmlrenderer/flying-saucer-pdfimplementation("org.xhtmlrenderer:flying-saucer-pdf:9.13.1")
thymeleaf+Flying Saucer(将html转换为pdf)
package com.jiangee.environment.utils;import com.lowagie.text.pdf.BaseFont;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.xhtmlrenderer.css.parser.property.PageSize;
import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.ByteArrayOutputStream;
import java.util.Locale;
import java.util.Map;@Component
public class ThymeleafPdf {@Resourceprivate TemplateEngine templateEngine;public byte[] generatePdf(String templateName, Map<String, Object> data) {Context context = new Context();context.setVariables(data);String htmlContent = templateEngine.process(templateName, context);try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {ITextRenderer renderer = new ITextRenderer();renderer.setDocumentFromString(htmlContent);// 获取resources/下的文件//加载本地字体,不然不显示中文String fontPath = this.getClass().getClassLoader().getResource("font/simsun.ttc").getPath();renderer.getFontResolver().addFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);renderer.layout();renderer.createPDF(outputStream);return outputStream.toByteArray();} catch (Exception e) {throw new RuntimeException("Error generating PDF", e);}}
}
public void exportHandoverSheet(String batchId, HttpServletResponse response) {// 准备数据Map<String, Object> data = new HashMap<>();Map<String, Object> invoice = new HashMap<>();invoice.put("number", "INV-2023-001");invoice.put("date", LocalDate.now());invoice.put("from", "ABC Company\n123 Main St\nNew York, NY 10001");invoice.put("to", "XYZ Client\n456 Oak Ave\nBoston, MA 02108");data.put("invoice", invoice);// 生成PDFbyte[] pdfBytes = thymeleafPdf.generatePdf("invoice", data);// 3. 设置响应头response.setContentType(MediaType.APPLICATION_PDF_VALUE);response.setHeader("Content-Disposition", "attachment; filename=invoice.pdf");response.setContentLength(pdfBytes.length);// 4. 写入响应流try (OutputStream out = response.getOutputStream()) {out.write(pdfBytes);out.flush();} catch (IOException e) {throw new RuntimeException(e);}}
注:templateName是html名字,
此时运行报错:找不到TemplateEngine,
需要再加一个依赖
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleafimplementation("org.springframework.boot:spring-boot-starter-thymeleaf:3.5.2")
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><meta charset="UTF-8"/><title>Invoice</title><style>@page {size: A4 landscape; /* 横向A4 */margin: 1cm;}body { font-family: SimSun, sans-serif; margin: 20px; }.header { text-align: center; margin-bottom: 30px; }.info { margin-bottom: 20px; }table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }th { background-color: #f2f2f2; }.total { text-align: right; font-weight: bold; }</style>
</head>
<body>
<div class="header"><h2>地下水环境调查送检样品交接表单</h2><hr/>
</div><div class="info"><p><strong>From:</strong> <span th:text="${invoice.from}"></span></p><p><strong>To:</strong> <span th:text="${invoice.to}"></span></p>
</div><table><thead><tr><th>Description</th><th>Quantity</th><th>Unit Price</th><th>Amount</th></tr></thead><tbody><tr th:each="item : ${invoice.items}"><td th:text="${item.description}"></td><td th:text="${item.quantity}"></td><td th:text="${'$' + #numbers.formatDecimal(item.unitPrice, 1, 2)}"></td><td th:text="${'$' + #numbers.formatDecimal(item.quantity * item.unitPrice, 1, 2)}"></td></tr></tbody>
</table><div class="total"><h3>Total: <span th:text="${'$' + #numbers.formatDecimal(invoice.total, 1, 2)}"></span></h3>
</div>
</body>
</html>