洪水预报-预报方案管理-PDF导出

master
yangzhe123 2025-08-27 16:43:41 +08:00
parent 154a9e51d1
commit a9466ce01b
4 changed files with 221 additions and 0 deletions

13
pom.xml
View File

@ -54,6 +54,19 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.5</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>7.2.5</version>
</dependency>
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId>

View File

@ -17,6 +17,8 @@ import com.gunshi.project.hsz.validate.markers.Update;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -27,13 +29,17 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/** /**
* : _ * : _
@ -43,6 +49,7 @@ import java.util.stream.Collectors;
@Tag(name = "预报_预测方案管理表") @Tag(name = "预报_预测方案管理表")
@RestController @RestController
@RequestMapping(value="/forecastProject") @RequestMapping(value="/forecastProject")
@Slf4j
public class ForecastProjectController { public class ForecastProjectController {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@ -175,4 +182,66 @@ public class ForecastProjectController {
} }
return R.ok(forecastProject); return R.ok(forecastProject);
} }
@Operation(summary = "pdf导出")
@GetMapping("export")
public void export(@RequestParam("ids") List<String> ids, HttpServletResponse response) {
try {
// 设置响应头
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\"forecast_reports.zip\"");
// 创建ZIP输出流
ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());
for (String projectId : ids) {
ForecastProject forecastProject = service.getById(projectId);
if (Objects.isNull(forecastProject)) {
throw new IllegalArgumentException("当前数据不存在");
}
List<ForecastResults> resultList = forecastResultsService.list(new QueryWrapper<ForecastResults>().eq("project_id", projectId).orderBy(true, true, "tm"));
if (CollectionUtils.isNotEmpty(resultList)) {
List<ForecastResultVo> vos = resultList.stream()
.map(result -> {
ForecastResultVo vo = new ForecastResultVo();
vo.setTm(sdf.format(result.getTm()));
vo.setYcRkQValue(result.getYcRkQValue());
vo.setRealRkQValue(result.getRealRkQValue());
vo.setYcCkQValue(result.getYcCkQValue());
vo.setRealCkQValue(result.getRealCkQValue());
vo.setYcSwHValue(result.getYcSwHValue());
vo.setRealSwHValue(result.getRealSwHValue());
BigDecimal ycSwHValue = result.getYcSwHValue() == null ? BigDecimal.ZERO : result.getYcSwHValue();
BigDecimal realSwHValue = result.getRealSwHValue() == null ? BigDecimal.ZERO : result.getRealSwHValue();
vo.setSwHDValue(ycSwHValue.subtract(realSwHValue));// 处理预测与实测水位差
vo.setDrp(result.getDrp());
vo.setIspreDrp(result.getIspreDrp());
vo.setR(result.getR());
vo.setFlLowLimLev(result.getFlLowLimLev());
vo.setCurrentYdgdyjz(result.getCurrentYdgdyjz());
vo.setPa(result.getPa());
return vo;
}).collect(Collectors.toList());
forecastProject.setVoList(vos);
forecastResultsService.handleVoList(forecastProject);
}
//进行pdf导出
// 为每个项目生成PDF
String fileName = "预报报告_" + forecastProject.getName() + "_" +
new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".pdf";
// 添加到ZIP
zipOut.putNextEntry(new ZipEntry(fileName));
service.generatePdf(forecastProject, zipOut);
zipOut.closeEntry();
}
zipOut.finish();
zipOut.close();
} catch (IOException e) {
log.error("PDF导出失败", e);
throw new RuntimeException("导出失败: " + e.getMessage());
}
}
} }

View File

@ -6,15 +6,42 @@ import com.gunshi.project.hsz.entity.vo.ForecastResultVo;
import com.gunshi.project.hsz.mapper.ForecastProjectMapper; 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.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired; 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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.zip.ZipOutputStream;
/** /**
* : _ * : _
@ -63,6 +90,118 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
} }
return forecastResultsService.saveBatch(retList); return forecastResultsService.saveBatch(retList);
} }
public void generatePdf(ForecastProject project, ZipOutputStream outputStream) {
// 使用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);
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); // 10列
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));
}
// 5. 关闭文档关键先关闭Document再关闭PdfDocument
document.close();
pdfDoc.close();
} catch (Exception e) {
log.error("生成PDF失败", e);
throw new RuntimeException("PDF生成失败");
}
try {
byte[] pdfBytes = baos.toByteArray();
outputStream.write(pdfBytes);
}catch (IOException e){
log.error("写入ZIP失败", e);
throw new RuntimeException("写入ZIP失败");
}
}
// 辅助方法:创建表格单元格
private Cell createCell(String text, PdfFont font, boolean isHeader) {
Cell cell = new Cell().add(new Paragraph(text).setFont(font).setFontSize(8));
if (isHeader) {
cell.setBackgroundColor(new DeviceRgb(220, 220, 220));
cell.setBold();
}
cell.setPadding(3);
return cell;
}
// 辅助方法:格式化日期
private String formatDate(Date date) {
if (date == null) return "无";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
// 辅助方法格式化BigDecimal
private String formatBigDecimal(BigDecimal value) {
if (value == null) return "-";
return value.setScale(2, RoundingMode.HALF_UP).toString();
}
} }

Binary file not shown.