2026-03-25提交:新增事件ID关联,上传附件下载附件接口
This commit is contained in:
parent
c7cbf45c2d
commit
6eaa7e3d0b
@ -5,6 +5,8 @@ import com.southern.power.grid.entity.*;
|
|||||||
import com.southern.power.grid.service.*;
|
import com.southern.power.grid.service.*;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@ -39,6 +41,9 @@ public class DnerController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IRegionalWeatherDataService regionalWeatherDataService;
|
private IRegionalWeatherDataService regionalWeatherDataService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DnerEventAttachmentService dnerEventAttachmentService;
|
||||||
|
|
||||||
@PostMapping("/area-tree/query")
|
@PostMapping("/area-tree/query")
|
||||||
public Result<List<AreaTreeVO>> queryAreaTree(@RequestBody @Valid AreaTreeReq req) {
|
public Result<List<AreaTreeVO>> queryAreaTree(@RequestBody @Valid AreaTreeReq req) {
|
||||||
return Result.success(dnerSiteAreaConfigurationService.queryAreaTree(req));
|
return Result.success(dnerSiteAreaConfigurationService.queryAreaTree(req));
|
||||||
@ -82,9 +87,20 @@ public class DnerController {
|
|||||||
* @return 返回结果
|
* @return 返回结果
|
||||||
*/
|
*/
|
||||||
@PostMapping("/excel/import")
|
@PostMapping("/excel/import")
|
||||||
public Result<String> importExcel(@RequestParam("file") MultipartFile file) {
|
public Result<String> importExcel(@RequestParam("file") MultipartFile file,
|
||||||
String taskNo = importTaskService.importExcel(file);
|
@RequestParam Long eventId) {
|
||||||
return Result.success(taskNo);
|
return Result.success(importTaskService.importExcel(file, eventId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载附件
|
||||||
|
*
|
||||||
|
* @param attachmentId 附件ID
|
||||||
|
* @return 响应体
|
||||||
|
*/
|
||||||
|
@GetMapping("/excel/download/{attachmentId}")
|
||||||
|
public ResponseEntity<Resource> downloadExcel(@PathVariable Long attachmentId) {
|
||||||
|
return dnerEventAttachmentService.downloadExcel(attachmentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 查询导入进度
|
// 2. 查询导入进度
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
package com.southern.power.grid.controller;
|
package com.southern.power.grid.controller;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.southern.power.grid.common.Result;
|
import com.southern.power.grid.common.Result;
|
||||||
import com.southern.power.grid.entity.DnerEvent;
|
import com.southern.power.grid.entity.DnerEvent;
|
||||||
import com.southern.power.grid.entity.DnerEventVO;
|
import com.southern.power.grid.entity.DnerEventVO;
|
||||||
@ -10,7 +7,6 @@ import com.southern.power.grid.service.DnerEventService;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -31,6 +31,11 @@ public class DnerEventAttachment {
|
|||||||
*/
|
*/
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储在本地的唯一文件名
|
||||||
|
*/
|
||||||
|
private String storedFileName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件存储路径
|
* 文件存储路径
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -23,6 +23,11 @@ public class DnerHourlyPowerOutageEvent {
|
|||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事件ID
|
||||||
|
*/
|
||||||
|
private Long eventId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 地区编码
|
* 地区编码
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.southern.power.grid.entity;
|
package com.southern.power.grid.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@ -31,4 +32,16 @@ public class ImportTask {
|
|||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务关联的文件ID
|
||||||
|
*/
|
||||||
|
private Long fileId;
|
||||||
|
|
||||||
|
// =============== 非数据库参数 ==================
|
||||||
|
/**
|
||||||
|
* 事件ID
|
||||||
|
*/
|
||||||
|
@TableField(exist = false)
|
||||||
|
private Long eventId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import com.southern.power.grid.service.impl.HourlyOutageExcelProcessService;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -31,7 +32,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
public class DataExcelListener extends AnalysisEventListener<DataExcelEntity> {
|
public class DataExcelListener extends AnalysisEventListener<DataExcelEntity> {
|
||||||
|
|
||||||
// 每批次大小
|
// 每批次大小
|
||||||
private static final int BATCH_SIZE = 500;
|
@Value("${file.import.batch-size}")
|
||||||
|
private int BATCH_SIZE;
|
||||||
|
|
||||||
// 缓存数据
|
// 缓存数据
|
||||||
private final List<DataExcelEntity> cacheList = new ArrayList<>(BATCH_SIZE);
|
private final List<DataExcelEntity> cacheList = new ArrayList<>(BATCH_SIZE);
|
||||||
@ -92,7 +94,7 @@ public class DataExcelListener extends AnalysisEventListener<DataExcelEntity> {
|
|||||||
private void batchInsert() {
|
private void batchInsert() {
|
||||||
try {
|
try {
|
||||||
// 批量插入(500条)
|
// 批量插入(500条)
|
||||||
hourlyOutageExcelProcessService.process(cacheList);
|
hourlyOutageExcelProcessService.process(cacheList, task.getEventId());
|
||||||
success += cacheList.size();
|
success += cacheList.size();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
fail += cacheList.size();
|
fail += cacheList.size();
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package com.southern.power.grid.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import com.southern.power.grid.entity.DnerEventAttachment;
|
import com.southern.power.grid.entity.DnerEventAttachment;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件附件 服务接口
|
* 事件附件 服务接口
|
||||||
@ -11,4 +13,11 @@ import com.southern.power.grid.entity.DnerEventAttachment;
|
|||||||
**/
|
**/
|
||||||
public interface DnerEventAttachmentService extends IService<DnerEventAttachment> {
|
public interface DnerEventAttachmentService extends IService<DnerEventAttachment> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载附件
|
||||||
|
*
|
||||||
|
* @param attachmentId 附件ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
ResponseEntity<Resource> downloadExcel(Long attachmentId);
|
||||||
}
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package com.southern.power.grid.service;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件操作 服务层
|
||||||
|
*
|
||||||
|
* @author: junzhangfm
|
||||||
|
* @date: 2026/3/25
|
||||||
|
**/
|
||||||
|
public interface IFileService {
|
||||||
|
/**
|
||||||
|
* 上传excel文件
|
||||||
|
*
|
||||||
|
* @param file 文件
|
||||||
|
* @param eventId 事件ID
|
||||||
|
*/
|
||||||
|
Long uploadExcel(MultipartFile file, Long eventId) throws IOException;
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
* @date: 2026/3/16
|
* @date: 2026/3/16
|
||||||
**/
|
**/
|
||||||
public interface IImportTaskService {
|
public interface IImportTaskService {
|
||||||
String importExcel(MultipartFile file);
|
String importExcel(MultipartFile file, Long eventId);
|
||||||
|
|
||||||
ImportTask getProgress(String taskNo);
|
ImportTask getProgress(String taskNo);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,18 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||||||
import com.southern.power.grid.dao.DnerEventAttachmentMapper;
|
import com.southern.power.grid.dao.DnerEventAttachmentMapper;
|
||||||
import com.southern.power.grid.entity.DnerEventAttachment;
|
import com.southern.power.grid.entity.DnerEventAttachment;
|
||||||
import com.southern.power.grid.service.DnerEventAttachmentService;
|
import com.southern.power.grid.service.DnerEventAttachmentService;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,4 +29,47 @@ public class DnerEventAttachmentServiceImpl
|
|||||||
extends ServiceImpl<DnerEventAttachmentMapper, DnerEventAttachment>
|
extends ServiceImpl<DnerEventAttachmentMapper, DnerEventAttachment>
|
||||||
implements DnerEventAttachmentService {
|
implements DnerEventAttachmentService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Resource> downloadExcel(Long attachmentId) {
|
||||||
|
// 1. 根据ID从数据库查询文件记录
|
||||||
|
DnerEventAttachment attachment = getById(attachmentId);
|
||||||
|
if (attachment == null) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取文件真实路径
|
||||||
|
String filePath = attachment.getFilePath();
|
||||||
|
File file = new File(filePath);
|
||||||
|
|
||||||
|
// 3. 校验文件是否存在
|
||||||
|
if (!file.exists()) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 封装文件资源
|
||||||
|
Resource resource = new FileSystemResource(file);
|
||||||
|
|
||||||
|
// 5. 处理中文名下载乱码(关键!)
|
||||||
|
String originalFilename = attachment.getFileName();
|
||||||
|
String encodeFileName = null;
|
||||||
|
try {
|
||||||
|
encodeFileName = URLEncoder.encode(originalFilename, StandardCharsets.UTF_8.toString())
|
||||||
|
.replace("+", "%20");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.error("URLEncoder.encode error!");
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 构建响应头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=\"" + encodeFileName + "\"; filename*=UTF-8''" + encodeFileName);
|
||||||
|
|
||||||
|
// 7. 返回文件流
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.headers(headers)
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.contentLength(file.length())
|
||||||
|
.body(resource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,85 @@
|
|||||||
|
package com.southern.power.grid.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.southern.power.grid.dao.DnerDailyPowerOutageEventMapper;
|
||||||
|
import com.southern.power.grid.dao.DnerEventAttachmentMapper;
|
||||||
|
import com.southern.power.grid.dao.DnerHourlyPowerOutageEventMapper;
|
||||||
|
import com.southern.power.grid.entity.DnerDailyPowerOutageEvent;
|
||||||
|
import com.southern.power.grid.entity.DnerEventAttachment;
|
||||||
|
import com.southern.power.grid.entity.DnerHourlyPowerOutageEvent;
|
||||||
|
import com.southern.power.grid.service.IFileService;
|
||||||
|
import com.southern.power.grid.utils.FileUploadUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件操作 服务实现类
|
||||||
|
*
|
||||||
|
* @author: junzhangfm
|
||||||
|
* @date: 2026/3/25
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class FileServiceImpl implements IFileService {
|
||||||
|
// 读取配置文件中的存储路径
|
||||||
|
@Value("${file.upload.path}")
|
||||||
|
private String uploadPath;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DnerEventAttachmentMapper dnerEventAttachmentMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DnerHourlyPowerOutageEventMapper dnerHourlyPowerOutageEventMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DnerDailyPowerOutageEventMapper dnerDailyPowerOutageEventMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long uploadExcel(MultipartFile file, Long eventId) throws IOException {
|
||||||
|
// 1. 校验是否是 Excel
|
||||||
|
if (!FileUploadUtil.isExcel(file)) {
|
||||||
|
throw new RuntimeException("Only .xlsx or .xls format Excel files are allowed to be uploaded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取文件信息
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
String suffix = FileUploadUtil.getFileSuffix(originalFilename);
|
||||||
|
String storedFilename = FileUploadUtil.generateUniqueFileName(suffix);
|
||||||
|
String absolutePath = uploadPath + storedFilename;
|
||||||
|
|
||||||
|
// 3. 保存到本地
|
||||||
|
FileUploadUtil.saveFile(file, absolutePath);
|
||||||
|
|
||||||
|
// 4. 记录到数据库
|
||||||
|
DnerEventAttachment record = new DnerEventAttachment();
|
||||||
|
record.setFileName(originalFilename);
|
||||||
|
record.setStoredFileName(storedFilename);
|
||||||
|
record.setFilePath(absolutePath);
|
||||||
|
record.setFileSize(file.getSize());
|
||||||
|
record.setFileType(suffix);
|
||||||
|
record.setCreateTime(LocalDateTime.now());
|
||||||
|
record.setCreator("admin"); // 默认admin
|
||||||
|
record.setEventId(eventId);
|
||||||
|
// 最新附件,其他附件设置为0
|
||||||
|
record.setIsLatest(1);
|
||||||
|
dnerEventAttachmentMapper.update(new UpdateWrapper<DnerEventAttachment>().set("is_latest", 0)
|
||||||
|
.eq("event_id", eventId));
|
||||||
|
// 插入记录
|
||||||
|
dnerEventAttachmentMapper.insert(record);
|
||||||
|
// 删除旧的分时图和K线图数据
|
||||||
|
dnerHourlyPowerOutageEventMapper.delete(
|
||||||
|
new QueryWrapper<DnerHourlyPowerOutageEvent>().eq("event_id", eventId));
|
||||||
|
dnerDailyPowerOutageEventMapper.delete(
|
||||||
|
new QueryWrapper<DnerDailyPowerOutageEvent>().eq("event_id", eventId));
|
||||||
|
return record.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -57,7 +57,7 @@ public class HourlyOutageExcelProcessService {
|
|||||||
* 对外主入口:处理一批 Excel 解析后的数据,按逻辑补齐气象数据并批量入库
|
* 对外主入口:处理一批 Excel 解析后的数据,按逻辑补齐气象数据并批量入库
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public void process(List<DataExcelEntity> excelRows) {
|
public void process(List<DataExcelEntity> excelRows, Long eventId) {
|
||||||
// 1. 加载南网区划配置表
|
// 1. 加载南网区划配置表
|
||||||
loadNwAreaConfig();
|
loadNwAreaConfig();
|
||||||
// 2. 加载气象区划配置表
|
// 2. 加载气象区划配置表
|
||||||
@ -121,6 +121,7 @@ public class HourlyOutageExcelProcessService {
|
|||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
// 不存在,创建新实体并放入 Map
|
// 不存在,创建新实体并放入 Map
|
||||||
DnerHourlyPowerOutageEvent entity = buildHourlyEvent(row, districtCode, regionalWeatherData);
|
DnerHourlyPowerOutageEvent entity = buildHourlyEvent(row, districtCode, regionalWeatherData);
|
||||||
|
entity.setEventId(eventId);
|
||||||
toInsertMap.put(key, entity);
|
toInsertMap.put(key, entity);
|
||||||
} else {
|
} else {
|
||||||
// 已存在,执行累加逻辑
|
// 已存在,执行累加逻辑
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
package com.southern.power.grid.service.impl;
|
package com.southern.power.grid.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.southern.power.grid.dao.ImportTaskMapper;
|
import com.southern.power.grid.dao.ImportTaskMapper;
|
||||||
import com.southern.power.grid.entity.ImportTask;
|
import com.southern.power.grid.entity.ImportTask;
|
||||||
import com.southern.power.grid.enums.ImportTaskStatusEnum;
|
import com.southern.power.grid.enums.ImportTaskStatusEnum;
|
||||||
|
import com.southern.power.grid.service.IFileService;
|
||||||
import com.southern.power.grid.service.IImportTaskService;
|
import com.southern.power.grid.service.IImportTaskService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -32,19 +34,11 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AsyncImportServiceImpl asyncImportService;
|
private AsyncImportServiceImpl asyncImportService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IFileService fileService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String importExcel(MultipartFile file) {
|
public String importExcel(MultipartFile file, Long eventId) {
|
||||||
// 通过hutool工具类生成唯一任务号
|
|
||||||
String taskNo = IdUtil.fastSimpleUUID();
|
|
||||||
|
|
||||||
// 创建任务
|
|
||||||
ImportTask task = new ImportTask();
|
|
||||||
task.setTaskNo(taskNo);
|
|
||||||
task.setStatus(ImportTaskStatusEnum.WAITING.getCode());
|
|
||||||
task.setTotal(0);
|
|
||||||
importTaskMapper.insert(task);
|
|
||||||
|
|
||||||
// 异步执行导入
|
|
||||||
// 把上传的文件流转成 **字节数组输入流**,保存到内存,避免Tomcat删除
|
// 把上传的文件流转成 **字节数组输入流**,保存到内存,避免Tomcat删除
|
||||||
InputStream inputStream;
|
InputStream inputStream;
|
||||||
try {
|
try {
|
||||||
@ -53,6 +47,28 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
|
|||||||
log.error("file exception!");
|
log.error("file exception!");
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
// 同步上传文件到本地,拒绝异步,tomcat可能会删除file对象,导致上传异常
|
||||||
|
Long fileId;
|
||||||
|
try {
|
||||||
|
fileId = fileService.uploadExcel(file, eventId);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("ImportTaskServiceImpl fileService.uploadExcel fail! {}", e.getMessage());
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过hutool工具类生成唯一任务号
|
||||||
|
String taskNo = IdUtil.fastSimpleUUID();
|
||||||
|
|
||||||
|
// 创建任务
|
||||||
|
ImportTask task = new ImportTask();
|
||||||
|
task.setTaskNo(taskNo);
|
||||||
|
task.setStatus(ImportTaskStatusEnum.WAITING.getCode());
|
||||||
|
task.setTotal(0);
|
||||||
|
task.setFileId(fileId);
|
||||||
|
task.setEventId(eventId);
|
||||||
|
importTaskMapper.insert(task);
|
||||||
|
|
||||||
|
// 异步执行导入
|
||||||
asyncImportService.doAsyncImport(inputStream, task);
|
asyncImportService.doAsyncImport(inputStream, task);
|
||||||
|
|
||||||
// 立即返回任务ID给前端
|
// 立即返回任务ID给前端
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
package com.southern.power.grid.utils;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传工具类
|
||||||
|
*
|
||||||
|
* @author: junzhangfm
|
||||||
|
* @date: 2026/3/25
|
||||||
|
**/
|
||||||
|
public class FileUploadUtil {
|
||||||
|
|
||||||
|
// 校验是否是 Excel 文件
|
||||||
|
public static boolean isExcel(MultipartFile file) {
|
||||||
|
String suffix = getFileSuffix(file.getOriginalFilename());
|
||||||
|
return "xlsx".equals(suffix) || "xls".equals(suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件后缀
|
||||||
|
public static String getFileSuffix(String fileName) {
|
||||||
|
if (fileName == null || !fileName.contains(".")) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成唯一文件名(防止覆盖)
|
||||||
|
public static String generateUniqueFileName(String suffix) {
|
||||||
|
return UUID.randomUUID().toString().replace("-", "") + "." + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存文件到本地
|
||||||
|
public static void saveFile(MultipartFile file, String absolutePath) throws IOException {
|
||||||
|
File dest = new File(absolutePath);
|
||||||
|
// 创建父目录
|
||||||
|
if (!dest.getParentFile().exists()) {
|
||||||
|
dest.getParentFile().mkdirs();
|
||||||
|
}
|
||||||
|
file.transferTo(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,6 +24,14 @@ spring:
|
|||||||
max-file-size: 100MB # 单个文件最大 默认1M
|
max-file-size: 100MB # 单个文件最大 默认1M
|
||||||
max-request-size: 100MB # 整个请求最大 默认10M
|
max-request-size: 100MB # 整个请求最大 默认10M
|
||||||
|
|
||||||
|
# 自定义本地文件存储路径(绝对路径,不要放在项目里!)
|
||||||
|
file:
|
||||||
|
upload:
|
||||||
|
path: E:/springboot-uploads/excel/ # Windows
|
||||||
|
# path: /home/springboot/uploads/excel/ # Linux
|
||||||
|
import:
|
||||||
|
batch-size: 500 # 批量导入大小
|
||||||
|
|
||||||
# MyBatis-Plus配置
|
# MyBatis-Plus配置
|
||||||
mybatis-plus:
|
mybatis-plus:
|
||||||
configuration:
|
configuration:
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
where t1.district_code = t2.org_code
|
where t1.district_code = t2.org_code
|
||||||
and t2.data_time >= #{param.avgTempStartDateTime}
|
and t2.data_time >= #{param.avgTempStartDateTime}
|
||||||
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
||||||
and t2.temperature > #{param.pastTimeAvgTempCount})
|
having avg(t2.temperature) > #{param.pastTimeAvgTempCount})
|
||||||
</if>
|
</if>
|
||||||
<if test="param.maxWindPastTime != null and param.maxWindPastTime != 0">
|
<if test="param.maxWindPastTime != null and param.maxWindPastTime != 0">
|
||||||
# 过去X分钟的平均风速超过Y m/s
|
# 过去X分钟的平均风速超过Y m/s
|
||||||
@ -62,7 +62,7 @@
|
|||||||
where t1.district_code = t2.org_code
|
where t1.district_code = t2.org_code
|
||||||
and t2.data_time >= #{param.maxWindStartDateTime}
|
and t2.data_time >= #{param.maxWindStartDateTime}
|
||||||
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
||||||
and t2.extreme_wind_speed_hourly > #{param.pastTimeMaxWindCount})
|
having avg(t2.extreme_wind_speed_hourly) > #{param.pastTimeMaxWindCount})
|
||||||
</if>
|
</if>
|
||||||
<if test="param.powerOutageTimePastTime != null and param.powerOutageTimePastTime != 0">
|
<if test="param.powerOutageTimePastTime != null and param.powerOutageTimePastTime != 0">
|
||||||
# 过去X小时的停电时长超Y小时
|
# 过去X小时的停电时长超Y小时
|
||||||
@ -92,7 +92,7 @@
|
|||||||
where t1.district_code = t2.org_code
|
where t1.district_code = t2.org_code
|
||||||
and t2.data_time >= #{param.powerOutageRatioStartDateTime}
|
and t2.data_time >= #{param.powerOutageRatioStartDateTime}
|
||||||
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
||||||
and (t2.not_restored_user_count/(t2.restored_user_count + t2.not_restored_user_count)) > #{param.pastTimePowerOutageRatioCount})
|
having avg(t2.not_restored_user_count/(t2.restored_user_count + t2.not_restored_user_count)) > #{param.pastTimePowerOutageRatioCount})
|
||||||
</if>
|
</if>
|
||||||
</when>
|
</when>
|
||||||
<otherwise>
|
<otherwise>
|
||||||
@ -128,7 +128,7 @@
|
|||||||
where t1.district_code = t2.org_code
|
where t1.district_code = t2.org_code
|
||||||
and t2.data_time >= #{param.avgTempStartDateTime}
|
and t2.data_time >= #{param.avgTempStartDateTime}
|
||||||
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
||||||
and t2.temperature > #{param.pastTimeAvgTempCount})
|
having avg(t2.temperature) > #{param.pastTimeAvgTempCount})
|
||||||
</if>
|
</if>
|
||||||
<if test="param.maxWindPastTime != null and param.maxWindPastTime != 0">
|
<if test="param.maxWindPastTime != null and param.maxWindPastTime != 0">
|
||||||
# 过去X天的平均风速超过Y m/s
|
# 过去X天的平均风速超过Y m/s
|
||||||
@ -138,7 +138,7 @@
|
|||||||
where t1.district_code = t2.org_code
|
where t1.district_code = t2.org_code
|
||||||
and t2.data_time >= #{param.maxWindStartDateTime}
|
and t2.data_time >= #{param.maxWindStartDateTime}
|
||||||
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
||||||
and t2.extreme_wind_speed_hourly > #{param.pastTimeMaxWindCount})
|
having avg(t2.extreme_wind_speed_hourly) > #{param.pastTimeMaxWindCount})
|
||||||
</if>
|
</if>
|
||||||
<if test="param.powerOutageTimePastTime != null and param.powerOutageTimePastTime != 0">
|
<if test="param.powerOutageTimePastTime != null and param.powerOutageTimePastTime != 0">
|
||||||
# 过去X小时的停电时长超Y小时
|
# 过去X小时的停电时长超Y小时
|
||||||
@ -168,7 +168,7 @@
|
|||||||
where t1.district_code = t2.org_code
|
where t1.district_code = t2.org_code
|
||||||
and t2.data_time >= #{param.powerOutageRatioStartDateTime}
|
and t2.data_time >= #{param.powerOutageRatioStartDateTime}
|
||||||
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
and t2.data_time <![CDATA[ < ]]> #{param.currentDateTime}
|
||||||
and (t2.not_restored_user_count/(t2.restored_user_count + t2.not_restored_user_count)) > #{param.pastTimePowerOutageRatioCount})
|
having avg(t2.not_restored_user_count/(t2.restored_user_count + t2.not_restored_user_count)) > #{param.pastTimePowerOutageRatioCount})
|
||||||
</if>
|
</if>
|
||||||
</when>
|
</when>
|
||||||
<otherwise>
|
<otherwise>
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
CREATE TABLE import_task
|
CREATE TABLE import_task
|
||||||
(
|
(
|
||||||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '任务ID',
|
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '任务ID',
|
||||||
|
file_id BIGINT NOT NULL COMMENT '文件ID',
|
||||||
task_no VARCHAR(64) NOT NULL UNIQUE COMMENT '任务唯一编号',
|
task_no VARCHAR(64) NOT NULL UNIQUE COMMENT '任务唯一编号',
|
||||||
total INT DEFAULT 0 COMMENT '总数据量',
|
total INT DEFAULT 0 COMMENT '总数据量',
|
||||||
success_count INT DEFAULT 0 COMMENT '成功数量',
|
success_count INT DEFAULT 0 COMMENT '成功数量',
|
||||||
@ -72,6 +73,7 @@ CREATE TABLE `weather_site_area_configuration`
|
|||||||
CREATE TABLE `dner_daily_power_outage_event`
|
CREATE TABLE `dner_daily_power_outage_event`
|
||||||
(
|
(
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`event_id` BIGINT(20) NOT NULL COMMENT '关联事件ID',
|
||||||
`org_code` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地区编码',
|
`org_code` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地区编码',
|
||||||
`data_time` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '资料日期',
|
`data_time` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '资料日期',
|
||||||
`hourly_precipitation` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '小时降水量',
|
`hourly_precipitation` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '小时降水量',
|
||||||
@ -105,6 +107,7 @@ CREATE TABLE `dner_daily_power_outage_event`
|
|||||||
CREATE TABLE `dner_hourly_power_outage_event`
|
CREATE TABLE `dner_hourly_power_outage_event`
|
||||||
(
|
(
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`event_id` BIGINT(20) NOT NULL COMMENT '关联事件ID',
|
||||||
`org_code` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地区编码',
|
`org_code` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地区编码',
|
||||||
`data_time` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '资料时次',
|
`data_time` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '资料时次',
|
||||||
`hourly_precipitation` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '小时降水量',
|
`hourly_precipitation` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '小时降水量',
|
||||||
@ -305,6 +308,7 @@ CREATE TABLE `dner_event_attachment`
|
|||||||
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '附件ID',
|
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '附件ID',
|
||||||
`event_id` BIGINT NOT NULL COMMENT '关联事件ID',
|
`event_id` BIGINT NOT NULL COMMENT '关联事件ID',
|
||||||
`file_name` VARCHAR(255) NOT NULL COMMENT '文件名',
|
`file_name` VARCHAR(255) NOT NULL COMMENT '文件名',
|
||||||
|
`stored_file_name` VARCHAR(255) NOT NULL COMMENT '存储在本地的唯一文件名',
|
||||||
`file_path` VARCHAR(512) NOT NULL COMMENT '文件存储路径',
|
`file_path` VARCHAR(512) NOT NULL COMMENT '文件存储路径',
|
||||||
`file_type` VARCHAR(32) NOT NULL COMMENT '文件类型',
|
`file_type` VARCHAR(32) NOT NULL COMMENT '文件类型',
|
||||||
`file_size` BIGINT NOT NULL COMMENT '文件大小(字节)',
|
`file_size` BIGINT NOT NULL COMMENT '文件大小(字节)',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user