优化方阵、光伏板、光伏板点方法逻辑和性能

This commit is contained in:
lcj
2025-04-27 18:05:00 +08:00
parent 19754c1ca9
commit a65a73c512
14 changed files with 350 additions and 141 deletions

View File

@ -3,6 +3,7 @@ package org.dromara;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
/**
@ -10,8 +11,9 @@ import org.springframework.scheduling.annotation.EnableAsync;
*
* @author Lion Li
*/
@EnableAsync
@SpringBootApplication
@EnableAsync
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class DromaraApplication {
public static void main(String[] args) {

View File

@ -1,14 +1,12 @@
package org.dromara.facility.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 设施-光伏板对象 fac_photovoltaic_panel
@ -65,15 +63,4 @@ public class FacPhotovoltaicPanel extends BaseEntity {
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -1,14 +1,12 @@
package org.dromara.facility.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 设施-光伏板立柱对象 fac_photovoltaic_panel_column
@ -65,15 +63,4 @@ public class FacPhotovoltaicPanelColumn extends BaseEntity {
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -1,14 +1,12 @@
package org.dromara.facility.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 设施-光伏板桩点对象 fac_photovoltaic_panel_point
@ -65,15 +63,4 @@ public class FacPhotovoltaicPanelPoint extends BaseEntity {
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -1,14 +1,12 @@
package org.dromara.facility.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 设施-光伏板支架对象 fac_photovoltaic_panel_support
@ -65,15 +63,4 @@ public class FacPhotovoltaicPanelSupport extends BaseEntity {
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -1,9 +1,13 @@
package org.dromara.facility.service;
import org.dromara.facility.domain.FacPhotovoltaicPanelColumn;
import org.dromara.facility.domain.FacPhotovoltaicPanelPoint;
import org.dromara.facility.domain.FacPhotovoltaicPanelSupport;
import org.dromara.facility.domain.req.photovoltaicpanelparts.PhotovoltaicPanelPartsCreateByGeoJsonReq;
import org.dromara.facility.domain.req.photovoltaicpanelparts.PhotovoltaicPanelPartsCreateReq;
import java.util.Collection;
import java.util.List;
/**
* 设施-光伏板桩点、立柱、支架Service接口
@ -21,6 +25,28 @@ public interface IFacPhotovoltaicPanelPartsService {
*/
Boolean insertPartsByGeoJson(PhotovoltaicPanelPartsCreateByGeoJsonReq geoJson);
/**
* 批量新增设施-光伏板(桩点、立柱、支架)内部方法
*
* @param pointList 桩点列表
* @param columnList 立柱列表
* @param supportList 支架列表
*/
void batchInsertPartsInner(List<FacPhotovoltaicPanelPoint> pointList,
List<FacPhotovoltaicPanelColumn> columnList,
List<FacPhotovoltaicPanelSupport> supportList);
/**
* 批量删除设施-光伏板(桩点、立柱、支架)内部方法
*
* @param pointList 桩点列表
* @param columnList 立柱列表
* @param supportList 支架列表
*/
void batchDeletePartsInner(List<FacPhotovoltaicPanelPoint> pointList,
List<FacPhotovoltaicPanelColumn> columnList,
List<FacPhotovoltaicPanelSupport> supportList);
/**
* 批量新增设施-光伏板(桩点、立柱、支架)
*

View File

@ -154,6 +154,9 @@ public class FacMatrixServiceImpl extends ServiceImpl<FacMatrixMapper, FacMatrix
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 获取当下项目下方阵信息
List<FacMatrix> oldMatrixList = this.lambdaQuery()
.eq(FacMatrix::getProjectId, projectId).list();
List<FacMatrix> matrixList = new ArrayList<>();
List<Feature> locationFeatures = geoJson.getLocationGeoJson().getFeatures();
List<FeatureByPoint> nameFeatures = geoJson.getNameGeoJson().getFeatures();
@ -183,6 +186,12 @@ public class FacMatrixServiceImpl extends ServiceImpl<FacMatrixMapper, FacMatrix
matrix.setMatrixName(name);
matrixList.add(matrix);
}
if (CollUtil.isEmpty(oldMatrixList)) {
boolean result = this.removeBatchByIds(oldMatrixList);
if (!result) {
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(matrixList)) {
boolean result = this.saveBatch(matrixList);
if (!result) {

View File

@ -4,9 +4,11 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.facility.domain.FacPhotovoltaicPanel;
import org.dromara.facility.domain.FacPhotovoltaicPanelColumn;
import org.dromara.facility.domain.FacPhotovoltaicPanelPoint;
@ -17,18 +19,29 @@ import org.dromara.facility.domain.req.photovoltaicpanelparts.PhotovoltaicPanelP
import org.dromara.facility.service.*;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.GeoJsonUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author lcj
* @date 2025/4/21 15:53
*/
@Slf4j
@Service
public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPanelPartsService {
@ -57,7 +70,6 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
* @return 是否新增成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertPartsByGeoJson(PhotovoltaicPanelPartsCreateByGeoJsonReq geoJson) {
Long projectId = geoJson.getProjectId();
if (projectService.getById(projectId) == null) {
@ -70,12 +82,39 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
throw new ServiceException("项目下未创建光伏板", HttpStatus.NOT_FOUND);
}
List<FeatureByPoint> features = geoJson.getPointGeoJson().getFeatures();
// 获取数据库中所有点的列表
List<FacPhotovoltaicPanelPoint> oldPointList = photovoltaicPanelPointService.lambdaQuery()
.eq(FacPhotovoltaicPanelPoint::getProjectId, projectId).list();
Map<String, FacPhotovoltaicPanelPoint> oldPointMap = oldPointList.stream()
.collect(Collectors.toMap(
FacPhotovoltaicPanelPoint::getName,
Function.identity(),
(existing, replacement) -> existing // 如果有重复,保留第一个
));
List<FacPhotovoltaicPanelColumn> oldColumnList = photovoltaicPanelColumnService.lambdaQuery()
.eq(FacPhotovoltaicPanelColumn::getProjectId, projectId).list();
Map<String, FacPhotovoltaicPanelColumn> oldColumnMap = oldColumnList.stream()
.collect(Collectors.toMap(
FacPhotovoltaicPanelColumn::getName,
Function.identity(),
(existing, replacement) -> existing // 如果有重复,保留第一个
));
List<FacPhotovoltaicPanelSupport> oldSupportList = photovoltaicPanelSupportService.lambdaQuery()
.eq(FacPhotovoltaicPanelSupport::getProjectId, projectId).list();
Map<String, FacPhotovoltaicPanelSupport> oldSupportMap = oldSupportList.stream()
.collect(Collectors.toMap(
FacPhotovoltaicPanelSupport::getName,
Function.identity(),
(existing, replacement) -> existing // 如果有重复,保留第一个
));
// 获取所有点列表
List<List<Double>> pointList = new ArrayList<>
List<List<Double>> pointPositionList = new ArrayList<>
(features.stream().map(featureByPoint -> featureByPoint.getGeometry().getCoordinates()).toList());
List<FacPhotovoltaicPanelPoint> photovoltaicPanelPointList = new ArrayList<>();
List<FacPhotovoltaicPanelColumn> photovoltaicPanelColumnList = new ArrayList<>();
List<FacPhotovoltaicPanelSupport> photovoltaicPanelSupportList = new ArrayList<>();
List<FacPhotovoltaicPanelPoint> pointList = new ArrayList<>();
List<FacPhotovoltaicPanelColumn> columnList = new ArrayList<>();
List<FacPhotovoltaicPanelSupport> supportList = new ArrayList<>();
// 获取当前登录用户
Long userId = LoginHelper.getUserId();
// 遍历所有光伏板,找到所有匹配的点
for (FacPhotovoltaicPanel photovoltaicPanel : photovoltaicPanelList) {
String positions = photovoltaicPanel.getPositions();
@ -85,9 +124,10 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
positionList.add(JSONUtil.toList(s, Double.class));
}
// 获取点在面内的点
List<List<Double>> pointInPlaneList = GeoJsonUtils.getPointInPlaneList(positionList, pointList);
List<List<Double>> pointInPlaneList = GeoJsonUtils.getPointInPlaneList(positionList, pointPositionList);
// 删除点在面内的点
pointList.removeAll(pointInPlaneList);
pointPositionList.removeAll(pointInPlaneList);
// 判断点在面内的点是否为空
if (CollUtil.isNotEmpty(pointInPlaneList)) {
int i = 1;
// 遍历点在面内的点,添加实体信息
@ -101,45 +141,181 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
photovoltaicPanelPoint.setMatrixId(matrixId);
photovoltaicPanelPoint.setName(name);
photovoltaicPanelPoint.setPositions(jsonStr);
photovoltaicPanelPointList.add(photovoltaicPanelPoint);
photovoltaicPanelPoint.setCreateBy(userId);
photovoltaicPanelPoint.setUpdateBy(userId);
if (CollUtil.isNotEmpty(oldPointMap) && oldPointMap.containsKey(name)) {
FacPhotovoltaicPanelPoint oldPoint = oldPointMap.get(name);
photovoltaicPanelPoint.setFinishType(oldPoint.getFinishType());
photovoltaicPanelPoint.setStatus(oldPoint.getStatus());
}
pointList.add(photovoltaicPanelPoint);
FacPhotovoltaicPanelColumn photovoltaicPanelColumn = new FacPhotovoltaicPanelColumn();
photovoltaicPanelColumn.setProjectId(projectId);
photovoltaicPanelColumn.setMatrixId(matrixId);
photovoltaicPanelColumn.setName(name);
photovoltaicPanelColumn.setPositions(jsonStr);
photovoltaicPanelColumnList.add(photovoltaicPanelColumn);
photovoltaicPanelColumn.setCreateBy(userId);
photovoltaicPanelColumn.setUpdateBy(userId);
if (CollUtil.isNotEmpty(oldColumnMap) && oldColumnMap.containsKey(name)) {
FacPhotovoltaicPanelColumn oldColumn = oldColumnMap.get(name);
photovoltaicPanelColumn.setFinishType(oldColumn.getFinishType());
photovoltaicPanelColumn.setStatus(oldColumn.getStatus());
}
columnList.add(photovoltaicPanelColumn);
FacPhotovoltaicPanelSupport photovoltaicPanelSupport = new FacPhotovoltaicPanelSupport();
photovoltaicPanelSupport.setProjectId(projectId);
photovoltaicPanelSupport.setMatrixId(matrixId);
photovoltaicPanelSupport.setName(name);
photovoltaicPanelSupport.setPositions(jsonStr);
photovoltaicPanelSupportList.add(photovoltaicPanelSupport);
photovoltaicPanelSupport.setCreateBy(userId);
photovoltaicPanelSupport.setUpdateBy(userId);
if (CollUtil.isNotEmpty(oldSupportMap) && oldSupportMap.containsKey(name)) {
FacPhotovoltaicPanelSupport oldSupport = oldSupportMap.get(name);
photovoltaicPanelSupport.setFinishType(oldSupport.getFinishType());
photovoltaicPanelSupport.setStatus(oldSupport.getStatus());
}
supportList.add(photovoltaicPanelSupport);
i++;
}
}
}
// 批量新增
if (CollUtil.isNotEmpty(photovoltaicPanelPointList)) {
boolean result = photovoltaicPanelPointService.saveBatch(photovoltaicPanelPointList);
if (!result) {
throw new ServiceException("批量新增光伏板桩点失败,数据库异常", HttpStatus.ERROR);
}
// 自定义线程池IO 密集型线程池)
ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
20, // 核心线程数
50, // 最大线程数
60L, // 线程空闲存活时间
TimeUnit.SECONDS, // 存活时间单位
new LinkedBlockingQueue<>(10000), // 阻塞队列容量
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:由调用线程处理任务
);
// 分批处理,避免长事务,假设每次处理 1000 条数据
int batchSize = 1000;
// 保存所有批次任务
List<CompletableFuture<Void>> deleteFutures = new ArrayList<>();
int deleteSize = oldPointList.size();
for (int i = 0; i < deleteSize; i += batchSize) {
int endIndex = Math.min(i + batchSize, deleteSize);
List<FacPhotovoltaicPanelPoint> batchPointList = oldPointList.subList(i, endIndex);
List<FacPhotovoltaicPanelColumn> batchColumnList = oldColumnList.subList(i, endIndex);
List<FacPhotovoltaicPanelSupport> batchSupportList = oldSupportList.subList(i, endIndex);
// 使用事务处理每批数据
// 获取代理
FacPhotovoltaicPanelPartsServiceImpl photovoltaicPanelPartsService = (FacPhotovoltaicPanelPartsServiceImpl) AopContext.currentProxy();
// 异步处理每批数据,将任务添加到异步任务列表
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> photovoltaicPanelPartsService.batchDeletePartsInner(batchPointList, batchColumnList, batchSupportList), customExecutor);
deleteFutures.add(future);
}
if (CollUtil.isNotEmpty(photovoltaicPanelColumnList)) {
boolean result = photovoltaicPanelColumnService.saveBatch(photovoltaicPanelColumnList);
if (!result) {
throw new ServiceException("批量新增光伏板立柱失败,数据库异常", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(photovoltaicPanelSupportList)) {
boolean result = photovoltaicPanelSupportService.saveBatch(photovoltaicPanelSupportList);
if (!result) {
throw new ServiceException("批量新增光伏板支架失败,数据库异常", HttpStatus.ERROR);
}
// 等待所有批次完成操作
CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0])).join();
// 保存所有批次任务
List<CompletableFuture<Void>> insertFutures = new ArrayList<>();
int totalSize = pointList.size();
for (int i = 0; i < totalSize; i += batchSize) {
int endIndex = Math.min(i + batchSize, totalSize);
List<FacPhotovoltaicPanelPoint> batchPointList = pointList.subList(i, endIndex);
List<FacPhotovoltaicPanelColumn> batchColumnList = columnList.subList(i, endIndex);
List<FacPhotovoltaicPanelSupport> batchSupportList = supportList.subList(i, endIndex);
// 使用事务处理每批数据
// 获取代理
FacPhotovoltaicPanelPartsServiceImpl photovoltaicPanelPartsService = (FacPhotovoltaicPanelPartsServiceImpl) AopContext.currentProxy();
// 异步处理每批数据,将任务添加到异步任务列表
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> photovoltaicPanelPartsService.batchInsertPartsInner(batchPointList, batchColumnList, batchSupportList), customExecutor);
insertFutures.add(future);
}
// 等待所有批次完成操作
CompletableFuture.allOf(insertFutures.toArray(new CompletableFuture[0])).join();
// 关闭线程池
customExecutor.shutdown();
return true;
}
/**
* 批量新增设施-光伏板(桩点、立柱、支架)内部方法
*
* @param pointList 桩点列表
* @param columnList 立柱列表
* @param supportList 支架列表
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void batchInsertPartsInner(List<FacPhotovoltaicPanelPoint> pointList,
List<FacPhotovoltaicPanelColumn> columnList,
List<FacPhotovoltaicPanelSupport> supportList) {
try {
if (CollUtil.isNotEmpty(pointList)) {
boolean result = photovoltaicPanelPointService.saveBatch(pointList);
if (!result) {
throw new ServiceException("批量新增光伏板桩点失败,数据库异常", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(columnList)) {
boolean result = photovoltaicPanelColumnService.saveBatch(columnList);
if (!result) {
throw new ServiceException("批量新增光伏板立柱失败,数据库异常", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(supportList)) {
boolean result = photovoltaicPanelSupportService.saveBatch(supportList);
if (!result) {
throw new ServiceException("批量新增光伏板支架失败,数据库异常", HttpStatus.ERROR);
}
}
} catch (DataIntegrityViolationException e) {
log.error("数据库唯一键冲突或违反其他完整性约束, 错误信息: {}", e.getMessage());
throw new ServiceException("数据已存在,无法重复添加");
} catch (DataAccessException e) {
log.error("数据库连接问题、事务问题等导致操作失败, 错误信息: {}", e.getMessage());
throw new ServiceException("数据库操作失败");
} catch (Exception e) {
// 捕获其他异常,做通用处理
log.error("批量添加光伏板点时发生未知错误,错误信息: {}", e.getMessage());
throw new ServiceException("批量添加光伏板点失败");
}
}
/**
* 批量删除设施-光伏板(桩点、立柱、支架)内部方法
*
* @param pointList 桩点列表
* @param columnList 立柱列表
* @param supportList 支架列表
*/
@Override
public void batchDeletePartsInner(List<FacPhotovoltaicPanelPoint> pointList,
List<FacPhotovoltaicPanelColumn> columnList,
List<FacPhotovoltaicPanelSupport> supportList) {
try {
if (CollUtil.isNotEmpty(pointList)) {
boolean result = photovoltaicPanelPointService.removeBatchByIds(pointList);
if (!result) {
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(columnList)) {
boolean result = photovoltaicPanelColumnService.removeBatchByIds(columnList);
if (!result) {
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(supportList)) {
boolean result = photovoltaicPanelSupportService.removeBatchByIds(supportList);
if (!result) {
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
}
}
} catch (DataIntegrityViolationException e) {
log.error("数据库唯一键冲突或违反其他完整性约束: {}", e.getMessage());
throw new ServiceException("数据已存在,无法重复添加");
} catch (DataAccessException e) {
log.error("数据库连接问题、事务问题等导致操作失败: {}", e.getMessage());
throw new ServiceException("数据库操作失败");
} catch (Exception e) {
// 捕获其他异常,做通用处理
log.error("批量删除光伏板点时发生未知错误,错误信息: {}", e.getMessage());
throw new ServiceException("批量添加光伏板点失败");
}
}
/**
* 批量新增设施-光伏板(桩点、立柱、支架)
*

View File

@ -13,7 +13,6 @@ import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.facility.domain.FacMatrix;
import org.dromara.facility.domain.FacPhotovoltaicPanel;
import org.dromara.facility.domain.req.geojson.FeatureByPlane;
import org.dromara.facility.domain.req.geojson.FeatureByPoint;
@ -37,6 +36,9 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 设施-光伏板Service业务层处理
@ -146,11 +148,22 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
List<FacMatrix> matrixList = matrixService.lambdaQuery()
// todo 获取项目下方阵信息
/* List<FacMatrix> matrixList = matrixService.lambdaQuery()
.eq(FacMatrix::getProjectId, projectId).list();
if (CollUtil.isEmpty(matrixList)) {
throw new ServiceException("项目下无方阵数据,请先创建方阵消息后再添加光伏板信息", HttpStatus.NOT_FOUND);
}
}*/
// 获取当下项目下光伏板的信息
List<FacPhotovoltaicPanel> oldPhotovoltaicPanelList = this.lambdaQuery()
.eq(FacPhotovoltaicPanel::getProjectId, projectId).list();
Map<String, FacPhotovoltaicPanel> photovoltaicPanelMap = oldPhotovoltaicPanelList.stream()
.collect(Collectors.toMap(
FacPhotovoltaicPanel::getName,
Function.identity(),
(existing, replacement) -> existing // 如果有重复,保留第一个
));
// 获取数据库中光伏板信息
List<FacPhotovoltaicPanel> photovoltaicPanelList = new ArrayList<>();
List<FeatureByPlane> locationFeatures = geoJson.getLocationGeoJson().getFeatures();
List<FeatureByPoint> nameFeatures = geoJson.getNameGeoJson().getFeatures();
@ -158,8 +171,8 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
FacPhotovoltaicPanel photovoltaicPanel = new FacPhotovoltaicPanel();
GeometryByPlane geometry = locationFeature.getGeometry();
List<List<Double>> coordinates = geometry.getCoordinates().get(0);
// 判断光伏板在哪个方阵里
Long matrixId = null;
// todo 判断光伏板在哪个方阵里
/* Long matrixId = null;
for (FacMatrix matrix : matrixList) {
String positions = matrix.getPositions();
List<List<Double>> positionList = new ArrayList<>();
@ -176,7 +189,8 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
if (matrixId == null) {
continue;
}
photovoltaicPanel.setMatrixId(matrixId);
photovoltaicPanel.setMatrixId(matrixId);*/
photovoltaicPanel.setMatrixId(1L);
// 获取光伏板名称
String name = null;
for (FeatureByPoint nameFeature : nameFeatures) {
@ -193,12 +207,28 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
photovoltaicPanel.setName(name);
photovoltaicPanel.setProjectId(projectId);
photovoltaicPanel.setPositions(JSONUtil.toJsonStr(coordinates));
// 如果有同名光伏板,则获取该光伏板的完成状态
if (CollUtil.isNotEmpty(photovoltaicPanelMap) && photovoltaicPanelMap.containsKey(name)) {
FacPhotovoltaicPanel oldPhotovoltaicPanel = photovoltaicPanelMap.get(name);
photovoltaicPanel.setFinishType(oldPhotovoltaicPanel.getFinishType());
photovoltaicPanel.setStatus(oldPhotovoltaicPanel.getStatus());
}
photovoltaicPanelList.add(photovoltaicPanel);
}
// 操作数据库,批量保存
boolean save = this.saveBatch(photovoltaicPanelList);
if (!save) {
throw new ServiceException("新增光伏板失败,数据库异常", HttpStatus.ERROR);
// 操作数据库
// 删除旧数据
if (CollUtil.isNotEmpty(oldPhotovoltaicPanelList)) {
boolean result = this.removeBatchByIds(oldPhotovoltaicPanelList);
if (!result) {
throw new ServiceException("数据库操作失败", HttpStatus.ERROR);
}
}
// 批量保存
if (CollUtil.isNotEmpty(photovoltaicPanelList)) {
boolean save = this.saveBatch(photovoltaicPanelList);
if (!save) {
throw new ServiceException("新增光伏板失败,数据库异常", HttpStatus.ERROR);
}
}
return true;
}

View File

@ -101,8 +101,8 @@ public class BusProjectFileController extends BaseController {
*/
@Log(title = "项目文件存储", businessType = BusinessType.IMPORT)
@PostMapping("/upload/dxf")
public R<Void> uploadDxf2Json(@RequestParam("file") MultipartFile file, ProjectFileUploadDxfReq req) {
return toAjax(busProjectFileService.uploadDxf2Json(file, req));
public R<Long> uploadDxf2Json(@RequestParam("file") MultipartFile file, ProjectFileUploadDxfReq req) {
return R.ok(busProjectFileService.uploadDxf2Json(file, req));
}
/**

View File

@ -25,11 +25,6 @@ public class ProjectFileUpdateReq implements Serializable {
*/
private Long projectId;
/**
* 文件类型
*/
private String fileType;
/**
* 文件名称
*/

View File

@ -81,7 +81,7 @@ public interface IBusProjectFileService extends IService<BusProjectFile> {
* @param req 请求
* @return 主键
*/
Boolean uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req);
Long uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req);
/**
* 获取项目文件存储视图对象

View File

@ -3,6 +3,7 @@ package org.dromara.project.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -64,7 +65,7 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
@Resource
private ScheduledExecutorService scheduledExecutorService;
private static final ConcurrentHashMap<Long, Boolean> USER_TASK_RUNNING = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, Boolean> USER_TASK_RUNNING = new ConcurrentHashMap<>();
/**
* 查询项目文件存储
@ -118,7 +119,7 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
BusProjectFile projectFile = new BusProjectFile();
BeanUtils.copyProperties(req, projectFile);
// 数据校验
validEntityBeforeSave(projectFile, false);
validEntityBeforeSave(projectFile);
// 判断是否存在
BusProjectFile oldProjectFile = this.getById(projectFile.getId());
if (oldProjectFile == null) {
@ -135,15 +136,13 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(BusProjectFile entity, Boolean create) {
private void validEntityBeforeSave(BusProjectFile entity) {
// TODO 做一些数据校验,如唯一约束
Long projectId = entity.getProjectId();
if (create) {
if (projectId == null) {
throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST);
}
if (projectId == null) {
throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST);
}
if (projectId != null && projectService.getById(projectId) == null) {
if (projectService.getById(projectId) == null) {
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);
}
}
@ -157,8 +156,12 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
Long userId = LoginHelper.getUserId();
List<BusProjectFile> projectFileList = this.listByIds(ids);
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
List<Long> projectId = projectFileList.stream().map(BusProjectFile::getProjectId).toList();
projectService.validAuth(projectId, userId);
}
return baseMapper.deleteByIds(ids) > 0;
}
@ -175,6 +178,15 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
if (projectFile == null) {
throw new ServiceException("对应项目文件存储信息不存在", HttpStatus.NOT_FOUND);
}
Long userId = LoginHelper.getUserId();
// 获取当前登录用户key值
String string = String.valueOf(userId + projectFile.getProjectId());
String md5 = MD5.create().digestHex16(string);
// 判断当前用户是否已经有一个正在处理的任务
Boolean alreadyRunning = USER_TASK_RUNNING.get(md5);
if (alreadyRunning != null && alreadyRunning) {
throw new ServiceException("正在转换,请稍后重试", HttpStatus.CONFLICT);
}
String filePath = projectFile.getFilePath();
String suffix = FileUtil.getSuffix(FileUtil.getName(filePath));
if (!suffix.equals(DesignMapFileConstant.JSONFileSuffix)) {
@ -201,10 +213,13 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req) {
public Long uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req) {
Long userId = LoginHelper.getUserId();
// 获取当前登录用户key值
String string = String.valueOf(userId + req.getProjectId());
String md5 = MD5.create().digestHex16(string);
// 判断当前用户是否已经有一个正在处理的任务
Boolean alreadyRunning = USER_TASK_RUNNING.putIfAbsent(userId, true);
Boolean alreadyRunning = USER_TASK_RUNNING.putIfAbsent(md5, true);
if (alreadyRunning != null && alreadyRunning) {
throw new ServiceException("当前有一个正在处理的转换任务,请等待完成后再上传", HttpStatus.CONFLICT);
}
@ -228,10 +243,11 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
String projectRoot = System.getProperty("user.dir");
String bashPath = DesignMapFileConstant.getDxfProjectPath(projectId);
String filePath = projectRoot + File.separator + bashPath;
String uuid = IdUtil.fastSimpleUUID();
if (!FileUtil.exist(filePath)) {
FileUtil.mkdir(filePath);
}
String inputDXFPath = filePath + File.separator + fileName;
String inputDXFPath = filePath + File.separator + uuid + "." + suffix;
try {
// 保存文件
File savedFile = new File(inputDXFPath);
@ -240,7 +256,6 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
throw new ServiceException("dxf 文件保存失败");
}
// 构造 JSON 输出路径
String uuid = IdUtil.fastSimpleUUID();
String outputJSONPath = filePath + File.separator + uuid + "." + DesignMapFileConstant.JSONFileSuffix;
// 获取 dxf2json.exe 路径
String exePath = projectRoot + File.separator + DesignMapFileConstant.DXF_BASE_PATH + File.separator + "main.exe";
@ -249,50 +264,66 @@ public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper,
BusProjectFile oldProjectFile = this.lambdaQuery()
.eq(BusProjectFile::getProjectId, projectId)
.one();
Long projectFileId;
String dxfFilePath = bashPath + File.separator + uuid + "." + suffix;
if (oldProjectFile != null) {
// 删除之前的文件
try {
FileUtil.del(projectRoot + File.separator + oldProjectFile.getFilePath());
FileUtil.del(projectRoot + File.separator + oldProjectFile.getRemark());
} catch (Exception e) {
log.error("删除项目文件失败", e);
}
projectFileId = oldProjectFile.getId();
BusProjectFile projectFile = new BusProjectFile();
projectFile.setId(projectFileId);
projectFile.setFileName(fileName);
projectFile.setRemark(dxfFilePath);
boolean result = this.updateById(projectFile);
if (!result) {
throw new ServiceException("数据库更新异常");
}
} else {
BusProjectFile projectFile = new BusProjectFile();
projectFile.setProjectId(projectId);
projectFile.setFileName(fileName);
projectFile.setRemark(dxfFilePath);
boolean save = this.save(projectFile);
if (!save) {
throw new ServiceException("数据库插入异常");
}
projectFileId = projectFile.getId();
}
SseMessageDto messageDto = new SseMessageDto();
messageDto.setMessage("DXF 文件上传成功,正在转换中......");
messageDto.setUserIds(List.of(userId));
SseMessageUtils.publishMessage(messageDto);
scheduledExecutorService.execute(() -> {
try {
// 构造命令行参数
Dxf2JsonUtils.dxf2json(exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG);
String jsonFilePath = bashPath + File.separator + uuid + "." + DesignMapFileConstant.JSONFileSuffix;
String jsonFileName = FileUtil.getPrefix(fileName) + "." + DesignMapFileConstant.JSONFileSuffix;
// 修改数据库信息
BusProjectFile projectFile = new BusProjectFile();
if (oldProjectFile != null) {
projectFile.setId(oldProjectFile.getId());
projectFile.setFileName(jsonFileName);
projectFile.setFilePath(jsonFilePath);
boolean update = this.updateById(projectFile);
if (!update) throw new ServiceException("数据库修改异常");
} else {
projectFile.setProjectId(projectId);
projectFile.setFileName(jsonFileName);
projectFile.setFilePath(jsonFilePath);
boolean save = this.save(projectFile);
if (!save) throw new ServiceException("数据库新增异常");
}
SseMessageDto dto = new SseMessageDto();
dto.setMessage("DXF 文件转换成 GeoJSON 成功");
dto.setUserIds(List.of(userId));
SseMessageUtils.publishMessage(dto);
projectFile.setId(projectFileId);
projectFile.setFilePath(jsonFilePath);
projectFile.setFileName(jsonFileName);
projectFile.setFileType(DesignMapFileConstant.JSONFileSuffix);
boolean update = this.updateById(projectFile);
if (!update) throw new ServiceException("数据库修改异常");
messageDto.setMessage("DXF 文件转换成 GeoJSON 成功");
SseMessageUtils.publishMessage(messageDto);
} catch (Exception e) {
log.error("DXF 转换失败", e);
SseMessageDto dto = new SseMessageDto();
dto.setMessage("DXF 文件转换失败,请联系管理员处理");
dto.setUserIds(List.of(userId));
SseMessageUtils.publishMessage(dto);
messageDto.setMessage("DXF 文件转换失败,请联系管理员处理");
SseMessageUtils.publishMessage(messageDto);
} finally {
// 无论成功或失败都释放状态
USER_TASK_RUNNING.remove(userId);
USER_TASK_RUNNING.remove(md5);
}
});
return true;
return projectFileId;
}
/**

View File

@ -59,14 +59,6 @@ public class Dxf2JsonUtils {
reader.close();
} catch (IOException | InterruptedException e) {
log.error("执行 dxf 转 json 命令行时出错", e);
}finally {
// 删除dxf文件
if (inputDXFFile.exists()) {
boolean delete = inputDXFFile.delete();
if (!delete) {
log.error("dxf文件删除失败路径{}", inputDXFPath);
}
}
}
}