dev #2

Merged
dashixiong merged 349 commits from dev into main 2026-02-11 01:55:46 +00:00
334 changed files with 47419 additions and 1113 deletions
Showing only changes of commit d9c0ff733a - Show all commits

View File

@ -2,10 +2,13 @@ package com.xzzn.web.controller.ems;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xzzn.common.annotation.Log;
@ -13,6 +16,8 @@ import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult;
import com.xzzn.common.enums.BusinessType;
import com.xzzn.ems.domain.EmsPointMatch;
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
import com.xzzn.ems.service.IEmsPointMatchService;
import com.xzzn.common.utils.poi.ExcelUtil;
import org.springframework.web.multipart.MultipartFile;
@ -62,4 +67,21 @@ public class EmsPointMatchController extends BaseController
return success(message);
}
/**
* 上传设备的点位清单
* @param request
* @return
* @throws Exception
*/
@PreAuthorize("@ss.hasPermi('system:user:import')")
@Log(title = "点位匹配", businessType = BusinessType.IMPORT)
@PostMapping("/importDataByDevice")
public void importDataByDevice(@Valid ImportPointDataRequest request, HttpServletResponse response) {
List<DevicePointMatchVo> list = emsPointMatchService.importDataByDevice(request, getUsername());
if (CollectionUtils.isNotEmpty(list)) {
ExcelUtil<DevicePointMatchVo> util = new ExcelUtil<>(DevicePointMatchVo.class);
util.exportExcel(response, list, "点位匹配数据");
}
}
}

View File

@ -62,6 +62,11 @@ public class RedisKeyConstants
*/
public static final String COOLING = "COOLING_";
/**
* 点位匹配数据 redis key
*/
public static final String POINT_MATCH = "POINT_MATCH_";
/**
* 存放单个设备同步过来的原始数据-最晚一次数据
*/

View File

@ -70,6 +70,10 @@ public class EmsPointMatch extends BaseEntity
@Excel(name = "点位是否需要区分多设备0-不需要 1-需要")
private Long needDiffDeviceId;
/** 设备唯一标识符 */
@Excel(name = "设备唯一标识符")
private String deviceId;
public void setId(Long id)
{
this.id = id;
@ -208,6 +212,14 @@ public class EmsPointMatch extends BaseEntity
return needDiffDeviceId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -230,6 +242,7 @@ public class EmsPointMatch extends BaseEntity
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.append("deviceId", getDeviceId())
.toString();
}
}

View File

@ -0,0 +1,96 @@
package com.xzzn.ems.domain.vo;
import com.xzzn.common.annotation.Excel;
import java.io.Serializable;
/**
* 点位清单上传参数
*/
public class DevicePointMatchVo implements Serializable {
private static final long serialVersionUID = 1L;
/** 点位匹配字段 */
@Excel(name = "点位匹配字段")
private String matchField;
/** 数据点位 */
@Excel(name = "数据点位")
private String dataPoint;
/** 数据点位名称 */
@Excel(name = "数据点位名称")
private String dataPointName;
/** 数据单位 */
@Excel(name = "数据单位")
private String dataUnit;
//
// /** 数据点位来源设备 */
// @Excel(name = "数据点位来源设备")
// private String dataDevice;
/** 寄存器地址 */
@Excel(name = "寄存器地址")
private String ipAddress;
/** 错误信息 */
@Excel(name = "错误信息")
private String errorMsg;
public String getMatchField() {
return matchField;
}
public void setMatchField(String matchField) {
this.matchField = matchField;
}
public String getDataPoint() {
return dataPoint;
}
public void setDataPoint(String dataPoint) {
this.dataPoint = dataPoint;
}
public String getDataPointName() {
return dataPointName;
}
public void setDataPointName(String dataPointName) {
this.dataPointName = dataPointName;
}
public String getDataUnit() {
return dataUnit;
}
public void setDataUnit(String dataUnit) {
this.dataUnit = dataUnit;
}
// public String getDataDevice() {
// return dataDevice;
// }
//
// public void setDataDevice(String dataDevice) {
// this.dataDevice = dataDevice;
// }
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}

View File

@ -0,0 +1,61 @@
package com.xzzn.ems.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.springframework.web.multipart.MultipartFile;
/**
* 上传设备点位清单请求参数
*/
public class ImportPointDataRequest {
/** 站点id */
@NotBlank(message = "站点ID不能为空")
private String siteId;
/** 设备id */
@NotBlank(message = "设备ID不能为空")
private String deviceId;
/** 设备类型 */
@NotBlank(message = "设备类型不能为空")
private String deviceCategory;
/** 上传点位清单文件 */
@NotNull(message = "点位清单文件不能为空")
private MultipartFile file;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDeviceCategory() {
return deviceCategory;
}
public void setDeviceCategory(String deviceCategory) {
this.deviceCategory = deviceCategory;
}
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
}

View File

@ -0,0 +1,82 @@
package com.xzzn.ems.enums;
import com.xzzn.ems.domain.EmsAmmeterData;
import com.xzzn.ems.domain.EmsBatteryCluster;
import com.xzzn.ems.domain.EmsBatteryData;
import com.xzzn.ems.domain.EmsBatteryGroup;
import com.xzzn.ems.domain.EmsBatteryStack;
import com.xzzn.ems.domain.EmsCoolingData;
import com.xzzn.ems.domain.EmsPcsBranchData;
import com.xzzn.ems.domain.EmsPcsData;
import com.xzzn.ems.domain.EmsXfData;
import java.util.HashMap;
import java.util.Map;
/**
* 设备匹配表枚举类
*/
public enum DeviceMatchTable
{
PCS("PCS", "ems_pcs_data", EmsPcsData.class),
BRANCH("BRANCH", "ems_pcs_branch_data", EmsPcsBranchData.class),
STACK("STACK", "ems_battery_stack", EmsBatteryStack.class),
CLUSTER("CLUSTER", "ems_battery_cluster", EmsBatteryCluster.class),
BATTERY("BATTERY", "ems_battery_data", EmsBatteryData.class),
AMMETER("AMMETER", "ems_ammeter_data", EmsAmmeterData.class),
COOLING("COOLING", "ems_cooling_data", EmsCoolingData.class),
DH("DH", "ems_dh_data", EmsBatteryData.class),
XF("XF", "ems_xf_data", EmsXfData.class),
BATTERY_GROUP("BATTERY_GROUP", "ems_battery_group", EmsBatteryGroup.class);
private final String code;
private final String matchTable;
private final Class<?> matchTableClass;
DeviceMatchTable(String code, String matchTable, Class<?> matchTableClass)
{
this.code = code;
this.matchTable = matchTable;
this.matchTableClass = matchTableClass;
}
public String getCode()
{
return code;
}
public String getMatchTable() {
return matchTable;
}
public Class<?> getMatchTableClass() {
return matchTableClass;
}
// 缓存code与matchTable的映射优化查询效率
private static final Map<String, String> DEVICE_MATCH_TABLE_MAP = new HashMap<>();
// 缓存table与实体类的映射优化查询效率
private static final Map<String, Class<?>> TABLE_TO_CLASS_MAP = new HashMap<>();
// 静态块初始化缓存
static {
for (DeviceMatchTable category : DeviceMatchTable.values()) {
DEVICE_MATCH_TABLE_MAP.put(category.code, category.matchTable);
TABLE_TO_CLASS_MAP.put(category.matchTable, category.matchTableClass);
}
}
// 通过code获取matchTable的方法
public static String getMatchTableByCode(String code) {
return DEVICE_MATCH_TABLE_MAP.get(code); // 从缓存中直接获取,效率高
}
// 通过table获取实体类的方法
public static Class<?> getClassByTable(String matchTable) {
return TABLE_TO_CLASS_MAP.get(matchTable); // 从缓存中直接获取,效率高
}
}

View File

@ -140,4 +140,8 @@ public interface EmsPointMatchMapper
// 根据站点,设备类别,点位,获取唯一数据
public EmsPointMatch getUniquePoint(@Param("siteId")String siteId, @Param("deviceCategory")String deviceCategory, @Param("dataPoint")String dataPoint);
EmsPointMatch getOnePointMatch(@Param("siteId") String siteId, @Param("deviceId") String deviceId, @Param("deviceCategory") String deviceCategory, @Param("dataPoint") String dataPoint);
List<EmsPointMatch> getDevicePointMatchList(@Param("siteId") String siteId, @Param("deviceId") String deviceId, @Param("deviceCategory") String deviceCategory);
}

View File

@ -3,6 +3,8 @@ package com.xzzn.ems.service;
import java.util.List;
import com.xzzn.ems.domain.EmsPointMatch;
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
/**
* 点位匹配Service接口
@ -29,4 +31,6 @@ public interface IEmsPointMatchService
* @return
*/
public String importPoint(List<EmsPointMatch> userList, boolean updateSupport, String operName);
public List<DevicePointMatchVo> importDataByDevice(ImportPointDataRequest request, String operName);
}

View File

@ -1,15 +1,33 @@
package com.xzzn.ems.service.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson2.JSON;
import com.xzzn.common.constant.RedisKeyConstants;
import com.xzzn.common.core.redis.RedisCache;
import com.xzzn.common.exception.ServiceException;
import com.xzzn.common.utils.StringUtils;
import com.xzzn.common.utils.bean.BeanValidators;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import com.xzzn.common.utils.poi.ExcelUtil;
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
import com.xzzn.ems.enums.DeviceMatchTable;
import com.xzzn.ems.mapper.EmsPointMatchMapper;
import com.xzzn.ems.domain.EmsPointMatch;
import com.xzzn.ems.service.IEmsPointMatchService;
import com.xzzn.ems.utils.MatchTableUtils;
import javax.validation.Validator;
@ -22,10 +40,13 @@ import javax.validation.Validator;
@Service
public class EmsPointMatchServiceImpl implements IEmsPointMatchService
{
private static final Logger log = LoggerFactory.getLogger(EmsPointMatchServiceImpl.class);
@Autowired
private EmsPointMatchMapper emsPointMatchMapper;
@Autowired
protected Validator validator;
@Autowired
private RedisCache redisCache;
/**
* 查询点位匹配列表
@ -92,5 +113,89 @@ public class EmsPointMatchServiceImpl implements IEmsPointMatchService
return successMsg.toString();
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<DevicePointMatchVo> importDataByDevice(ImportPointDataRequest request, String operName) {
ExcelUtil<DevicePointMatchVo> util = new ExcelUtil<>(DevicePointMatchVo.class);
List<DevicePointMatchVo> pointMatchList = new ArrayList<>();
MultipartFile file = request.getFile();
if (file.isEmpty()) {
throw new ServiceException("点位清单文件不能为空");
}
try {
pointMatchList = util.importExcel(file.getInputStream());
} catch (IOException e) {
log.info("点位清单导入失败:{}", e.getMessage());
throw new ServiceException("点位清单导入失败!");
}
if (CollectionUtils.isEmpty(pointMatchList)) {
throw new ServiceException("导入用户数据不能为空!");
}
String siteId = request.getSiteId();
String deviceId = request.getDeviceId();
String deviceCategory = request.getDeviceCategory();
List<DevicePointMatchVo> errorList = new ArrayList<>();
for (DevicePointMatchVo pointMatch : pointMatchList) {
try {
//校验点位清单文件内容
if (validDevicePointMatch(pointMatch, errorList)) {
continue;
}
EmsPointMatch savePoint = new EmsPointMatch();
BeanUtils.copyProperties(pointMatch, savePoint);
savePoint.setSiteId(siteId);
savePoint.setDeviceId(deviceId);
savePoint.setDeviceCategory(deviceCategory);
savePoint.setMatchTable(DeviceMatchTable.getMatchTableByCode(deviceCategory));
savePoint.setPointName(MatchTableUtils.getFieldAnnotation(DeviceMatchTable.getClassByTable(savePoint.getMatchTable()), StringUtils.toCamelCase(savePoint.getMatchField())));
savePoint.setCreateBy(operName);
savePoint.setUpdateBy(operName);
// 验证点位是否存在
EmsPointMatch dbPoint = emsPointMatchMapper.getOnePointMatch(siteId, deviceId, deviceCategory, pointMatch.getDataPoint());
if (StringUtils.isNull(dbPoint)) {
emsPointMatchMapper.insertEmsPointMatch(savePoint);
} else {
emsPointMatchMapper.updateEmsPointMatch(savePoint);
}
} catch (Exception e) {
log.info("点位清单导入失败:{}", e.getMessage());
throw new ServiceException("点位清单导入失败!");
}
}
// 同步到Redis
syncToRedis(siteId, deviceId, deviceCategory);
return errorList;
}
private boolean validDevicePointMatch(DevicePointMatchVo pointMatch, List<DevicePointMatchVo> errorList) {
StringBuilder errorMsg = new StringBuilder();
if (StringUtils.isBlank(pointMatch.getMatchField())) {
errorMsg.append("点位匹配字段不能为空;");
}
if (StringUtils.isBlank(pointMatch.getDataPoint())) {
errorMsg.append("数据点位不能为空;");
}
if (StringUtils.isBlank(pointMatch.getDataPointName())) {
errorMsg.append("数据点位名称不能为空;");
}
// if (StringUtils.isBlank(pointMatch.getDataDevice())) {
// errorMsg.append("数据点位来源设备不能为空;");
// }
if (errorMsg.length() > 0) {
pointMatch.setErrorMsg(errorMsg.toString());
errorList.add(pointMatch);
return true;
}
return false;
}
private void syncToRedis(String siteId, String deviceId, String deviceCategory) {
// 同步到Redis
String pointMatchKey = RedisKeyConstants.POINT_MATCH + deviceCategory + "_" + siteId + "_" + deviceId;
List<EmsPointMatch> pointMatchData = emsPointMatchMapper.getDevicePointMatchList(siteId, deviceId, deviceCategory);
// log.info("同步点位匹配数据到Redis key:{} data:{}", pointMatchKey, pointMatchData);
redisCache.setCacheObject(pointMatchKey, pointMatchData);
log.info("点位匹配数据同步完成 data:{}", JSON.toJSONString(redisCache.getCacheObject(pointMatchKey)));
}
}

View File

@ -0,0 +1,33 @@
package com.xzzn.ems.utils;
import com.xzzn.common.annotation.Excel;
import com.xzzn.common.utils.StringUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 匹配表工具类
*/
public class MatchTableUtils {
/**
* 获取字段注解信息
*/
public static String getFieldAnnotation(Class<?> clazz, String filedName)
{
List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : tempFields) {
if (StringUtils.equals(filedName, field.getName()) && field.isAnnotationPresent(Excel.class))
{
Excel column = field.getAnnotation(Excel.class);
return column.name();
}
}
return null;
}
}

View File

@ -24,10 +24,11 @@
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<result property="deviceId" column="device_id" />
</resultMap>
<sql id="selectEmsPointMatchVo">
select id, point_name, match_table, match_field, site_id, device_category, data_point, data_point_name, data_device, data_unit, ip_address, ip_port, data_type, need_diff_device_id, create_by, create_time, update_by, update_time, remark from ems_point_match
select id, point_name, match_table, match_field, site_id, device_category, data_point, data_point_name, data_device, data_unit, ip_address, ip_port, data_type, need_diff_device_id, create_by, create_time, update_by, update_time, remark, device_id from ems_point_match
</sql>
<select id="selectEmsPointMatchList" parameterType="EmsPointMatch" resultMap="EmsPointMatchResult">
@ -75,6 +76,7 @@
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
<if test="deviceId != null">device_id,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="pointName != null">#{pointName},</if>
@ -95,6 +97,7 @@
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
<if test="deviceId != null">#{deviceId},</if>
</trim>
</insert>
@ -119,6 +122,7 @@
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="deviceId != null">device_id = #{deviceId},</if>
</trim>
where id = #{id}
</update>
@ -426,4 +430,20 @@
and device_category = #{deviceCategory}
and data_point = #{dataPoint}
</select>
<select id="getOnePointMatch" resultMap="EmsPointMatchResult">
<include refid="selectEmsPointMatchVo"/>
where site_id = #{siteId}
and device_category = #{deviceCategory}
and device_id = #{deviceId}
and data_point = #{dataPoint}
order by update_time desc
limit 1
</select>
<select id="getDevicePointMatchList" resultMap="EmsPointMatchResult">
<include refid="selectEmsPointMatchVo"/>
where site_id = #{siteId}
and device_category = #{deviceCategory}
and device_id = #{deviceId}
</select>
</mapper>