修改excel导出逻辑

master
yangzhe123 2025-12-08 17:07:55 +08:00
parent 564d028889
commit 7e4bdbce28
3 changed files with 149 additions and 44 deletions

View File

@ -48,12 +48,19 @@ public class ForecastDispatchPlanController {
return R.ok(forecastDispatchPlanService.deleteById(id)); return R.ok(forecastDispatchPlanService.deleteById(id));
} }
// @Operation(summary = "导出")
// @PostMapping("/export")
// public void export(@RequestBody @Validated ForecastDispatchPlanPageSo page, HttpServletResponse response) {
// page.getPageSo().setPageSize(90000);
// Page<ForecastDispatchPlan> forecastDispatchPlanPage = forecastDispatchPlanService.pageDetail(page);
// List<ForecastDispatchPlan> records = forecastDispatchPlanPage.getRecords();
// forecastDispatchPlanService.export(records,response);
// }
@Operation(summary = "导出") @Operation(summary = "导出")
@PostMapping("/export") @PostMapping("/export")
public void export(@RequestBody @Validated ForecastDispatchPlanPageSo page, HttpServletResponse response) { public void export(@RequestParam("ids") List<String> ids, HttpServletResponse response) {
page.getPageSo().setPageSize(90000); List<ForecastDispatchPlan> records = forecastDispatchPlanService.selectByIds(ids);
Page<ForecastDispatchPlan> forecastDispatchPlanPage = forecastDispatchPlanService.pageDetail(page);
List<ForecastDispatchPlan> records = forecastDispatchPlanPage.getRecords();
forecastDispatchPlanService.export(records,response); forecastDispatchPlanService.export(records,response);
} }
} }

View File

@ -49,6 +49,15 @@ public class ForecastDispatchPlan implements Serializable {
@NotNull(message = "方案名称不能为空") @NotNull(message = "方案名称不能为空")
private String planName; private String planName;
/**
*
*/
@TableField(value = "forecast_plan_name")
@Schema(description = "方案名称")
@Size(max = 255, message = "方案名称最大长度要小于 255")
@NotNull(message = "方案名称不能为空")
private String forecastPlanName;
/** /**
* *
*/ */

View File

@ -13,16 +13,21 @@ import com.ruoyi.common.utils.StringUtils;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
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.Serializable; import java.io.*;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/** /**
* : * :
@ -58,6 +63,19 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
return forecastDispatchPlanPage; return forecastDispatchPlanPage;
} }
public List<ForecastDispatchPlan> selectByIds(List<String> ids) {
LambdaQueryWrapper<ForecastDispatchPlan> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(ForecastDispatchPlan::getId, ids);
List<ForecastDispatchPlan> forecastDispatchPlans = this.baseMapper.selectList(queryWrapper);
for (ForecastDispatchPlan record : forecastDispatchPlans) {
List<ForecastDispatchCommand> forecastDispatchCommandList = forecastDispatchCommandService.lambdaQuery().eq(ForecastDispatchCommand::getPlanId, record.getId()).list();
record.setForecastDispatchCommands(forecastDispatchCommandList);
ForecastDispatchResult forecastDispatchResult = forecastDispatchResultService.lambdaQuery().eq(ForecastDispatchResult::getPlanId, record.getId()).one();
record.setForecastDispatchResult(forecastDispatchResult);
}
return forecastDispatchPlans;
}
public Boolean deleteById(Serializable id) { public Boolean deleteById(Serializable id) {
boolean flag = removeById(id); boolean flag = removeById(id);
if(flag){ if(flag){
@ -83,60 +101,114 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
forecastDispatchCommandService.saveBatch(forecastDispatchCommands); forecastDispatchCommandService.saveBatch(forecastDispatchCommands);
return true; return true;
} }
public void export(List<ForecastDispatchPlan> page, HttpServletResponse response) { public void export(List<ForecastDispatchPlan> page, HttpServletResponse response) {
// 创建临时目录
String tempDir = System.getProperty("java.io.tmpdir") + File.separator + "export_" + UUID.randomUUID();
File dir = new File(tempDir);
if (!dir.exists()) {
dir.mkdirs();
}
List<File> excelFiles = new ArrayList<>();
try { try {
// 为每个方案创建Excel文件
for (int i = 0; i < page.size(); i++) {
ForecastDispatchPlan plan = page.get(i);
File excelFile = createExcelForPlan(plan, tempDir, i + 1);
excelFiles.add(excelFile);
}
// 创建ZIP压缩包
String zipFileName = "调度方案数据导出_" +
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".zip";
// 设置响应头 // 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setContentType("application/zip");
response.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("调度方案数据导出", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition",
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); "attachment;filename*=utf-8''" + URLEncoder.encode(zipFileName, "UTF-8").replaceAll("\\+", "%20"));
// 创建Excel工作簿 // 创建ZIP输出流
Workbook workbook = new XSSFWorkbook(); ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
// 创建单元格样式 // 将Excel文件添加到ZIP
CellStyle headerStyle = createHeaderStyle(workbook); for (File excelFile : excelFiles) {
CellStyle dataStyle = createDataStyle(workbook); ZipEntry zipEntry = new ZipEntry(excelFile.getName());
CellStyle titleStyle = createTitleStyle(workbook); zos.putNextEntry(zipEntry);
// 在同一个Sheet页中按方案分组导出数据 try (FileInputStream fis = new FileInputStream(excelFile)) {
exportGroupedData(workbook, page, headerStyle, dataStyle, titleStyle); byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
}
zos.closeEntry();
}
zos.close();
// 写入响应流
workbook.write(response.getOutputStream());
workbook.close();
} catch (Exception e) { } catch (Exception e) {
log.error("导出Excel失败", e); log.error("导出Excel失败", e);
throw new RuntimeException("导出失败"); throw new RuntimeException("导出失败");
} finally {
// 清理临时文件
for (File file : excelFiles) {
if (file.exists()) {
file.delete();
}
}
if (dir.exists()) {
dir.delete();
}
} }
} }
/** /**
* * Excel
*/ */
private void exportGroupedData(Workbook workbook, List<ForecastDispatchPlan> dataList, CellStyle headerStyle, CellStyle dataStyle, CellStyle titleStyle) { private File createExcelForPlan(ForecastDispatchPlan plan, String tempDir, int index) throws IOException {
Sheet sheet = workbook.createSheet("调度方案数据"); // 创建Excel工作簿
Workbook workbook = new XSSFWorkbook();
// 创建单元格样式
CellStyle headerStyle = createHeaderStyle(workbook);
CellStyle dataStyle = createDataStyle(workbook);
CellStyle titleStyle = createTitleStyle(workbook);
// 创建Sheet
String sheetName = "调度方案";
Sheet sheet = workbook.createSheet(sheetName);
int currentRow = 0; int currentRow = 0;
for (ForecastDispatchPlan plan : dataList) { // 1. 导出调度方案基本信息
// 1. 导出调度方案基本信息 currentRow = exportPlanBasicInfo(sheet, currentRow, plan, titleStyle, dataStyle);
currentRow = exportPlanBasicInfo(sheet, currentRow, plan, titleStyle, dataStyle);
// 2. 导出调度结果 // 2. 导出调度结果
currentRow = exportPlanResult(sheet, currentRow, plan, headerStyle, dataStyle); currentRow = exportPlanResult(sheet, currentRow, plan, headerStyle, dataStyle);
// 3. 导出调度指令 // 3. 导出调度指令
currentRow = exportPlanCommands(sheet, currentRow, plan, headerStyle, dataStyle); currentRow = exportPlanCommands(sheet, currentRow, plan, headerStyle, dataStyle);
// 添加空行分隔不同方案 // 生成文件名
currentRow += 2; String fileName = plan.getPlanName();
File excelFile = new File(tempDir, fileName + ".xlsx");
// 写入文件
try (FileOutputStream fos = new FileOutputStream(excelFile)) {
workbook.write(fos);
} }
workbook.close();
return excelFile;
} }
/** /**
* *
*/ */
private int exportPlanBasicInfo(Sheet sheet, int startRow, ForecastDispatchPlan plan, CellStyle titleStyle, CellStyle dataStyle) { private int exportPlanBasicInfo(Sheet sheet, int startRow, ForecastDispatchPlan plan, CellStyle titleStyle, CellStyle dataStyle) {
// 方案标题 // 方案标题
@ -145,6 +217,9 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
titleCell.setCellValue("调度方案:" + getStringValue(plan.getPlanName())); titleCell.setCellValue("调度方案:" + getStringValue(plan.getPlanName()));
titleCell.setCellStyle(titleStyle); titleCell.setCellStyle(titleStyle);
// 合并单元格标题跨5列
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, 4));
// 基本信息表头 // 基本信息表头
Row headerRow = sheet.createRow(startRow++); Row headerRow = sheet.createRow(startRow++);
String[] headers = {"开始时间", "结束时间", "制定时间", "制定人", "水库控制水位(m)"}; String[] headers = {"开始时间", "结束时间", "制定时间", "制定人", "水库控制水位(m)"};
@ -167,14 +242,16 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
// 设置数据行样式 // 设置数据行样式
for (int i = 0; i < headers.length; i++) { for (int i = 0; i < headers.length; i++) {
dataRow.getCell(i).setCellStyle(dataStyle); if (dataRow.getCell(i) != null) {
dataRow.getCell(i).setCellStyle(dataStyle);
}
} }
return startRow; return startRow;
} }
/** /**
* *
*/ */
private int exportPlanResult(Sheet sheet, int startRow, ForecastDispatchPlan plan, CellStyle headerStyle, CellStyle dataStyle) { private int exportPlanResult(Sheet sheet, int startRow, ForecastDispatchPlan plan, CellStyle headerStyle, CellStyle dataStyle) {
ForecastDispatchResult result = plan.getForecastDispatchResult(); ForecastDispatchResult result = plan.getForecastDispatchResult();
@ -188,6 +265,9 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
resultTitleCell.setCellValue("调度结果"); resultTitleCell.setCellValue("调度结果");
resultTitleCell.setCellStyle(headerStyle); resultTitleCell.setCellStyle(headerStyle);
// 合并单元格结果标题跨7列
sheet.addMergedRegion(new CellRangeAddress(resultTitleRow.getRowNum(), resultTitleRow.getRowNum(), 0, 6));
// 结果表头 // 结果表头
Row resultHeaderRow = sheet.createRow(startRow++); Row resultHeaderRow = sheet.createRow(startRow++);
String[] resultHeaders = { String[] resultHeaders = {
@ -219,14 +299,16 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
// 设置数据行样式 // 设置数据行样式
for (int i = 0; i < resultHeaders.length; i++) { for (int i = 0; i < resultHeaders.length; i++) {
resultDataRow.getCell(i).setCellStyle(dataStyle); if (resultDataRow.getCell(i) != null) {
resultDataRow.getCell(i).setCellStyle(dataStyle);
}
} }
return startRow; return startRow;
} }
/** /**
* *
*/ */
private int exportPlanCommands(Sheet sheet, int startRow, ForecastDispatchPlan plan, CellStyle headerStyle, CellStyle dataStyle) { private int exportPlanCommands(Sheet sheet, int startRow, ForecastDispatchPlan plan, CellStyle headerStyle, CellStyle dataStyle) {
List<ForecastDispatchCommand> commands = plan.getForecastDispatchCommands(); List<ForecastDispatchCommand> commands = plan.getForecastDispatchCommands();
@ -240,6 +322,9 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
commandTitleCell.setCellValue("调度指令"); commandTitleCell.setCellValue("调度指令");
commandTitleCell.setCellStyle(headerStyle); commandTitleCell.setCellStyle(headerStyle);
// 合并单元格指令标题跨5列
sheet.addMergedRegion(new CellRangeAddress(commandTitleRow.getRowNum(), commandTitleRow.getRowNum(), 0, 4));
// 指令表头 // 指令表头
Row commandHeaderRow = sheet.createRow(startRow++); Row commandHeaderRow = sheet.createRow(startRow++);
String[] commandHeaders = { String[] commandHeaders = {
@ -264,7 +349,9 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
// 设置数据行样式 // 设置数据行样式
for (int i = 0; i < commandHeaders.length; i++) { for (int i = 0; i < commandHeaders.length; i++) {
commandDataRow.getCell(i).setCellStyle(dataStyle); if (commandDataRow.getCell(i) != null) {
commandDataRow.getCell(i).setCellStyle(dataStyle);
}
} }
} }
@ -272,7 +359,7 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
} }
/** /**
* *
*/ */
private CellStyle createTitleStyle(Workbook workbook) { private CellStyle createTitleStyle(Workbook workbook) {
CellStyle style = workbook.createCellStyle(); CellStyle style = workbook.createCellStyle();
@ -284,7 +371,7 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
} }
/** /**
* *
*/ */
private CellStyle createHeaderStyle(Workbook workbook) { private CellStyle createHeaderStyle(Workbook workbook) {
CellStyle style = workbook.createCellStyle(); CellStyle style = workbook.createCellStyle();
@ -304,7 +391,7 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
} }
/** /**
* *
*/ */
private CellStyle createDataStyle(Workbook workbook) { private CellStyle createDataStyle(Workbook workbook) {
CellStyle style = workbook.createCellStyle(); CellStyle style = workbook.createCellStyle();
@ -318,7 +405,7 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
} }
/** /**
* *
*/ */
private String formatDateTime(LocalDateTime dateTime) { private String formatDateTime(LocalDateTime dateTime) {
if (dateTime == null) { if (dateTime == null) {
@ -329,14 +416,14 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
} }
/** /**
* *
*/ */
private String getStringValue(String value) { private String getStringValue(String value) {
return value == null ? "" : value; return value == null ? "" : value;
} }
/** /**
* *
*/ */
private String getGateStatus(Integer status) { private String getGateStatus(Integer status) {
if (status == null) { if (status == null) {
@ -344,4 +431,6 @@ public class ForecastDispatchPlanService extends ServiceImpl<ForecastDispatchPla
} }
return status == 1 ? "开" : "关"; return status == 1 ? "开" : "关";
} }
} }