Browse Source

fix:【生成报告】修改

master
zhangjing 3 hours ago
parent
commit
3aa0631d8a
4 changed files with 140 additions and 6 deletions
  1. +7
    -0
      pom.xml
  2. +38
    -0
      src/main/java/com/fkzy/warn/controller/PdfController.java
  3. +89
    -0
      src/main/java/com/fkzy/warn/service/PdfService.java
  4. +6
    -6
      src/main/resources/bootstrap-dev.yml

+ 7
- 0
pom.xml View File

@ -171,6 +171,13 @@
<systemPath>${project.basedir}/lib/minio-7.0.2-all.jar</systemPath> <systemPath>${project.basedir}/lib/minio-7.0.2-all.jar</systemPath>
</dependency> </dependency>
<!--html生成pdf -->
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.49.0</version> <!-- 检查最新版:https://github.com/microsoft/playwright-java -->
</dependency>
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-all</artifactId> <artifactId>netty-all</artifactId>

+ 38
- 0
src/main/java/com/fkzy/warn/controller/PdfController.java View File

@ -0,0 +1,38 @@
package com.fkzy.warn.controller;
import com.fkzy.warn.model.Report;
import com.fkzy.warn.service.PdfService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
* @author zhangjing
* @date 2026/01/13 10:40
* @description
*/
@Api(tags = "生成报告相关")
@RestController
@RequestMapping("generateReport/")
@Slf4j
public class PdfController {
@Autowired
private PdfService pdfService;
@PostMapping("download")
public ResponseEntity<byte[]> 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);
}
}

+ 89
- 0
src/main/java/com/fkzy/warn/service/PdfService.java View File

@ -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("<div style='font-size:10px; text-align:center; width:100%;'>公司名称</div>")
.setFooterTemplate(
"<div style='font-size:9px; width:100%;'>" +
"<span style='float:left;'>© 2026 MyCompany</span>" +
"<span style='float:right;'>第 <span class='pageNumber'></span> 页 / 共 <span class='totalPages'></span> 页</span>" +
"</div>")
);
browser.close();
return pdfBytes;
}
}
}

+ 6
- 6
src/main/resources/bootstrap-dev.yml View File

@ -5,7 +5,7 @@ spring:
datasource: datasource:
type: com.alibaba.druid.pool.DruidDataSource type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver 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 username: root
password: Zjtc!@#0804 password: Zjtc!@#0804
druid: druid:
@ -20,7 +20,7 @@ spring:
#Redis #Redis
redis: redis:
host: 182.151.63.212
host: 182.151.8.209
port: 63799 port: 63799
password: zjtc321! password: zjtc321!
pool: pool:
@ -44,11 +44,11 @@ mybatis-plus:
call-setters-on-nulls: true call-setters-on-nulls: true
minio: minio:
host: http://182.151.8.209:9000
host: http://182.151.8.209:9000 # endpoint MinIO服务所在地址
url: ${minio.host}/${minio.bucket}/ url: ${minio.host}/${minio.bucket}/
access-key: zjtc access-key: zjtc
secret-key: zjtc321!
bucket: cert
secret-key: Zjtc!@#0804
bucket: fkzy
ali: ali:
accessKeyId: http://182.151.8.209:8081/gas_apportal/publicApi/auth/logout accessKeyId: http://182.151.8.209:8081/gas_apportal/publicApi/auth/logout
@ -59,7 +59,7 @@ file:
#附件上传盘符,liunx服务器需要切换 #附件上传盘符,liunx服务器需要切换
fileUploadRootPath: D:/ fileUploadRootPath: D:/
fileUploadPath: /upload/ fileUploadPath: /upload/
preViewRealPath: http://182.151.8.209:9000/cert/.
preViewRealPath: http://182.151.8.209:9000/fkzy/

Loading…
Cancel
Save