package com.estate.expert.admin.controller.admin;
|
|
import com.estate.expert.admin.domain.business.device.DeviceType;
|
import com.estate.expert.admin.domain.common.request.PlanPageRequest;
|
import com.estate.expert.admin.domain.common.request.ProjectPageRequest;
|
import com.estate.expert.admin.domain.common.request.RecordPageRequest;
|
import com.estate.expert.admin.domain.standard.hierachy.HierarchyIds;
|
import com.estate.expert.admin.domain.standard.problem.Problem;
|
import com.estate.expert.admin.domain.user.User;
|
import com.estate.expert.admin.enums.BizResultCode;
|
import com.estate.expert.admin.io.processor.DataProcessorBase;
|
import com.estate.expert.admin.io.processor.RowDataProcessorBase;
|
import com.estate.expert.admin.io.processor.impl.business.DeviceProcessor;
|
import com.estate.expert.admin.io.processor.impl.business.PlanProcessor;
|
import com.estate.expert.admin.io.processor.impl.business.ProjectProcessor;
|
import com.estate.expert.admin.io.processor.impl.matrix.CompareMatrixProcessor;
|
import com.estate.expert.admin.io.processor.impl.matrix.MembershipMatrixProcessor;
|
import com.estate.expert.admin.io.processor.impl.record.DeviceErrorRecordProcessor;
|
import com.estate.expert.admin.io.processor.impl.record.SystemErrorRecordProcessor;
|
import com.estate.expert.admin.io.processor.impl.record.WarningRecordProcessor;
|
import com.estate.expert.admin.io.processor.impl.standard.ProblemProcessor;
|
import com.estate.expert.admin.service.*;
|
import com.estate.expert.admin.service.expert.DeviceExpertService;
|
import com.estate.expert.admin.service.expert.SysExpertService;
|
import com.estate.expert.common.domain.Session;
|
import com.estate.expert.common.rpc.Result;
|
import io.swagger.annotations.Api;
|
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiParam;
|
import lombok.SneakyThrows;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.core.io.InputStreamResource;
|
import org.springframework.http.MediaType;
|
import org.springframework.http.ResponseEntity;
|
import org.springframework.stereotype.Controller;
|
import org.springframework.validation.annotation.Validated;
|
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import javax.annotation.Resource;
|
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayOutputStream;
|
import java.net.URLEncoder;
|
import java.nio.charset.StandardCharsets;
|
import java.util.List;
|
|
@Slf4j
|
@CrossOrigin
|
@Api(tags = "管理后台/导入导出")
|
@RequestMapping("/admin/io")
|
@Controller
|
@Validated
|
public class ExportController {
|
|
@Resource
|
private ErrorRecordService errorRecordService;
|
|
@Resource
|
private WarningRecordService warningRecordService;
|
|
@Resource
|
private ProjectService projectService;
|
|
@Resource
|
private DeviceService deviceService;
|
|
@Resource
|
private PlanService planService;
|
|
@Resource
|
private CheckTaskService checkTaskService;
|
|
@Resource
|
private ClientService clientService;
|
|
@Resource
|
private SysExpertService sysExpertService;
|
|
@Resource
|
private DeviceExpertService deviceExpertService;
|
|
@Resource
|
private HierarchyService hierarchyService;
|
|
@Resource
|
private ProblemService problemService;
|
|
@ApiOperation("综合问题导出")
|
@PostMapping("/systemError/export")
|
public ResponseEntity<InputStreamResource> exportSystemErrorRecords(@Validated @RequestBody RecordPageRequest request){
|
var result = errorRecordService.listSystemErrors(request.getClientId(), request.getPlanId(), request.getTaskId(),
|
request.getStartDate(), request.getEndDate());
|
return downloadRowData(new SystemErrorRecordProcessor(), result);
|
}
|
|
@ApiOperation("设备问题导出")
|
@PostMapping("/deviceError/export")
|
public ResponseEntity<InputStreamResource> exportDeviceErrorRecords(@Validated @RequestBody RecordPageRequest request){
|
var result = errorRecordService.listDeviceErrors(request.getClientId(), request.getPlanId(), request.getTaskId(),
|
request.getStartDate(), request.getEndDate());
|
return downloadRowData(new DeviceErrorRecordProcessor(), result);
|
}
|
|
@ApiOperation("正确做法导出")
|
@PostMapping("/warning/export")
|
public ResponseEntity<InputStreamResource> exportWarningRecords(@Validated @RequestBody RecordPageRequest request){
|
var result = warningRecordService.list(request.getClientId(), request.getPlanId(), request.getTaskId(),
|
request.getStartDate(), request.getEndDate());
|
return downloadRowData(new WarningRecordProcessor(), result);
|
}
|
|
@ApiOperation("项目导出")
|
@PostMapping("/project/export")
|
public ResponseEntity<InputStreamResource> exportProjects(@Validated @RequestBody ProjectPageRequest request){
|
var result = projectService.list(request.getKeyword(), request.getProjectTypes(), request.getClientIds());
|
return downloadRowData(new ProjectProcessor(clientService, projectService), result, "项目导出");
|
}
|
|
@ApiOperation("项目导入模版")
|
@PostMapping("/project/template")
|
public ResponseEntity<InputStreamResource> downloadProjectTemplate(){
|
return downloadRowData(new ProjectProcessor(clientService, projectService), List.of());
|
}
|
|
@ApiOperation("项目导入")
|
@PostMapping("/project/import")
|
@ResponseBody
|
public Result importProjectRecords(
|
Session session,
|
@RequestParam("file") MultipartFile file) {
|
return importData(
|
"项目",
|
session,
|
file,
|
() -> new ProjectProcessor(clientService, projectService).loadFromWorkbook(file.getInputStream()),
|
records -> projectService.importEntities((User) session.getUser(), records)
|
);
|
}
|
|
@ApiOperation("设备导出")
|
@PostMapping("/device/export")
|
public ResponseEntity<InputStreamResource> exportDeviceRecords(@RequestParam(value = "keyword", required = false) String keyword,
|
@RequestParam(value = "deviceType", required = false) DeviceType deviceType){
|
var result = deviceService.list(keyword, deviceType);
|
return downloadRowData(new DeviceProcessor(), result, "设备导出");
|
}
|
|
@ApiOperation("设备导入模版")
|
@GetMapping("/device/template")
|
public ResponseEntity<InputStreamResource> downloadDeviceTemplate(){
|
return downloadRowData(new DeviceProcessor(), List.of());
|
}
|
|
@ApiOperation("设备导入")
|
@PostMapping("/device/import")
|
@ResponseBody
|
public Result importDeviceRecords(
|
Session session,
|
@RequestParam("file") MultipartFile file) {
|
return importData(
|
"设备",
|
session,
|
file,
|
() -> new DeviceProcessor().loadFromWorkbook(file.getInputStream()),
|
records -> deviceService.importEntities((User) session.getUser(), records)
|
);
|
}
|
|
////// 模糊数学专家 - 隶属度矩阵导入导出 //////
|
|
@ApiOperation("综合体系-模糊数学-隶属度矩阵导出")
|
@PostMapping("/system/fuzzy/membershipMatrix/export")
|
public ResponseEntity<InputStreamResource> exportSystemFuzzyMembershipMatrix(
|
@ApiParam("专家ID") @RequestParam(value = "expertId", required = false) Integer expertId) {
|
if(expertId == null) {
|
expertId = sysExpertService.getDefaultExpert().getId();
|
}
|
var matrix = sysExpertService.getMembershipMatrix(expertId);
|
BizResultCode.MEMBERSHIP_MATRIX_LOAD_ERROR.check(matrix == null);
|
|
var expert = sysExpertService.get(expertId);
|
String filename = expert != null ? "综合体系-" + expert.getName() + "-隶属度矩阵" : "综合体系-隶属度矩阵";
|
|
return downloadData(new MembershipMatrixProcessor(), matrix, filename);
|
}
|
|
@ApiOperation("综合体系-模糊数学-隶属度矩阵导入模版")
|
@PostMapping("/system/fuzzy/membershipMatrix/template")
|
public ResponseEntity<InputStreamResource> downloadSystemFuzzyMembershipMatrixTemplate() {
|
return exportSystemFuzzyMembershipMatrix(null);
|
}
|
|
@ApiOperation("综合体系-模糊数学-隶属度矩阵导入")
|
@PostMapping("/system/fuzzy/membershipMatrix/import")
|
@ResponseBody
|
public Result importSystemFuzzyMembershipMatrix(
|
@ApiParam("专家ID") @RequestParam("expertId") Integer expertId,
|
@RequestParam("file") MultipartFile file) {
|
try {
|
sysExpertService.importMembershipMatrix(expertId, file.getInputStream());
|
return Result.success("隶属度矩阵导入成功");
|
} catch (Exception e) {
|
log.error("综合体系隶属度矩阵导入失败", e);
|
return Result.error("导入失败: " + e.getMessage());
|
}
|
}
|
|
@ApiOperation("设备体系-模糊数学-隶属度矩阵导出")
|
@PostMapping("/device/fuzzy/membershipMatrix/export")
|
public ResponseEntity<InputStreamResource> exportDeviceFuzzyMembershipMatrix(
|
@ApiParam("专家ID") @RequestParam(value = "expertId", required = false) Integer expertId) {
|
if(expertId == null) {
|
expertId = deviceExpertService.getDefaultExpert().getId();
|
}
|
var matrix = deviceExpertService.getMembershipMatrix(expertId);
|
BizResultCode.MEMBERSHIP_MATRIX_LOAD_ERROR.check(matrix == null);
|
|
var expert = deviceExpertService.get(expertId);
|
String filename = expert != null ? "设备体系-" + expert.getName() + "-隶属度矩阵" : "设备体系-隶属度矩阵";
|
|
return downloadData(new MembershipMatrixProcessor(), matrix, filename);
|
}
|
|
@ApiOperation("设备体系-模糊数学-隶属度矩阵导入模版")
|
@PostMapping("/device/fuzzy/membershipMatrix/template")
|
public ResponseEntity<InputStreamResource> downloadDeviceFuzzyMembershipMatrixTemplate() {
|
return exportDeviceFuzzyMembershipMatrix(null);
|
}
|
|
@ApiOperation("设备体系-模糊数学-隶属度矩阵导入")
|
@PostMapping("/device/fuzzy/membershipMatrix/import")
|
@ResponseBody
|
public Result importDeviceFuzzyMembershipMatrix(
|
@ApiParam("专家ID") @RequestParam("expertId") Integer expertId,
|
@RequestParam("file") MultipartFile file) {
|
try {
|
deviceExpertService.importMembershipMatrix(expertId, file.getInputStream());
|
return Result.success("隶属度矩阵导入成功");
|
} catch (Exception e) {
|
log.error("设备体系隶属度矩阵导入失败", e);
|
return Result.error("导入失败: " + e.getMessage());
|
}
|
}
|
|
////// 模糊数学专家 - 判断矩阵导入导出 //////
|
|
@ApiOperation("综合体系-模糊数学-判断矩阵导出")
|
@PostMapping("/system/fuzzy/compareMatrix/export")
|
public ResponseEntity<InputStreamResource> exportSystemFuzzyCompareMatrix(
|
@ApiParam("专家ID") @RequestParam Integer expertId) {
|
var expert = sysExpertService.get(expertId);
|
if(expert == null) {
|
throw new RuntimeException("专家不存在");
|
}
|
|
var hierarchyTree = sysExpertService.getHierarchyTree(expertId);
|
var compareMatrixMap = expert.getCompareMatrixMap();
|
|
// 如果没有判断矩阵,自动生成默认矩阵(所有比值为1)
|
if(compareMatrixMap == null || compareMatrixMap.isEmpty()) {
|
compareMatrixMap = generateDefaultCompareMatrixMap(hierarchyTree);
|
}
|
|
String filename = "综合体系-" + expert.getName() + "-判断矩阵";
|
return downloadData(new CompareMatrixProcessor(hierarchyTree), compareMatrixMap, filename);
|
}
|
|
@ApiOperation("综合体系-模糊数学-判断矩阵导入模版")
|
@PostMapping("/system/fuzzy/compareMatrix/template")
|
public ResponseEntity<InputStreamResource> downloadSystemFuzzyCompareMatrixTemplate(
|
@ApiParam("专家ID") @RequestParam Integer expertId) {
|
return exportSystemFuzzyCompareMatrix(expertId);
|
}
|
|
@ApiOperation("综合体系-模糊数学-判断矩阵导入")
|
@PostMapping("/system/fuzzy/compareMatrix/import")
|
@ResponseBody
|
public Result importSystemFuzzyCompareMatrix(
|
@ApiParam("专家ID") @RequestParam Integer expertId,
|
@RequestParam("file") MultipartFile file) {
|
try {
|
var hierarchyTree = sysExpertService.getHierarchyTree(expertId);
|
var compareMatrixMap = new CompareMatrixProcessor(hierarchyTree).loadFromWorkbook(file.getInputStream());
|
|
// 验证所有矩阵
|
for(var matrix : compareMatrixMap.values()) {
|
CompareMatrixProcessor.validate(matrix);
|
}
|
|
// 更新专家的判断矩阵
|
var expert = sysExpertService.get(expertId);
|
expert.setCompareMatrixMap(compareMatrixMap);
|
sysExpertService.edit(expert);
|
|
return Result.success("判断矩阵导入成功,共导入 " + compareMatrixMap.size() + " 个节点");
|
} catch (Exception e) {
|
log.error("综合体系判断矩阵导入失败", e);
|
return Result.error("导入失败: " + e.getMessage());
|
}
|
}
|
|
@ApiOperation("设备体系-模糊数学-判断矩阵导出")
|
@PostMapping("/device/fuzzy/compareMatrix/export")
|
public ResponseEntity<InputStreamResource> exportDeviceFuzzyCompareMatrix(
|
@ApiParam("专家ID") @RequestParam Integer expertId) {
|
var expert = deviceExpertService.get(expertId);
|
if(expert == null) {
|
throw new RuntimeException("专家不存在");
|
}
|
|
var hierarchyTree = deviceExpertService.getHierarchyTree(expertId);
|
var compareMatrixMap = expert.getCompareMatrixMap();
|
|
// 如果没有判断矩阵,自动生成默认矩阵(所有比值为1)
|
if(compareMatrixMap == null || compareMatrixMap.isEmpty()) {
|
compareMatrixMap = generateDefaultCompareMatrixMap(hierarchyTree);
|
}
|
|
String filename = "设备体系-" + expert.getName() + "-判断矩阵";
|
return downloadData(new CompareMatrixProcessor(hierarchyTree), compareMatrixMap, filename);
|
}
|
|
@ApiOperation("设备体系-模糊数学-判断矩阵导入模版")
|
@PostMapping("/device/fuzzy/compareMatrix/template")
|
public ResponseEntity<InputStreamResource> downloadDeviceFuzzyCompareMatrixTemplate(
|
@ApiParam("专家ID") @RequestParam Integer expertId) {
|
return exportDeviceFuzzyCompareMatrix(expertId);
|
}
|
|
@ApiOperation("设备体系-模糊数学-判断矩阵导入")
|
@PostMapping("/device/fuzzy/compareMatrix/import")
|
@ResponseBody
|
public Result importDeviceFuzzyCompareMatrix(
|
@ApiParam("专家ID") @RequestParam Integer expertId,
|
@RequestParam("file") MultipartFile file) {
|
try {
|
var hierarchyTree = deviceExpertService.getHierarchyTree(expertId);
|
var compareMatrixMap = new CompareMatrixProcessor(hierarchyTree).loadFromWorkbook(file.getInputStream());
|
|
// 验证所有矩阵
|
for(var matrix : compareMatrixMap.values()) {
|
CompareMatrixProcessor.validate(matrix);
|
}
|
|
// 更新专家的判断矩阵
|
var expert = deviceExpertService.get(expertId);
|
expert.setCompareMatrixMap(compareMatrixMap);
|
deviceExpertService.edit(expert);
|
|
return Result.success("判断矩阵导入成功,共导入 " + compareMatrixMap.size() + " 个节点");
|
} catch (Exception e) {
|
log.error("设备体系判断矩阵导入失败", e);
|
return Result.error("导入失败: " + e.getMessage());
|
}
|
}
|
|
@ApiOperation("检查计划导出")
|
@PostMapping("/plan/export")
|
public ResponseEntity<InputStreamResource> exportPlans(@Validated @RequestBody PlanPageRequest request){
|
var result = planService.list(request.getKeyword(), request.getPlanTypes(), request.getPlanStates(),
|
request.getClientIds(), request.getCreatorId());
|
return downloadRowData(new PlanProcessor(checkTaskService), result, "检查计划导出");
|
}
|
|
@ApiOperation("体系问题导出(综合体系第6层/其他体系第4层叶子节点)")
|
@PostMapping("/problem/export")
|
public ResponseEntity<InputStreamResource> exportProblems(
|
@ApiParam("体系ID(1=综合体系-6层,其他=设备体系-4层)") @RequestParam Integer hierarchyId,
|
@ApiParam("体系路径(单个节点)") @RequestParam String hierarchyPath) {
|
var result = problemService.findProblems(hierarchyId, List.of(hierarchyPath), null);
|
|
var hierarchy = hierarchyService.get(hierarchyId);
|
String filename = hierarchy != null ? hierarchy.getName() + "-问题导出" : "问题导出";
|
|
return downloadRowData(new ProblemProcessor(hierarchyService, hierarchyId), result, filename);
|
}
|
|
@ApiOperation("体系问题导入模版(综合体系第6层/其他体系第4层叶子节点)")
|
@PostMapping("/problem/template")
|
public ResponseEntity<InputStreamResource> downloadProblemTemplate(
|
@ApiParam("体系ID(1=综合体系-6层,其他=设备体系-4层)") @RequestParam Integer hierarchyId) {
|
return downloadRowData(new ProblemProcessor(hierarchyService, hierarchyId), List.of());
|
}
|
|
@ApiOperation("体系问题导入(综合体系第6层/其他体系第4层叶子节点)")
|
@PostMapping("/problem/import")
|
@ResponseBody
|
public Result importProblems(
|
Session session,
|
@ApiParam("体系ID(1=综合体系-6层,其他=设备体系-4层)") @RequestParam Integer hierarchyId,
|
@ApiParam("体系路径(问题将归属到此路径下)") @RequestParam String hierarchyPath,
|
@RequestParam("file") MultipartFile file) {
|
return importData(
|
"问题",
|
session,
|
file,
|
() -> {
|
var records = new ProblemProcessor(hierarchyService, hierarchyId).loadFromWorkbook(file.getInputStream());
|
// 设置所有问题的体系路径
|
if(records != null) {
|
for(var problem : records) {
|
problem.setHierarchyPath(hierarchyPath);
|
problem.setHierarchyId(hierarchyId);
|
}
|
// 验证所有问题必须是叶子节点
|
validateLeafNodes(hierarchyId, records);
|
}
|
return records;
|
},
|
records -> problemService.importEntities((User) session.getUser(), records)
|
);
|
}
|
|
/**
|
* 生成默认的判断矩阵Map(所有比值为1)
|
* 为体系树中所有有子节点的节点生成默认判断矩阵
|
*/
|
private java.util.Map<String, com.estate.expert.admin.domain.standard.expert.matrix.CompareMatrix> generateDefaultCompareMatrixMap(
|
com.estate.expert.admin.utils.tree.TreeRoot<com.estate.expert.admin.domain.standard.hierachy.HierarchyData> hierarchyTree) {
|
java.util.Map<String, com.estate.expert.admin.domain.standard.expert.matrix.CompareMatrix> matrixMap = new java.util.TreeMap<>();
|
|
// 递归遍历所有节点
|
generateDefaultMatrixForNode(hierarchyTree.root(), matrixMap);
|
|
return matrixMap;
|
}
|
|
/**
|
* 递归为节点及其子节点生成默认判断矩阵
|
*/
|
private void generateDefaultMatrixForNode(
|
com.estate.expert.admin.utils.tree.TreeNode<com.estate.expert.admin.domain.standard.hierachy.HierarchyData> node,
|
java.util.Map<String, com.estate.expert.admin.domain.standard.expert.matrix.CompareMatrix> matrixMap) {
|
|
// 如果节点有子节点,则为其生成判断矩阵
|
if(node.getChildren() != null && !node.getChildren().isEmpty()) {
|
String nodePath = node.getPath();
|
|
// 跳过根节点或无效路径
|
if(!"/".equals(nodePath) && nodePath != null && nodePath.length() > 1) {
|
var children = node.getChildren().values();
|
String[] childNames = children.stream()
|
.map(com.estate.expert.admin.utils.tree.TreeNode::getName)
|
.toArray(String[]::new);
|
|
// 创建默认矩阵(所有值为1)
|
var matrix = new com.estate.expert.admin.domain.standard.expert.matrix.CompareMatrix(childNames);
|
matrixMap.put(nodePath, matrix);
|
}
|
|
// 递归处理子节点
|
for(var child : node.getChildren().values()) {
|
generateDefaultMatrixForNode(child, matrixMap);
|
}
|
}
|
}
|
|
/**
|
* 验证问题是否都是叶子节点
|
* 综合体系(ID=1):第6层
|
* 其他体系(ID!=1):第4层
|
*/
|
private void validateLeafNodes(Integer hierarchyId, List<Problem> problems) {
|
var hierarchy = hierarchyService.get(hierarchyId);
|
if(hierarchy == null) {
|
throw new RuntimeException("体系不存在");
|
}
|
|
var root = hierarchy.getContent();
|
if(root == null) {
|
throw new RuntimeException("体系结构为空");
|
}
|
|
// 根据体系ID确定要求的层级
|
// ID=1 是综合体系(第6层),其他都是设备体系(第4层)
|
int requiredDepth;
|
String hierarchyName;
|
if(hierarchyId == HierarchyIds.SYSTEM) {
|
requiredDepth = 6;
|
hierarchyName = "综合体系";
|
} else {
|
requiredDepth = 4;
|
hierarchyName = "设备体系";
|
}
|
|
// 所有问题共享同一个体系路径,只需验证一次
|
if(!problems.isEmpty()) {
|
var path = problems.get(0).getHierarchyPath();
|
|
if(path == null || path.trim().isEmpty()) {
|
throw new RuntimeException("体系路径为空");
|
}
|
|
var node = root.get(path);
|
if(node == null) {
|
throw new RuntimeException("体系路径【" + path + "】不存在");
|
}
|
|
// 检查是否是要求的层级
|
if(node.getDepth() != requiredDepth) {
|
throw new RuntimeException("体系路径不在" + hierarchyName + "第" + requiredDepth + "层(当前在第" + node.getDepth() + "层)");
|
}
|
|
// 检查是否是叶子节点
|
if(node.getChildren() != null && !node.getChildren().isEmpty()) {
|
throw new RuntimeException("体系路径不是叶子节点(存在子节点)");
|
}
|
}
|
}
|
|
/**
|
* 通用的数据导入方法
|
*
|
* @param dataType 数据类型名称(用于日志和错误提示)
|
* @param session 会话信息
|
* @param file 上传的文件
|
* @param loader 数据加载函数
|
* @param importer 数据导入函数
|
* @param <T> 数据类型
|
* @return 导入结果
|
*/
|
private <T> Result importData(
|
String dataType,
|
Session session,
|
MultipartFile file,
|
DataLoader<T> loader,
|
DataImporter<T> importer) {
|
try {
|
// 1. 加载数据
|
var records = loader.load();
|
|
// 2. 验证数据
|
if(records == null || records.isEmpty()) {
|
return Result.error("导入文件中没有有效数据");
|
}
|
|
// 3. 执行导入
|
importer.doImport(records);
|
|
// 4. 返回成功结果
|
return Result.success("成功导入 " + records.size() + " 个" + dataType);
|
|
} catch (Exception e) {
|
log.error("{}导入失败", dataType, e);
|
return Result.error("导入失败: " + e.getMessage());
|
}
|
}
|
|
/**
|
* 数据加载函数接口
|
*/
|
@FunctionalInterface
|
private interface DataLoader<T> {
|
List<T> load() throws Exception;
|
}
|
|
/**
|
* 数据导入函数接口
|
*/
|
@FunctionalInterface
|
private interface DataImporter<T> {
|
void doImport(List<T> records);
|
}
|
|
// 生成Excel文件并写入下载的流
|
@SneakyThrows
|
public <T> ResponseEntity<InputStreamResource> downloadRowData(RowDataProcessorBase<T> processor, List<T> records) {
|
return downloadData(processor, records);
|
}
|
|
// 生成Excel文件并写入下载的流(带文件名)
|
@SneakyThrows
|
public <T> ResponseEntity<InputStreamResource> downloadRowData(RowDataProcessorBase<T> processor, List<T> records, String filename) {
|
return downloadData(processor, records, filename);
|
}
|
|
// 生成Excel文件并写入下载的流
|
@SneakyThrows
|
public <V> ResponseEntity<InputStreamResource> downloadData(DataProcessorBase<V> processor, V data) {
|
return downloadData(processor, data, null);
|
}
|
|
// 生成Excel文件并写入下载的流(带文件名)
|
@SneakyThrows
|
public <V> ResponseEntity<InputStreamResource> downloadData(DataProcessorBase<V> processor, V data, String filename) {
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
processor.saveWorkbook(baos, data);
|
|
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
InputStreamResource resource = new InputStreamResource(bais);
|
|
var responseBuilder = ResponseEntity.ok()
|
.contentType(MediaType.parseMediaType("application/vnd.ms-excel;charset=UTF-8"));
|
|
// 如果指定了文件名,则设置 Content-Disposition 头(支持中文)
|
if(filename != null && !filename.trim().isEmpty()) {
|
String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString()).replace("+", "%20");
|
responseBuilder.header("Content-Disposition",
|
"attachment; filename*=UTF-8''" + encodedFilename + ".xlsx");
|
}
|
|
return responseBuilder.body(resource);
|
}
|
|
}
|