generateReport(@RequestBody String url) {
+ byte[] pdfBytes = pdfService.generatePdfFromUrl(url);
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_PDF);
+ headers.setContentDispositionFormData("attachment", "report.pdf");
+
+ return ResponseEntity.ok()
+ .headers(headers)
+ .body(pdfBytes);
+ }
+}
diff --git a/src/main/java/com/fkzy/warn/service/PdfService.java b/src/main/java/com/fkzy/warn/service/PdfService.java
new file mode 100644
index 0000000..84b66c8
--- /dev/null
+++ b/src/main/java/com/fkzy/warn/service/PdfService.java
@@ -0,0 +1,89 @@
+package com.fkzy.warn.service;
+
+import com.microsoft.playwright.options.Margin;
+import com.microsoft.playwright.options.WaitUntilState;
+import org.springframework.stereotype.Service;
+
+import com.microsoft.playwright.*;
+import org.springframework.stereotype.Service;
+import java.util.regex.Pattern;
+
+/**
+ * @author zhangjing
+ * @date 2026/01/13 10:33
+ * @description
+ */
+@Service
+public class PdfService {
+ // 可选:限制只允许访问你自己的域名(安全)
+ private static final Pattern ALLOWED_URL_PATTERN =
+ Pattern.compile("^https://your-domain\\.com/report/.*");
+
+ public byte[] generatePdfFromUrl(String reportUrl) {
+ // 安全校验:防止 SSRF 攻击
+// if (!ALLOWED_URL_PATTERN.matcher(reportUrl).matches()) {
+// throw new IllegalArgumentException("Invalid report URL");
+// }
+
+ try (Playwright playwright = Playwright.create()) {
+ Browser browser = playwright.chromium().launch();
+ Page page = browser.newPage();
+
+ // 1. 导航到前端报表页面
+ page.navigate(reportUrl, new Page.NavigateOptions()
+ .setWaitUntil(WaitUntilState.NETWORKIDLE)); // 等待网络空闲
+
+ // 2. 【关键】等待 ECharts 渲染完成
+ // 方法一:前端在图表加载完成后添加特定 class(推荐)
+ page.waitForSelector("body.report-ready", new Page.WaitForSelectorOptions()
+ .setTimeout(30_000)); // 最多等 30 秒
+
+ // 方法二(备选):等待某个图表容器有内容
+ // page.waitForFunction("() => document.querySelector('#chart').children.length > 0");
+
+ // 3. 【可选】注入水印和 Logo(如果前端没做)
+ // 注意:如果前端已包含水印/Logo,此步可跳过
+// page.addStyleTag(new Page.AddStyleTagOptions().setContent("""
+// .playwright-watermark {
+// position: fixed;
+// top: 50%;
+// left: 50%;
+// transform: translate(-50%, -50%) rotate(-45deg);
+// font-size: 80px;
+// color: rgba(0, 0, 0, 0.08);
+// pointer-events: none;
+// z-index: 9999;
+// white-space: nowrap;
+// }
+// """));
+ page.evaluate("() => { " +
+ "const wm = document.createElement('div');" +
+ "wm.className = 'playwright-watermark';" +
+ "wm.innerText = '机密';" +
+ "document.body.appendChild(wm);" +
+ "}");
+
+ // 4. 生成 PDF
+ Margin margin = new Margin();
+ margin.top="2cm";
+ margin.bottom="2cm";
+ margin.left="1.5cm";
+ margin.right="1.5cm";
+ byte[] pdfBytes = page.pdf(new Page.PdfOptions()
+ .setFormat("A4")
+ .setPrintBackground(true)
+ .setMargin(margin)
+ .setDisplayHeaderFooter(true)
+ .setHeaderTemplate("公司名称
")
+ .setFooterTemplate(
+ "" +
+ "© 2026 MyCompany" +
+ "第 页 / 共 页" +
+ "
")
+ );
+
+ browser.close();
+ return pdfBytes;
+ }
+ }
+}
diff --git a/src/main/resources/bootstrap-dev.yml b/src/main/resources/bootstrap-dev.yml
index 5b86776..ebf3692 100644
--- a/src/main/resources/bootstrap-dev.yml
+++ b/src/main/resources/bootstrap-dev.yml
@@ -5,7 +5,7 @@ spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://182.151.8.209:3306/fkzy_operation?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2b8&allowMultiQueries=true
+ url: jdbc:mysql://182.151.8.209:33066/fkzy_operation?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2b8&allowMultiQueries=true
username: root
password: Zjtc!@#0804
druid:
@@ -20,7 +20,7 @@ spring:
#Redis
redis:
- host: 182.151.63.212
+ host: 182.151.8.209
port: 63799
password: zjtc321!
pool:
@@ -44,11 +44,11 @@ mybatis-plus:
call-setters-on-nulls: true
minio:
- host: http://182.151.8.209:9000
+ host: http://182.151.8.209:9000 # endpoint MinIO服务所在地址
url: ${minio.host}/${minio.bucket}/
access-key: zjtc
- secret-key: zjtc321!
- bucket: cert
+ secret-key: Zjtc!@#0804
+ bucket: fkzy
ali:
accessKeyId: http://182.151.8.209:8081/gas_apportal/publicApi/auth/logout
@@ -59,7 +59,7 @@ file:
#附件上传盘符,liunx服务器需要切换
fileUploadRootPath: D:/
fileUploadPath: /upload/
- preViewRealPath: http://182.151.8.209:9000/cert/.
+ preViewRealPath: http://182.151.8.209:9000/fkzy/