新增pdf页码
parent
1739cfadef
commit
b8c07682b9
|
|
@ -7,6 +7,7 @@ import com.gunshi.project.hsz.mapper.ForecastProjectMapper;
|
||||||
import com.gunshi.project.hsz.model.ForecastProject;
|
import com.gunshi.project.hsz.model.ForecastProject;
|
||||||
import com.gunshi.project.hsz.model.ForecastResults;
|
import com.gunshi.project.hsz.model.ForecastResults;
|
||||||
import com.itextpdf.io.font.PdfEncodings;
|
import com.itextpdf.io.font.PdfEncodings;
|
||||||
|
import com.itextpdf.kernel.colors.Color;
|
||||||
import com.itextpdf.kernel.colors.DeviceRgb;
|
import com.itextpdf.kernel.colors.DeviceRgb;
|
||||||
import com.itextpdf.kernel.events.Event;
|
import com.itextpdf.kernel.events.Event;
|
||||||
import com.itextpdf.kernel.events.IEventHandler;
|
import com.itextpdf.kernel.events.IEventHandler;
|
||||||
|
|
@ -19,6 +20,7 @@ import com.itextpdf.kernel.pdf.PdfDocument;
|
||||||
import com.itextpdf.kernel.pdf.PdfPage;
|
import com.itextpdf.kernel.pdf.PdfPage;
|
||||||
import com.itextpdf.kernel.pdf.PdfWriter;
|
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||||
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
|
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
|
||||||
|
import com.itextpdf.kernel.pdf.colorspace.PdfColorSpace;
|
||||||
import com.itextpdf.layout.Canvas;
|
import com.itextpdf.layout.Canvas;
|
||||||
import com.itextpdf.layout.Document;
|
import com.itextpdf.layout.Document;
|
||||||
import com.itextpdf.layout.element.Cell;
|
import com.itextpdf.layout.element.Cell;
|
||||||
|
|
@ -32,6 +34,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
@ -92,93 +95,175 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generatePdf(ForecastProject project, ZipOutputStream outputStream) {
|
public void generatePdf(ForecastProject project, ZipOutputStream outputStream) {
|
||||||
|
// 第一次生成:获取总页码
|
||||||
|
int totalPages = calculateTotalPages(project);
|
||||||
|
|
||||||
// 使用ByteArrayOutputStream作为缓冲
|
// 第二次生成:正式生成带页码的PDF
|
||||||
|
generatePdfWithPageNumbers(project, outputStream, totalPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一次生成:计算总页码
|
||||||
|
private int calculateTotalPages(ForecastProject project) {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
PdfDocument pdfDoc = null;
|
|
||||||
Document document = null;
|
|
||||||
try{
|
|
||||||
PdfWriter writer = new PdfWriter(baos);
|
|
||||||
pdfDoc = new PdfDocument(writer);
|
|
||||||
document = new Document(pdfDoc,PageSize.A4.rotate());
|
|
||||||
// 设置字体
|
|
||||||
String fontPath = "/fonts/ChineseFonts.ttf";
|
|
||||||
PdfFont font = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H);
|
|
||||||
// 第一行:基本信息
|
|
||||||
Paragraph header1 = new Paragraph()
|
|
||||||
.add("预见期(小时): " + (project.getForecastPeriod() != null ? project.getForecastPeriod() : "无") + " ")
|
|
||||||
.add("预热期(天): " + (project.getForecastWarm() != null ? project.getForecastWarm() : "无") + " ")
|
|
||||||
.add("预报时间: " + formatDate(project.getForecastTm()) + " ")
|
|
||||||
.add("开始时间: " + formatDate(project.getStartTm()) + " ")
|
|
||||||
.add("结束时间: " + formatDate(project.getEndTm()))
|
|
||||||
.setFont(font)
|
|
||||||
.setFontSize(10);
|
|
||||||
|
|
||||||
document.add(header1);
|
try (PdfWriter writer = new PdfWriter(baos);
|
||||||
document.add(new Paragraph("\n"));
|
PdfDocument pdfDoc = new PdfDocument(writer);
|
||||||
|
Document document = new Document(pdfDoc, PageSize.A4.rotate())) {
|
||||||
|
|
||||||
// 第二行:统计信息
|
// 设置字体
|
||||||
Paragraph header2 = new Paragraph()
|
String fontPath = "/fonts/ChineseFonts.ttf";
|
||||||
.add("预报最高调洪水位(m): " + (project.getYcMaxSwH() != null ? project.getYcMaxSwH().setScale(2, RoundingMode.HALF_UP) : "无") + " ")
|
PdfFont font = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H);
|
||||||
.add("预报最大入库流量(m³/s): " + (project.getYcMaxRkQ() != null ? project.getYcMaxRkQ().setScale(2, RoundingMode.HALF_UP) : "无") + " ")
|
|
||||||
.add("预报最大下泄流量(m³/s): " + (project.getYcMaxCkQ() != null ? project.getYcMaxCkQ().setScale(2, RoundingMode.HALF_UP) : "无") + " ")
|
|
||||||
.add("预报洪水总量(万m³): " + (project.getYcSumFlood() != null ? project.getYcSumFlood().setScale(2, RoundingMode.HALF_UP) : "无"))
|
|
||||||
.setFont(font)
|
|
||||||
.setFontSize(10);
|
|
||||||
|
|
||||||
document.add(header2);
|
// 添加内容(但不添加页码)
|
||||||
document.add(new Paragraph("\n"));
|
addContentToDocument(document, font, project, false);
|
||||||
|
|
||||||
// 第三行:数据表格
|
// 返回总页数
|
||||||
if (CollectionUtils.isNotEmpty(project.getVoList())) {
|
return pdfDoc.getNumberOfPages();
|
||||||
Table table = new Table(9); // 10列
|
|
||||||
table.setWidth(UnitValue.createPercentValue(100));
|
|
||||||
|
|
||||||
// 表头
|
} catch (Exception e) {
|
||||||
table.addHeaderCell(createCell("序号", font, true));
|
log.error("计算PDF页数失败", e);
|
||||||
table.addHeaderCell(createCell("时间", font, true));
|
throw new RuntimeException("PDF页数计算失败");
|
||||||
table.addHeaderCell(createCell("降雨量(mm)", font, true));
|
}
|
||||||
table.addHeaderCell(createCell("实测水位(m)", font, true));
|
}
|
||||||
table.addHeaderCell(createCell("预报水位(m)", font, true));
|
|
||||||
table.addHeaderCell(createCell("入库流量(m³/s)", font, true));
|
// 第二次生成:正式生成带页码的PDF
|
||||||
table.addHeaderCell(createCell("预报入库流量(m³/s)", font, true));
|
private void generatePdfWithPageNumbers(ForecastProject project, ZipOutputStream outputStream, int totalPages) {
|
||||||
table.addHeaderCell(createCell("实际出库流量(m³/s)", font, true));
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
table.addHeaderCell(createCell("预报出库流量(m³/s)", font, true));
|
|
||||||
|
try (PdfWriter writer = new PdfWriter(baos);
|
||||||
|
PdfDocument pdfDoc = new PdfDocument(writer);
|
||||||
|
Document document = new Document(pdfDoc, PageSize.A4.rotate())) {
|
||||||
|
|
||||||
|
// 设置字体
|
||||||
|
String fontPath = "/fonts/ChineseFonts.ttf";
|
||||||
|
PdfFont font = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H);
|
||||||
|
|
||||||
|
// 添加页码处理器
|
||||||
|
PageNumberEventHandler eventHandler = new PageNumberEventHandler(font, totalPages);
|
||||||
|
pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, eventHandler);
|
||||||
|
|
||||||
|
// 添加内容
|
||||||
|
addContentToDocument(document, font, project, true);
|
||||||
|
|
||||||
// 表格数据
|
|
||||||
int index = 1;
|
|
||||||
for (ForecastResultVo vo : project.getVoList()) {
|
|
||||||
table.addCell(createCell(String.valueOf(index++), font, false));
|
|
||||||
table.addCell(createCell(vo.getTm(), font, false));
|
|
||||||
table.addCell(createCell(formatBigDecimal(vo.getDrp()), font, false));
|
|
||||||
table.addCell(createCell(formatBigDecimal(vo.getRealSwHValue()), font, false));
|
|
||||||
table.addCell(createCell(formatBigDecimal(vo.getYcSwHValue()), font, false));
|
|
||||||
table.addCell(createCell(formatBigDecimal(vo.getRealRkQValue()), font, false));
|
|
||||||
table.addCell(createCell(formatBigDecimal(vo.getYcRkQValue()), font, false));
|
|
||||||
table.addCell(createCell(formatBigDecimal(vo.getRealCkQValue()), font, false));
|
|
||||||
table.addCell(createCell(formatBigDecimal(vo.getYcCkQValue()), font, false));
|
|
||||||
}
|
|
||||||
document.add(table);
|
|
||||||
} else {
|
|
||||||
document.add(new Paragraph("无预报结果数据").setFont(font));
|
|
||||||
}
|
|
||||||
// 5. 关闭文档(关键:先关闭Document,再关闭PdfDocument)
|
|
||||||
document.close();
|
|
||||||
pdfDoc.close();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("生成PDF失败", e);
|
log.error("生成PDF失败", e);
|
||||||
throw new RuntimeException("PDF生成失败");
|
throw new RuntimeException("PDF生成失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在try-with-resources块外获取字节数组并写入输出流
|
||||||
try {
|
try {
|
||||||
byte[] pdfBytes = baos.toByteArray();
|
byte[] pdfBytes = baos.toByteArray();
|
||||||
outputStream.write(pdfBytes);
|
outputStream.write(pdfBytes);
|
||||||
}catch (IOException e){
|
} catch (IOException e) {
|
||||||
log.error("写入ZIP失败", e);
|
log.error("写入ZIP失败", e);
|
||||||
throw new RuntimeException("写入ZIP失败");
|
throw new RuntimeException("写入ZIP失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 页码事件处理器 - 简化版本
|
||||||
|
private static class PageNumberEventHandler implements IEventHandler {
|
||||||
|
private final PdfFont font;
|
||||||
|
private final int totalPages;
|
||||||
|
|
||||||
|
public PageNumberEventHandler(PdfFont font, int totalPages) {
|
||||||
|
this.font = font;
|
||||||
|
this.totalPages = totalPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleEvent(Event event) {
|
||||||
|
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
|
||||||
|
PdfDocument pdfDoc = docEvent.getDocument();
|
||||||
|
PdfPage page = docEvent.getPage();
|
||||||
|
int currentPage = pdfDoc.getPageNumber(page);
|
||||||
|
|
||||||
|
// 获取页面尺寸
|
||||||
|
Rectangle pageSize = page.getPageSize();
|
||||||
|
|
||||||
|
// 创建画布
|
||||||
|
PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), pdfDoc);
|
||||||
|
|
||||||
|
// 设置页码文本
|
||||||
|
String pageText = "第 " + currentPage + " 页 / 共 " + totalPages + " 页";
|
||||||
|
|
||||||
|
// 直接使用PdfCanvas绘制文本(更简单的方式)
|
||||||
|
pdfCanvas.beginText()
|
||||||
|
.setFontAndSize(font, 10)
|
||||||
|
.moveText((pageSize.getLeft() + pageSize.getRight()) / 2 - 50, pageSize.getBottom() + 20)
|
||||||
|
.showText(pageText)
|
||||||
|
.endText();
|
||||||
|
|
||||||
|
pdfCanvas.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加内容到文档的公共方法
|
||||||
|
private void addContentToDocument(Document document, PdfFont font, ForecastProject project, boolean addPageMargins) throws IOException {
|
||||||
|
if (addPageMargins) {
|
||||||
|
// 为页码预留底部边距
|
||||||
|
document.setMargins(36, 36, 36, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一行:基本信息
|
||||||
|
Paragraph header1 = new Paragraph()
|
||||||
|
.add("预见期(小时): " + (project.getForecastPeriod() != null ? project.getForecastPeriod() : "无") + " ")
|
||||||
|
.add("预热期(天): " + (project.getForecastWarm() != null ? project.getForecastWarm() : "无") + " ")
|
||||||
|
.add("预报时间: " + formatDate(project.getForecastTm()) + " ")
|
||||||
|
.add("开始时间: " + formatDate(project.getStartTm()) + " ")
|
||||||
|
.add("结束时间: " + formatDate(project.getEndTm()))
|
||||||
|
.setFont(font)
|
||||||
|
.setFontSize(10);
|
||||||
|
|
||||||
|
document.add(header1);
|
||||||
|
document.add(new Paragraph("\n"));
|
||||||
|
|
||||||
|
// 第二行:统计信息
|
||||||
|
Paragraph header2 = new Paragraph()
|
||||||
|
.add("预报最高调洪水位(m): " + (project.getYcMaxSwH() != null ? project.getYcMaxSwH().setScale(2, RoundingMode.HALF_UP) : "无") + " ")
|
||||||
|
.add("预报最大入库流量(m³/s): " + (project.getYcMaxRkQ() != null ? project.getYcMaxRkQ().setScale(2, RoundingMode.HALF_UP) : "无") + " ")
|
||||||
|
.add("预报最大下泄流量(m³/s): " + (project.getYcMaxCkQ() != null ? project.getYcMaxCkQ().setScale(2, RoundingMode.HALF_UP) : "无") + " ")
|
||||||
|
.add("预报洪水总量(万m³): " + (project.getYcSumFlood() != null ? project.getYcSumFlood().setScale(2, RoundingMode.HALF_UP) : "无"))
|
||||||
|
.setFont(font)
|
||||||
|
.setFontSize(10);
|
||||||
|
|
||||||
|
document.add(header2);
|
||||||
|
document.add(new Paragraph("\n"));
|
||||||
|
|
||||||
|
// 第三行:数据表格
|
||||||
|
if (CollectionUtils.isNotEmpty(project.getVoList())) {
|
||||||
|
Table table = new Table(9);
|
||||||
|
table.setWidth(UnitValue.createPercentValue(100));
|
||||||
|
|
||||||
|
// 表头
|
||||||
|
table.addHeaderCell(createCell("序号", font, true));
|
||||||
|
table.addHeaderCell(createCell("时间", font, true));
|
||||||
|
table.addHeaderCell(createCell("降雨量(mm)", font, true));
|
||||||
|
table.addHeaderCell(createCell("实测水位(m)", font, true));
|
||||||
|
table.addHeaderCell(createCell("预报水位(m)", font, true));
|
||||||
|
table.addHeaderCell(createCell("入库流量(m³/s)", font, true));
|
||||||
|
table.addHeaderCell(createCell("预报入库流量(m³/s)", font, true));
|
||||||
|
table.addHeaderCell(createCell("实际出库流量(m³/s)", font, true));
|
||||||
|
table.addHeaderCell(createCell("预报出库流量(m³/s)", font, true));
|
||||||
|
|
||||||
|
// 表格数据
|
||||||
|
int index = 1;
|
||||||
|
for (ForecastResultVo vo : project.getVoList()) {
|
||||||
|
table.addCell(createCell(String.valueOf(index++), font, false));
|
||||||
|
table.addCell(createCell(vo.getTm(), font, false));
|
||||||
|
table.addCell(createCell(formatBigDecimal(vo.getDrp()), font, false));
|
||||||
|
table.addCell(createCell(formatBigDecimal(vo.getRealSwHValue()), font, false));
|
||||||
|
table.addCell(createCell(formatBigDecimal(vo.getYcSwHValue()), font, false));
|
||||||
|
table.addCell(createCell(formatBigDecimal(vo.getRealRkQValue()), font, false));
|
||||||
|
table.addCell(createCell(formatBigDecimal(vo.getYcRkQValue()), font, false));
|
||||||
|
table.addCell(createCell(formatBigDecimal(vo.getRealCkQValue()), font, false));
|
||||||
|
table.addCell(createCell(formatBigDecimal(vo.getYcCkQValue()), font, false));
|
||||||
|
}
|
||||||
|
document.add(table);
|
||||||
|
} else {
|
||||||
|
document.add(new Paragraph("无预报结果数据").setFont(font));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 辅助方法:创建表格单元格
|
// 辅助方法:创建表格单元格
|
||||||
private Cell createCell(String text, PdfFont font, boolean isHeader) {
|
private Cell createCell(String text, PdfFont font, boolean isHeader) {
|
||||||
Cell cell = new Cell().add(new Paragraph(text).setFont(font).setFontSize(8));
|
Cell cell = new Cell().add(new Paragraph(text).setFont(font).setFontSize(8));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue