dev #2
@ -39,8 +39,9 @@
|
|||||||
|
|
||||||
<!-- Mysql驱动包 -->
|
<!-- Mysql驱动包 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
|
<version>8.0.33</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 核心模块-->
|
<!-- 核心模块-->
|
||||||
|
|||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.core.page.TableDataInfo;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsAlarmRecords;
|
||||||
|
import com.xzzn.ems.domain.vo.AlarmRecordListRequestVo;
|
||||||
|
import com.xzzn.ems.domain.vo.AlarmRecordListResponseVo;
|
||||||
|
import com.xzzn.ems.service.IEmsAlarmRecordsService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控-故障告警
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/siteAlarm")
|
||||||
|
public class EmsAlarmRecordsController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsAlarmRecordsService iEmsAlarmRecordsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取告警详情列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAlarmDetailList")
|
||||||
|
public TableDataInfo getAlarmDetailList(AlarmRecordListRequestVo requestVo)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<AlarmRecordListResponseVo> list = iEmsAlarmRecordsService.getAlarmRecordDetailList(requestVo);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成工单
|
||||||
|
*/
|
||||||
|
@PostMapping("/createTicketNo")
|
||||||
|
public AjaxResult createTicketNo(@RequestBody EmsAlarmRecords emsAlarmRecords)
|
||||||
|
{
|
||||||
|
Long id = emsAlarmRecords.getId();
|
||||||
|
if (id == null) {
|
||||||
|
return error("告警id不能为空");
|
||||||
|
}
|
||||||
|
String ticketNo= iEmsAlarmRecordsService.createTicketNo(id,getUserId());
|
||||||
|
if (StringUtils.isNotEmpty(ticketNo) && ticketNo.contains("T")) {
|
||||||
|
return AjaxResult.success("操作成功", ticketNo);
|
||||||
|
} else {
|
||||||
|
return error(ticketNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.vo.EnergyPriceVo;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.xzzn.common.annotation.Log;
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.enums.BusinessType;
|
||||||
|
import com.xzzn.ems.service.IEmsEnergyPriceConfigService;
|
||||||
|
import com.xzzn.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电价配置Controller
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-09-28
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/energyPriceConfig")
|
||||||
|
public class EmsEnergyPriceConfigController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IEmsEnergyPriceConfigService emsEnergyPriceConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询电价配置列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(String siteId, String startTime,String endTime)
|
||||||
|
{
|
||||||
|
List<EnergyPriceVo> list = emsEnergyPriceConfigService.selectEmsEnergyPriceConfigList(siteId,startTime,endTime);
|
||||||
|
return getDataTable2(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取电价配置详细信息
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||||
|
{
|
||||||
|
return success(emsEnergyPriceConfigService.selectEmsEnergyPriceConfigById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增电价配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:add')")
|
||||||
|
@Log(title = "电价配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody EnergyPriceVo priceVo)
|
||||||
|
{
|
||||||
|
return toAjax(emsEnergyPriceConfigService.insertEmsEnergyPriceConfig(priceVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改电价配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:edit')")
|
||||||
|
@Log(title = "电价配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody EnergyPriceVo priceVo)
|
||||||
|
{
|
||||||
|
return toAjax(emsEnergyPriceConfigService.updateEmsEnergyPriceConfig(priceVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除电价配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:remove')")
|
||||||
|
@Log(title = "电价配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(emsEnergyPriceConfigService.deleteEmsEnergyPriceConfigByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import com.xzzn.ems.service.IEmsFaultProtectionPlanService;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
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;
|
||||||
|
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.EmsFaultProtectionPlan;
|
||||||
|
import com.xzzn.common.utils.poi.ExcelUtil;
|
||||||
|
import com.xzzn.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 故障告警保护方案Controller
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-10-22
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/protectPlan")
|
||||||
|
public class EmsFaultProtectionPlanController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IEmsFaultProtectionPlanService emsFaultProtectionPlanService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询故障告警保护方案列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:plan:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(EmsFaultProtectionPlan emsFaultProtectionPlan)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<EmsFaultProtectionPlan> list = emsFaultProtectionPlanService.selectEmsFaultProtectionPlanList(emsFaultProtectionPlan);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出故障告警保护方案列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:plan:export')")
|
||||||
|
@Log(title = "故障告警保护方案", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, EmsFaultProtectionPlan emsFaultProtectionPlan)
|
||||||
|
{
|
||||||
|
List<EmsFaultProtectionPlan> list = emsFaultProtectionPlanService.selectEmsFaultProtectionPlanList(emsFaultProtectionPlan);
|
||||||
|
ExcelUtil<EmsFaultProtectionPlan> util = new ExcelUtil<EmsFaultProtectionPlan>(EmsFaultProtectionPlan.class);
|
||||||
|
util.exportExcel(response, list, "故障告警保护方案数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取故障告警保护方案详细信息
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:plan:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||||
|
{
|
||||||
|
return success(emsFaultProtectionPlanService.selectEmsFaultProtectionPlanById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增故障告警保护方案
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:plan:add')")
|
||||||
|
@Log(title = "故障告警保护方案", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody EmsFaultProtectionPlan emsFaultProtectionPlan)
|
||||||
|
{
|
||||||
|
emsFaultProtectionPlan.setCreateBy(getUsername());
|
||||||
|
return toAjax(emsFaultProtectionPlanService.insertEmsFaultProtectionPlan(emsFaultProtectionPlan));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改故障告警保护方案
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:plan:edit')")
|
||||||
|
@Log(title = "故障告警保护方案", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody EmsFaultProtectionPlan emsFaultProtectionPlan)
|
||||||
|
{
|
||||||
|
emsFaultProtectionPlan.setUpdateBy(getUsername());
|
||||||
|
return toAjax(emsFaultProtectionPlanService.updateEmsFaultProtectionPlan(emsFaultProtectionPlan));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除故障告警保护方案
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:plan:remove')")
|
||||||
|
@Log(title = "故障告警保护方案", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(emsFaultProtectionPlanService.deleteEmsFaultProtectionPlanByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.enums.DeviceCategory;
|
||||||
|
import com.xzzn.ems.domain.vo.*;
|
||||||
|
import com.xzzn.ems.service.IGeneralQueryService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 综合查询
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/generalQuery")
|
||||||
|
public class EmsGeneralQueryController extends BaseController{
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IGeneralQueryService iGeneralQueryService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备枚举
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAllDeviceCategory")
|
||||||
|
public AjaxResult getDeviceCategory()
|
||||||
|
{
|
||||||
|
// 获取所有枚举的信息
|
||||||
|
List<Map<String, String>> deviceCategoryList = new ArrayList<>();
|
||||||
|
for (DeviceCategory category : DeviceCategory.values()) {
|
||||||
|
Map<String, String> categoryMap = new HashMap<>();
|
||||||
|
categoryMap.put("name", category.getInfo());
|
||||||
|
categoryMap.put("code", category.getCode());
|
||||||
|
deviceCategoryList.add(categoryMap);
|
||||||
|
}
|
||||||
|
return success(deviceCategoryList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点位模糊查询
|
||||||
|
*/
|
||||||
|
@PostMapping("/pointFuzzyQuery")
|
||||||
|
public AjaxResult pointFuzzyQuery(@RequestBody PointNameRequest request)
|
||||||
|
{
|
||||||
|
return success(iGeneralQueryService.getPointNameList(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据点位查询点位数据变化
|
||||||
|
*/
|
||||||
|
@PostMapping("/getPointValueList")
|
||||||
|
public AjaxResult getPointValueList(@RequestBody PointNameRequest request)
|
||||||
|
{
|
||||||
|
List<GeneralQueryResponse> result = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
result = iGeneralQueryService.getPointValueList(request);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("<UNK>",e);
|
||||||
|
return error("报错请重试!");
|
||||||
|
}
|
||||||
|
return success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备枚举
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAllBatteryIdsBySites/{siteIds}")
|
||||||
|
public AjaxResult getAllBatteryIdsBySites(@PathVariable String[] siteIds)
|
||||||
|
{
|
||||||
|
return success(iGeneralQueryService.getAllBatteryIdsBySites(siteIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -34,9 +34,13 @@ public class EmsHomePageController extends BaseController{
|
|||||||
* 首页看板数据
|
* 首页看板数据
|
||||||
*/
|
*/
|
||||||
@GetMapping("/dataList")
|
@GetMapping("/dataList")
|
||||||
public AjaxResult list()
|
public AjaxResult list() throws Exception
|
||||||
{
|
{
|
||||||
return success(homePageService.getHomePageDataList());
|
try {
|
||||||
|
return success(homePageService.getHomePageDataList());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return error(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,106 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
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;
|
||||||
|
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.EmsMqttTopicConfig;
|
||||||
|
import com.xzzn.ems.service.IEmsMqttTopicConfigService;
|
||||||
|
import com.xzzn.common.utils.poi.ExcelUtil;
|
||||||
|
import com.xzzn.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 站点topic配置Controller
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-11-06
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/mqttConfig")
|
||||||
|
public class EmsMqttTopicConfigController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IEmsMqttTopicConfigService emsMqttTopicConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询站点topic配置列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(EmsMqttTopicConfig emsMqttTopicConfig)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<EmsMqttTopicConfig> list = emsMqttTopicConfigService.selectEmsMqttTopicConfigList(emsMqttTopicConfig);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出站点topic配置列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:export')")
|
||||||
|
@Log(title = "站点topic配置", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, EmsMqttTopicConfig emsMqttTopicConfig)
|
||||||
|
{
|
||||||
|
List<EmsMqttTopicConfig> list = emsMqttTopicConfigService.selectEmsMqttTopicConfigList(emsMqttTopicConfig);
|
||||||
|
ExcelUtil<EmsMqttTopicConfig> util = new ExcelUtil<EmsMqttTopicConfig>(EmsMqttTopicConfig.class);
|
||||||
|
util.exportExcel(response, list, "站点topic配置数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取站点topic配置详细信息
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||||
|
{
|
||||||
|
return success(emsMqttTopicConfigService.selectEmsMqttTopicConfigById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增站点topic配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:add')")
|
||||||
|
@Log(title = "站点topic配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody EmsMqttTopicConfig emsMqttTopicConfig)
|
||||||
|
{
|
||||||
|
emsMqttTopicConfig.setCreateBy(getUsername());
|
||||||
|
return toAjax(emsMqttTopicConfigService.insertEmsMqttTopicConfig(emsMqttTopicConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改站点topic配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:edit')")
|
||||||
|
@Log(title = "站点topic配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody EmsMqttTopicConfig emsMqttTopicConfig)
|
||||||
|
{
|
||||||
|
emsMqttTopicConfig.setUpdateBy(getUsername());
|
||||||
|
return toAjax(emsMqttTopicConfigService.updateEmsMqttTopicConfig(emsMqttTopicConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除站点topic配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:remove')")
|
||||||
|
@Log(title = "站点topic配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(emsMqttTopicConfigService.deleteEmsMqttTopicConfigByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
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;
|
||||||
|
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.DevicePointMatchExportVo;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点位匹配Controller
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-11-04
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/pointMatch")
|
||||||
|
public class EmsPointMatchController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IEmsPointMatchService emsPointMatchService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出点位匹配列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:match:export')")
|
||||||
|
@Log(title = "点位匹配", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, EmsPointMatch emsPointMatch)
|
||||||
|
{
|
||||||
|
List<DevicePointMatchExportVo> list = emsPointMatchService.selectEmsPointMatchList(emsPointMatch);
|
||||||
|
ExcelUtil<DevicePointMatchExportVo> util = new ExcelUtil<>(DevicePointMatchExportVo.class);
|
||||||
|
util.exportExcel(response, list, "点位匹配数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传点位清单
|
||||||
|
* @param file
|
||||||
|
* @param updateSupport
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:user:import')")
|
||||||
|
@Log(title = "点位匹配", businessType = BusinessType.IMPORT)
|
||||||
|
@PostMapping("/importData")
|
||||||
|
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
|
||||||
|
{
|
||||||
|
ExcelUtil<EmsPointMatch> util = new ExcelUtil<EmsPointMatch>(EmsPointMatch.class);
|
||||||
|
List<EmsPointMatch> pointMatcheList = util.importExcel(file.getInputStream());
|
||||||
|
String operName = getUsername();
|
||||||
|
String message = emsPointMatchService.importPoint(pointMatcheList, updateSupport, operName);
|
||||||
|
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, "点位匹配数据");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,205 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.common.annotation.Log;
|
||||||
|
import com.xzzn.common.config.RuoYiConfig;
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.core.page.TableDataInfo;
|
||||||
|
import com.xzzn.common.enums.BusinessType;
|
||||||
|
import com.xzzn.common.utils.file.FileUploadUtils;
|
||||||
|
import com.xzzn.common.utils.file.MimeTypeUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsSiteSetting;
|
||||||
|
import com.xzzn.ems.domain.vo.DeviceUpdateRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.DevicesSettingVo;
|
||||||
|
import com.xzzn.ems.domain.vo.PointDataRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointQueryResponse;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteDeviceListVo;
|
||||||
|
import com.xzzn.ems.service.IEmsDeviceSettingService;
|
||||||
|
import com.xzzn.ems.service.IEmsSiteService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
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.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 站点配置
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/siteConfig")
|
||||||
|
public class EmsSiteConfigController extends BaseController{
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsSiteService iEmsSiteService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsDeviceSettingService iEmsDeviceSettingService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取站点列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/getSiteInfoList")
|
||||||
|
public TableDataInfo getSiteInfoList(@RequestParam String siteName, @RequestParam String startTime, @RequestParam String endTime)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<EmsSiteSetting> list = iEmsSiteService.getAllSiteInfoList(siteName,startTime,endTime);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备列表-分页
|
||||||
|
*/
|
||||||
|
@GetMapping("/getDeviceInfoList")
|
||||||
|
public TableDataInfo getDeviceInfoList(@RequestParam(value = "siteId", required = false) String siteId,
|
||||||
|
@RequestParam(value = "deviceCategory", required = false) String deviceCategory)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<SiteDeviceListVo> list = iEmsSiteService.getAllDeviceListNoDisp(siteId, deviceCategory);
|
||||||
|
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备详细信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/getDeviceDetailInfo")
|
||||||
|
public AjaxResult getDeviceDetailInfo(@RequestParam Long id)
|
||||||
|
{
|
||||||
|
return success(iEmsDeviceSettingService.getDeviceDetailInfo(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备列表-不分页
|
||||||
|
*/
|
||||||
|
@GetMapping("/getDeviceList")
|
||||||
|
public AjaxResult getDeviceInfoList2(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iEmsSiteService.getAllDeviceList(siteId, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有设备类别
|
||||||
|
*/
|
||||||
|
@GetMapping("/getDeviceCategory")
|
||||||
|
public AjaxResult getDeviceCategory()
|
||||||
|
{
|
||||||
|
return success(iEmsDeviceSettingService.getDeviceCategory());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增设备
|
||||||
|
*/
|
||||||
|
@PostMapping("/addDevice")
|
||||||
|
public AjaxResult addDevice(@RequestBody DevicesSettingVo devicesSetting)
|
||||||
|
{
|
||||||
|
int result = iEmsDeviceSettingService.addDevice(devicesSetting);
|
||||||
|
if (result > 0) {
|
||||||
|
return AjaxResult.success(result);
|
||||||
|
} else {
|
||||||
|
return AjaxResult.error("该设备已存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传设备图片
|
||||||
|
*/
|
||||||
|
@PostMapping("/uploadDeviceImg")
|
||||||
|
public AjaxResult uploadDeviceImg(@RequestParam("avatarfile") MultipartFile file) throws Exception
|
||||||
|
{
|
||||||
|
if (!file.isEmpty()) {
|
||||||
|
String avatar = FileUploadUtils.upload(RuoYiConfig.getDevicePath(), file, MimeTypeUtils.IMAGE_EXTENSION);
|
||||||
|
|
||||||
|
AjaxResult ajax = AjaxResult.success();
|
||||||
|
ajax.put("imgUrl", avatar);
|
||||||
|
return ajax;
|
||||||
|
}
|
||||||
|
return error("上传图片异常,请联系管理员");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改Modbus设备配置
|
||||||
|
*/
|
||||||
|
@PostMapping("/updateDevice")
|
||||||
|
public AjaxResult updateDevice(@RequestBody DevicesSettingVo emsDevicesSetting)
|
||||||
|
{
|
||||||
|
int result = iEmsDeviceSettingService.updateDevice(emsDevicesSetting);
|
||||||
|
if (result > 0) {
|
||||||
|
return AjaxResult.success(result);
|
||||||
|
} else if (result == -1) {
|
||||||
|
return AjaxResult.error("数据不存在");
|
||||||
|
} else if (result == -2) {
|
||||||
|
return AjaxResult.error("该设备已存在");
|
||||||
|
}
|
||||||
|
return AjaxResult.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Modbus设备配置
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/deleteService/{id}")
|
||||||
|
public AjaxResult deleteService(@PathVariable Long id)
|
||||||
|
{
|
||||||
|
return toAjax(iEmsDeviceSettingService.deleteEmsDevicesSettingById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单个站点单个设备点位查询-点位清单
|
||||||
|
*/
|
||||||
|
@GetMapping("/getDevicePointList")
|
||||||
|
public TableDataInfo getDevicePointList(@Validated PointDataRequest request)
|
||||||
|
{
|
||||||
|
List<PointQueryResponse> result = iEmsDeviceSettingService.getSingleSiteDevicePoints(request);
|
||||||
|
return getDataTable2(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定站点下的所有设备类别
|
||||||
|
*/
|
||||||
|
@GetMapping("/getSiteAllDeviceCategory")
|
||||||
|
public AjaxResult getSiteAllDeviceCategory(String siteId)
|
||||||
|
{
|
||||||
|
return success(iEmsDeviceSettingService.getSiteAllDeviceCategory(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备类别获取父类的设备id
|
||||||
|
*/
|
||||||
|
@GetMapping("/getParentDeviceId")
|
||||||
|
public AjaxResult getParentDeviceId(@RequestParam String siteId, @RequestParam String deviceCategory)
|
||||||
|
{
|
||||||
|
return success(iEmsSiteService.getParentCategoryDeviceId(siteId, deviceCategory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定站点下的指定设备类型的设备
|
||||||
|
*/
|
||||||
|
@GetMapping("/getDeviceListBySiteAndCategory")
|
||||||
|
public AjaxResult getDeviceListBySiteAndCategory(String siteId,String deviceCategory)
|
||||||
|
{
|
||||||
|
return success(iEmsDeviceSettingService.getDeviceListBySiteAndCategory(siteId, deviceCategory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PCS设备开关机
|
||||||
|
*/
|
||||||
|
// @PreAuthorize("@ss.hasPermi('system:device:onAndOff')")
|
||||||
|
@Log(title = "开关机", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/updateDeviceStatus")
|
||||||
|
public AjaxResult updateDeviceStatus(@Valid @RequestBody DeviceUpdateRequest request)
|
||||||
|
{
|
||||||
|
return success(iEmsDeviceSettingService.updateDeviceStatus(request));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ package com.xzzn.web.controller.ems;
|
|||||||
|
|
||||||
import com.xzzn.common.core.controller.BaseController;
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
import com.xzzn.common.core.domain.AjaxResult;
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
import com.xzzn.ems.service.IEmsSiteService;
|
import com.xzzn.ems.domain.vo.DateSearchRequest;
|
||||||
import com.xzzn.ems.service.IHomePageService;
|
import com.xzzn.ems.service.IHomePageService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
// * 站点地图
|
* 站点地图
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@ -26,9 +26,22 @@ public class EmsSiteMapController extends BaseController{
|
|||||||
* 获取某个站点基本信息
|
* 获取某个站点基本信息
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getSingleSiteBaseInfo")
|
@GetMapping("/getSingleSiteBaseInfo")
|
||||||
public AjaxResult getSingleSiteBaseInfo(@RequestParam Long siteId)
|
public AjaxResult getSingleSiteBaseInfo(@RequestParam String siteId)
|
||||||
{
|
{
|
||||||
return success(homePageService.getSingleSiteBaseInfo(siteId));
|
return success(homePageService.getSingleSiteBaseInfo(siteId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取某个站点7天充放电数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/getSevenChargeData")
|
||||||
|
public AjaxResult getSevenChargeData(DateSearchRequest request)
|
||||||
|
{
|
||||||
|
String siteId = request.getSiteId();
|
||||||
|
if(siteId == null || siteId.isEmpty()) {
|
||||||
|
return error("站点必传");
|
||||||
|
}
|
||||||
|
return success(homePageService.getSevenChargeData(request));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,22 @@ package com.xzzn.web.controller.ems;
|
|||||||
|
|
||||||
import com.xzzn.common.core.controller.BaseController;
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
import com.xzzn.common.core.domain.AjaxResult;
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.core.page.TableDataInfo;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.vo.BMSBatteryDataList;
|
||||||
|
import com.xzzn.ems.domain.vo.BatteryDataStatsListVo;
|
||||||
|
import com.xzzn.ems.domain.vo.DateSearchRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.RunningGraphRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteBatteryDataList;
|
||||||
|
import com.xzzn.ems.service.IEmsSiteService;
|
||||||
|
import com.xzzn.ems.service.IEmsStatsReportService;
|
||||||
import com.xzzn.ems.service.ISingleSiteService;
|
import com.xzzn.ems.service.ISingleSiteService;
|
||||||
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 java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 单站监控
|
* 单站监控
|
||||||
@ -17,12 +29,16 @@ public class EmsSiteMonitorController extends BaseController{
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISingleSiteService iSingleSiteService;
|
private ISingleSiteService iSingleSiteService;
|
||||||
|
@Autowired
|
||||||
|
private IEmsSiteService iEmsSiteService;
|
||||||
|
@Autowired
|
||||||
|
private IEmsStatsReportService iemsStatsReportService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取单站首页数据
|
* 获取单站首页数据
|
||||||
*/
|
*/
|
||||||
@GetMapping("/homeView")
|
@GetMapping("/homeView")
|
||||||
public AjaxResult getSingleSiteViewInfo(@RequestParam Long siteId)
|
public AjaxResult getSingleSiteViewInfo(@RequestParam String siteId)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getSiteMonitorDataVo(siteId));
|
return success(iSingleSiteService.getSiteMonitorDataVo(siteId));
|
||||||
}
|
}
|
||||||
@ -31,7 +47,7 @@ public class EmsSiteMonitorController extends BaseController{
|
|||||||
* 单站监控-设备监控-实时运行头部数据
|
* 单站监控-设备监控-实时运行头部数据
|
||||||
*/
|
*/
|
||||||
@GetMapping("/runningHeadInfo")
|
@GetMapping("/runningHeadInfo")
|
||||||
public AjaxResult getRunningHeadInfo(@RequestParam Long siteId)
|
public AjaxResult getRunningHeadInfo(@RequestParam String siteId)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getSiteRunningHeadInfo(siteId));
|
return success(iSingleSiteService.getSiteRunningHeadInfo(siteId));
|
||||||
}
|
}
|
||||||
@ -39,17 +55,35 @@ public class EmsSiteMonitorController extends BaseController{
|
|||||||
/**
|
/**
|
||||||
* 单站监控-设备监控-实时运行曲线图数据
|
* 单站监控-设备监控-实时运行曲线图数据
|
||||||
*/
|
*/
|
||||||
@GetMapping("/runningGraph")
|
@GetMapping("/runningGraph/storagePower")
|
||||||
public AjaxResult getRunningGraph(@RequestParam Long siteId)
|
public AjaxResult getRunningGraphStorage(RunningGraphRequest request)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getRunningGraph(siteId));
|
return success(iSingleSiteService.getRunningGraphStorage(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/runningGraph/pcsMaxTemp")
|
||||||
|
public AjaxResult getRunningGraphPcsMaxTemp(RunningGraphRequest request)
|
||||||
|
{
|
||||||
|
return success(iSingleSiteService.getRunningGraphPcsMaxTemp(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/runningGraph/batteryAveSoc")
|
||||||
|
public AjaxResult getRunningGraphBatterySoc(RunningGraphRequest request)
|
||||||
|
{
|
||||||
|
return success(iSingleSiteService.getRunningGraphBatterySoc(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/runningGraph/batteryAveTemp")
|
||||||
|
public AjaxResult getRunningGraphBatteryTemp(RunningGraphRequest request)
|
||||||
|
{
|
||||||
|
return success(iSingleSiteService.getRunningGraphBatteryTemp(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单站监控-设备监控-PCS
|
* 单站监控-设备监控-PCS
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getPcsDetailInfo")
|
@GetMapping("/getPcsDetailInfo")
|
||||||
public AjaxResult getPcsDetailInfo(@RequestParam Long siteId)
|
public AjaxResult getPcsDetailInfo(@RequestParam String siteId)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getPcsDetailInfo(siteId));
|
return success(iSingleSiteService.getPcsDetailInfo(siteId));
|
||||||
}
|
}
|
||||||
@ -58,7 +92,7 @@ public class EmsSiteMonitorController extends BaseController{
|
|||||||
* 单站监控-设备监控-BMS总览
|
* 单站监控-设备监控-BMS总览
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getBMSOverView")
|
@GetMapping("/getBMSOverView")
|
||||||
public AjaxResult getBMSOverView(@RequestParam Long siteId)
|
public AjaxResult getBMSOverView(@RequestParam String siteId)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getBMSOverView(siteId));
|
return success(iSingleSiteService.getBMSOverView(siteId));
|
||||||
}
|
}
|
||||||
@ -67,7 +101,7 @@ public class EmsSiteMonitorController extends BaseController{
|
|||||||
* 单站监控-设备监控-BMS电池簇
|
* 单站监控-设备监控-BMS电池簇
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getBMSBatteryCluster")
|
@GetMapping("/getBMSBatteryCluster")
|
||||||
public AjaxResult getBMSBatteryCluster(@RequestParam Long siteId)
|
public AjaxResult getBMSBatteryCluster(@RequestParam String siteId)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getBMSBatteryCluster(siteId));
|
return success(iSingleSiteService.getBMSBatteryCluster(siteId));
|
||||||
}
|
}
|
||||||
@ -76,26 +110,122 @@ public class EmsSiteMonitorController extends BaseController{
|
|||||||
* 获取所有电池堆
|
* 获取所有电池堆
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getStackNameList")
|
@GetMapping("/getStackNameList")
|
||||||
public AjaxResult getStackNameList(@RequestParam Long siteId)
|
public AjaxResult getStackNameList(@RequestParam String siteId)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getBMSBatteryCluster(siteId));
|
return success(iEmsSiteService.getAllStackInfo(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有pcs
|
||||||
|
*/
|
||||||
|
@GetMapping("/getPcsNameList")
|
||||||
|
public AjaxResult getPcsNameList(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iEmsSiteService.getAllPcsInfo(siteId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有电池簇
|
* 获取所有电池簇
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getClusterNameList")
|
@GetMapping("/getClusterNameList")
|
||||||
public AjaxResult getClusterNameList(@RequestParam Long siteId)
|
public AjaxResult getClusterNameList(@RequestParam String siteId, @RequestParam String stackDeviceId)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getBMSBatteryCluster(siteId));
|
return success(iEmsSiteService.getAllClusterInfo(siteId, stackDeviceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 液冷设备参数
|
* 液冷设备参数
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getCoolingDataList")
|
@GetMapping("/getCoolingDataList")
|
||||||
public AjaxResult getCoolingDataList(@RequestParam Long siteId)
|
public AjaxResult getCoolingDataList(@RequestParam String siteId)
|
||||||
{
|
{
|
||||||
return success(iSingleSiteService.getCoolingDataList(siteId));
|
return success(iSingleSiteService.getCoolingDataList(siteId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取电池簇下面的单体电池数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/getClusterDataInfoList")
|
||||||
|
public TableDataInfo getClusterDataInfoList(@RequestParam String clusterDeviceId,@RequestParam String siteId,
|
||||||
|
@RequestParam String stackDeviceId,@RequestParam String batteryId)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
SiteBatteryDataList siteBatteryDataList = new SiteBatteryDataList();
|
||||||
|
// 簇最大最小单体id数据
|
||||||
|
List<BMSBatteryDataList> clusterBatteryDataList = iSingleSiteService.getClusterBatteryList(siteId,stackDeviceId,clusterDeviceId);
|
||||||
|
siteBatteryDataList.setClusterList(clusterBatteryDataList);
|
||||||
|
// 单体电池数据
|
||||||
|
List<BatteryDataStatsListVo> List = iSingleSiteService.getClusterDataInfoList(clusterDeviceId,siteId,stackDeviceId,batteryId);
|
||||||
|
// 对batteryList进行分页处理
|
||||||
|
List<BatteryDataStatsListVo> batteryList = paginateList(List);
|
||||||
|
siteBatteryDataList.setBatteryList(batteryList);
|
||||||
|
|
||||||
|
// 封装分页信息
|
||||||
|
TableDataInfo pageInfo = new TableDataInfo();
|
||||||
|
pageInfo.setTotal(List.size());
|
||||||
|
pageInfo.setRows(Arrays.asList(siteBatteryDataList));
|
||||||
|
pageInfo.setCode(0);
|
||||||
|
pageInfo.setMsg("查询成功");
|
||||||
|
return pageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单个单体电池曲线图
|
||||||
|
*/
|
||||||
|
@GetMapping("/getSingleBatteryData")
|
||||||
|
public AjaxResult getSingleBatteryData(DateSearchRequest requestVo)
|
||||||
|
{
|
||||||
|
return success(iemsStatsReportService.getSingleBatteryData(requestVo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电表数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAmmeterDataList")
|
||||||
|
public AjaxResult getAmmeterDataList(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iSingleSiteService.getAmmeterDataList(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动环数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/getDhDataList")
|
||||||
|
public AjaxResult getDhDataList(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iSingleSiteService.getDhDataList(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消防数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/getXfDataList")
|
||||||
|
public AjaxResult getXfDataList(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iSingleSiteService.getXfDataList(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EMS数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/getEmsDataList")
|
||||||
|
public AjaxResult getEmsDataList(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iSingleSiteService.getEmsDataList(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控-首页-点位展示
|
||||||
|
* 储能功率、电网功率、负荷功率、光伏功率
|
||||||
|
* SOC、SOH、电池平均温度
|
||||||
|
*/
|
||||||
|
@GetMapping("/getPointData")
|
||||||
|
public AjaxResult getPointData(DateSearchRequest requestVo)
|
||||||
|
{
|
||||||
|
if (!StringUtils.isEmpty(requestVo.getSiteId())) {
|
||||||
|
return success(iSingleSiteService.getPointData(requestVo));
|
||||||
|
} else {
|
||||||
|
return error("缺少必传项");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,179 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.common.annotation.Log;
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.core.page.TableDataInfo;
|
||||||
|
import com.xzzn.common.enums.BusinessType;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.vo.AmmeterRevenueStatisListVo;
|
||||||
|
import com.xzzn.ems.domain.vo.AmmeterStatisListVo;
|
||||||
|
import com.xzzn.ems.domain.vo.ClusterStatisListVo;
|
||||||
|
import com.xzzn.ems.domain.vo.DateSearchRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.StatisAmmeterDateRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.StatisClusterDateRequest;
|
||||||
|
import com.xzzn.ems.service.IEmsStatsReportService;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控-统计报表
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/statsReport")
|
||||||
|
public class EmsStatisticalReportController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsStatsReportService ieEmsStatsReportService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-收益指标查询
|
||||||
|
*/
|
||||||
|
@GetMapping("/getRevenueData")
|
||||||
|
public AjaxResult getRevenueData(DateSearchRequest requestVo)
|
||||||
|
{
|
||||||
|
return success(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-电量指标查询
|
||||||
|
*/
|
||||||
|
@GetMapping("/getElectricData")
|
||||||
|
public AjaxResult getElectricData(DateSearchRequest requestVo)
|
||||||
|
{
|
||||||
|
if (!StringUtils.isEmpty(requestVo.getSiteId())) {
|
||||||
|
return success(ieEmsStatsReportService.getElectricDataResult(requestVo));
|
||||||
|
} else {
|
||||||
|
return error("站点id必传");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-PCS曲线
|
||||||
|
*/
|
||||||
|
@GetMapping("/getPCSData")
|
||||||
|
public AjaxResult getPCSData(DateSearchRequest requestVo)
|
||||||
|
{
|
||||||
|
if (!StringUtils.isEmpty(requestVo.getSiteId())&&
|
||||||
|
!StringUtils.isEmpty(requestVo.getDataType())) {
|
||||||
|
return success(ieEmsStatsReportService.getPCSDataResult(requestVo));
|
||||||
|
} else {
|
||||||
|
return error("缺少必传项");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-电池堆曲线
|
||||||
|
*/
|
||||||
|
@GetMapping("/getStackData")
|
||||||
|
public AjaxResult getStackData(DateSearchRequest requestVo)
|
||||||
|
{
|
||||||
|
if (!StringUtils.isEmpty(requestVo.getSiteId()) &&
|
||||||
|
!StringUtils.isEmpty(requestVo.getDataType())) {
|
||||||
|
return success(ieEmsStatsReportService.getStackDataResult(requestVo));
|
||||||
|
} else {
|
||||||
|
return error("缺少必传项");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-电池温度等数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/getClusterData")
|
||||||
|
public TableDataInfo getClusterData(StatisClusterDateRequest requestVo)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<ClusterStatisListVo> dataList = new ArrayList<>();
|
||||||
|
if (!StringUtils.isEmpty(requestVo.getStackId()) &&
|
||||||
|
!StringUtils.isEmpty(requestVo.getClusterId())) {
|
||||||
|
dataList = ieEmsStatsReportService.getClusterDataResult(requestVo);
|
||||||
|
return getDataTable(dataList);
|
||||||
|
} else {
|
||||||
|
return getDataTable(dataList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-获取站点下所有电表
|
||||||
|
*/
|
||||||
|
@GetMapping("/getLoadNameList")
|
||||||
|
public AjaxResult getLoadNameList(String siteId)
|
||||||
|
{
|
||||||
|
if (!StringUtils.isEmpty(siteId)) {
|
||||||
|
return success(ieEmsStatsReportService.getLoadNameList(siteId));
|
||||||
|
} else {
|
||||||
|
return error("缺少必传项");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-电表报表
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAmmeterData")
|
||||||
|
public TableDataInfo getAmmeterData(StatisAmmeterDateRequest requestVo)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<AmmeterStatisListVo> dataList = ieEmsStatsReportService.getAmmeterDataResult(requestVo);
|
||||||
|
return getDataTable(dataList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出电表报表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:ammeterData:export')")
|
||||||
|
@Log(title = "电表报表", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/exportAmmeterData")
|
||||||
|
public void exportAmmeterData(HttpServletResponse response, StatisAmmeterDateRequest requestVo)
|
||||||
|
{
|
||||||
|
ieEmsStatsReportService.exportAmmeterData(response, requestVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-电表收益报表
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAmmeterRevenueData")
|
||||||
|
public TableDataInfo getAmmeterRevenueData(StatisAmmeterDateRequest requestVo)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<AmmeterRevenueStatisListVo> dataList = ieEmsStatsReportService.getAmmeterRevenueDataResult(requestVo);
|
||||||
|
return getDataTable(dataList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出收益报表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:ammeterRevenueData:export')")
|
||||||
|
@Log(title = "收益报表", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/exportAmmeterRevenueData")
|
||||||
|
public void exportAmmeterRevenueData(HttpServletResponse response, StatisAmmeterDateRequest requestVo)
|
||||||
|
{
|
||||||
|
ieEmsStatsReportService.exportAmmeterRevenueData(response, requestVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 概率统计-功率曲线
|
||||||
|
*/
|
||||||
|
@GetMapping("/getPowerData")
|
||||||
|
public AjaxResult getPowerData(DateSearchRequest requestVo)
|
||||||
|
{
|
||||||
|
if (!StringUtils.isEmpty(requestVo.getSiteId())) {
|
||||||
|
return success(ieEmsStatsReportService.getPowerDataList(requestVo));
|
||||||
|
} else {
|
||||||
|
return error("缺少必传项");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRunning;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.ems.service.IEmsStrategyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略Controller
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-07-10
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/system/strategyRunning")
|
||||||
|
public class EmsStrategyController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IEmsStrategyService emsStrategyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取站点策略配置
|
||||||
|
*/
|
||||||
|
@GetMapping("/list")
|
||||||
|
public AjaxResult list(String siteId) {
|
||||||
|
return success(emsStrategyService.selectEmsStrategyRunningList(siteId));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 停止策略
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/stop")
|
||||||
|
public AjaxResult stop(Long id)
|
||||||
|
{
|
||||||
|
return toAjax(emsStrategyService.stopRunningStrategy(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取主策略列表
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/getMainStrategyList")
|
||||||
|
public AjaxResult getMainStrategyList()
|
||||||
|
{
|
||||||
|
return success(emsStrategyService.getMainStrategyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取辅助策略列表
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/getAuxStrategyList")
|
||||||
|
public AjaxResult getAuxStrategyList()
|
||||||
|
{
|
||||||
|
return success(emsStrategyService.getAuxStrategyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置策略
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/configStrategy")
|
||||||
|
public AjaxResult configStrategy(@RequestBody EmsStrategyRunning emsStrategyRunning)
|
||||||
|
{
|
||||||
|
if (emsStrategyRunning.getMainStrategyId() == null
|
||||||
|
|| StringUtils.isEmpty(emsStrategyRunning.getSiteId())){
|
||||||
|
return error("缺少必填字段");
|
||||||
|
}
|
||||||
|
emsStrategyRunning.setCreateBy(getUsername());
|
||||||
|
emsStrategyRunning.setUpdateBy(getUsername());
|
||||||
|
int result = emsStrategyService.configStrategy(emsStrategyRunning);
|
||||||
|
if (result == -1){
|
||||||
|
return error("不支持重复添加");
|
||||||
|
}
|
||||||
|
return success(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyTemp;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyTimeConfig;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
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;
|
||||||
|
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.EmsStrategyCurve;
|
||||||
|
import com.xzzn.ems.service.IEmsStrategyCurveService;
|
||||||
|
import com.xzzn.common.utils.poi.ExcelUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策曲线Controller
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-07-11
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/strategy/curve")
|
||||||
|
public class EmsStrategyCurveController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IEmsStrategyCurveService emsStrategyCurveService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询策曲线列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:curve:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public AjaxResult list(EmsStrategyCurve emsStrategyCurve)
|
||||||
|
{
|
||||||
|
return success(emsStrategyCurveService.selectEmsStrategyCurveList(emsStrategyCurve));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出策曲线列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:curve:export')")
|
||||||
|
@Log(title = "策曲线", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, EmsStrategyCurve emsStrategyCurve)
|
||||||
|
{
|
||||||
|
List<EmsStrategyCurve> list = emsStrategyCurveService.selectEmsStrategyCurveList(emsStrategyCurve);
|
||||||
|
ExcelUtil<EmsStrategyCurve> util = new ExcelUtil<EmsStrategyCurve>(EmsStrategyCurve.class);
|
||||||
|
util.exportExcel(response, list, "策曲线数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取策曲线详细信息
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:curve:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||||
|
{
|
||||||
|
return success(emsStrategyCurveService.selectEmsStrategyCurveById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增策曲线
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:curve:add')")
|
||||||
|
@Log(title = "策曲线", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody EmsStrategyCurve emsStrategyCurve)
|
||||||
|
{
|
||||||
|
return toAjax(emsStrategyCurveService.insertEmsStrategyCurve(emsStrategyCurve));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改策曲线
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:curve:edit')")
|
||||||
|
@Log(title = "策曲线", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody EmsStrategyCurve emsStrategyCurve)
|
||||||
|
{
|
||||||
|
return toAjax(emsStrategyCurveService.updateEmsStrategyCurve(emsStrategyCurve));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除策曲线
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:curve:remove')")
|
||||||
|
@Log(title = "策曲线", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(emsStrategyCurveService.deleteEmsStrategyCurveByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取策略曲线图数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/curveList")
|
||||||
|
public AjaxResult getCurveList(EmsStrategyTemp tempConfig)
|
||||||
|
{
|
||||||
|
return success(emsStrategyCurveService.getStrategyCurveList(tempConfig));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.vo.StrategyTempConfigRequest;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
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;
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.enums.BusinessType;
|
||||||
|
import com.xzzn.ems.service.IEmsStrategyTempService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板Controller
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-07-11
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/strategy/temp")
|
||||||
|
public class EmsStrategyTempController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IEmsStrategyTempService emsStrategyTempService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据策略id站点id获取所有模板名称
|
||||||
|
*/
|
||||||
|
@GetMapping("/getTempNameList")
|
||||||
|
public AjaxResult getTempNameList(Long strategyId, String siteId)
|
||||||
|
{
|
||||||
|
return success(emsStrategyTempService.getTempNameList(strategyId, siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个模板时间配置详细信息
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:temp:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public AjaxResult list(String templateId)
|
||||||
|
{
|
||||||
|
return success(emsStrategyTempService.selectEmsStrategyTempList(templateId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增模板及时间配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:temp:add')")
|
||||||
|
@Log(title = "模板", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody StrategyTempConfigRequest requestVo)
|
||||||
|
{
|
||||||
|
boolean result = emsStrategyTempService.addNewTempAndTimeConfig(requestVo);
|
||||||
|
if (result) {
|
||||||
|
return success();
|
||||||
|
} else {
|
||||||
|
return AjaxResult.error("新增失败请重试!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改模板
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:temp:edit')")
|
||||||
|
@Log(title = "模板", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody StrategyTempConfigRequest requestVo)
|
||||||
|
{
|
||||||
|
boolean result = emsStrategyTempService.updateEmsStrategyTemp(requestVo);
|
||||||
|
if (result) {
|
||||||
|
return success();
|
||||||
|
} else {
|
||||||
|
return AjaxResult.error("更新失败,请重试!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除模板
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:temp:remove')")
|
||||||
|
@Log(title = "模板", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{templateId}")
|
||||||
|
public AjaxResult remove(@PathVariable String templateId)
|
||||||
|
{
|
||||||
|
return success(emsStrategyTempService.deleteStrategyTempById(templateId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
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;
|
||||||
|
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.EmsStrategyTimeConfig;
|
||||||
|
import com.xzzn.ems.service.IEmsStrategyTimeConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间配置Controller
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-07-11
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/strategy/timeConfig")
|
||||||
|
public class EmsStrategyTimeConfigController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IEmsStrategyTimeConfigService emsStrategyTimeConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询时间配置列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public AjaxResult list(EmsStrategyTimeConfig emsStrategyTimeConfig)
|
||||||
|
{
|
||||||
|
return success(emsStrategyTimeConfigService.getStrategyTimeList(emsStrategyTimeConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取时间配置详细信息
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||||
|
{
|
||||||
|
return success(emsStrategyTimeConfigService.selectEmsStrategyTimeConfigById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增时间配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:add')")
|
||||||
|
@Log(title = "时间配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody List<EmsStrategyTimeConfig> emsStrategyTimeConfigList)
|
||||||
|
{
|
||||||
|
boolean result = emsStrategyTimeConfigService.insertEmsStrategyTimeConfig(emsStrategyTimeConfigList);
|
||||||
|
if (result){
|
||||||
|
return success();
|
||||||
|
}else {
|
||||||
|
return error("编辑失败请重试!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改时间配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:edit')")
|
||||||
|
@Log(title = "时间配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody EmsStrategyTimeConfig emsStrategyTimeConfig)
|
||||||
|
{
|
||||||
|
return toAjax(emsStrategyTimeConfigService.updateEmsStrategyTimeConfig(emsStrategyTimeConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除时间配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:config:remove')")
|
||||||
|
@Log(title = "时间配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(emsStrategyTimeConfigService.deleteEmsStrategyTimeConfigByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
|
|
||||||
import com.xzzn.common.utils.poi.ExcelUtil;
|
import com.xzzn.common.utils.poi.ExcelUtil;
|
||||||
import com.xzzn.ems.domain.EmsTicket;
|
import com.xzzn.ems.domain.EmsTicket;
|
||||||
|
import com.xzzn.ems.domain.vo.TicketListVo;
|
||||||
import com.xzzn.ems.service.IEmsTicketService;
|
import com.xzzn.ems.service.IEmsTicketService;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -40,10 +41,10 @@ public class EmsTicketController extends BaseController
|
|||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('system:ticket:list')")
|
@PreAuthorize("@ss.hasPermi('system:ticket:list')")
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(EmsTicket emsTicket)
|
public TableDataInfo list(Long[] status)
|
||||||
{
|
{
|
||||||
startPage();
|
startPage();
|
||||||
List<EmsTicket> list = emsTicketService.selectEmsTicketList(emsTicket);
|
List<TicketListVo> list = emsTicketService.getAllTicketList(status);
|
||||||
return getDataTable(list);
|
return getDataTable(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,4 +103,15 @@ public class EmsTicketController extends BaseController
|
|||||||
{
|
{
|
||||||
return toAjax(emsTicketService.deleteEmsTicketByIds(ids));
|
return toAjax(emsTicketService.deleteEmsTicketByIds(ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 废弃工单
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:ticket:delete')")
|
||||||
|
@Log(title = "工单主", businessType = BusinessType.DELETE)
|
||||||
|
@PostMapping("/drop")
|
||||||
|
public AjaxResult drop(@RequestBody EmsTicket emsTicket)
|
||||||
|
{
|
||||||
|
return toAjax(emsTicketService.dropEmsTicketById(emsTicket.getId()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,295 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.common.constant.RedisKeyConstants;
|
||||||
|
import com.xzzn.common.core.redis.RedisCache;
|
||||||
|
import com.xzzn.common.enums.TopicHandleType;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsMqttTopicConfig;
|
||||||
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
|
import com.xzzn.ems.service.IDDSDataProcessService;
|
||||||
|
import com.xzzn.ems.service.IDeviceDataProcessService;
|
||||||
|
import com.xzzn.ems.service.IEmsMqttMessageService;
|
||||||
|
import com.xzzn.ems.service.IEmsStrategyService;
|
||||||
|
import com.xzzn.ems.service.IFXXAlarmDataProcessService;
|
||||||
|
import com.xzzn.ems.service.IFXXDataProcessService;
|
||||||
|
import com.xzzn.ems.service.IMqttSyncLogService;
|
||||||
|
import com.xzzn.framework.manager.MqttLifecycleManager;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
import com.xzzn.framework.web.service.MqttSubscriber;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MqttMessageController implements MqttPublisher, MqttSubscriber {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MqttMessageController.class);
|
||||||
|
|
||||||
|
|
||||||
|
private final MqttLifecycleManager mqttLifecycleManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsMqttMessageService emsMqttMessageService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IFXXDataProcessService fXXDataProcessService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IDDSDataProcessService dDSDataProcessService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IDeviceDataProcessService deviceDataProcessService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IFXXAlarmDataProcessService fXXAlarmDataProcessService;
|
||||||
|
@Autowired
|
||||||
|
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
|
||||||
|
@Autowired
|
||||||
|
private IEmsStrategyService emsStrategyService;
|
||||||
|
@Autowired
|
||||||
|
private IMqttSyncLogService iMqttSyncLogService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisCache redisCache;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public MqttMessageController(MqttLifecycleManager mqttLifecycleManager) {
|
||||||
|
this.mqttLifecycleManager = mqttLifecycleManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
List<EmsMqttTopicConfig> topicConfigList = emsMqttTopicConfigMapper.selectEmsMqttTopicConfigList(null);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty (topicConfigList)) {
|
||||||
|
log.info ("未查询到任何 MQTT 主题配置,跳过订阅");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (EmsMqttTopicConfig topicConfig : topicConfigList) {
|
||||||
|
String topic = topicConfig.getMqttTopic();
|
||||||
|
if (StringUtils.isEmpty(topic)) {
|
||||||
|
log.info ("主题配置 ID:" +topicConfig.getId() +"的 mqttTopic 为空,跳过订阅");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qos = topicConfig.getQos() == null ? 1 : topicConfig.getQos();
|
||||||
|
if (qos < 0 || qos > 2) {
|
||||||
|
log.info ("主题:" + topic +"的 QoS值"+ qos + "不合法,自动调整为1");
|
||||||
|
qos = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMqttMessageListener listener = getMqttListenerByTopic(topic, topicConfig.getHandleType());
|
||||||
|
subscribe(topic, qos, listener);
|
||||||
|
}
|
||||||
|
// 订阅奉贤系统状态主题
|
||||||
|
/*subscribe("021_FXX_01_UP", 1, this::handleDeviceData);
|
||||||
|
subscribe("021_FXX_01_RECALL", 1, this::handleDeviceData);
|
||||||
|
subscribe("021_FXX_01_DOWN", 1, this::handleDeviceData);
|
||||||
|
subscribe("021_FXX_01", 1, this::handleSystemStatus);
|
||||||
|
subscribe("021_FXX_01_ALARM_UP", 1, this::handleAlarmData);
|
||||||
|
|
||||||
|
// 订阅电动所系统状态主题
|
||||||
|
subscribe("021_DDS_01_UP", 1, this::handleDeviceData);
|
||||||
|
subscribe("021_DDS_01_RECALL", 1, this::handleDeviceData);
|
||||||
|
subscribe("021_DDS_01_DOWN", 1, this::handleDeviceData);
|
||||||
|
subscribe("021_DDS_01", 1, this::handleSystemStatus);*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private IMqttMessageListener getMqttListenerByTopic(String topic, String handleType) {
|
||||||
|
TopicHandleType topicHandleType = TopicHandleType.getEnumByCode(handleType);
|
||||||
|
switch (topicHandleType) {
|
||||||
|
case DEVICE:
|
||||||
|
return this::handleDeviceData;
|
||||||
|
case DEVICE_ALARM:
|
||||||
|
return this::handleAlarmData;
|
||||||
|
case STRATEGY:
|
||||||
|
if (topic.equals("FAULT_PROTECTION_PLAN_UP")) {
|
||||||
|
return this::handleFaultProtPlanData;
|
||||||
|
} else if (topic.equals("FAULT_ALARM_RECORD_UP")) {
|
||||||
|
return this::handleFaultAlarmData;
|
||||||
|
} else if (topic.equals("FAULT_PLAN_ISSUE_UP")) {
|
||||||
|
return this::handleFaultPlanIssueData;
|
||||||
|
} else if (topic.equals("DEVICE_CHANGE_LOG_UP")) {
|
||||||
|
return this::handleDeviceChangeLogData;
|
||||||
|
} else {
|
||||||
|
return this::handleStrategyData;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.warn("Unknown handle type: " + handleType + ", using default handler");
|
||||||
|
return this::handleSystemStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理系统状态消息
|
||||||
|
private void handleSystemStatus(String topic, MqttMessage message) {
|
||||||
|
String payload = new String(message.getPayload());
|
||||||
|
System.out.println("[SYSTEM] Status update: " + payload);
|
||||||
|
|
||||||
|
try {
|
||||||
|
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to process system status message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理设备数据
|
||||||
|
private void handleDeviceData(String topic, MqttMessage message) {
|
||||||
|
String payload = new String(message.getPayload());
|
||||||
|
log.error("[DEVICE] data: " + payload);
|
||||||
|
try {
|
||||||
|
// 业务处理逻辑
|
||||||
|
// if (topic.startsWith("021_DDS")) {
|
||||||
|
// dDSDataProcessService.handleDdsData(payload);
|
||||||
|
// } else if (topic.startsWith("021_FXX")) {
|
||||||
|
// fXXDataProcessService.handleFxData(payload);
|
||||||
|
// }
|
||||||
|
deviceDataProcessService.handleDeviceData(payload, getSiteIdByTopic(topic));
|
||||||
|
|
||||||
|
emsMqttMessageService.insertMqttOriginalMessage(topic, payload);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to process device data message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理告警数据
|
||||||
|
private void handleAlarmData(String topic, MqttMessage message) {
|
||||||
|
String payload = new String(message.getPayload());
|
||||||
|
System.out.println("[DEVICE] data: " + payload);
|
||||||
|
try {
|
||||||
|
// 业务处理逻辑
|
||||||
|
// if (topic.startsWith("021_FXX")) {
|
||||||
|
// fXXAlarmDataProcessService.handleFxAlarmData(payload);
|
||||||
|
// }
|
||||||
|
deviceDataProcessService.handleAlarmData(payload, getSiteIdByTopic(topic));
|
||||||
|
|
||||||
|
emsMqttMessageService.insertMqttOriginalMessage(topic, payload);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
log.error("Failed to process device alarm data message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSiteIdByTopic(String topic) {
|
||||||
|
String siteId = redisCache.getCacheObject(RedisKeyConstants.SITE_ID + topic);
|
||||||
|
if (StringUtils.isEmpty(siteId)) {
|
||||||
|
EmsMqttTopicConfig topicConfig = emsMqttTopicConfigMapper.selectOneByTopic(topic);
|
||||||
|
siteId = topicConfig.getSiteId();
|
||||||
|
redisCache.setCacheObject(RedisKeyConstants.SITE_ID + topic, siteId);
|
||||||
|
}
|
||||||
|
log.info("当前处理数据站点:" + siteId + ",topic: " + topic);
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理运行策略数据:云端-本地
|
||||||
|
private void handleStrategyData(String topic, MqttMessage message) {
|
||||||
|
String payload = new String(message.getPayload());
|
||||||
|
System.out.println("[处理运行策略数据] data: " + payload);
|
||||||
|
try {
|
||||||
|
// 业务处理逻辑
|
||||||
|
iMqttSyncLogService.handleMqttStrategyData(payload);
|
||||||
|
|
||||||
|
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to process strategy data message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理设备保护告警策略数据:云端-本地
|
||||||
|
private void handleFaultProtPlanData(String topic, MqttMessage message) {
|
||||||
|
String payload = new String(message.getPayload());
|
||||||
|
System.out.println("[处理设备保护告警策略数据] data: " + payload);
|
||||||
|
try {
|
||||||
|
// 业务处理逻辑
|
||||||
|
iMqttSyncLogService.handleMqttPlanData(payload);
|
||||||
|
|
||||||
|
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to process fault plan data message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理保护策略告警信息:本地-云端
|
||||||
|
private void handleFaultAlarmData(String topic, MqttMessage message) {
|
||||||
|
String payload = new String(message.getPayload());
|
||||||
|
System.out.println("[处理本地保护策略告警信息到云端] data: " + payload);
|
||||||
|
try {
|
||||||
|
// 业务处理逻辑
|
||||||
|
iMqttSyncLogService.handleFaultAlarmData(payload);
|
||||||
|
|
||||||
|
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to process fault plan alarm data message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理保护策略下发日志:本地-云端
|
||||||
|
private void handleFaultPlanIssueData(String topic, MqttMessage message) {
|
||||||
|
String payload = new String(message.getPayload());
|
||||||
|
System.out.println("[处理本地保护策略下发日志到云端] data: " + payload);
|
||||||
|
try {
|
||||||
|
// 业务处理逻辑
|
||||||
|
iMqttSyncLogService.handleFaultPlanIssueData(payload);
|
||||||
|
|
||||||
|
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to process fault plan issue log message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理设备状态变更日志:本地-云端
|
||||||
|
private void handleDeviceChangeLogData(String topic, MqttMessage message) {
|
||||||
|
String payload = new String(message.getPayload());
|
||||||
|
System.out.println("[处理本地的保护策略告警信息到云端] data: " + payload);
|
||||||
|
try {
|
||||||
|
// 业务处理逻辑
|
||||||
|
iMqttSyncLogService.handleDeviceChangeLogData(payload);
|
||||||
|
|
||||||
|
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to process device change log message: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(String topic, String message) throws MqttException {
|
||||||
|
mqttLifecycleManager.publish(topic, message, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(String topic, String message, int qos) throws MqttException {
|
||||||
|
mqttLifecycleManager.publish(topic, message, qos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void subscribe(String topic, int qos, IMqttMessageListener listener) {
|
||||||
|
mqttLifecycleManager.subscribe(topic, qos, listener);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送设备控制命令
|
||||||
|
public void sendDeviceCommand(String deviceId, String command) {
|
||||||
|
try {
|
||||||
|
String topic = "devices/" + deviceId + "/commands";
|
||||||
|
publish(topic, command, 1);
|
||||||
|
} catch (MqttException e) {
|
||||||
|
System.err.println("Failed to send command to device " + deviceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -3,6 +3,8 @@ package com.xzzn.web.controller.system;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import com.xzzn.system.service.impl.SysUserServiceImpl;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@ -52,6 +54,8 @@ public class SysUserController extends BaseController
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysPostService postService;
|
private ISysPostService postService;
|
||||||
|
@Autowired
|
||||||
|
private SysUserServiceImpl sysUserServiceImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户列表
|
* 获取用户列表
|
||||||
@ -253,4 +257,13 @@ public class SysUserController extends BaseController
|
|||||||
{
|
{
|
||||||
return success(deptService.selectDeptTreeList(dept));
|
return success(deptService.selectDeptTreeList(dept));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有用户
|
||||||
|
*/
|
||||||
|
@GetMapping("/getAllUser")
|
||||||
|
public AjaxResult getAllUser(SysUser user)
|
||||||
|
{
|
||||||
|
return success(userService.selectUserList(user));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,61 +1,61 @@
|
|||||||
# 数据源配置
|
## 数据源配置
|
||||||
spring:
|
#spring:
|
||||||
datasource:
|
# datasource:
|
||||||
type: com.alibaba.druid.pool.DruidDataSource
|
# type: com.alibaba.druid.pool.DruidDataSource
|
||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
# driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
druid:
|
# druid:
|
||||||
# 主库数据源
|
# # 主库数据源
|
||||||
master:
|
# master:
|
||||||
url: jdbc:mysql://122.51.194.184:13306/setri_ems?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
# url: jdbc:mysql://122.51.194.184:13306/setri_ems?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
username: ems
|
# username: ems
|
||||||
password: 12345678
|
# password: 12345678
|
||||||
# 从库数据源
|
# # 从库数据源
|
||||||
slave:
|
# slave:
|
||||||
# 从数据源开关/默认关闭
|
# # 从数据源开关/默认关闭
|
||||||
enabled: false
|
# enabled: false
|
||||||
url:
|
# url:
|
||||||
username:
|
# username:
|
||||||
password:
|
# password:
|
||||||
# 初始连接数
|
# # 初始连接数
|
||||||
initialSize: 5
|
# initialSize: 5
|
||||||
# 最小连接池数量
|
# # 最小连接池数量
|
||||||
minIdle: 10
|
# minIdle: 10
|
||||||
# 最大连接池数量
|
# # 最大连接池数量
|
||||||
maxActive: 20
|
# maxActive: 20
|
||||||
# 配置获取连接等待超时的时间
|
# # 配置获取连接等待超时的时间
|
||||||
maxWait: 60000
|
# maxWait: 60000
|
||||||
# 配置连接超时时间
|
# # 配置连接超时时间
|
||||||
connectTimeout: 30000
|
# connectTimeout: 30000
|
||||||
# 配置网络超时时间
|
# # 配置网络超时时间
|
||||||
socketTimeout: 60000
|
# socketTimeout: 60000
|
||||||
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
# # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||||
timeBetweenEvictionRunsMillis: 60000
|
# timeBetweenEvictionRunsMillis: 60000
|
||||||
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
# # 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||||
minEvictableIdleTimeMillis: 300000
|
# minEvictableIdleTimeMillis: 300000
|
||||||
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
# # 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||||
maxEvictableIdleTimeMillis: 900000
|
# maxEvictableIdleTimeMillis: 900000
|
||||||
# 配置检测连接是否有效
|
# # 配置检测连接是否有效
|
||||||
validationQuery: SELECT 1 FROM DUAL
|
# validationQuery: SELECT 1 FROM DUAL
|
||||||
testWhileIdle: true
|
# testWhileIdle: true
|
||||||
testOnBorrow: false
|
# testOnBorrow: false
|
||||||
testOnReturn: false
|
# testOnReturn: false
|
||||||
webStatFilter:
|
# webStatFilter:
|
||||||
enabled: true
|
# enabled: true
|
||||||
statViewServlet:
|
# statViewServlet:
|
||||||
enabled: true
|
# enabled: true
|
||||||
# 设置白名单,不填则允许所有访问
|
# # 设置白名单,不填则允许所有访问
|
||||||
allow:
|
# allow:
|
||||||
url-pattern: /druid/*
|
# url-pattern: /druid/*
|
||||||
# 控制台管理用户名和密码
|
# # 控制台管理用户名和密码
|
||||||
login-username: xzzn
|
# login-username: xzzn
|
||||||
login-password: 123456
|
# login-password: 123456
|
||||||
filter:
|
# filter:
|
||||||
stat:
|
# stat:
|
||||||
enabled: true
|
# enabled: true
|
||||||
# 慢SQL记录
|
# # 慢SQL记录
|
||||||
log-slow-sql: true
|
# log-slow-sql: true
|
||||||
slow-sql-millis: 1000
|
# slow-sql-millis: 1000
|
||||||
merge-sql: true
|
# merge-sql: true
|
||||||
wall:
|
# wall:
|
||||||
config:
|
# config:
|
||||||
multi-statement-allow: true
|
# multi-statement-allow: true
|
||||||
207
ems-admin/src/main/resources/application-local.yml
Normal file
207
ems-admin/src/main/resources/application-local.yml
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
# 项目相关配置
|
||||||
|
xzzn:
|
||||||
|
# 名称
|
||||||
|
name: EMS
|
||||||
|
# 版本
|
||||||
|
version: 0.0.1
|
||||||
|
# 版权年份
|
||||||
|
copyrightYear: 2025
|
||||||
|
# 文件路径 示例( Windows配置D:/xzzn/uploadPath,Linux配置 /home/xzzn/uploadPath)
|
||||||
|
profile: ../uploadPath
|
||||||
|
# 获取ip地址开关
|
||||||
|
addressEnabled: false
|
||||||
|
# 验证码类型 math 数字计算 char 字符验证
|
||||||
|
captchaType: math
|
||||||
|
|
||||||
|
# 开发环境配置
|
||||||
|
server:
|
||||||
|
# 服务器的HTTP端口,默认为8080
|
||||||
|
port: 8089
|
||||||
|
servlet:
|
||||||
|
# 应用的访问路径
|
||||||
|
context-path: /
|
||||||
|
tomcat:
|
||||||
|
# tomcat的URI编码
|
||||||
|
uri-encoding: UTF-8
|
||||||
|
# 连接数满后的排队数,默认为100
|
||||||
|
accept-count: 1000
|
||||||
|
threads:
|
||||||
|
# tomcat最大线程数,默认为200
|
||||||
|
max: 800
|
||||||
|
# Tomcat启动初始化的线程数,默认值10
|
||||||
|
min-spare: 100
|
||||||
|
|
||||||
|
# 日志配置
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
com.xzzn: info
|
||||||
|
org.springframework: warn
|
||||||
|
|
||||||
|
# 用户配置
|
||||||
|
user:
|
||||||
|
password:
|
||||||
|
# 密码最大错误次数
|
||||||
|
maxRetryCount: 5
|
||||||
|
# 密码锁定时间(默认10分钟)
|
||||||
|
lockTime: 10
|
||||||
|
|
||||||
|
# Spring配置
|
||||||
|
spring:
|
||||||
|
# 资源信息
|
||||||
|
messages:
|
||||||
|
# 国际化资源文件路径
|
||||||
|
basename: i18n/messages
|
||||||
|
# 文件上传
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
# 单个文件大小
|
||||||
|
max-file-size: 10MB
|
||||||
|
# 设置总上传的文件大小
|
||||||
|
max-request-size: 20MB
|
||||||
|
# 服务模块
|
||||||
|
devtools:
|
||||||
|
restart:
|
||||||
|
# 热部署开关
|
||||||
|
enabled: true
|
||||||
|
# redis 配置
|
||||||
|
redis:
|
||||||
|
# 地址
|
||||||
|
host: 127.0.0.1
|
||||||
|
# 端口,默认为6379
|
||||||
|
port: 6379
|
||||||
|
# 数据库索引
|
||||||
|
database: 0
|
||||||
|
# 密码
|
||||||
|
password: 12345678
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 10s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# 连接池中的最小空闲连接
|
||||||
|
min-idle: 0
|
||||||
|
# 连接池中的最大空闲连接
|
||||||
|
max-idle: 8
|
||||||
|
# 连接池的最大数据库连接数
|
||||||
|
max-active: 8
|
||||||
|
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
|
max-wait: -1ms
|
||||||
|
# 数据源配置
|
||||||
|
datasource:
|
||||||
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
druid:
|
||||||
|
# 主库数据源
|
||||||
|
master:
|
||||||
|
url: jdbc:mysql://127.0.0.1:3306/setri_ems?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
|
username: ems
|
||||||
|
password: Aa112211!
|
||||||
|
# 从库数据源
|
||||||
|
slave:
|
||||||
|
# 从数据源开关/默认关闭
|
||||||
|
enabled: false
|
||||||
|
url:
|
||||||
|
username:
|
||||||
|
password:
|
||||||
|
# 初始连接数
|
||||||
|
initialSize: 5
|
||||||
|
# 最小连接池数量
|
||||||
|
minIdle: 10
|
||||||
|
# 最大连接池数量
|
||||||
|
maxActive: 20
|
||||||
|
# 配置获取连接等待超时的时间
|
||||||
|
maxWait: 60000
|
||||||
|
# 配置连接超时时间
|
||||||
|
connectTimeout: 30000
|
||||||
|
# 配置网络超时时间
|
||||||
|
socketTimeout: 60000
|
||||||
|
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||||
|
timeBetweenEvictionRunsMillis: 60000
|
||||||
|
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||||
|
minEvictableIdleTimeMillis: 300000
|
||||||
|
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||||
|
maxEvictableIdleTimeMillis: 900000
|
||||||
|
# 配置检测连接是否有效
|
||||||
|
validationQuery: SELECT 1 FROM DUAL
|
||||||
|
testWhileIdle: true
|
||||||
|
testOnBorrow: false
|
||||||
|
testOnReturn: false
|
||||||
|
webStatFilter:
|
||||||
|
enabled: true
|
||||||
|
statViewServlet:
|
||||||
|
enabled: true
|
||||||
|
# 设置白名单,不填则允许所有访问
|
||||||
|
allow:
|
||||||
|
url-pattern: /druid/*
|
||||||
|
# 控制台管理用户名和密码
|
||||||
|
login-username: xzzn
|
||||||
|
login-password: 123456
|
||||||
|
filter:
|
||||||
|
stat:
|
||||||
|
enabled: true
|
||||||
|
# 慢SQL记录
|
||||||
|
log-slow-sql: true
|
||||||
|
slow-sql-millis: 1000
|
||||||
|
merge-sql: true
|
||||||
|
wall:
|
||||||
|
config:
|
||||||
|
multi-statement-allow: true
|
||||||
|
|
||||||
|
# token配置
|
||||||
|
token:
|
||||||
|
# 令牌自定义标识
|
||||||
|
header: Authorization
|
||||||
|
# 令牌密钥
|
||||||
|
secret: abcdefghijklmnopqrstuvwxyz
|
||||||
|
# 令牌有效期(默认30分钟)
|
||||||
|
expireTime: 30
|
||||||
|
|
||||||
|
# MyBatis配置
|
||||||
|
mybatis:
|
||||||
|
# 搜索指定包别名
|
||||||
|
typeAliasesPackage: com.xzzn.**.domain
|
||||||
|
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||||
|
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||||
|
# 加载全局的配置文件
|
||||||
|
configLocation: classpath:mybatis/mybatis-config.xml
|
||||||
|
|
||||||
|
# PageHelper分页插件
|
||||||
|
pagehelper:
|
||||||
|
helperDialect: mysql
|
||||||
|
supportMethodsArguments: true
|
||||||
|
params: count=countSql
|
||||||
|
|
||||||
|
# Swagger配置
|
||||||
|
swagger:
|
||||||
|
# 是否开启swagger
|
||||||
|
enabled: true
|
||||||
|
# 请求前缀
|
||||||
|
pathMapping: /dev-api
|
||||||
|
|
||||||
|
# 防止XSS攻击
|
||||||
|
xss:
|
||||||
|
# 过滤开关
|
||||||
|
enabled: true
|
||||||
|
# 排除链接(多个用逗号分隔)
|
||||||
|
excludes: /system/notice
|
||||||
|
# 匹配链接
|
||||||
|
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||||
|
|
||||||
|
mqtt:
|
||||||
|
broker.url: tcp://121.5.164.6:1883
|
||||||
|
client.id: ems-cloud
|
||||||
|
username: dmbroker
|
||||||
|
password: qwer1234
|
||||||
|
connection-timeout: 15
|
||||||
|
keep-alive-interval: 30
|
||||||
|
automatic-reconnect: true
|
||||||
|
topic: 021_DDS_01_UP
|
||||||
|
siteId: 021_DDS_01
|
||||||
|
|
||||||
|
modbus:
|
||||||
|
pool:
|
||||||
|
max-total: 20
|
||||||
|
max-idle: 10
|
||||||
|
min-idle: 3
|
||||||
|
poll:
|
||||||
|
interval: "0 */5 * * * *" # 5分钟间隔
|
||||||
|
timeout: 30000 # 30秒超时
|
||||||
207
ems-admin/src/main/resources/application-prod.yml
Normal file
207
ems-admin/src/main/resources/application-prod.yml
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
# 项目相关配置
|
||||||
|
xzzn:
|
||||||
|
# 名称
|
||||||
|
name: EMS
|
||||||
|
# 版本
|
||||||
|
version: 0.0.1
|
||||||
|
# 版权年份
|
||||||
|
copyrightYear: 2025
|
||||||
|
# 文件路径 示例( Windows配置D:/xzzn/uploadPath,Linux配置 /home/xzzn/uploadPath)
|
||||||
|
profile: /home/xzzn/uploadPath
|
||||||
|
# 获取ip地址开关
|
||||||
|
addressEnabled: false
|
||||||
|
# 验证码类型 math 数字计算 char 字符验证
|
||||||
|
captchaType: math
|
||||||
|
|
||||||
|
# 开发环境配置
|
||||||
|
server:
|
||||||
|
# 服务器的HTTP端口,默认为8080
|
||||||
|
port: 8089
|
||||||
|
servlet:
|
||||||
|
# 应用的访问路径
|
||||||
|
context-path: /
|
||||||
|
tomcat:
|
||||||
|
# tomcat的URI编码
|
||||||
|
uri-encoding: UTF-8
|
||||||
|
# 连接数满后的排队数,默认为100
|
||||||
|
accept-count: 1000
|
||||||
|
threads:
|
||||||
|
# tomcat最大线程数,默认为200
|
||||||
|
max: 800
|
||||||
|
# Tomcat启动初始化的线程数,默认值10
|
||||||
|
min-spare: 100
|
||||||
|
|
||||||
|
# 日志配置
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
com.xzzn: info
|
||||||
|
org.springframework: warn
|
||||||
|
|
||||||
|
# 用户配置
|
||||||
|
user:
|
||||||
|
password:
|
||||||
|
# 密码最大错误次数
|
||||||
|
maxRetryCount: 5
|
||||||
|
# 密码锁定时间(默认10分钟)
|
||||||
|
lockTime: 10
|
||||||
|
|
||||||
|
# Spring配置
|
||||||
|
spring:
|
||||||
|
# 资源信息
|
||||||
|
messages:
|
||||||
|
# 国际化资源文件路径
|
||||||
|
basename: i18n/messages
|
||||||
|
# 文件上传
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
# 单个文件大小
|
||||||
|
max-file-size: 10MB
|
||||||
|
# 设置总上传的文件大小
|
||||||
|
max-request-size: 20MB
|
||||||
|
# 服务模块
|
||||||
|
devtools:
|
||||||
|
restart:
|
||||||
|
# 热部署开关
|
||||||
|
enabled: true
|
||||||
|
# redis 配置
|
||||||
|
redis:
|
||||||
|
# 地址
|
||||||
|
host: 172.17.0.9
|
||||||
|
# 端口,默认为6379
|
||||||
|
port: 6379
|
||||||
|
# 数据库索引
|
||||||
|
database: 0
|
||||||
|
# 密码
|
||||||
|
password: 12345678
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 10s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# 连接池中的最小空闲连接
|
||||||
|
min-idle: 0
|
||||||
|
# 连接池中的最大空闲连接
|
||||||
|
max-idle: 8
|
||||||
|
# 连接池的最大数据库连接数
|
||||||
|
max-active: 8
|
||||||
|
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
|
max-wait: -1ms
|
||||||
|
# 数据源配置
|
||||||
|
datasource:
|
||||||
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
druid:
|
||||||
|
# 主库数据源
|
||||||
|
master:
|
||||||
|
url: jdbc:mysql://172.17.0.13:3306/setri_ems?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
|
username: ems
|
||||||
|
password: Aa112211!
|
||||||
|
# 从库数据源
|
||||||
|
slave:
|
||||||
|
# 从数据源开关/默认关闭
|
||||||
|
enabled: false
|
||||||
|
url:
|
||||||
|
username:
|
||||||
|
password:
|
||||||
|
# 初始连接数
|
||||||
|
initialSize: 5
|
||||||
|
# 最小连接池数量
|
||||||
|
minIdle: 10
|
||||||
|
# 最大连接池数量
|
||||||
|
maxActive: 20
|
||||||
|
# 配置获取连接等待超时的时间
|
||||||
|
maxWait: 60000
|
||||||
|
# 配置连接超时时间
|
||||||
|
connectTimeout: 30000
|
||||||
|
# 配置网络超时时间
|
||||||
|
socketTimeout: 60000
|
||||||
|
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||||
|
timeBetweenEvictionRunsMillis: 60000
|
||||||
|
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||||
|
minEvictableIdleTimeMillis: 300000
|
||||||
|
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||||
|
maxEvictableIdleTimeMillis: 900000
|
||||||
|
# 配置检测连接是否有效
|
||||||
|
validationQuery: SELECT 1 FROM DUAL
|
||||||
|
testWhileIdle: true
|
||||||
|
testOnBorrow: false
|
||||||
|
testOnReturn: false
|
||||||
|
webStatFilter:
|
||||||
|
enabled: true
|
||||||
|
statViewServlet:
|
||||||
|
enabled: true
|
||||||
|
# 设置白名单,不填则允许所有访问
|
||||||
|
allow:
|
||||||
|
url-pattern: /druid/*
|
||||||
|
# 控制台管理用户名和密码
|
||||||
|
login-username: xzzn
|
||||||
|
login-password: 123456
|
||||||
|
filter:
|
||||||
|
stat:
|
||||||
|
enabled: true
|
||||||
|
# 慢SQL记录
|
||||||
|
log-slow-sql: true
|
||||||
|
slow-sql-millis: 1000
|
||||||
|
merge-sql: true
|
||||||
|
wall:
|
||||||
|
config:
|
||||||
|
multi-statement-allow: true
|
||||||
|
|
||||||
|
# token配置
|
||||||
|
token:
|
||||||
|
# 令牌自定义标识
|
||||||
|
header: Authorization
|
||||||
|
# 令牌密钥
|
||||||
|
secret: abcdefghijklmnopqrstuvwxyz
|
||||||
|
# 令牌有效期(默认30分钟)
|
||||||
|
expireTime: 30
|
||||||
|
|
||||||
|
# MyBatis配置
|
||||||
|
mybatis:
|
||||||
|
# 搜索指定包别名
|
||||||
|
typeAliasesPackage: com.xzzn.**.domain
|
||||||
|
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||||
|
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||||
|
# 加载全局的配置文件
|
||||||
|
configLocation: classpath:mybatis/mybatis-config.xml
|
||||||
|
|
||||||
|
# PageHelper分页插件
|
||||||
|
pagehelper:
|
||||||
|
helperDialect: mysql
|
||||||
|
supportMethodsArguments: true
|
||||||
|
params: count=countSql
|
||||||
|
|
||||||
|
# Swagger配置
|
||||||
|
swagger:
|
||||||
|
# 是否开启swagger
|
||||||
|
enabled: true
|
||||||
|
# 请求前缀
|
||||||
|
pathMapping: /dev-api
|
||||||
|
|
||||||
|
# 防止XSS攻击
|
||||||
|
xss:
|
||||||
|
# 过滤开关
|
||||||
|
enabled: true
|
||||||
|
# 排除链接(多个用逗号分隔)
|
||||||
|
excludes: /system/notice
|
||||||
|
# 匹配链接
|
||||||
|
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||||
|
|
||||||
|
mqtt:
|
||||||
|
broker.url: tcp://121.5.164.6:1883
|
||||||
|
client.id: ems-cloud
|
||||||
|
username: dmbroker
|
||||||
|
password: qwer1234
|
||||||
|
connection-timeout: 15
|
||||||
|
keep-alive-interval: 30
|
||||||
|
automatic-reconnect: true
|
||||||
|
topic:
|
||||||
|
siteId:
|
||||||
|
|
||||||
|
modbus:
|
||||||
|
pool:
|
||||||
|
max-total: 20
|
||||||
|
max-idle: 10
|
||||||
|
min-idle: 3
|
||||||
|
poll:
|
||||||
|
interval: "0 */5 * * * *" # 5分钟间隔
|
||||||
|
timeout: 30000 # 30秒超时
|
||||||
@ -34,7 +34,7 @@ server:
|
|||||||
# 日志配置
|
# 日志配置
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
com.xzzn: debug
|
com.xzzn: info
|
||||||
org.springframework: warn
|
org.springframework: warn
|
||||||
|
|
||||||
# 用户配置
|
# 用户配置
|
||||||
@ -87,6 +87,66 @@ spring:
|
|||||||
max-active: 8
|
max-active: 8
|
||||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
max-wait: -1ms
|
max-wait: -1ms
|
||||||
|
# 数据源配置
|
||||||
|
datasource:
|
||||||
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
druid:
|
||||||
|
# 主库数据源
|
||||||
|
master:
|
||||||
|
url: jdbc:mysql://122.51.194.184:13306/setri_ems?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
|
username: ems
|
||||||
|
password: 12345678
|
||||||
|
# 从库数据源
|
||||||
|
slave:
|
||||||
|
# 从数据源开关/默认关闭
|
||||||
|
enabled: false
|
||||||
|
url:
|
||||||
|
username:
|
||||||
|
password:
|
||||||
|
# 初始连接数
|
||||||
|
initialSize: 5
|
||||||
|
# 最小连接池数量
|
||||||
|
minIdle: 10
|
||||||
|
# 最大连接池数量
|
||||||
|
maxActive: 20
|
||||||
|
# 配置获取连接等待超时的时间
|
||||||
|
maxWait: 60000
|
||||||
|
# 配置连接超时时间
|
||||||
|
connectTimeout: 30000
|
||||||
|
# 配置网络超时时间
|
||||||
|
socketTimeout: 60000
|
||||||
|
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||||
|
timeBetweenEvictionRunsMillis: 60000
|
||||||
|
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||||
|
minEvictableIdleTimeMillis: 300000
|
||||||
|
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||||
|
maxEvictableIdleTimeMillis: 900000
|
||||||
|
# 配置检测连接是否有效
|
||||||
|
validationQuery: SELECT 1 FROM DUAL
|
||||||
|
testWhileIdle: true
|
||||||
|
testOnBorrow: false
|
||||||
|
testOnReturn: false
|
||||||
|
webStatFilter:
|
||||||
|
enabled: true
|
||||||
|
statViewServlet:
|
||||||
|
enabled: true
|
||||||
|
# 设置白名单,不填则允许所有访问
|
||||||
|
allow:
|
||||||
|
url-pattern: /druid/*
|
||||||
|
# 控制台管理用户名和密码
|
||||||
|
login-username: xzzn
|
||||||
|
login-password: 123456
|
||||||
|
filter:
|
||||||
|
stat:
|
||||||
|
enabled: true
|
||||||
|
# 慢SQL记录
|
||||||
|
log-slow-sql: true
|
||||||
|
slow-sql-millis: 1000
|
||||||
|
merge-sql: true
|
||||||
|
wall:
|
||||||
|
config:
|
||||||
|
multi-statement-allow: true
|
||||||
|
|
||||||
# token配置
|
# token配置
|
||||||
token:
|
token:
|
||||||
@ -127,3 +187,23 @@ xss:
|
|||||||
excludes: /system/notice
|
excludes: /system/notice
|
||||||
# 匹配链接
|
# 匹配链接
|
||||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||||
|
|
||||||
|
mqtt:
|
||||||
|
broker.url: tcp://122.51.194.184:1883
|
||||||
|
client.id: ems-cloud
|
||||||
|
username: dmbroker
|
||||||
|
password: qwer1234
|
||||||
|
connection-timeout: 15
|
||||||
|
keep-alive-interval: 30
|
||||||
|
automatic-reconnect: true
|
||||||
|
topic:
|
||||||
|
siteId:
|
||||||
|
|
||||||
|
modbus:
|
||||||
|
pool:
|
||||||
|
max-total: 20
|
||||||
|
max-idle: 10
|
||||||
|
min-idle: 3
|
||||||
|
poll:
|
||||||
|
interval: "0 */5 * * * *" # 5分钟间隔
|
||||||
|
timeout: 30000 # 30秒超时
|
||||||
|
|||||||
@ -119,6 +119,12 @@
|
|||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- modbus4j (保留兼容) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.infiniteautomation</groupId>
|
||||||
|
<artifactId>modbus4j</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.xzzn.common.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记:调用insert后需要同步数据到其他服务器
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface SyncAfterInsert {
|
||||||
|
}
|
||||||
@ -119,4 +119,12 @@ public class RuoYiConfig
|
|||||||
{
|
{
|
||||||
return getProfile() + "/upload";
|
return getProfile() + "/upload";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取头像上传路径
|
||||||
|
*/
|
||||||
|
public static String getDevicePath()
|
||||||
|
{
|
||||||
|
return getProfile() + "/device";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -170,4 +170,9 @@ public class Constants
|
|||||||
*/
|
*/
|
||||||
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
|
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
|
||||||
"org.springframework", "org.apache", "com.xzzn.common.utils.file", "com.xzzn.common.config", "com.xzzn.generator" };
|
"org.springframework", "org.apache", "com.xzzn.common.utils.file", "com.xzzn.common.config", "com.xzzn.generator" };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 昨日充放电最晚数据有效期
|
||||||
|
*/
|
||||||
|
public static final Integer DATE_VALID_TIME = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,125 @@
|
|||||||
|
package com.xzzn.common.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据存储 Redis key 常量
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public class RedisKeyConstants
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* pcs数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String PCS = "PCS_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcs branch数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String BRANCH = "BRANCH_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stack电池堆数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String STACK = "STACK_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cluster电池簇数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String CLUSTER = "CLUSTER_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* battery单体电池数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String BATTERY = "BATTERY_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电表数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String AMMETER = "AMMETER_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动环数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String DH = "DH_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消防数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String XF = "XF_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电池组 redis key
|
||||||
|
*/
|
||||||
|
public static final String GROUP = "GROUP_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMSD原始数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String ORIGINAL_BMSD = "BMSD_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 冷却数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String COOLING = "COOLING_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EMS数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String EMS = "EMS_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点位匹配数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String POINT_MATCH = "POINT_MATCH_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点位枚举匹配数据 redis key
|
||||||
|
*/
|
||||||
|
public static final String POINT_ENUM_MATCH = "POINT_ENUM_MATCH_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* topic对应站点ID redis key
|
||||||
|
*/
|
||||||
|
public static final String SITE_ID = "SITE_ID_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存放单个设备同步过来的原始数据-最晚一次数据
|
||||||
|
*/
|
||||||
|
public static final String ORIGINAL_MQTT_DATA = "MQTT_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存放单个设备同步过来的告警点位原始数据-最晚一次数据
|
||||||
|
*/
|
||||||
|
public static final String ORIGINAL_MQTT_DATA_ALARM = "MQTT_ALARM_";
|
||||||
|
|
||||||
|
/** 存放订阅失败告警信息 */
|
||||||
|
public static final String TOPIC_FAILED_ALRAM_RECORD = "topic_failed_";
|
||||||
|
/** topic 内没有数据设备维度告警 */
|
||||||
|
public static final String TOPIC_EMPTY_ALARM_RECORD = "topic_empty_";
|
||||||
|
/** modbus读取 没有数据设备维度告警 */
|
||||||
|
public static final String MODBUS_EMPTY_ALARM_RECORD = "modbus_empty_";
|
||||||
|
/** modbus读取 设备离线告警 */
|
||||||
|
public static final String MODBUS_OFFLINE_ALARM_RECORD = "modbus_offline_";
|
||||||
|
|
||||||
|
/** 设备信息初始化 */
|
||||||
|
public static final String INIT_DEVICE_INFO = "init_device_info";
|
||||||
|
/** 告警匹配信息 */
|
||||||
|
public static final String ALARM_MATCH_INFO = "alarm_message_info";
|
||||||
|
|
||||||
|
/** 现有的告警数据 */
|
||||||
|
public static final String LATEST_ALARM_RECORD = "LATEST_ALARM_RECORD";
|
||||||
|
|
||||||
|
/** 预存电价时间配置 */
|
||||||
|
public static final String ENERGY_PRICE_TIME = "energy_price_time_";
|
||||||
|
|
||||||
|
/** dds昨日累计总收益 */
|
||||||
|
public static final String DDS_TOTAL_REVENUE = "total_revenue_";
|
||||||
|
/** fx实时总收益和当日实时收益 */
|
||||||
|
public static final String FXX_REALTIME_REVENUE = "realtime_revenue_";
|
||||||
|
|
||||||
|
/** 每个设备最新数据-设置失效时间-判断是否正常同步数据 */
|
||||||
|
public static final String SYNC_DATA= "SYNC_DATA_";
|
||||||
|
|
||||||
|
/** 每个设备最新数据-设置失效时间-判断是否正常同步数据 */
|
||||||
|
public static final String SYNC_DATA_ALARM = "SYNC_DATA_ALARM_";
|
||||||
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
package com.xzzn.common.core.controller;
|
package com.xzzn.common.core.controller;
|
||||||
|
|
||||||
import java.beans.PropertyEditorSupport;
|
import java.beans.PropertyEditorSupport;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -199,4 +201,76 @@ public class BaseController
|
|||||||
{
|
{
|
||||||
return getLoginUser().getUsername();
|
return getLoginUser().getUsername();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动处理分页
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
protected TableDataInfo getDataTable2(List<?> list)
|
||||||
|
{
|
||||||
|
// 1. 处理原列表为null的情况,避免空指针
|
||||||
|
List<?> targetList = (list == null) ? Collections.emptyList() : list;
|
||||||
|
List<?> subList;
|
||||||
|
|
||||||
|
// 2. 获取分页参数
|
||||||
|
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||||
|
int pageNum = pageDomain.getPageNum();
|
||||||
|
int pageSize = pageDomain.getPageSize();
|
||||||
|
|
||||||
|
// 3. 判断分页参数是否有效(pageNum和pageSize均为正数时才分页)
|
||||||
|
if (pageNum > 0 && pageSize > 0) {
|
||||||
|
// 计算起始索引(确保不小于0)
|
||||||
|
int startIndex = Math.max((pageNum - 1) * pageSize, 0);
|
||||||
|
|
||||||
|
// 关键修复:若起始索引已超出列表大小,直接返回空列表
|
||||||
|
if (startIndex >= targetList.size()) {
|
||||||
|
subList = Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
// 计算结束索引(不超过列表大小,且不小于起始索引)
|
||||||
|
int endIndex = Math.min(startIndex + pageSize, targetList.size());
|
||||||
|
endIndex = Math.max(endIndex, startIndex); // 防止endIndex < startIndex
|
||||||
|
|
||||||
|
// 截取子列表(转换为新ArrayList,避免视图依赖)
|
||||||
|
subList = new ArrayList<>(targetList.subList(startIndex, endIndex));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 分页参数无效时,返回全部数据
|
||||||
|
subList = new ArrayList<>(targetList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 封装返回结果
|
||||||
|
TableDataInfo rspData = new TableDataInfo();
|
||||||
|
rspData.setCode(HttpStatus.SUCCESS);
|
||||||
|
rspData.setMsg("查询成功");
|
||||||
|
rspData.setRows(subList);
|
||||||
|
rspData.setTotal(targetList.size());
|
||||||
|
return rspData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用分页工具方法
|
||||||
|
*/
|
||||||
|
protected <T> List<T> paginateList(List<T> sourceList) {
|
||||||
|
if (sourceList == null || sourceList.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
// 分页梳理
|
||||||
|
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||||
|
int pageNum = pageDomain.getPageNum();
|
||||||
|
int pageSize = pageDomain.getPageSize();
|
||||||
|
int startIndex = 0;
|
||||||
|
int endIndex = sourceList.size();
|
||||||
|
if (pageNum > 0 && pageSize > 0) {
|
||||||
|
// 计算起始索引(处理页码小于1的情况)
|
||||||
|
startIndex = Math.max((pageNum - 1) * pageSize, 0);
|
||||||
|
// 计算结束索引(处理超出列表长度的情况)
|
||||||
|
endIndex = Math.min(startIndex + pageSize, sourceList.size());
|
||||||
|
}
|
||||||
|
// 防止越界
|
||||||
|
if (startIndex >= sourceList.size()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
// 截取分页数据
|
||||||
|
return sourceList.subList(startIndex, endIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,6 +92,8 @@ public class SysUser extends BaseEntity
|
|||||||
/** 角色ID */
|
/** 角色ID */
|
||||||
private Long roleId;
|
private Long roleId;
|
||||||
|
|
||||||
|
private String belongSite;
|
||||||
|
|
||||||
public SysUser()
|
public SysUser()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -310,6 +312,14 @@ public class SysUser extends BaseEntity
|
|||||||
this.roleId = roleId;
|
this.roleId = roleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getBelongSite() {
|
||||||
|
return belongSite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBelongSite(String belongSite) {
|
||||||
|
this.belongSite = belongSite;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
@ -332,7 +342,7 @@ public class SysUser extends BaseEntity
|
|||||||
.append("updateBy", getUpdateBy())
|
.append("updateBy", getUpdateBy())
|
||||||
.append("updateTime", getUpdateTime())
|
.append("updateTime", getUpdateTime())
|
||||||
.append("remark", getRemark())
|
.append("remark", getRemark())
|
||||||
.append("dept", getDept())
|
.append("belongSite", getBelongSite())
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,111 @@
|
|||||||
|
package com.xzzn.common.core.modbus;
|
||||||
|
|
||||||
|
import com.serotonin.modbus4j.ModbusFactory;
|
||||||
|
import com.serotonin.modbus4j.ModbusMaster;
|
||||||
|
import com.serotonin.modbus4j.ip.IpParameters;
|
||||||
|
import com.xzzn.common.core.modbus.domain.DeviceConfig;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modbus连接管理器
|
||||||
|
* 使用长连接模式,维护连接缓存,复用已有连接
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class Modbus4jConnectionManager {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(Modbus4jConnectionManager.class);
|
||||||
|
|
||||||
|
private final ModbusFactory modbusFactory = new ModbusFactory();
|
||||||
|
|
||||||
|
private final Map<String, ModbusMaster> connectionCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取或创建连接(长连接模式)
|
||||||
|
*/
|
||||||
|
public ModbusMaster borrowMaster(DeviceConfig config) throws Exception {
|
||||||
|
String key = buildConnectionKey(config);
|
||||||
|
ModbusMaster master = connectionCache.get(key);
|
||||||
|
|
||||||
|
if (master == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
master = connectionCache.get(key);
|
||||||
|
if (master == null) {
|
||||||
|
master = createNewConnection(config);
|
||||||
|
connectionCache.put(key, master);
|
||||||
|
logger.info("创建新Modbus长连接: {}:{}", config.getHost(), config.getPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 归还连接(长连接模式,不关闭)
|
||||||
|
*/
|
||||||
|
public void returnMaster(DeviceConfig config, ModbusMaster master) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 废弃连接(发生异常时关闭并移除)
|
||||||
|
*/
|
||||||
|
public void invalidateMaster(DeviceConfig config, ModbusMaster master) {
|
||||||
|
String key = buildConnectionKey(config);
|
||||||
|
connectionCache.remove(key);
|
||||||
|
destroyMaster(master, config);
|
||||||
|
logger.warn("废弃并移除Modbus连接: {}:{}", config.getHost(), config.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModbusMaster createNewConnection(DeviceConfig config) throws Exception {
|
||||||
|
IpParameters params = new IpParameters();
|
||||||
|
params.setHost(config.getHost());
|
||||||
|
params.setPort(config.getPort());
|
||||||
|
params.setEncapsulated(false);
|
||||||
|
|
||||||
|
ModbusMaster master = modbusFactory.createTcpMaster(params, true);
|
||||||
|
master.init();
|
||||||
|
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroyMaster(ModbusMaster master, DeviceConfig config) {
|
||||||
|
if (master != null) {
|
||||||
|
try {
|
||||||
|
master.destroy();
|
||||||
|
logger.debug("已关闭Modbus连接: {}:{}", config.getHost(), config.getPort());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("关闭Modbus连接异常: {}:{}", config.getHost(), config.getPort(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildConnectionKey(DeviceConfig config) {
|
||||||
|
return config.getHost() + ":" + config.getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭所有连接
|
||||||
|
*/
|
||||||
|
public void closeAllConnections() {
|
||||||
|
for (Map.Entry<String, ModbusMaster> entry : connectionCache.entrySet()) {
|
||||||
|
try {
|
||||||
|
if (entry.getValue() != null) {
|
||||||
|
entry.getValue().destroy();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("关闭Modbus连接异常: {}", entry.getKey(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connectionCache.clear();
|
||||||
|
logger.info("已关闭所有Modbus连接");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,486 @@
|
|||||||
|
package com.xzzn.common.core.modbus;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.serotonin.modbus4j.BatchRead;
|
||||||
|
import com.serotonin.modbus4j.BatchResults;
|
||||||
|
import com.serotonin.modbus4j.ModbusMaster;
|
||||||
|
import com.serotonin.modbus4j.code.DataType;
|
||||||
|
import com.serotonin.modbus4j.exception.ErrorResponseException;
|
||||||
|
import com.serotonin.modbus4j.exception.ModbusTransportException;
|
||||||
|
import com.serotonin.modbus4j.locator.BaseLocator;
|
||||||
|
import com.serotonin.modbus4j.msg.WriteCoilRequest;
|
||||||
|
import com.serotonin.modbus4j.msg.WriteCoilResponse;
|
||||||
|
import com.serotonin.modbus4j.msg.WriteCoilsRequest;
|
||||||
|
import com.serotonin.modbus4j.msg.WriteCoilsResponse;
|
||||||
|
import com.serotonin.modbus4j.msg.WriteRegisterRequest;
|
||||||
|
import com.serotonin.modbus4j.msg.WriteRegisterResponse;
|
||||||
|
import com.serotonin.modbus4j.msg.WriteRegistersRequest;
|
||||||
|
import com.serotonin.modbus4j.msg.WriteRegistersResponse;
|
||||||
|
import com.xzzn.common.core.modbus.domain.DeviceConfig;
|
||||||
|
import com.xzzn.common.core.modbus.domain.TagConfig;
|
||||||
|
import com.xzzn.common.core.modbus.domain.WriteTagConfig;
|
||||||
|
import com.xzzn.common.core.redis.RedisCache;
|
||||||
|
import com.xzzn.common.enums.ModBusType;
|
||||||
|
import com.xzzn.common.enums.RegisterType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import static com.xzzn.common.enums.RegisterType.COIL;
|
||||||
|
import static com.xzzn.common.enums.RegisterType.DISCRETE_INPUT;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ModbusProcessor {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ModbusProcessor.class);
|
||||||
|
@Value("${modbus.read-timeout:8000}")
|
||||||
|
private int readTimeout;
|
||||||
|
@Value("${modbus.write-timeout:5000}")
|
||||||
|
private int writeTimeout;
|
||||||
|
@Value("${modbus.read-retries:1}")
|
||||||
|
private int readRetries;
|
||||||
|
@Value("${modbus.write-retries:1}")
|
||||||
|
private int writeRetries;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisCache redisCache;
|
||||||
|
@Autowired
|
||||||
|
private Modbus4jConnectionManager connectionManager;
|
||||||
|
|
||||||
|
public boolean writeDataToDevice(DeviceConfig config) {
|
||||||
|
logger.info("writeDataToDevice: {}", JSON.toJSONString(config));
|
||||||
|
ModbusMaster master = null;
|
||||||
|
boolean result = false;
|
||||||
|
boolean hasError = false;
|
||||||
|
try {
|
||||||
|
master = connectionManager.borrowMaster(config);
|
||||||
|
master.setTimeout(writeTimeout);
|
||||||
|
master.setRetries(0);
|
||||||
|
result = writeTagValue(master, config, config.getWriteTags());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to borrow connection or write to devices '{}'", config.getDeviceName(), e);
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (master != null) {
|
||||||
|
if (hasError) {
|
||||||
|
// 发生异常时废弃连接,下次重新创建
|
||||||
|
connectionManager.invalidateMaster(config, master);
|
||||||
|
} else {
|
||||||
|
// 正常时归还连接
|
||||||
|
connectionManager.returnMaster(config, master);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean writeDataToDeviceWithRetry(DeviceConfig config) {
|
||||||
|
logger.info("writeDataToDevice: {}", JSON.toJSONString(config));
|
||||||
|
ModbusMaster master = null;
|
||||||
|
boolean result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
master = connectionManager.borrowMaster(config);
|
||||||
|
master.setTimeout(writeTimeout); // 设置超时时间
|
||||||
|
master.setRetries(0);
|
||||||
|
|
||||||
|
// 使用重试装饰器
|
||||||
|
ModbusMaster finalMaster = master;
|
||||||
|
result = RetryableModbusOperation.executeWithRetry(() -> {
|
||||||
|
return writeTagValue(finalMaster, config, config.getWriteTags());
|
||||||
|
}, writeRetries); // 最大重试次数由配置控制
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to borrow connection or write to devices '{}'", config.getDeviceName(), e);
|
||||||
|
result = false;
|
||||||
|
} finally {
|
||||||
|
if (master != null) {
|
||||||
|
connectionManager.returnMaster(config, master);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean writeTagValue(ModbusMaster master, DeviceConfig config, List<WriteTagConfig> tags) {
|
||||||
|
tags.forEach(tag -> {
|
||||||
|
Map<Integer, RegisterType> type = ModBusType.REGISTER_TYPE;
|
||||||
|
int firstDigit = Integer.parseInt(tag.getAddress().substring(0, 1));
|
||||||
|
int address = convertAddress(tag.getAddress());
|
||||||
|
RegisterType registerType = type.get(firstDigit);
|
||||||
|
logger.info("Register type: {}, address: {}, firstDigit: {}", registerType, tag.getAddress(), firstDigit);
|
||||||
|
switch (registerType) {
|
||||||
|
case COIL: {
|
||||||
|
boolean result = writeCoilRequest(master, config.getSlaveId(), address, Boolean.parseBoolean(String.valueOf(tag.getValue())));
|
||||||
|
tag.setWrite(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HOLDING_REGISTER: {
|
||||||
|
Number value = Double.parseDouble(String.valueOf(tag.getValue()));
|
||||||
|
double doubleValue = value.doubleValue();
|
||||||
|
// 检查是否在16位有符号整数范围内
|
||||||
|
if (doubleValue < -32768 || doubleValue > 32767) {
|
||||||
|
logger.warn("Value {} out of range for 16-bit signed register at address {}", doubleValue, address);
|
||||||
|
}
|
||||||
|
boolean result = writeRegisterRequest(master, config.getSlaveId(), address, (int) doubleValue);
|
||||||
|
tag.setWrite(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
logger.error("Unsupported register type: {}", registerType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
List<WriteTagConfig> collect = tags.stream().filter(tag -> !Objects.equals(tag.isWrite(), true)).collect(Collectors.toList());
|
||||||
|
if (!collect.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean writeCoilRequest(ModbusMaster master, int slaveId, int address, boolean value) {
|
||||||
|
try {
|
||||||
|
WriteCoilRequest request = new WriteCoilRequest(slaveId, address, value);
|
||||||
|
WriteCoilResponse response = (WriteCoilResponse)master.send(request);
|
||||||
|
if (response.isException()) {
|
||||||
|
logger.info("Write coil failed: " + response.getExceptionMessage());
|
||||||
|
} else {
|
||||||
|
logger.info("Write coil successful");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to write coil value '{}' to address '{}'", value, address, e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeCoilsRequest(ModbusMaster master, int slaveId, int address, boolean[] values) {
|
||||||
|
try {
|
||||||
|
WriteCoilsRequest request = new WriteCoilsRequest(slaveId, address, values);
|
||||||
|
WriteCoilsResponse response = (WriteCoilsResponse)master.send(request);
|
||||||
|
if (response.isException()) {
|
||||||
|
logger.info("Write coils failed: " + response.getExceptionMessage());
|
||||||
|
} else {
|
||||||
|
logger.info("Write coils successful");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to write coils value '{}' to address '{}'", values, address, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean writeRegisterRequest(ModbusMaster master, int slaveId, int address, int value) {
|
||||||
|
try {
|
||||||
|
WriteRegisterRequest request = new WriteRegisterRequest(slaveId, address, value);
|
||||||
|
WriteRegisterResponse response = (WriteRegisterResponse)master.send(request);
|
||||||
|
if (response.isException()) {
|
||||||
|
logger.info("Write register failed: " + response.getExceptionMessage());
|
||||||
|
} else {
|
||||||
|
logger.info("Write register successful");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to write register value '{}' to address '{}'", value, address, e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeRegistersRequest(ModbusMaster master, int slaveId, int address, short[] values) {
|
||||||
|
try {
|
||||||
|
WriteRegistersRequest request = new WriteRegistersRequest(slaveId, address, values);
|
||||||
|
WriteRegistersResponse response = (WriteRegistersResponse)master.send(request);
|
||||||
|
if (response.isException()) {
|
||||||
|
logger.info("Write registers failed: " + response.getExceptionMessage());
|
||||||
|
} else {
|
||||||
|
logger.info("Write registers successful");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to write registers value '{}' to address '{}'", values, address, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCoilValue(ModbusMaster master, int slaveId, int address, int value) {
|
||||||
|
// 写入单个线圈(从站ID, 地址, 布尔值)
|
||||||
|
BaseLocator<Boolean> coilLocator = BaseLocator.coilStatus(slaveId, address);
|
||||||
|
try {
|
||||||
|
// 写入布尔值到线圈
|
||||||
|
master.setValue(coilLocator, value);
|
||||||
|
logger.info("set coil successful");
|
||||||
|
} catch (ModbusTransportException | ErrorResponseException e) {
|
||||||
|
logger.error("Failed to set coil value '{}' to address '{}'", value, address, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setRegisterValue(ModbusMaster master, int slaveId, int address, int value) {
|
||||||
|
// 写入单个保持寄存器(从站, 地址, 16位整数)
|
||||||
|
BaseLocator<Number> holdingLocator = BaseLocator.holdingRegister(slaveId, address, DataType.TWO_BYTE_INT_SIGNED);
|
||||||
|
try {
|
||||||
|
// 写入整数值到保持寄存器
|
||||||
|
master.setValue(holdingLocator, value);
|
||||||
|
logger.info("set register successful");
|
||||||
|
} catch (ModbusTransportException | ErrorResponseException e) {
|
||||||
|
logger.error("Failed to set register value '{}' to address '{}'", value, address, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModbusMaster borrowMaster(DeviceConfig config) throws Exception {
|
||||||
|
ModbusMaster master = connectionManager.borrowMaster(config);
|
||||||
|
// 设置了Modbus通信的超时时间为5000毫秒(5秒)。当主设备与从设备通信时,若在5秒内未收到响应,则认为通信超时并抛出异常。这有助于避免长时间等待无响应的设备。
|
||||||
|
master.setTimeout(readTimeout);
|
||||||
|
master.setRetries(readRetries);
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> readDataFromDevice(DeviceConfig config, ModbusMaster master) {
|
||||||
|
Map<String, Object> deviceData = new HashMap<>();
|
||||||
|
boolean hasError = false;
|
||||||
|
try {
|
||||||
|
BatchResults<String> results = readTagValues(master, config.getSlaveId(), config.getTags());
|
||||||
|
for (TagConfig tag : config.getTags()) {
|
||||||
|
if (Objects.equals(tag.getDataType(), "FOUR_BYTE_FLOAT_DBCA")){
|
||||||
|
Object value = results.getValue(tag.getKey());
|
||||||
|
value = convertValueToFloat(value);
|
||||||
|
deviceData.put(tag.getKey(), value);
|
||||||
|
}else {
|
||||||
|
deviceData.put(tag.getKey(), results.getValue(tag.getKey()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed read from devices '{}'", config.getDeviceName(), e);
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (master != null) {
|
||||||
|
if (hasError) {
|
||||||
|
// 发生异常时废弃连接,下次重新创建
|
||||||
|
connectionManager.invalidateMaster(config, master);
|
||||||
|
} else {
|
||||||
|
// 正常时归还连接
|
||||||
|
connectionManager.returnMaster(config, master);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object readTagValue(ModbusMaster master, int slaveId, TagConfig tag) throws Exception {
|
||||||
|
Object value;
|
||||||
|
Map<Integer, RegisterType> type = ModBusType.REGISTER_TYPE;
|
||||||
|
Map<String, Integer> DATA_LENGTH = ModBusType.LENGTH;
|
||||||
|
int firstDigit = Integer.parseInt(tag.getAddress().substring(0, 1));
|
||||||
|
int address = 0;
|
||||||
|
int addressLength = tag.getAddress().length();
|
||||||
|
int exp = (int) Math.pow(10, addressLength-1);
|
||||||
|
if (firstDigit != 0){
|
||||||
|
int digit = Integer.parseInt(tag.getAddress());
|
||||||
|
address = digit % (exp);
|
||||||
|
}else {
|
||||||
|
address = Integer.parseInt(tag.getAddress());
|
||||||
|
}
|
||||||
|
RegisterType registerType = type.get(firstDigit);
|
||||||
|
int dataLength = DATA_LENGTH.get(tag.getDataType());
|
||||||
|
// 增加配置校验和警告
|
||||||
|
if ((Objects.equals(registerType, COIL) || Objects.equals(registerType, DISCRETE_INPUT))) {
|
||||||
|
logger.warn("Configuration warning for tag '{}': ModBusType is {} but DataType is {}. DataType should be BOOLEAN. Proceeding with BOOLEAN read.",
|
||||||
|
tag.getKey(), registerType, tag.getDataType());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
switch (registerType) {
|
||||||
|
case COIL: {
|
||||||
|
|
||||||
|
BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, address);
|
||||||
|
value = master.getValue(loc);
|
||||||
|
logger.info("读取线圈{}成功: {}",tag.getAddress(), value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DISCRETE_INPUT: {
|
||||||
|
BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, address);
|
||||||
|
value = master.getValue(loc);
|
||||||
|
logger.info("读取输入{}成功: {}",tag.getAddress(), value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HOLDING_REGISTER: {
|
||||||
|
if (dataLength == 28){
|
||||||
|
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, address, 4);
|
||||||
|
value = master.getValue(locator);
|
||||||
|
//将 value 转换为二进制数据
|
||||||
|
value = convertValueToFloat(value);
|
||||||
|
}else{
|
||||||
|
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, address, dataLength);
|
||||||
|
value = master.getValue(locator);
|
||||||
|
}
|
||||||
|
logger.info("读取保持寄存器{}成功: {}",tag.getAddress(), value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INPUT_REGISTER: {
|
||||||
|
BaseLocator<Number> locator = BaseLocator.inputRegister(slaveId, address, dataLength);
|
||||||
|
value= master.getValue(locator);
|
||||||
|
logger.info("读取输入寄存器{}成功: {}",tag.getAddress(), value);
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
logger.error("Unsupported register type: {}", registerType);
|
||||||
|
value = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
logger.error("Failed to read tag '{}'", tag.getKey(), e);
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private BatchResults<String> readTagValues(ModbusMaster master, int slaveId, List<TagConfig> tags) throws Exception {
|
||||||
|
try {
|
||||||
|
BatchResults<String> results = sendBatchRead(master, slaveId, tags);
|
||||||
|
logBatchResults(tags, results);
|
||||||
|
return results;
|
||||||
|
} catch (Exception e){
|
||||||
|
if (isTimeoutException(e)) {
|
||||||
|
logger.warn("批量读取超时,尝试降级为单点读取,slaveId: {}", slaveId);
|
||||||
|
BatchResults<String> fallback = new BatchResults<>();
|
||||||
|
for (TagConfig tag : tags) {
|
||||||
|
Object value = readTagValue(master, slaveId, tag);
|
||||||
|
fallback.addResult(tag.getKey(), value);
|
||||||
|
}
|
||||||
|
logBatchResults(tags, fallback);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
logger.error("Failed to read master '{}'", slaveId, e);
|
||||||
|
throw new Exception(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BatchResults<String> sendBatchRead(ModbusMaster master, int slaveId, List<TagConfig> tags) throws Exception {
|
||||||
|
BatchRead<String> batch = new BatchRead<>();
|
||||||
|
tags.forEach(tag -> {
|
||||||
|
Map<Integer, RegisterType> type = ModBusType.REGISTER_TYPE;
|
||||||
|
Map<String, Integer> DATA_LENGTH = ModBusType.LENGTH;
|
||||||
|
int firstDigit = Integer.parseInt(tag.getAddress().substring(0, 1));
|
||||||
|
int address = 0;
|
||||||
|
int addressLength = tag.getAddress().length();
|
||||||
|
int exp = (int) Math.pow(10, addressLength - 1);
|
||||||
|
if (firstDigit != 0) {
|
||||||
|
int digit = Integer.parseInt(tag.getAddress());
|
||||||
|
address = digit % (exp);
|
||||||
|
} else {
|
||||||
|
address = Integer.parseInt(tag.getAddress());
|
||||||
|
}
|
||||||
|
RegisterType registerType = type.get(firstDigit);
|
||||||
|
int dataLength = DATA_LENGTH.get(tag.getDataType());
|
||||||
|
switch (registerType) {
|
||||||
|
case COIL: {
|
||||||
|
BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, address);
|
||||||
|
batch.addLocator(tag.getKey(), loc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DISCRETE_INPUT: {
|
||||||
|
BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, address);
|
||||||
|
batch.addLocator(tag.getKey(), loc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HOLDING_REGISTER: {
|
||||||
|
if (dataLength == 28) {
|
||||||
|
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, address, 4);
|
||||||
|
batch.addLocator(tag.getKey(), locator);
|
||||||
|
} else {
|
||||||
|
BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, address, dataLength);
|
||||||
|
batch.addLocator(tag.getKey(), loc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INPUT_REGISTER: {
|
||||||
|
BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, address, dataLength);
|
||||||
|
batch.addLocator(tag.getKey(), loc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return master.send(batch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logBatchResults(List<TagConfig> tags, BatchResults<String> results) {
|
||||||
|
List<String> logInfoList = new ArrayList<>();
|
||||||
|
for (TagConfig tag : tags) {
|
||||||
|
StringBuilder logInfo = new StringBuilder();
|
||||||
|
logInfo.append(tag.getAddress());
|
||||||
|
if (tag.getBit() != null) {
|
||||||
|
logInfo.append("(").append(tag.getBit()).append("):");
|
||||||
|
} else {
|
||||||
|
logInfo.append(":");
|
||||||
|
}
|
||||||
|
logInfo.append(results.getValue(tag.getKey()));
|
||||||
|
logInfoList.add(logInfo.toString());
|
||||||
|
}
|
||||||
|
logger.info("批处理读取寄存器成功: {}", JSON.toJSONString(logInfoList));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTimeoutException(Throwable e) {
|
||||||
|
Throwable current = e;
|
||||||
|
while (current != null) {
|
||||||
|
if (current instanceof com.serotonin.modbus4j.sero.messaging.TimeoutException) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
current = current.getCause();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float convertValueToFloat(Object value) {
|
||||||
|
if (!(value instanceof Number)) {
|
||||||
|
throw new IllegalArgumentException("Input must be a Number");
|
||||||
|
}
|
||||||
|
|
||||||
|
int intValue = ((Number) value).intValue();
|
||||||
|
String binaryData = Integer.toBinaryString(intValue);
|
||||||
|
|
||||||
|
// 补足32位二进制字符串
|
||||||
|
if (binaryData.length() < 32) {
|
||||||
|
binaryData = String.format("%32s", binaryData).replace(' ', '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分割为4个字节并重组为 dcba 格式
|
||||||
|
byte[] reorderedBytes = new byte[4];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int start = i * 8;
|
||||||
|
String byteStr = binaryData.substring(start, start + 8);
|
||||||
|
reorderedBytes[3 - i] = (byte) Integer.parseInt(byteStr, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 ByteBuffer 提高可读性和安全性
|
||||||
|
return Float.intBitsToFloat(
|
||||||
|
java.nio.ByteBuffer.wrap(reorderedBytes).getInt()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 转换寄存器地址 */
|
||||||
|
public static int convertAddress(String address) {
|
||||||
|
if (StringUtils.isBlank(address)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int firstDigit = Integer.parseInt(address.substring(0, 1));
|
||||||
|
int addressLength = address.length();
|
||||||
|
int exp = (int) Math.pow(10, addressLength-1);
|
||||||
|
if (firstDigit != 0){
|
||||||
|
int digit = Integer.parseInt(address);
|
||||||
|
return digit % (exp);
|
||||||
|
} else {
|
||||||
|
return Integer.parseInt(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.xzzn.common.core.modbus;
|
||||||
|
|
||||||
|
|
||||||
|
import com.serotonin.modbus4j.ModbusFactory;
|
||||||
|
import com.serotonin.modbus4j.ModbusMaster;
|
||||||
|
import com.serotonin.modbus4j.ip.IpParameters;
|
||||||
|
|
||||||
|
import org.apache.commons.pool2.BasePooledObjectFactory;
|
||||||
|
import org.apache.commons.pool2.PooledObject;
|
||||||
|
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||||
|
|
||||||
|
public class PooledModbusMasterFactory extends BasePooledObjectFactory<ModbusMaster> {
|
||||||
|
|
||||||
|
private final String host;
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
public PooledModbusMasterFactory(String host, int port) {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModbusMaster create() throws Exception {
|
||||||
|
IpParameters params = new IpParameters();
|
||||||
|
params.setHost(this.host);
|
||||||
|
params.setPort(this.port);
|
||||||
|
params.setEncapsulated(false);
|
||||||
|
|
||||||
|
ModbusMaster master = new ModbusFactory().createTcpMaster(params, true);
|
||||||
|
master.init();
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PooledObject<ModbusMaster> wrap(ModbusMaster master) {
|
||||||
|
return new DefaultPooledObject<>(master);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyObject(PooledObject<ModbusMaster> p) throws Exception {
|
||||||
|
if (p.getObject() != null) {
|
||||||
|
p.getObject().destroy();
|
||||||
|
}
|
||||||
|
super.destroyObject(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateObject(PooledObject<ModbusMaster> p) {
|
||||||
|
// testConnectivity() 方法在 modbus4j 中不存在。
|
||||||
|
// 一个真正的验证需要执行一次读操作,但这需要 slaveId,而工厂是通用的,不知道 slaveId。
|
||||||
|
// 因此,我们使用一个较弱的验证,只检查 master 对象是否已初始化。
|
||||||
|
// 这无法检测到被远程设备断开的连接,错误将在实际读取操作中被捕获。
|
||||||
|
if (p.getObject() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return p.getObject().isInitialized();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.xzzn.common.core.modbus;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modbus重试
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RetryableModbusOperation {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(RetryableModbusOperation.class);
|
||||||
|
|
||||||
|
public interface ModbusOperation<T> {
|
||||||
|
T execute() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T executeWithRetry(ModbusOperation<T> operation, int maxRetries) {
|
||||||
|
int retryCount = 0;
|
||||||
|
Exception lastException = null;
|
||||||
|
|
||||||
|
while (retryCount <= maxRetries) {
|
||||||
|
try {
|
||||||
|
return operation.execute();
|
||||||
|
} catch (Exception e) {
|
||||||
|
lastException = e;
|
||||||
|
retryCount++;
|
||||||
|
if (retryCount <= maxRetries) {
|
||||||
|
logger.info("Operation failed, retrying... (Attempt {})", retryCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.error("Max retries ({}) reached. Last error: {}", maxRetries,
|
||||||
|
lastException != null ? lastException.getMessage() : "Unknown");
|
||||||
|
throw new RuntimeException("Operation failed after " + maxRetries + " retries", lastException);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
package com.xzzn.common.core.modbus.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "modbus")
|
||||||
|
public class ModbusProperties {
|
||||||
|
|
||||||
|
private PoolConfig pool = new PoolConfig();
|
||||||
|
private TimeoutConfig timeout = new TimeoutConfig();
|
||||||
|
|
||||||
|
public PoolConfig getPool() {
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPool(PoolConfig pool) {
|
||||||
|
this.pool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeoutConfig getTimeout() {
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeout(TimeoutConfig timeout) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PoolConfig {
|
||||||
|
private int maxTotal = 20;
|
||||||
|
private int maxIdle = 10;
|
||||||
|
private int minIdle = 3;
|
||||||
|
private long maxWait = 5000;
|
||||||
|
private long timeBetweenEvictionRuns = 30000;
|
||||||
|
private long minEvictableIdleTime = 60000;
|
||||||
|
|
||||||
|
public int getMaxTotal() {
|
||||||
|
return maxTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxTotal(int maxTotal) {
|
||||||
|
this.maxTotal = maxTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxIdle() {
|
||||||
|
return maxIdle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxIdle(int maxIdle) {
|
||||||
|
this.maxIdle = maxIdle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinIdle() {
|
||||||
|
return minIdle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinIdle(int minIdle) {
|
||||||
|
this.minIdle = minIdle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxWait() {
|
||||||
|
return maxWait;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxWait(long maxWait) {
|
||||||
|
this.maxWait = maxWait;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimeBetweenEvictionRuns() {
|
||||||
|
return timeBetweenEvictionRuns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeBetweenEvictionRuns(long timeBetweenEvictionRuns) {
|
||||||
|
this.timeBetweenEvictionRuns = timeBetweenEvictionRuns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMinEvictableIdleTime() {
|
||||||
|
return minEvictableIdleTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinEvictableIdleTime(long minEvictableIdleTime) {
|
||||||
|
this.minEvictableIdleTime = minEvictableIdleTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TimeoutConfig {
|
||||||
|
private int read = 10000;
|
||||||
|
private int write = 5000;
|
||||||
|
|
||||||
|
public int getRead() {
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRead(int read) {
|
||||||
|
this.read = read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWrite() {
|
||||||
|
return write;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWrite(int write) {
|
||||||
|
this.write = write;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package com.xzzn.common.core.modbus.domain;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class DeviceConfig {
|
||||||
|
|
||||||
|
|
||||||
|
private String deviceNumber;
|
||||||
|
private String deviceName;
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private long time;
|
||||||
|
private int slaveId;
|
||||||
|
private boolean enabled;
|
||||||
|
private List<TagConfig> tags;
|
||||||
|
private List<WriteTagConfig> writeTags;
|
||||||
|
|
||||||
|
public String getDeviceNumber() {
|
||||||
|
return deviceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceNumber(String deviceNumber) {
|
||||||
|
this.deviceNumber = deviceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceName() {
|
||||||
|
return deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceName(String deviceName) {
|
||||||
|
this.deviceName = deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTime(long time) {
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSlaveId() {
|
||||||
|
return slaveId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlaveId(int slaveId) {
|
||||||
|
this.slaveId = slaveId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TagConfig> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTags(List<TagConfig> tags) {
|
||||||
|
this.tags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WriteTagConfig> getWriteTags() {
|
||||||
|
return writeTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWriteTags(List<WriteTagConfig> writeTags) {
|
||||||
|
this.writeTags = writeTags;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
package com.xzzn.common.core.modbus.domain;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class TagConfig {
|
||||||
|
private String key;
|
||||||
|
private String des;
|
||||||
|
private String address;
|
||||||
|
private String dataType;
|
||||||
|
private float a;
|
||||||
|
private float k;
|
||||||
|
private float b;
|
||||||
|
private Integer bit;
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDes() {
|
||||||
|
return des;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDes(String des) {
|
||||||
|
this.des = des;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataType() {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataType(String dataType) {
|
||||||
|
this.dataType = dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setA(float a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getK() {
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setK(float k) {
|
||||||
|
this.k = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setB(float b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBit() {
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBit(Integer bit) {
|
||||||
|
this.bit = bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.xzzn.common.core.modbus.domain;
|
||||||
|
|
||||||
|
public class WriteTagConfig {
|
||||||
|
private Object value;
|
||||||
|
private String address;
|
||||||
|
private boolean isWrite;
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Object value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWrite() {
|
||||||
|
return isWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWrite(boolean write) {
|
||||||
|
isWrite = write;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,10 +7,8 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.BoundSetOperations;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.data.redis.core.HashOperations;
|
import org.springframework.data.redis.core.*;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.data.redis.core.ValueOperations;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -243,6 +241,18 @@ public class RedisCache
|
|||||||
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Hash中的多条数据
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @param hKey Hash键
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean deleteAllCacheMapValue(final String key, final Object[] hKey)
|
||||||
|
{
|
||||||
|
return redisTemplate.opsForHash().delete(key, hKey) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除Hash中的某条数据
|
* 删除Hash中的某条数据
|
||||||
*
|
*
|
||||||
@ -255,6 +265,18 @@ public class RedisCache
|
|||||||
return redisTemplate.opsForHash().delete(key, hKey) > 0;
|
return redisTemplate.opsForHash().delete(key, hKey) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量往Hash中存入数据
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @param value 值
|
||||||
|
*/
|
||||||
|
public <T> void setAllCacheMapValue(final String key, final Map<String, T> value)
|
||||||
|
{
|
||||||
|
redisTemplate.opsForHash().putAll(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得缓存的基本对象列表
|
* 获得缓存的基本对象列表
|
||||||
*
|
*
|
||||||
@ -265,4 +287,89 @@ public class RedisCache
|
|||||||
{
|
{
|
||||||
return redisTemplate.keys(pattern);
|
return redisTemplate.keys(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除list
|
||||||
|
*
|
||||||
|
* @param key Redis键
|
||||||
|
* @return 对象列表
|
||||||
|
*/
|
||||||
|
public boolean deleteList(final String key)
|
||||||
|
{
|
||||||
|
return redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量缓存
|
||||||
|
* @param cacheMap
|
||||||
|
*/
|
||||||
|
public <T> void multiSet(final Map<String, String> cacheMap)
|
||||||
|
{
|
||||||
|
|
||||||
|
redisTemplate.opsForValue().multiSet(cacheMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量设置键值对,并为每个键设置相同的过期时间
|
||||||
|
* @param keyValueMap 键值对集合
|
||||||
|
* @param timeout 过期时间
|
||||||
|
* @param unit 时间单位
|
||||||
|
*/
|
||||||
|
public void multiSetWithExpire(Map<String, String> keyValueMap, long timeout, TimeUnit unit) {
|
||||||
|
if (keyValueMap.isEmpty()) {
|
||||||
|
return; // 空集合直接返回
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用Redis管道批量执行命令
|
||||||
|
redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||||
|
// 循环处理每个键值对
|
||||||
|
for (Map.Entry<String, String> entry : keyValueMap.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
String value = entry.getValue();
|
||||||
|
|
||||||
|
// 1. 设置键值对
|
||||||
|
operations.opsForValue().set(key, value);
|
||||||
|
// 2. 设置过期时间
|
||||||
|
operations.expire(key, timeout, unit);
|
||||||
|
}
|
||||||
|
return null; // 管道操作无需返回值
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定站点的所有历史测试数据缓存(最精准)
|
||||||
|
* @param testSiteId 测试数据所属的站点ID(如"test-site-001")
|
||||||
|
*/
|
||||||
|
public void deleteTestCacheBySite(String testSiteId) {
|
||||||
|
System.out.println("开删除缓存redis:" + testSiteId + "<UNK>");
|
||||||
|
if (testSiteId == null || testSiteId.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造键前缀:测试站点ID开头的所有缓存键(无论粒度和时间)
|
||||||
|
String pattern = testSiteId + "_*";
|
||||||
|
deleteCacheByPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据键前缀批量删除缓存(核心方法)
|
||||||
|
* @param pattern 键匹配模式(支持Redis的通配符:*表示任意字符,?表示单个字符)
|
||||||
|
*/
|
||||||
|
public void deleteCacheByPattern(String pattern) {
|
||||||
|
try {
|
||||||
|
// 1. 查找所有匹配的键(注意:keys命令在大数据量时可能阻塞Redis,建议生产环境用scan)
|
||||||
|
Set<String> keys = redisTemplate.keys(pattern);
|
||||||
|
if (keys == null || keys.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 批量删除匹配的键
|
||||||
|
long deleteCount = redisTemplate.delete(keys);
|
||||||
|
System.out.println("删除缓存数据:" + deleteCount + "<UNK>");
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* alarm-告警等级
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum AlarmLevelStatus
|
||||||
|
{
|
||||||
|
WARNING("A", "提示"), GENERAL("B", "一般"), SERIOUS("C", "严重"), EMERGENCY("D", "紧急");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
AlarmLevelStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* alarm-告警状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum AlarmStatus
|
||||||
|
{
|
||||||
|
WAITING("0", "待处理"), DONE("1", "已处理"),PROCESSING("2", "处理中");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
AlarmStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ammeter-电表数据类别
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum AmmeterCategory
|
||||||
|
{
|
||||||
|
CURRENT_FORWARD_ACTIVE("1", "当前正向有功电能"),
|
||||||
|
CURRENT_FORWARD_REACTIVE("2", "当前正向无功电能"),
|
||||||
|
CURRENT_REVERSE_ACTIVE("3", "当前反向有功电能"),
|
||||||
|
CURRENT_REVERSE_REACTIVE("4", "当前反向无功电能"),
|
||||||
|
A_POWER("3", "A相功率"),
|
||||||
|
B_POWER("4", "B相功率"),
|
||||||
|
C_POWER("5", "C相功率");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
AmmeterCategory(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcs-branch-支路状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum BranchStatus
|
||||||
|
{
|
||||||
|
STANDBY("0", "备用"), NORMAL("1", "正常"), SWITCHING("2", "切换中");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
BranchStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电状态&放电状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum ChargeStatus
|
||||||
|
{
|
||||||
|
CHARGING("1", "充电"), STANDBY("2", "待机"), DISCHARGING("3", "放电");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
ChargeStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device-通信状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum CommunicationStatus
|
||||||
|
{
|
||||||
|
OK("0", "正常"), SUSPEND("1", "通信中断") ,EXCEPTION("2", "异常");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
CommunicationStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcs-控制模式
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum ControlModeStatus
|
||||||
|
{
|
||||||
|
REMOTE("0", "远程"), LOCAL("1", "本地");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
ControlModeStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
ems-common/src/main/java/com/xzzn/common/enums/CostType.java
Normal file
42
ems-common/src/main/java/com/xzzn/common/enums/CostType.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电量类型
|
||||||
|
*/
|
||||||
|
public enum CostType
|
||||||
|
{
|
||||||
|
PEAK("peak", "尖"),
|
||||||
|
HIGH("high", "峰"),
|
||||||
|
FLAT("flat", "平"),
|
||||||
|
VALLEY("valley", "谷"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
CostType(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CostType getEnumByCode(String code)
|
||||||
|
{
|
||||||
|
for (CostType costType : CostType.values()) {
|
||||||
|
if (costType.code.equals(code)) {
|
||||||
|
return costType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
import org.apache.xmlbeans.impl.common.NameUtil;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device-设备类别
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum DeviceCategory
|
||||||
|
{
|
||||||
|
PCS("PCS", "PCS设备", null),
|
||||||
|
BRANCH("BRANCH", "PCS分支设备", PCS),
|
||||||
|
STACK("STACK", "电池堆", null),
|
||||||
|
CLUSTER("CLUSTER", "电池簇", STACK),
|
||||||
|
BATTERY("BATTERY", "单体电池", CLUSTER),
|
||||||
|
AMMETER("AMMETER", "电表", null),
|
||||||
|
COOLING("COOLING", "冷却", null),
|
||||||
|
DH("DH", "动环", null),
|
||||||
|
XF("XF", "消防", null),
|
||||||
|
BATTERY_GROUP("BATTERY_GROUP", "电池组", null),
|
||||||
|
EMS("EMS", "EMS设备", null),;
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
private final DeviceCategory parentCategory;
|
||||||
|
|
||||||
|
DeviceCategory(String code, String info, DeviceCategory parentCategory)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
this.parentCategory = parentCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceCategory getParentCategory()
|
||||||
|
{
|
||||||
|
return parentCategory;
|
||||||
|
}
|
||||||
|
// 缓存info与code的映射(优化查询效率)
|
||||||
|
private static final Map<String, String> INFO_CODE_MAP = new HashMap<>();
|
||||||
|
|
||||||
|
// 静态块初始化缓存
|
||||||
|
static {
|
||||||
|
for (DeviceCategory category : DeviceCategory.values()) {
|
||||||
|
INFO_CODE_MAP.put(category.info, category.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过info获取code的方法
|
||||||
|
public static String getCodeByInfo(String info) {
|
||||||
|
return INFO_CODE_MAP.get(info); // 从缓存中直接获取,效率高
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过code获取父类code
|
||||||
|
// 根据字符串编码查找对应的枚举
|
||||||
|
public static DeviceCategory fromCode(String code) {
|
||||||
|
for (DeviceCategory category : values()) {
|
||||||
|
if (category.code.equalsIgnoreCase(code)) { // 忽略大小写,增强兼容性
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getInfoByCode(String code) {
|
||||||
|
for (DeviceCategory category : DeviceCategory.values()) {
|
||||||
|
if (category.code.equals(code)) {
|
||||||
|
return category.info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device-通信状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum DeviceRunningStatus
|
||||||
|
{
|
||||||
|
OFFLINE("0", "离线"),
|
||||||
|
ONLINE("1", "在线");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
DeviceRunningStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device-设备类型
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum DeviceType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 网络设备
|
||||||
|
*/
|
||||||
|
TCP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 串口设备
|
||||||
|
*/
|
||||||
|
RTU
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcs-并网状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum GridStatus
|
||||||
|
{
|
||||||
|
GRID("0", "并网"), NOTGRID("1", "未并网");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
GridStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
import com.serotonin.modbus4j.code.DataType;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
public class ModBusType {
|
||||||
|
|
||||||
|
|
||||||
|
public static final Map<Integer, RegisterType> REGISTER_TYPE = new HashMap<Integer, RegisterType>();
|
||||||
|
public static final Map<String, Integer> LENGTH = new HashMap<String, Integer>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
REGISTER_TYPE.put(0, RegisterType.COIL);
|
||||||
|
REGISTER_TYPE.put(1, RegisterType.DISCRETE_INPUT);
|
||||||
|
REGISTER_TYPE.put(4, RegisterType.HOLDING_REGISTER);
|
||||||
|
REGISTER_TYPE.put(3, RegisterType.INPUT_REGISTER);
|
||||||
|
|
||||||
|
|
||||||
|
LENGTH.put("BINARY",DataType.BINARY);
|
||||||
|
LENGTH.put("TWO_BYTE_INT_UNSIGNED",DataType.TWO_BYTE_INT_UNSIGNED);
|
||||||
|
LENGTH.put("TWO_BYTE_INT_SIGNED",DataType.TWO_BYTE_INT_SIGNED);
|
||||||
|
LENGTH.put("TWO_BYTE_INT_UNSIGNED_SWAPPED",DataType.TWO_BYTE_INT_UNSIGNED_SWAPPED);
|
||||||
|
LENGTH.put("TWO_BYTE_INT_SIGNED_SWAPPED",DataType.TWO_BYTE_INT_SIGNED_SWAPPED);
|
||||||
|
LENGTH.put("FOUR_BYTE_INT_UNSIGNED",DataType.FOUR_BYTE_INT_UNSIGNED);
|
||||||
|
LENGTH.put("FOUR_BYTE_INT_SIGNED",DataType.FOUR_BYTE_INT_SIGNED);
|
||||||
|
LENGTH.put("FOUR_BYTE_INT_UNSIGNED_SWAPPED",DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED);
|
||||||
|
LENGTH.put("FOUR_BYTE_INT_SIGNED_SWAPPED",DataType.FOUR_BYTE_INT_SIGNED_SWAPPED);
|
||||||
|
LENGTH.put("FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED",DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED);
|
||||||
|
LENGTH.put("FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED",DataType.FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED);
|
||||||
|
LENGTH.put("FOUR_BYTE_FLOAT",DataType.FOUR_BYTE_FLOAT);
|
||||||
|
LENGTH.put("FOUR_BYTE_FLOAT_SWAPPED",DataType.FOUR_BYTE_FLOAT_SWAPPED);
|
||||||
|
LENGTH.put("FOUR_BYTE_FLOAT_SWAPPED_INVERTED",DataType.FOUR_BYTE_FLOAT_SWAPPED_INVERTED);
|
||||||
|
LENGTH.put("EIGHT_BYTE_INT_UNSIGNED",DataType.EIGHT_BYTE_INT_UNSIGNED);
|
||||||
|
LENGTH.put("EIGHT_BYTE_INT_SIGNED",DataType.EIGHT_BYTE_INT_SIGNED);
|
||||||
|
LENGTH.put("EIGHT_BYTE_INT_UNSIGNED_SWAPPED",DataType.EIGHT_BYTE_INT_UNSIGNED_SWAPPED);
|
||||||
|
LENGTH.put("EIGHT_BYTE_INT_SIGNED_SWAPPED",DataType.EIGHT_BYTE_INT_SIGNED_SWAPPED);
|
||||||
|
LENGTH.put("EIGHT_BYTE_FLOAT",DataType.EIGHT_BYTE_FLOAT);
|
||||||
|
LENGTH.put("EIGHT_BYTE_FLOAT_SWAPPED",DataType.EIGHT_BYTE_FLOAT_SWAPPED);
|
||||||
|
LENGTH.put("TWO_BYTE_BCD",DataType.TWO_BYTE_BCD);
|
||||||
|
LENGTH.put("FOUR_BYTE_BCD",DataType.FOUR_BYTE_BCD);
|
||||||
|
LENGTH.put("FOUR_BYTE_BCD_SWAPPED",DataType.FOUR_BYTE_BCD_SWAPPED);
|
||||||
|
LENGTH.put("CHAR",DataType.CHAR);
|
||||||
|
LENGTH.put("VARCHAR",DataType.VARCHAR);
|
||||||
|
|
||||||
|
LENGTH.put("FOUR_BYTE_FLOAT_DBCA",28);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备点位类型
|
||||||
|
*/
|
||||||
|
public enum PointType
|
||||||
|
{
|
||||||
|
YES(1, "是"),
|
||||||
|
NO(0, "否");
|
||||||
|
|
||||||
|
private final Integer code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
private static final Map<Integer, String> CODE_NAME_MAP = new HashMap<>(PointType.values().length);
|
||||||
|
|
||||||
|
static {
|
||||||
|
Arrays.stream(PointType.values()).forEach(record -> {
|
||||||
|
CODE_NAME_MAP.put(record.code, record.info);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PointType(Integer code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfoByCode(Integer code) {
|
||||||
|
return CODE_NAME_MAP.get(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警保护方案状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum ProtPlanStatus
|
||||||
|
{
|
||||||
|
STOP(0L, "未启用"), RUNNING(1L, "已启用");
|
||||||
|
|
||||||
|
private final Long code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
ProtPlanStatus(Long code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
public enum RegisterType {
|
||||||
|
COIL,
|
||||||
|
DISCRETE_INPUT,
|
||||||
|
HOLDING_REGISTER,
|
||||||
|
INPUT_REGISTER
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strategy模板-sdc限制
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum SdcLimitType
|
||||||
|
{
|
||||||
|
OFF("0", "关"), ON("1", "开");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
SdcLimitType(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum SiteDevice
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 电池堆
|
||||||
|
*/
|
||||||
|
BMSD,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电池簇
|
||||||
|
*/
|
||||||
|
BMSC,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PCS设备
|
||||||
|
*/
|
||||||
|
PCS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电表-总表
|
||||||
|
*/
|
||||||
|
LOAD,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电表-光伏电表
|
||||||
|
*/
|
||||||
|
METEGF,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电表-储能电表
|
||||||
|
*/
|
||||||
|
METE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电表-储能电表
|
||||||
|
*/
|
||||||
|
METE0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动环
|
||||||
|
*/
|
||||||
|
donghuan,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动环
|
||||||
|
*/
|
||||||
|
DH,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消防
|
||||||
|
*/
|
||||||
|
XF,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 中水冷却
|
||||||
|
*/
|
||||||
|
ZSLQ,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EMS
|
||||||
|
*/
|
||||||
|
EMS
|
||||||
|
}
|
||||||
31
ems-common/src/main/java/com/xzzn/common/enums/SiteEnum.java
Normal file
31
ems-common/src/main/java/com/xzzn/common/enums/SiteEnum.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device-设备类型
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum SiteEnum
|
||||||
|
{
|
||||||
|
DDS("021_DDS_01", "电动所内部"), FX("021_FXX_01", "奉贤西部污水处理厂");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
SiteEnum(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
ems-common/src/main/java/com/xzzn/common/enums/SocLimit.java
Normal file
32
ems-common/src/main/java/com/xzzn/common/enums/SocLimit.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SOC限制 (%) 1 = 开,0 = 关
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum SocLimit
|
||||||
|
{
|
||||||
|
OFF(0, "关"),
|
||||||
|
ON(1, "开"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final Integer code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
SocLimit(Integer code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strategy-策略状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum StrategyStatus
|
||||||
|
{
|
||||||
|
NOT_ENABLED("0", "未启用"), RUNNING("1", "已运行"),SUSPENDED("2", "已暂停"), DISABLE("3", "禁用"),DELETE("4", "删除");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
StrategyStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcs-开关状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum SwitchStatus
|
||||||
|
{
|
||||||
|
CLOSED("0", "闭合"), DISCONNECT("1", "断开"), FAULT_DISCONNECT("2", "故障断开");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
SwitchStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ticket - 工单状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum TicketStatus
|
||||||
|
{
|
||||||
|
WAITING("1", "待处理"), PROCESSING("2", "处理中"),DONE("3", "已处理");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
TicketStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT主题处理类型未知类型
|
||||||
|
*/
|
||||||
|
public enum TopicHandleType {
|
||||||
|
DEVICE("DEVICE", "设备数据"),
|
||||||
|
DEVICE_ALARM("DEVICE_ALARM", "设备告警数据"),
|
||||||
|
STRATEGY("STRATEGY", "策略数据"),
|
||||||
|
SYSTEM("SYSTEM", "系统数据"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
TopicHandleType(String code, String info) {
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据名称查找枚举
|
||||||
|
public static TopicHandleType getEnumByCode(String code) {
|
||||||
|
for (TopicHandleType type : values()) {
|
||||||
|
if (type.getName().equals(code)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 默认返回SYSTEM
|
||||||
|
return SYSTEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcs-工作状态
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
public enum WorkStatus
|
||||||
|
{
|
||||||
|
NORMAL("0", "运行"), STOP("1", "停机"), ABNORMAL("2", "故障");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
WorkStatus(String code, String info)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
ems-common/src/main/java/com/xzzn/common/enums/YesOrNo.java
Normal file
33
ems-common/src/main/java/com/xzzn/common/enums/YesOrNo.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package com.xzzn.common.enums;
|
||||||
|
|
||||||
|
public enum YesOrNo
|
||||||
|
{
|
||||||
|
YES(1, "是", "Y"),
|
||||||
|
NO(0, "否", "N");
|
||||||
|
|
||||||
|
private final Integer code;
|
||||||
|
private final String info;
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
YesOrNo(Integer code, String info, String value)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package com.xzzn.common.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class DataUtils {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(DataUtils.class);
|
||||||
|
|
||||||
|
public static String getJSONFromFile(InputStream inputStream) {
|
||||||
|
BufferedReader bufferReader = null;
|
||||||
|
StringBuffer stringBuffer = new StringBuffer();
|
||||||
|
try {
|
||||||
|
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
|
||||||
|
bufferReader = new BufferedReader(inputStreamReader);
|
||||||
|
stringBuffer = new StringBuffer();
|
||||||
|
String lineData = null;
|
||||||
|
while ((lineData = bufferReader.readLine()) != null) {
|
||||||
|
stringBuffer.append(lineData);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("getJSONFromFile error", e);
|
||||||
|
} finally {
|
||||||
|
if (null != bufferReader) {
|
||||||
|
try {
|
||||||
|
bufferReader.close();
|
||||||
|
inputStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("getJSONFromFile error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringBuffer.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,8 +8,14 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 时间工具类
|
* 时间工具类
|
||||||
@ -18,6 +24,8 @@ import org.apache.commons.lang3.time.DateFormatUtils;
|
|||||||
*/
|
*/
|
||||||
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
||||||
{
|
{
|
||||||
|
private static final org.apache.commons.logging.Log log = LogFactory.getLog(DateUtils.class);
|
||||||
|
|
||||||
public static String YYYY = "yyyy";
|
public static String YYYY = "yyyy";
|
||||||
|
|
||||||
public static String YYYY_MM = "yyyy-MM";
|
public static String YYYY_MM = "yyyy-MM";
|
||||||
@ -28,6 +36,13 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
|||||||
|
|
||||||
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
public static String YYYYMMDD = "yyyyMMdd";
|
||||||
|
|
||||||
|
public static String YYYY_MM_DD_HH_MM_00 = "yyyy-MM-dd HH:mm:00";
|
||||||
|
|
||||||
|
private static final DateTimeFormatter DAY_INPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
private static final DateTimeFormatter MIN_HOUR_INPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
private static String[] parsePatterns = {
|
private static String[] parsePatterns = {
|
||||||
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
|
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
|
||||||
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
|
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
|
||||||
@ -144,6 +159,14 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
|||||||
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
|
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算相差分钟
|
||||||
|
*/
|
||||||
|
public static int differentMinutesByMillisecond(Date date1, Date date2)
|
||||||
|
{
|
||||||
|
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 60)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算时间差
|
* 计算时间差
|
||||||
*
|
*
|
||||||
@ -188,4 +211,258 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
|||||||
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
|
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
|
||||||
return Date.from(zdt.toInstant());
|
return Date.from(zdt.toInstant());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Long getNowMonthLong() {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
long month = (long) calendar.get(Calendar.MONTH) + 1; // 月份从0开始,所以要加1
|
||||||
|
return month;
|
||||||
|
}
|
||||||
|
public static Long getNowDayLong() {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
long date = calendar.get(Calendar.DAY_OF_MONTH); // 月份从0开始,所以要加1
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalDateTime 转 Date(带时区)
|
||||||
|
public static Date convertToDate(LocalDateTime localDateTime) {
|
||||||
|
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
|
||||||
|
return Date.from(zonedDateTime.toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取昨天的日期,格式为yyyy-MM-dd 23:59:59
|
||||||
|
* @return 昨天的日期字符串
|
||||||
|
*/
|
||||||
|
public static String getYesterdayDate() {
|
||||||
|
// 获取今天的日期
|
||||||
|
LocalDate today = LocalDate.now();
|
||||||
|
// 减去一天得到昨天
|
||||||
|
LocalDate yesterday = today.minusDays(1);
|
||||||
|
// 将日期转换为LocalDateTime,并设置时间为23:59:59
|
||||||
|
LocalDateTime yesterdayEndTime = yesterday.atTime(23, 59, 59);
|
||||||
|
// 定义日期格式化器
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
|
||||||
|
// 格式化并返回
|
||||||
|
return yesterdayEndTime.format(formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验传入日期是否今天
|
||||||
|
* @param dataDate
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean checkIsToday(String dataDate) {
|
||||||
|
boolean flag = false;
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
int todayMonth = calendar.get(Calendar.MONTH) + 1;
|
||||||
|
int todayDay = calendar.get(Calendar.DAY_OF_MONTH);
|
||||||
|
if (StringUtils.isNotEmpty(dataDate)){
|
||||||
|
String[] pcsDateArray = dataDate.split("-");
|
||||||
|
if (todayMonth == Integer.parseInt(pcsDateArray[1]) &&
|
||||||
|
todayDay == Integer.parseInt(pcsDateArray[2])) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将时间转换为月份(YYYY-MM)
|
||||||
|
*/
|
||||||
|
public static String formatMonth(LocalDateTime time) {
|
||||||
|
return time.format(DateTimeFormatter.ofPattern("yyyy-MM"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加 LocalDateTime ==> String
|
||||||
|
*/
|
||||||
|
public static String convertToString(LocalDateTime time) {
|
||||||
|
return time.format(DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将输入时间调整到下一分钟的整点(秒数强制为00)
|
||||||
|
* 例如:2026-09-03 18:34:49 -> 2026-09-03 18:35:00
|
||||||
|
* @param timeStr 输入时间字符串(支持yyyy-MM-dd HH:mm:ss格式)
|
||||||
|
* @return 调整后的时间字符串(yyyy-MM-dd HH:mm:00)
|
||||||
|
* @throws ParseException 时间格式错误时抛出
|
||||||
|
*/
|
||||||
|
public static String adjustToNextMinute(String timeStr) throws ParseException {
|
||||||
|
// 1. 解析原始时间(使用包含秒数的格式)
|
||||||
|
SimpleDateFormat fullFormat = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
|
||||||
|
Date originalDate = fullFormat.parse(timeStr);
|
||||||
|
|
||||||
|
// 2. 使用Calendar调整时间
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.setTime(originalDate);
|
||||||
|
|
||||||
|
// 3. 如果当前秒数大于0,自动进1分钟(否则保持当前分钟)
|
||||||
|
if (cal.get(Calendar.SECOND) > 0) {
|
||||||
|
cal.add(Calendar.MINUTE, 1); // 分钟+1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 强制设置秒数和毫秒为0
|
||||||
|
cal.set(Calendar.SECOND, 0);
|
||||||
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
|
||||||
|
// 5. 格式化为目标字符串
|
||||||
|
return new SimpleDateFormat(YYYY_MM_DD_HH_MM_00).format(cal.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将"yyyy-MM-dd"字符串转换为Date类型的"yyyy-MM-dd 23:59:59"
|
||||||
|
*/
|
||||||
|
public static Date adjustToEndOfDay(String dateStr) {
|
||||||
|
// 1. 解析字符串为LocalDate(仅日期)
|
||||||
|
LocalDate localDate = LocalDate.parse(dateStr, DAY_INPUT_FORMATTER);
|
||||||
|
|
||||||
|
// 2. 补充时间为23:59:59,转换为LocalDateTime
|
||||||
|
LocalDateTime localDateTime = localDate.atTime(23, 59, 59);
|
||||||
|
|
||||||
|
// 3. 转换为Date类型(兼容旧API)
|
||||||
|
return Date.from(
|
||||||
|
localDateTime.atZone(TimeZone.getDefault().toZoneId()) // 适配系统时区
|
||||||
|
.toInstant()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 "yyyy-MM-dd HH:mm:ss" 字符串转换为Date类型的"yyyy-MM-dd HH:00:00"
|
||||||
|
*/
|
||||||
|
public static Date adjustToStartOfHour(String inputTime) {
|
||||||
|
// 1. 解析输入字符串为LocalDateTime(包含日期和小时、分钟)
|
||||||
|
LocalDateTime inputLdt = LocalDateTime.parse(inputTime, MIN_HOUR_INPUT_FORMATTER);
|
||||||
|
|
||||||
|
// 2. 调整分钟为00,秒为00(保留日期和小时不变)
|
||||||
|
LocalDateTime adjustedLdt = inputLdt
|
||||||
|
.withMinute(00) // 强制设为00分
|
||||||
|
.withSecond(00); // 强制设为00秒
|
||||||
|
|
||||||
|
// 3. 转换为Date类型(适配旧API)
|
||||||
|
return Date.from(
|
||||||
|
adjustedLdt.atZone(TimeZone.getDefault().toZoneId()) // 适配系统时区
|
||||||
|
.toInstant()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 "yyyy-MM-dd HH:mm:ss" 字符串转换为Date类型的"yyyy-MM-dd HH:mm:00"
|
||||||
|
*/
|
||||||
|
public static Date adjustToStartOfMinutes(String inputTime) {
|
||||||
|
// 1. 解析输入字符串为LocalDateTime(包含日期和小时、分钟)
|
||||||
|
LocalDateTime inputLdt = LocalDateTime.parse(inputTime, MIN_HOUR_INPUT_FORMATTER);
|
||||||
|
|
||||||
|
// 2. 调整分钟为00,秒为00(保留日期和小时不变)
|
||||||
|
LocalDateTime adjustedLdt = inputLdt
|
||||||
|
.withSecond(00); // 强制设为00秒
|
||||||
|
|
||||||
|
// 3. 转换为Date类型(适配旧API)
|
||||||
|
return Date.from(
|
||||||
|
adjustedLdt.atZone(TimeZone.getDefault().toZoneId()) // 适配系统时区
|
||||||
|
.toInstant()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将时间转换为月份(YYYY-MM-DD HH:mm:00)
|
||||||
|
*/
|
||||||
|
public static Date timeConvertToDate(LocalDateTime time) {
|
||||||
|
String dateStr = convertToString(time);
|
||||||
|
return dateTime(YYYY_MM_DD_HH_MM_SS,dateStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加 Date ==> LocalDateTime
|
||||||
|
*/
|
||||||
|
public static LocalDateTime toLocalDateTime(Date date)
|
||||||
|
{
|
||||||
|
if (date == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Date → LocalDateTime(保留原始时间)
|
||||||
|
LocalDateTime dateTime = date.toInstant()
|
||||||
|
.atZone(TimeZone.getDefault().toZoneId()) // 关联时区
|
||||||
|
.toLocalDateTime();
|
||||||
|
return dateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间戳转时间
|
||||||
|
public static Date convertUpdateTime(Long updateTime) {
|
||||||
|
if (updateTime == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容10位(秒级)和13位(毫秒级)
|
||||||
|
int length = String.valueOf(updateTime).length();
|
||||||
|
if (length == 10) { // 10位秒级 -> 转换为毫秒级
|
||||||
|
updateTime *= 1000;
|
||||||
|
} else if (length != 13) { // 既不是10位也不是13位,视为非法
|
||||||
|
System.err.println("时间戳格式错误,必须是10位(秒)或13位(毫秒)");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 转换为Date
|
||||||
|
return new Date(updateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取昨天的日期,格式为yyyy-MM-dd
|
||||||
|
* @return 昨天的日期字符串
|
||||||
|
*/
|
||||||
|
public static String getYesterdayDayString() {
|
||||||
|
// 获取今天的日期
|
||||||
|
LocalDate today = LocalDate.now();
|
||||||
|
// 减去一天得到昨天
|
||||||
|
LocalDate yesterday = today.minusDays(1);
|
||||||
|
// 定义日期格式化器
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD);
|
||||||
|
// 格式化并返回
|
||||||
|
return yesterday.format(formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取日期的开始时间
|
||||||
|
* @param dateString 格式为yyyy-MM-dd的日期字符串
|
||||||
|
* @return 日期的开始时间字符串
|
||||||
|
*/
|
||||||
|
public static String getDayBeginString(String dateString) {
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
|
try {
|
||||||
|
// 解析日期字符串
|
||||||
|
LocalDate date = LocalDate.parse(dateString, formatter);
|
||||||
|
|
||||||
|
// 创建时间段的开始时间 00:00:00
|
||||||
|
LocalDateTime startTime = date.atTime(LocalTime.MIN);
|
||||||
|
|
||||||
|
return convertToString(startTime);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
log.info("Error parsing date: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateString + " 00:00:00";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取日期的结束时间
|
||||||
|
* @param dateString 格式为yyyy-MM-dd的日期字符串
|
||||||
|
* @return 日期的结束时间字符串
|
||||||
|
*/
|
||||||
|
public static String getDayEndString(String dateString) {
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
|
try {
|
||||||
|
// 解析日期字符串
|
||||||
|
LocalDate date = LocalDate.parse(dateString, formatter);
|
||||||
|
|
||||||
|
// 创建时间段的结束时间 23:59:59
|
||||||
|
LocalDateTime endTime = date.atTime(LocalTime.MAX);
|
||||||
|
|
||||||
|
return convertToString(endTime);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
log.info("Error parsing date: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateString + " 23:59:59";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
44
ems-common/src/main/java/com/xzzn/common/utils/MapUtils.java
Normal file
44
ems-common/src/main/java/com/xzzn/common/utils/MapUtils.java
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package com.xzzn.common.utils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class MapUtils {
|
||||||
|
/**
|
||||||
|
* 从Map中获取值并转为Integer(适配tinyint字段)
|
||||||
|
* @param map 数据源Map
|
||||||
|
* @param key 字段名
|
||||||
|
* @return 转换后的Integer,默认返回0(可根据业务调整默认值)
|
||||||
|
*/
|
||||||
|
public static Integer getInteger(Map<String, Object> map, String key) {
|
||||||
|
// 1. 处理Map为null或key不存在的情况
|
||||||
|
if (map == null || !map.containsKey(key)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// 2. 获取原始值
|
||||||
|
Object value = map.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// 3. 转换为Integer(处理常见类型)
|
||||||
|
if (value instanceof Integer) {
|
||||||
|
return (Integer) value;
|
||||||
|
} else if (value instanceof Long) {
|
||||||
|
// 若Map中存的是Long(如JSON解析时数字默认转为Long)
|
||||||
|
return ((Long) value).intValue();
|
||||||
|
} else if (value instanceof String) {
|
||||||
|
// 若值是字符串类型(如"1")
|
||||||
|
try {
|
||||||
|
return Integer.parseInt((String) value);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// 字符串无法转数字,返回默认值
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (value instanceof Boolean) {
|
||||||
|
// 特殊情况:布尔值转整数(true→1,false→0)
|
||||||
|
return (Boolean) value ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
// 其他不支持的类型,返回默认值
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,17 @@
|
|||||||
package com.xzzn.common.utils;
|
package com.xzzn.common.utils;
|
||||||
|
|
||||||
|
import com.xzzn.common.constant.Constants;
|
||||||
|
import com.xzzn.common.core.text.StrFormatter;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import com.xzzn.common.constant.Constants;
|
|
||||||
import com.xzzn.common.core.text.StrFormatter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串工具类
|
* 字符串工具类
|
||||||
@ -719,4 +722,49 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
|
|||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static BigDecimal getBigDecimal(Object s){
|
||||||
|
BigDecimal result;
|
||||||
|
try {
|
||||||
|
result = new BigDecimal(s.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long getLong(Object s){
|
||||||
|
Long result;
|
||||||
|
try {
|
||||||
|
result = Long.parseLong(s.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Long.parseLong("0");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getString(Object s){
|
||||||
|
if (s == null) return null;
|
||||||
|
String result;
|
||||||
|
try {
|
||||||
|
result = String.valueOf(s);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 补全三位数字(返回字符串)
|
||||||
|
public static String fillThreeDigits(String value) {
|
||||||
|
if (value == null || value.trim().isEmpty()) {
|
||||||
|
return "000";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int num = Integer.parseInt(value.trim());
|
||||||
|
return String.format("%03d", num);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -46,7 +46,20 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.paho</groupId>
|
||||||
|
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.retry</groupId>
|
||||||
|
<artifactId>spring-retry</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.resilience4j</groupId>
|
||||||
|
<artifactId>resilience4j-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- 获取系统信息 -->
|
<!-- 获取系统信息 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.oshi</groupId>
|
<groupId>com.github.oshi</groupId>
|
||||||
@ -60,5 +73,4 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
package com.xzzn.framework.aspectj;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsDeviceChangeLog;
|
||||||
|
import com.xzzn.ems.domain.MqttSyncLog;
|
||||||
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
|
import com.xzzn.ems.mapper.MqttSyncLogMapper;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
import org.apache.juli.logging.Log;
|
||||||
|
import org.apache.juli.logging.LogFactory;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备运行状态变更日志同步
|
||||||
|
* 本地 - 云端
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class DeviceChangeLogAspect {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(DeviceChangeLogAspect.class);
|
||||||
|
@Autowired
|
||||||
|
private MqttPublisher mqttPublisher;
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private static final String MQTT_TOPIC = "DEVICE_CHANGE_LOG_UP";
|
||||||
|
private static final String TABLE_NAME = "ems_device_change_log";
|
||||||
|
@Autowired
|
||||||
|
private MqttSyncLogMapper mqttSyncLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
|
||||||
|
|
||||||
|
// 定义切点:拦截策略相关表的Mapper方法
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsDeviceChangeLogMapper.insertEmsDeviceChangeLog(..)) && args(insertEntity)) ")
|
||||||
|
public void insertPointCut(EmsDeviceChangeLog insertEntity) {
|
||||||
|
logger.info("【新增设备运行状态变更日志】DeviceChangeLogAspect 实例化");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法执行成功后发布同步消息
|
||||||
|
@AfterReturning(pointcut = "insertPointCut(insertEntity)", returning = "result")
|
||||||
|
public void afterInsert(JoinPoint joinPoint, EmsDeviceChangeLog insertEntity, Integer result) {
|
||||||
|
logger.info("【新增设备运行状态变更日志下发数据切面进入成功】");
|
||||||
|
if (result == 0 || insertEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String operateType = "INSERT";
|
||||||
|
String siteId = insertEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType,siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
String content = objectMapper.writeValueAsString(insertEntity);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// mqtt同步到云端
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建同步信息
|
||||||
|
private MqttSyncLog createMessageObject(String operateType, String siteId) {
|
||||||
|
MqttSyncLog message = new MqttSyncLog();
|
||||||
|
message.setSyncId(UUID.randomUUID().toString());
|
||||||
|
message.setOperateType(operateType);
|
||||||
|
message.setTableName(TABLE_NAME);
|
||||||
|
message.setCreateTime(new Date());
|
||||||
|
message.setTopic(MQTT_TOPIC);
|
||||||
|
message.setStatus("SUCCESS");
|
||||||
|
message.setSyncObject(siteId);
|
||||||
|
message.setTarget("CLOUD");
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
package com.xzzn.framework.aspectj;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsAlarmRecords;
|
||||||
|
import com.xzzn.ems.domain.MqttSyncLog;
|
||||||
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
|
import com.xzzn.ems.mapper.MqttSyncLogMapper;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
import org.apache.juli.logging.Log;
|
||||||
|
import org.apache.juli.logging.LogFactory;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地保护告警信息同步云端
|
||||||
|
* 本地 - 云端
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class FaultPlanAlarmAspect
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(FaultPlanAlarmAspect.class);
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
@Autowired
|
||||||
|
private MqttSyncLogMapper mqttSyncLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private MqttPublisher mqttPublisher;
|
||||||
|
@Autowired
|
||||||
|
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
|
||||||
|
|
||||||
|
private static final String MQTT_TOPIC = "FAULT_ALARM_RECORD_UP";
|
||||||
|
private static final String TABLE_NAME = "ems_alarm_records";
|
||||||
|
// 切入点:拦截所有添加了@SyncAfterInsert注解的方法
|
||||||
|
@Pointcut("@annotation(com.xzzn.common.annotation.SyncAfterInsert)")
|
||||||
|
public void syncInsertPointcut() {}
|
||||||
|
|
||||||
|
// 方法执行成功后同步数据
|
||||||
|
@AfterReturning(pointcut = "syncInsertPointcut()", returning = "result")
|
||||||
|
public void afterInsert(JoinPoint joinPoint, Integer result) {
|
||||||
|
logger.info("【新增保护策略告警数据切面进入成功】");
|
||||||
|
if (result == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取参数中的EmsAlarmRecords对象
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
EmsAlarmRecords alarmRecords = null;
|
||||||
|
for (Object arg : args) {
|
||||||
|
if (arg instanceof EmsAlarmRecords) {
|
||||||
|
alarmRecords = (EmsAlarmRecords) arg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (alarmRecords == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject("INSERT", alarmRecords.getSiteId());
|
||||||
|
try {
|
||||||
|
// 同步内容
|
||||||
|
String content = objectMapper.writeValueAsString(alarmRecords);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题-同步到云端
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建同步信息
|
||||||
|
private MqttSyncLog createMessageObject(String operateType, String siteId) {
|
||||||
|
MqttSyncLog message = new MqttSyncLog();
|
||||||
|
message.setSyncId(UUID.randomUUID().toString());
|
||||||
|
message.setOperateType(operateType);
|
||||||
|
message.setTableName(TABLE_NAME);
|
||||||
|
message.setCreateTime(new Date());
|
||||||
|
message.setTopic(MQTT_TOPIC);
|
||||||
|
message.setStatus("SUCCESS");
|
||||||
|
message.setSyncObject(siteId);
|
||||||
|
message.setTarget("CLOUD");
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,98 @@
|
|||||||
|
package com.xzzn.framework.aspectj;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsFaultIssueLog;
|
||||||
|
import com.xzzn.ems.domain.MqttSyncLog;
|
||||||
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
|
import com.xzzn.ems.mapper.MqttSyncLogMapper;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
import org.apache.juli.logging.Log;
|
||||||
|
import org.apache.juli.logging.LogFactory;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保护告警方案下发日志同步
|
||||||
|
* 本地 - 云端
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class FaultPlanIssueAspect {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(FaultPlanIssueAspect.class);
|
||||||
|
@Autowired
|
||||||
|
private MqttPublisher mqttPublisher;
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private static final String MQTT_TOPIC = "FAULT_PLAN_ISSUE_UP";
|
||||||
|
private static final String TABLE_NAME = "ems_fault_issue_log";
|
||||||
|
@Autowired
|
||||||
|
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
|
||||||
|
@Autowired
|
||||||
|
private MqttSyncLogMapper mqttSyncLogMapper;
|
||||||
|
|
||||||
|
// 定义切点:拦截策略相关表的Mapper方法
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsFaultIssueLogMapper.insertEmsFaultIssueLog(..)) && args(insertEntity)) ")
|
||||||
|
public void insertPointCut(EmsFaultIssueLog insertEntity) {
|
||||||
|
logger.info("【新增保护告警策略下发数据】FaultPlanIssueAspect 实例化");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法执行成功后发布同步消息
|
||||||
|
@AfterReturning(pointcut = "insertPointCut(insertEntity)", returning = "result")
|
||||||
|
public void afterInsert(JoinPoint joinPoint, EmsFaultIssueLog insertEntity, Integer result) {
|
||||||
|
logger.info("【新增保护告警策略下发数据切面进入成功】");
|
||||||
|
if (result == 0 || insertEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String operateType = "INSERT";
|
||||||
|
String siteId = insertEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType,siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
String content = objectMapper.writeValueAsString(insertEntity);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// mqtt同步到云端
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建同步信息
|
||||||
|
private MqttSyncLog createMessageObject(String operateType, String siteId) {
|
||||||
|
MqttSyncLog message = new MqttSyncLog();
|
||||||
|
message.setSyncId(UUID.randomUUID().toString());
|
||||||
|
message.setOperateType(operateType);
|
||||||
|
message.setTableName(TABLE_NAME);
|
||||||
|
message.setCreateTime(new Date());
|
||||||
|
message.setTopic(MQTT_TOPIC);
|
||||||
|
message.setStatus("SUCCESS");
|
||||||
|
message.setSyncObject(siteId);
|
||||||
|
message.setTarget("CLOUD");
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,277 @@
|
|||||||
|
package com.xzzn.framework.aspectj;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsFaultProtectionPlan;
|
||||||
|
import com.xzzn.ems.domain.MqttSyncLog;
|
||||||
|
import com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
|
import com.xzzn.ems.mapper.MqttSyncLogMapper;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
import org.apache.juli.logging.Log;
|
||||||
|
import org.apache.juli.logging.LogFactory;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cglib.beans.BeanMap;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备保护告警方案同步
|
||||||
|
* 云端 - 本地
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class FaultProtPlanAspect {
|
||||||
|
private static final Log logger = LogFactory.getLog(FaultProtPlanAspect.class);
|
||||||
|
@Autowired
|
||||||
|
private MqttPublisher mqttPublisher;
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private static final String MQTT_TOPIC = "FAULT_PROTECTION_PLAN_UP";
|
||||||
|
private static final String TABLE_NAME = "ems_fault_protection_plan";
|
||||||
|
@Autowired
|
||||||
|
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
|
||||||
|
@Autowired
|
||||||
|
private MqttSyncLogMapper mqttSyncLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsFaultProtectionPlanMapper emsFaultProtectionPlanMapper;
|
||||||
|
|
||||||
|
// 用ThreadLocal暂存删除前的对象
|
||||||
|
private ThreadLocal<EmsFaultProtectionPlan> beforeDeleteThreadLocal = new ThreadLocal<>();
|
||||||
|
@Before("execution(* com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper.deleteEmsFaultProtectionPlanByIds(..)) && args(ids)")
|
||||||
|
public void beforeDelete(JoinPoint joinPoint, Long[] ids) {
|
||||||
|
// 获取删除的id
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
if (args == null || args.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Long[] id = (Long[]) args[0];
|
||||||
|
|
||||||
|
// 查询删除前的数据
|
||||||
|
EmsFaultProtectionPlan faultInfo = emsFaultProtectionPlanMapper.selectEmsFaultProtectionPlanById(id[0]);
|
||||||
|
beforeDeleteThreadLocal.set(faultInfo); // 暂存
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义切点:拦截策略相关表的Mapper方法
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper.insertEmsFaultProtectionPlan(..)) && args(insertEntity)) ")
|
||||||
|
public void insertPointCut(EmsFaultProtectionPlan insertEntity) {
|
||||||
|
logger.info("【新增设备保护告警】FaultProtPlanAspect 实例化");
|
||||||
|
}
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(..)) && args(updateEntity)) ")
|
||||||
|
public void updatePointCut(EmsFaultProtectionPlan updateEntity) {
|
||||||
|
logger.info("【更新设备保护告警】FaultProtPlanAspect 实例化");
|
||||||
|
}
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper.deleteEmsFaultProtectionPlanByIds(..)) && args(ids)) ")
|
||||||
|
public void deletePointCut(Long[] ids) {
|
||||||
|
logger.info("【删除设备保护告警】FaultProtPlanAspect 实例化");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法执行成功后发布同步消息
|
||||||
|
@AfterReturning(pointcut = "insertPointCut(insertEntity)", returning = "result")
|
||||||
|
public void afterInsert(JoinPoint joinPoint, EmsFaultProtectionPlan insertEntity, Integer result) {
|
||||||
|
logger.info("【新增设备保护告警切面进入成功】");
|
||||||
|
if (result == 0 || insertEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
String siteId = insertEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType,siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
String content = convertEntityToJson(insertEntity);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
@AfterReturning(pointcut = "updatePointCut(updateEntity)", returning = "result")
|
||||||
|
public void afterUpdate(JoinPoint joinPoint, EmsFaultProtectionPlan updateEntity, Integer result) {
|
||||||
|
logger.info("【更新设备保护告警切面进入成功】");
|
||||||
|
if (result == 0 || updateEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
String siteId = updateEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType,siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
String content = convertEntityToJson(updateEntity);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
@AfterReturning(pointcut = "deletePointCut(id)", returning = "result")
|
||||||
|
public void afterDelete(JoinPoint joinPoint, Long[] id, Integer result) {
|
||||||
|
logger.info("【删除设备保护告警切面进入成功】");
|
||||||
|
if (result == 0 || id == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
|
||||||
|
// 从ThreadLocal中获取删除前的对象
|
||||||
|
EmsFaultProtectionPlan faultInfo = beforeDeleteThreadLocal.get();
|
||||||
|
if (faultInfo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType,faultInfo.getSiteId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
String content = convertEntityToJson(faultInfo);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建同步信息
|
||||||
|
private MqttSyncLog createMessageObject(String operateType, String siteId) {
|
||||||
|
MqttSyncLog message = new MqttSyncLog();
|
||||||
|
message.setSyncId(UUID.randomUUID().toString());
|
||||||
|
message.setOperateType(operateType);
|
||||||
|
message.setTableName(TABLE_NAME);
|
||||||
|
message.setCreateTime(new Date());
|
||||||
|
message.setTopic(MQTT_TOPIC);
|
||||||
|
message.setStatus("SUCCESS");
|
||||||
|
message.setSyncObject("CLOUD");
|
||||||
|
message.setTarget(siteId);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从方法名判断操作类型(示例:insert→INSERT,update→UPDATE,delete→DELETE)
|
||||||
|
private String getOperateType(String methodName) {
|
||||||
|
if (methodName.startsWith("insert")) return "INSERT";
|
||||||
|
if (methodName.startsWith("stop")) return "STOP";
|
||||||
|
if (methodName.startsWith("update") || methodName.startsWith("stop")) return "UPDATE";
|
||||||
|
if (methodName.startsWith("delete")) return "DELETE";
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从方法参数提取数据(示例:若参数是实体类,转成Map)
|
||||||
|
private Map<String, Object> extractDataFromParams(Object[] args) {
|
||||||
|
// 实际需反射获取实体类的字段和值(如id、name等)
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
if (args == null || args.length == 0) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
Object arg = args[i];
|
||||||
|
if (arg == null) {
|
||||||
|
continue; // 跳过null参数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理基本类型/包装类/字符串(直接作为值存入,key为"param0"、"param1"等)
|
||||||
|
if (isBasicType(arg.getClass())) {
|
||||||
|
String key = "param" + i; // 基本类型参数用"param0"、"param1"作为key
|
||||||
|
data.put(key, arg);
|
||||||
|
} else {
|
||||||
|
Map<String, Object> beanMap = beanToMap(arg);
|
||||||
|
data.putAll(beanMap); // 合并实体类的字段到结果Map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为基本类型或包装类或字符串
|
||||||
|
*/
|
||||||
|
private boolean isBasicType(Class<?> clazz) {
|
||||||
|
return clazz.isPrimitive() // 基本类型(int、long、boolean等)
|
||||||
|
|| clazz == String.class // 字符串
|
||||||
|
|| Number.class.isAssignableFrom(clazz) // 数字包装类(Integer、Long等)
|
||||||
|
|| clazz == Boolean.class; // 布尔包装类
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将实体类转换为Map(字段名为key,字段值为value)
|
||||||
|
*/
|
||||||
|
private Map<String, Object> beanToMap(Object bean) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
if (bean == null) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方式1:使用BeanMap(简洁高效)
|
||||||
|
BeanMap beanMap = BeanMap.create(bean);
|
||||||
|
for (Object key : beanMap.keySet()) {
|
||||||
|
map.put(key.toString(), beanMap.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在方法中转换
|
||||||
|
public String convertEntityToJson(EmsFaultProtectionPlan insertEntity) throws Exception {
|
||||||
|
if (insertEntity == null) {
|
||||||
|
return null; // 空对象返回空JSON
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将实体类转换为JSON字符串
|
||||||
|
return objectMapper.writeValueAsString(insertEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -25,7 +25,7 @@ import com.xzzn.common.utils.ip.IpUtils;
|
|||||||
* @author xzzn
|
* @author xzzn
|
||||||
*/
|
*/
|
||||||
@Aspect
|
@Aspect
|
||||||
@Component
|
@Component("customRateLimiterAspect")
|
||||||
public class RateLimiterAspect
|
public class RateLimiterAspect
|
||||||
{
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
|
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
|
||||||
|
|||||||
@ -0,0 +1,272 @@
|
|||||||
|
package com.xzzn.framework.aspectj;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRunning;
|
||||||
|
import com.xzzn.ems.domain.MqttSyncLog;
|
||||||
|
import com.xzzn.ems.domain.vo.StrategyRunningVo;
|
||||||
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
|
||||||
|
import com.xzzn.ems.mapper.MqttSyncLogMapper;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cglib.beans.BeanMap;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略运行切面同步
|
||||||
|
* 云端 - 本地
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class StrategyRunningSyncAspect {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(StrategyRunningSyncAspect.class);
|
||||||
|
@Autowired
|
||||||
|
private MqttPublisher mqttPublisher;
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private static final String MQTT_TOPIC = "EMS_STRATEGY_UP";
|
||||||
|
private static final String TABLE_NAME = "ems_strategy_running";
|
||||||
|
@Autowired
|
||||||
|
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
|
||||||
|
@Autowired
|
||||||
|
private MqttSyncLogMapper mqttSyncLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyRunningMapper emsStrategyRunningMapper;
|
||||||
|
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsStrategyRunningMapper.stopEmsStrategyRunning(..)) && args(id)) ")
|
||||||
|
public void stopPointCut(Long id) {
|
||||||
|
logger.info("【停止策略切面】StrategyAspect 被实例化");
|
||||||
|
}
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsStrategyRunningMapper.insertEmsStrategyRunning(..)) && args(insertEntity)) ")
|
||||||
|
public void insertPointCut(EmsStrategyRunning insertEntity) {
|
||||||
|
logger.info("【新增策略切面】StrategyAspect 被实例化");
|
||||||
|
}
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsStrategyRunningMapper.updateEmsStrategyRunning(..)) && args(updateEntity)) ")
|
||||||
|
public void updatePointCut(EmsStrategyRunning updateEntity) {
|
||||||
|
logger.info("【更新策略切面】StrategyAspect 被实例化");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法执行成功后发布同步消息
|
||||||
|
@AfterReturning(pointcut = "updatePointCut(updateEntity)", returning = "result")
|
||||||
|
public void afterUpdate(JoinPoint joinPoint, EmsStrategyRunning updateEntity, Integer result) {
|
||||||
|
logger.info("【更新策略切面进入成功】");
|
||||||
|
if (result == 0 || updateEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
String siteId = updateEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType,siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
List<StrategyRunningVo> runningVos = emsStrategyRunningMapper.getRunningList(siteId);
|
||||||
|
if (runningVos == null || runningVos.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StrategyRunningVo runningVo = runningVos.get(0);
|
||||||
|
String content = objectMapper.writeValueAsString(runningVo);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterReturning(pointcut = "insertPointCut(insertEntity)", returning = "result")
|
||||||
|
public void afterInsert(JoinPoint joinPoint, EmsStrategyRunning insertEntity, Integer result) {
|
||||||
|
logger.info("【新增策略切面进入成功】");
|
||||||
|
if (result == 0 || insertEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
String siteId = insertEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType, siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
List<StrategyRunningVo> runningVos = emsStrategyRunningMapper.getRunningList(siteId);
|
||||||
|
if (runningVos == null || runningVos.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StrategyRunningVo runningVo = runningVos.get(0);
|
||||||
|
String content = objectMapper.writeValueAsString(runningVo);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterReturning(pointcut = "stopPointCut(id)", returning = "result")
|
||||||
|
public void afterStop(JoinPoint joinPoint, Long id, Integer result) {
|
||||||
|
logger.info("【停止策略切面进入成功】");
|
||||||
|
if (result == 0 || id == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
EmsStrategyRunning emsStrategyRunning = emsStrategyRunningMapper.selectEmsStrategyRunningById(id);
|
||||||
|
String siteId = emsStrategyRunning==null ? null : emsStrategyRunning.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType, siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
Map<String, Object> idMap = new HashMap<>();
|
||||||
|
idMap.put("id", id); // 手动将参数值映射到"id"字段
|
||||||
|
String content = JSON.toJSONString(idMap);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建同步信息
|
||||||
|
private MqttSyncLog createMessageObject(String operateType, String siteId) {
|
||||||
|
MqttSyncLog message = new MqttSyncLog();
|
||||||
|
message.setSyncId(UUID.randomUUID().toString());
|
||||||
|
message.setOperateType(operateType);
|
||||||
|
message.setTableName(TABLE_NAME);
|
||||||
|
message.setCreateTime(new Date());
|
||||||
|
message.setTopic(MQTT_TOPIC);
|
||||||
|
message.setStatus("SUCCESS");
|
||||||
|
message.setSyncObject("CLOUD");
|
||||||
|
message.setTarget(siteId);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
// 从方法名判断操作类型(示例:insert→INSERT,update→UPDATE,delete→DELETE)
|
||||||
|
private String getOperateType(String methodName) {
|
||||||
|
if (methodName.startsWith("insert")) return "INSERT";
|
||||||
|
if (methodName.startsWith("stop")) return "STOP";
|
||||||
|
if (methodName.startsWith("update") || methodName.startsWith("stop")) return "UPDATE";
|
||||||
|
if (methodName.startsWith("delete")) return "DELETE";
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从方法参数提取数据(示例:若参数是实体类,转成Map)
|
||||||
|
private Map<String, Object> extractDataFromParams(Object[] args) {
|
||||||
|
// 实际需反射获取实体类的字段和值(如id、name等)
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
if (args == null || args.length == 0) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
Object arg = args[i];
|
||||||
|
if (arg == null) {
|
||||||
|
continue; // 跳过null参数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理基本类型/包装类/字符串(直接作为值存入,key为"param0"、"param1"等)
|
||||||
|
if (isBasicType(arg.getClass())) {
|
||||||
|
String key = "param" + i; // 基本类型参数用"param0"、"param1"作为key
|
||||||
|
data.put(key, arg);
|
||||||
|
} else {
|
||||||
|
Map<String, Object> beanMap = beanToMap(arg);
|
||||||
|
data.putAll(beanMap); // 合并实体类的字段到结果Map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为基本类型或包装类或字符串
|
||||||
|
*/
|
||||||
|
private boolean isBasicType(Class<?> clazz) {
|
||||||
|
return clazz.isPrimitive() // 基本类型(int、long、boolean等)
|
||||||
|
|| clazz == String.class // 字符串
|
||||||
|
|| Number.class.isAssignableFrom(clazz) // 数字包装类(Integer、Long等)
|
||||||
|
|| clazz == Boolean.class; // 布尔包装类
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将实体类转换为Map(字段名为key,字段值为value)
|
||||||
|
*/
|
||||||
|
private Map<String, Object> beanToMap(Object bean) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
if (bean == null) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方式1:使用BeanMap(简洁高效)
|
||||||
|
BeanMap beanMap = BeanMap.create(bean);
|
||||||
|
for (Object key : beanMap.keySet()) {
|
||||||
|
map.put(key.toString(), beanMap.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在方法中转换
|
||||||
|
public String convertEntityToJson(EmsStrategyRunning insertEntity) throws Exception {
|
||||||
|
if (insertEntity == null) {
|
||||||
|
return null; // 空对象返回空JSON
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将实体类转换为JSON字符串
|
||||||
|
return objectMapper.writeValueAsString(insertEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,261 @@
|
|||||||
|
package com.xzzn.framework.aspectj;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.common.utils.bean.BeanUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategy;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRunning;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyTemp;
|
||||||
|
import com.xzzn.ems.domain.MqttSyncLog;
|
||||||
|
import com.xzzn.ems.domain.vo.SyncStrategyTempVo;
|
||||||
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyTempMapper;
|
||||||
|
import com.xzzn.ems.mapper.MqttSyncLogMapper;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cglib.beans.BeanMap;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略模板数据同步
|
||||||
|
* 云端 - 本地
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class StrategyTempSyncAspect {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(StrategyTempSyncAspect.class);
|
||||||
|
@Autowired
|
||||||
|
private MqttPublisher mqttPublisher;
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private static final String MQTT_TOPIC = "EMS_STRATEGY_UP";
|
||||||
|
private static final String TABLE_NAME = "ems_strategy_temp";
|
||||||
|
@Autowired
|
||||||
|
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
|
||||||
|
@Autowired
|
||||||
|
private MqttSyncLogMapper mqttSyncLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyMapper emsStrategyMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyTempMapper emsStrategyTempMapper;
|
||||||
|
|
||||||
|
// 用ThreadLocal暂存删除前的对象
|
||||||
|
private ThreadLocal<EmsStrategyTemp> beforeDeleteThreadLocal = new ThreadLocal<>();
|
||||||
|
@Before("execution(* com.xzzn.ems.mapper.EmsStrategyTempMapper.deleteTempByTempId(..)) && args(templateId)")
|
||||||
|
public void beforeDelete(JoinPoint joinPoint, String templateId) {
|
||||||
|
// 查询删除前的数据-仅存一获取siteId
|
||||||
|
List<EmsStrategyTemp> tempList = emsStrategyTempMapper.selectStrategyTempByTempId(templateId);
|
||||||
|
if (tempList != null && tempList.size() > 0) {
|
||||||
|
beforeDeleteThreadLocal.set(tempList.get(0)); // 暂存
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsStrategyTempMapper.deleteTempByTempId(..)) && args(templateId)) ")
|
||||||
|
public void deletePointCut(String templateId) {
|
||||||
|
logger.info("【删除策略模版切面】StrategyTempSyncAspect 被实例化");
|
||||||
|
}
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsStrategyTempMapper.insertEmsStrategyTemp(..)) && args(insertEntity)) ")
|
||||||
|
public void insertPointCut(EmsStrategyTemp insertEntity) {
|
||||||
|
logger.info("【新增策略模版切面】StrategyTempSyncAspect 被实例化");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法执行成功后发布同步消息
|
||||||
|
@AfterReturning(pointcut = "insertPointCut(insertEntity)", returning = "result")
|
||||||
|
public void afterInsert(JoinPoint joinPoint, EmsStrategyTemp insertEntity, Integer result) {
|
||||||
|
logger.info("【新增策略切面进入成功】");
|
||||||
|
if (result == 0 || insertEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
String siteId = insertEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType, siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 校验策略id是否存在
|
||||||
|
Long strategyId = insertEntity.getStrategyId();
|
||||||
|
if (strategyId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 数据转换
|
||||||
|
SyncStrategyTempVo tempVo = convertEntity(insertEntity);
|
||||||
|
String content = JSON.toJSONString(tempVo);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
private SyncStrategyTempVo convertEntity(EmsStrategyTemp insertEntity) {
|
||||||
|
SyncStrategyTempVo tempVo = new SyncStrategyTempVo();
|
||||||
|
BeanUtils.copyProperties(insertEntity, tempVo);
|
||||||
|
EmsStrategy strategy = emsStrategyMapper.selectEmsStrategyById(insertEntity.getStrategyId());
|
||||||
|
if (strategy != null) {
|
||||||
|
tempVo.setStrategyName(strategy.getStrategyName());
|
||||||
|
tempVo.setStrategyType(strategy.getStrategyType());
|
||||||
|
}
|
||||||
|
return tempVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterReturning(pointcut = "deletePointCut(templateId)", returning = "result")
|
||||||
|
public void afterDelete(JoinPoint joinPoint, String templateId, Integer result) {
|
||||||
|
logger.info("【删除策略模版切面进入成功】");
|
||||||
|
if (result == 0 || StringUtils.isEmpty(templateId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
// 从ThreadLocal中获取删除前的对象
|
||||||
|
EmsStrategyTemp strategyTemp = beforeDeleteThreadLocal.get();
|
||||||
|
String siteId = "";
|
||||||
|
if (strategyTemp != null) {
|
||||||
|
siteId = strategyTemp.getSiteId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType, siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
Map<String, Object> idMap = new HashMap<>();
|
||||||
|
idMap.put("templateId", templateId); // 手动将参数值映射到"id"字段
|
||||||
|
String content = JSON.toJSONString(idMap);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建同步信息
|
||||||
|
private MqttSyncLog createMessageObject(String operateType, String siteId) {
|
||||||
|
MqttSyncLog message = new MqttSyncLog();
|
||||||
|
message.setSyncId(UUID.randomUUID().toString());
|
||||||
|
message.setOperateType(operateType);
|
||||||
|
message.setTableName(TABLE_NAME);
|
||||||
|
message.setCreateTime(new Date());
|
||||||
|
message.setTopic(MQTT_TOPIC);
|
||||||
|
message.setStatus("SUCCESS");
|
||||||
|
message.setSyncObject("CLOUD");
|
||||||
|
message.setTarget(siteId);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
// 从方法名判断操作类型(示例:insert→INSERT,update→UPDATE,delete→DELETE)
|
||||||
|
private String getOperateType(String methodName) {
|
||||||
|
if (methodName.startsWith("insert")) return "INSERT";
|
||||||
|
if (methodName.startsWith("stop")) return "STOP";
|
||||||
|
if (methodName.startsWith("update") || methodName.startsWith("stop")) return "UPDATE";
|
||||||
|
if (methodName.startsWith("delete")) return "DELETE";
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从方法参数提取数据(示例:若参数是实体类,转成Map)
|
||||||
|
private Map<String, Object> extractDataFromParams(Object[] args) {
|
||||||
|
// 实际需反射获取实体类的字段和值(如id、name等)
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
if (args == null || args.length == 0) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
Object arg = args[i];
|
||||||
|
if (arg == null) {
|
||||||
|
continue; // 跳过null参数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理基本类型/包装类/字符串(直接作为值存入,key为"param0"、"param1"等)
|
||||||
|
if (isBasicType(arg.getClass())) {
|
||||||
|
String key = "param" + i; // 基本类型参数用"param0"、"param1"作为key
|
||||||
|
data.put(key, arg);
|
||||||
|
} else {
|
||||||
|
Map<String, Object> beanMap = beanToMap(arg);
|
||||||
|
data.putAll(beanMap); // 合并实体类的字段到结果Map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为基本类型或包装类或字符串
|
||||||
|
*/
|
||||||
|
private boolean isBasicType(Class<?> clazz) {
|
||||||
|
return clazz.isPrimitive() // 基本类型(int、long、boolean等)
|
||||||
|
|| clazz == String.class // 字符串
|
||||||
|
|| Number.class.isAssignableFrom(clazz) // 数字包装类(Integer、Long等)
|
||||||
|
|| clazz == Boolean.class; // 布尔包装类
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将实体类转换为Map(字段名为key,字段值为value)
|
||||||
|
*/
|
||||||
|
private Map<String, Object> beanToMap(Object bean) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
if (bean == null) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方式1:使用BeanMap(简洁高效)
|
||||||
|
BeanMap beanMap = BeanMap.create(bean);
|
||||||
|
for (Object key : beanMap.keySet()) {
|
||||||
|
map.put(key.toString(), beanMap.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在方法中转换
|
||||||
|
public String convertEntityToJson(EmsStrategyRunning insertEntity) throws Exception {
|
||||||
|
if (insertEntity == null) {
|
||||||
|
return null; // 空对象返回空JSON
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将实体类转换为JSON字符串
|
||||||
|
return objectMapper.writeValueAsString(insertEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,241 @@
|
|||||||
|
package com.xzzn.framework.aspectj;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.common.utils.bean.BeanUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategy;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRunning;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyTimeConfig;
|
||||||
|
import com.xzzn.ems.domain.MqttSyncLog;
|
||||||
|
import com.xzzn.ems.domain.vo.SyncStrategyTimeConfigVo;
|
||||||
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyTempMapper;
|
||||||
|
import com.xzzn.ems.mapper.MqttSyncLogMapper;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cglib.beans.BeanMap;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略时间配置同步
|
||||||
|
* 云端 - 本地
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class StrategyTimeConfigSyncAspect {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(StrategyTimeConfigSyncAspect.class);
|
||||||
|
@Autowired
|
||||||
|
private MqttPublisher mqttPublisher;
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private static final String MQTT_TOPIC = "EMS_STRATEGY_UP";
|
||||||
|
private static final String TABLE_NAME = "ems_strategy_temp";
|
||||||
|
@Autowired
|
||||||
|
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
|
||||||
|
@Autowired
|
||||||
|
private MqttSyncLogMapper mqttSyncLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyMapper emsStrategyMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyTempMapper emsStrategyTempMapper;
|
||||||
|
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper.insertEmsStrategyTimeConfig(..)) && args(insertEntity)) ")
|
||||||
|
public void insertPointCut(EmsStrategyTimeConfig insertEntity) {
|
||||||
|
logger.info("【新增策略模版时间配置切面】StrategyTimeConfigSyncAspect 被实例化");
|
||||||
|
}
|
||||||
|
@Pointcut("(execution(* com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper.updateEmsStrategyTimeConfig(..)) && args(updateEntity)) ")
|
||||||
|
public void updatePointCut(EmsStrategyTimeConfig updateEntity) {
|
||||||
|
logger.info("【更新策略模版时间配置切面】StrategyTimeConfigSyncAspect 被实例化");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法执行成功后发布同步消息
|
||||||
|
@AfterReturning(pointcut = "insertPointCut(insertEntity)", returning = "result")
|
||||||
|
public void afterInsert(JoinPoint joinPoint, EmsStrategyTimeConfig insertEntity, Integer result) {
|
||||||
|
logger.info("【新增策略模版时间切面进入成功】");
|
||||||
|
if (result == 0 || insertEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
String siteId = insertEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType, siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 校验策略id是否存在
|
||||||
|
Long strategyId = insertEntity.getStrategyId();
|
||||||
|
if (strategyId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 数据转换
|
||||||
|
SyncStrategyTimeConfigVo timeConfigVo = convertEntity(insertEntity);
|
||||||
|
String content = objectMapper.writeValueAsString(timeConfigVo);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
private SyncStrategyTimeConfigVo convertEntity(EmsStrategyTimeConfig insertEntity) {
|
||||||
|
SyncStrategyTimeConfigVo timeConfigVo = new SyncStrategyTimeConfigVo();
|
||||||
|
BeanUtils.copyProperties(insertEntity, timeConfigVo);
|
||||||
|
EmsStrategy strategy = emsStrategyMapper.selectEmsStrategyById(insertEntity.getStrategyId());
|
||||||
|
if (strategy != null) {
|
||||||
|
timeConfigVo.setStrategyName(strategy.getStrategyName());
|
||||||
|
timeConfigVo.setStrategyType(strategy.getStrategyType());
|
||||||
|
}
|
||||||
|
return timeConfigVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterReturning(pointcut = "updatePointCut(updateEntity)", returning = "result")
|
||||||
|
public void afterUpdate(JoinPoint joinPoint, EmsStrategyTimeConfig updateEntity, Integer result) {
|
||||||
|
logger.info("【删除策略模版切面进入成功】");
|
||||||
|
if (result == 0 || updateEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验是否配置监听topic-监听则不发布
|
||||||
|
String topic = emsMqttTopicConfigMapper.checkTopicIsExist(MQTT_TOPIC);
|
||||||
|
if (!StringUtils.isEmpty(topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析方法名,获取操作类型(INSERT/UPDATE/DELETE)和表名
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
String operateType = getOperateType(methodName);
|
||||||
|
String siteId = updateEntity.getSiteId();
|
||||||
|
|
||||||
|
// 构建日志同步消息
|
||||||
|
MqttSyncLog message = createMessageObject(operateType, siteId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 数据转换
|
||||||
|
SyncStrategyTimeConfigVo timeConfigVo = convertEntity(updateEntity);
|
||||||
|
String content = objectMapper.writeValueAsString(timeConfigVo);
|
||||||
|
message.setContent(content);
|
||||||
|
|
||||||
|
// 发布到MQTT主题
|
||||||
|
mqttPublisher.publish(MQTT_TOPIC, objectMapper.writeValueAsString(message), 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.setStatus("FAIL");
|
||||||
|
message.setErrorMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
// 存储同步信息
|
||||||
|
mqttSyncLogMapper.insertMqttSyncLog(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建同步信息
|
||||||
|
private MqttSyncLog createMessageObject(String operateType, String siteId) {
|
||||||
|
MqttSyncLog message = new MqttSyncLog();
|
||||||
|
message.setSyncId(UUID.randomUUID().toString());
|
||||||
|
message.setOperateType(operateType);
|
||||||
|
message.setTableName(TABLE_NAME);
|
||||||
|
message.setCreateTime(new Date());
|
||||||
|
message.setTopic(MQTT_TOPIC);
|
||||||
|
message.setStatus("SUCCESS");
|
||||||
|
message.setSyncObject("CLOUD");
|
||||||
|
message.setTarget(siteId);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
// 从方法名判断操作类型(示例:insert→INSERT,update→UPDATE,delete→DELETE)
|
||||||
|
private String getOperateType(String methodName) {
|
||||||
|
if (methodName.startsWith("insert")) return "INSERT";
|
||||||
|
if (methodName.startsWith("stop")) return "STOP";
|
||||||
|
if (methodName.startsWith("update") || methodName.startsWith("stop")) return "UPDATE";
|
||||||
|
if (methodName.startsWith("delete")) return "DELETE";
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从方法参数提取数据(示例:若参数是实体类,转成Map)
|
||||||
|
private Map<String, Object> extractDataFromParams(Object[] args) {
|
||||||
|
// 实际需反射获取实体类的字段和值(如id、name等)
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
if (args == null || args.length == 0) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
Object arg = args[i];
|
||||||
|
if (arg == null) {
|
||||||
|
continue; // 跳过null参数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理基本类型/包装类/字符串(直接作为值存入,key为"param0"、"param1"等)
|
||||||
|
if (isBasicType(arg.getClass())) {
|
||||||
|
String key = "param" + i; // 基本类型参数用"param0"、"param1"作为key
|
||||||
|
data.put(key, arg);
|
||||||
|
} else {
|
||||||
|
Map<String, Object> beanMap = beanToMap(arg);
|
||||||
|
data.putAll(beanMap); // 合并实体类的字段到结果Map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为基本类型或包装类或字符串
|
||||||
|
*/
|
||||||
|
private boolean isBasicType(Class<?> clazz) {
|
||||||
|
return clazz.isPrimitive() // 基本类型(int、long、boolean等)
|
||||||
|
|| clazz == String.class // 字符串
|
||||||
|
|| Number.class.isAssignableFrom(clazz) // 数字包装类(Integer、Long等)
|
||||||
|
|| clazz == Boolean.class; // 布尔包装类
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将实体类转换为Map(字段名为key,字段值为value)
|
||||||
|
*/
|
||||||
|
private Map<String, Object> beanToMap(Object bean) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
if (bean == null) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方式1:使用BeanMap(简洁高效)
|
||||||
|
BeanMap beanMap = BeanMap.create(bean);
|
||||||
|
for (Object key : beanMap.keySet()) {
|
||||||
|
map.put(key.toString(), beanMap.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在方法中转换
|
||||||
|
public String convertEntityToJson(EmsStrategyRunning insertEntity) throws Exception {
|
||||||
|
if (insertEntity == null) {
|
||||||
|
return null; // 空对象返回空JSON
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将实体类转换为JSON字符串
|
||||||
|
return objectMapper.writeValueAsString(insertEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,8 +13,9 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
|||||||
* @author xzzn
|
* @author xzzn
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
// 表示通过aop框架暴露该代理对象,AopContext能够访问
|
// proxyTargetClass = true表示使用cglib代理,false表示jdk动态代理
|
||||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
// exposeProxy = true表示通过aop框架暴露该代理对象,AopContext能够访问
|
||||||
|
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
|
||||||
// 指定要扫描的Mapper类的包的路径
|
// 指定要扫描的Mapper类的包的路径
|
||||||
@MapperScan("com.xzzn.**.mapper")
|
@MapperScan("com.xzzn.**.mapper")
|
||||||
public class ApplicationConfig
|
public class ApplicationConfig
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
package com.xzzn.framework.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableAsync
|
||||||
|
public class AsyncConfig {
|
||||||
|
|
||||||
|
@Bean("modbusTaskExecutor")
|
||||||
|
public Executor taskExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setCorePoolSize(5);
|
||||||
|
executor.setMaxPoolSize(10);
|
||||||
|
executor.setQueueCapacity(100);
|
||||||
|
executor.setKeepAliveSeconds(300);
|
||||||
|
executor.setThreadNamePrefix("ModbusPoller-");
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
executor.initialize();
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 策略下方定时任务
|
||||||
|
*//*
|
||||||
|
|
||||||
|
*/
|
||||||
|
/*@Bean("strategyTaskExecutor")
|
||||||
|
public Executor strategyTaskExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setCorePoolSize(5);
|
||||||
|
executor.setMaxPoolSize(10);
|
||||||
|
executor.setQueueCapacity(100);
|
||||||
|
executor.setKeepAliveSeconds(300);
|
||||||
|
executor.setThreadNamePrefix("StrategyPoller-");
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
executor.initialize();
|
||||||
|
return executor;
|
||||||
|
}*//*
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.xzzn.framework.config;
|
||||||
|
|
||||||
|
import com.xzzn.framework.config.properties.MqttProperties;
|
||||||
|
import org.eclipse.paho.client.mqttv3.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class MqttConfig {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MqttConfig.class);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MqttProperties mqttProperties;
|
||||||
|
@Bean
|
||||||
|
public MqttConnectOptions mqttConnectOptions() {
|
||||||
|
MqttConnectOptions options = new MqttConnectOptions();
|
||||||
|
options.setServerURIs(new String[]{mqttProperties.getBrokerUrl()});
|
||||||
|
if (!mqttProperties.getUsername().isEmpty()) options.setUserName(mqttProperties.getUsername());
|
||||||
|
if (!mqttProperties.getPassword().isEmpty()) options.setPassword(mqttProperties.getPassword().toCharArray());
|
||||||
|
options.setConnectionTimeout(mqttProperties.getConnectionTimeout());
|
||||||
|
options.setKeepAliveInterval(mqttProperties.getKeepAliveInterval());
|
||||||
|
options.setAutomaticReconnect(mqttProperties.isAutomaticReconnect());
|
||||||
|
options.setCleanSession(true);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
package com.xzzn.framework.config.properties;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class MqttProperties {
|
||||||
|
@Value("${mqtt.broker.url}")
|
||||||
|
private String brokerUrl;
|
||||||
|
|
||||||
|
@Value("${mqtt.client.id:}")
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
@Value("${mqtt.username:}")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Value("${mqtt.password:}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Value("${mqtt.connection-timeout:10}")
|
||||||
|
private int connectionTimeout;
|
||||||
|
|
||||||
|
@Value("${mqtt.keep-alive-interval:60}")
|
||||||
|
private int keepAliveInterval;
|
||||||
|
|
||||||
|
@Value("${mqtt.automatic-reconnect:true}")
|
||||||
|
private boolean automaticReconnect;
|
||||||
|
|
||||||
|
public String getBrokerUrl() {
|
||||||
|
return brokerUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBrokerUrl(String brokerUrl) {
|
||||||
|
this.brokerUrl = brokerUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getConnectionTimeout() {
|
||||||
|
return connectionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnectionTimeout(int connectionTimeout) {
|
||||||
|
this.connectionTimeout = connectionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeepAliveInterval() {
|
||||||
|
return keepAliveInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeepAliveInterval(int keepAliveInterval) {
|
||||||
|
this.keepAliveInterval = keepAliveInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAutomaticReconnect() {
|
||||||
|
return automaticReconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutomaticReconnect(boolean automaticReconnect) {
|
||||||
|
this.automaticReconnect = automaticReconnect;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
package com.xzzn.framework.manager;
|
||||||
|
|
||||||
|
import com.xzzn.ems.service.IEmsAlarmRecordsService;
|
||||||
|
import org.eclipse.paho.client.mqttv3.*;
|
||||||
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.ApplicationArguments;
|
||||||
|
import org.springframework.boot.ApplicationRunner;
|
||||||
|
import org.springframework.context.SmartLifecycle;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle, MqttCallback {
|
||||||
|
|
||||||
|
private final MqttConnectOptions connectOptions;
|
||||||
|
private final IEmsAlarmRecordsService iEmsAlarmRecordsService;
|
||||||
|
private MqttClient mqttClient;
|
||||||
|
private volatile boolean running = false;
|
||||||
|
|
||||||
|
// 存储订阅关系: topic -> (listener, qos)
|
||||||
|
private final ConcurrentHashMap<String, SubscriptionInfo> subscriptions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public MqttLifecycleManager(MqttConnectOptions connectOptions, IEmsAlarmRecordsService iEmsAlarmRecordsService) {
|
||||||
|
this.connectOptions = connectOptions;
|
||||||
|
this.iEmsAlarmRecordsService = iEmsAlarmRecordsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spring Boot 启动完成后执行
|
||||||
|
@Override
|
||||||
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
if (running) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String clientId = connectOptions.getUserName() + "-" + System.currentTimeMillis();
|
||||||
|
mqttClient = new MqttClient(
|
||||||
|
connectOptions.getServerURIs()[0],
|
||||||
|
clientId,
|
||||||
|
new MemoryPersistence()
|
||||||
|
);
|
||||||
|
|
||||||
|
mqttClient.setCallback(this);
|
||||||
|
mqttClient.connect(connectOptions);
|
||||||
|
|
||||||
|
// 重连后自动重新订阅
|
||||||
|
resubscribeAll();
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
System.out.println("MQTT client connected to: " + connectOptions.getServerURIs()[0]);
|
||||||
|
} catch (MqttException e) {
|
||||||
|
System.err.println("MQTT connection failed: " + e.getMessage());
|
||||||
|
// 添加重试逻辑
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
if (mqttClient != null && mqttClient.isConnected()) {
|
||||||
|
try {
|
||||||
|
mqttClient.disconnect();
|
||||||
|
mqttClient.close();
|
||||||
|
} catch (MqttException e) {
|
||||||
|
System.err.println("Error disconnecting MQTT client: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MQTT 回调方法
|
||||||
|
@Override
|
||||||
|
public void connectionLost(Throwable cause) {
|
||||||
|
System.err.println("MQTT connection lost: " + cause.getMessage());
|
||||||
|
running = false;
|
||||||
|
// 自动重连由 MqttConnectOptions 处理
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||||
|
SubscriptionInfo info = subscriptions.get(topic);
|
||||||
|
if (info != null && info.getListener() != null) {
|
||||||
|
info.getListener().messageArrived(topic, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||||
|
// 消息发布完成处理
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订阅方法
|
||||||
|
public void subscribe(String topic, int qos, IMqttMessageListener listener) {
|
||||||
|
try {
|
||||||
|
if (mqttClient != null && mqttClient.isConnected()) {
|
||||||
|
mqttClient.subscribe(topic, qos);
|
||||||
|
}
|
||||||
|
subscriptions.put(topic, new SubscriptionInfo(listener, qos));
|
||||||
|
} catch (MqttException e) {
|
||||||
|
System.err.println("Subscribe failed: " + e.getMessage());
|
||||||
|
// 订阅失败-增加告警
|
||||||
|
iEmsAlarmRecordsService.addSubFailedAlarmRecord(topic);
|
||||||
|
}
|
||||||
|
// 订阅成功了-校验是否存在未处理或者处理中的订阅失败信息
|
||||||
|
iEmsAlarmRecordsService.checkFailedRecord(topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布方法
|
||||||
|
public void publish(String topic, String payload, int qos) throws MqttException {
|
||||||
|
if (mqttClient != null && mqttClient.isConnected()) {
|
||||||
|
MqttMessage message = new MqttMessage(payload.getBytes());
|
||||||
|
message.setQos(qos);
|
||||||
|
mqttClient.publish(topic, message);
|
||||||
|
} else {
|
||||||
|
throw new MqttException(MqttException.REASON_CODE_CLIENT_NOT_CONNECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新订阅所有主题
|
||||||
|
private void resubscribeAll() {
|
||||||
|
if (mqttClient == null || !mqttClient.isConnected()) return;
|
||||||
|
|
||||||
|
subscriptions.forEach((topic, info) -> {
|
||||||
|
try {
|
||||||
|
mqttClient.subscribe(topic, info.getQos());
|
||||||
|
} catch (MqttException e) {
|
||||||
|
System.err.println("Resubscribe failed for topic: " + topic);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订阅信息内部类
|
||||||
|
private static class SubscriptionInfo {
|
||||||
|
private final IMqttMessageListener listener;
|
||||||
|
private final int qos;
|
||||||
|
|
||||||
|
public SubscriptionInfo(IMqttMessageListener listener, int qos) {
|
||||||
|
this.listener = listener;
|
||||||
|
this.qos = qos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMqttMessageListener getListener() {
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getQos() {
|
||||||
|
return qos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package com.xzzn.framework.web.service;
|
||||||
|
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
|
||||||
|
public interface MqttPublisher {
|
||||||
|
void publish(String topic, String message) throws MqttException;
|
||||||
|
void publish(String topic, String message, int qos) throws MqttException;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package com.xzzn.framework.web.service;
|
||||||
|
|
||||||
|
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
|
||||||
|
|
||||||
|
public interface MqttSubscriber {
|
||||||
|
void subscribe(String topic, int qos, IMqttMessageListener listener);
|
||||||
|
}
|
||||||
@ -34,6 +34,10 @@
|
|||||||
<groupId>com.xzzn</groupId>
|
<groupId>com.xzzn</groupId>
|
||||||
<artifactId>ems-common</artifactId>
|
<artifactId>ems-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.xzzn</groupId>
|
||||||
|
<artifactId>ems-framework</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
package com.xzzn.quartz.config;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modbus操作执行器配置
|
||||||
|
* 所有Modbus读写操作必须通过此单线程执行器串行执行,避免并发访问导致通讯故障
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class ModbusExecutorConfig {
|
||||||
|
|
||||||
|
private final ExecutorService modbusExecutor = Executors.newSingleThreadExecutor(r -> {
|
||||||
|
Thread t = new Thread(r, "modbus-io-thread");
|
||||||
|
t.setDaemon(false);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
|
||||||
|
@Bean(name = "modbusExecutor")
|
||||||
|
public ExecutorService modbusExecutor() {
|
||||||
|
return modbusExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void shutdown() {
|
||||||
|
modbusExecutor.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.xzzn.quartz.config;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ScheduledTask {
|
||||||
|
|
||||||
|
|
||||||
|
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
|
||||||
|
private final Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public void startTask(String deviceId, Runnable task, long period) {
|
||||||
|
stopTask(deviceId); // 如果已有同ID任务在运行,先停止
|
||||||
|
ScheduledFuture<?> future = executor.scheduleAtFixedRate(task, 0, period, TimeUnit.MILLISECONDS);
|
||||||
|
futureMap.put(deviceId, future);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopTask(String deviceId) {
|
||||||
|
ScheduledFuture<?> future = futureMap.get(deviceId);
|
||||||
|
if (future != null && !future.isDone()) {
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
futureMap.remove(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
343
ems-quartz/src/main/java/com/xzzn/quartz/task/ModbusPoller.java
Normal file
343
ems-quartz/src/main/java/com/xzzn/quartz/task/ModbusPoller.java
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
package com.xzzn.quartz.task;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.serotonin.modbus4j.ModbusMaster;
|
||||||
|
import com.xzzn.common.constant.RedisKeyConstants;
|
||||||
|
import com.xzzn.common.core.modbus.ModbusProcessor;
|
||||||
|
import com.xzzn.common.core.modbus.domain.DeviceConfig;
|
||||||
|
import com.xzzn.common.core.redis.RedisCache;
|
||||||
|
import com.xzzn.common.enums.DeviceRunningStatus;
|
||||||
|
import com.xzzn.common.utils.DateUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsDevicesSetting;
|
||||||
|
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
||||||
|
import com.xzzn.ems.service.IEmsAlarmRecordsService;
|
||||||
|
import com.xzzn.ems.service.impl.DeviceDataProcessServiceImpl;
|
||||||
|
import com.xzzn.framework.manager.MqttLifecycleManager;
|
||||||
|
import com.xzzn.framework.web.service.MqttPublisher;
|
||||||
|
import com.xzzn.quartz.config.ScheduledTask;
|
||||||
|
import com.xzzn.quartz.domain.SysJob;
|
||||||
|
import com.xzzn.quartz.service.ISysJobService;
|
||||||
|
import com.xzzn.quartz.util.CronUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮询设备-通过modbus协议读取数据
|
||||||
|
*/
|
||||||
|
@Component("modbusPoller")
|
||||||
|
public class ModbusPoller {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ModbusPoller.class);
|
||||||
|
|
||||||
|
private final MqttLifecycleManager mqttLifecycleManager;
|
||||||
|
private final ScheduledTask scheduledTask;
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private final Map<String, Integer> deviceFailureCounts = new ConcurrentHashMap<>();
|
||||||
|
private final AtomicBoolean polling = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
@Resource(name = "modbusExecutor")
|
||||||
|
private ExecutorService modbusExecutor;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ModbusProcessor modbusProcessor;
|
||||||
|
@Autowired
|
||||||
|
private IEmsAlarmRecordsService iEmsAlarmRecordsService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysJobService iSysJobService;
|
||||||
|
@Autowired
|
||||||
|
private DeviceDataProcessServiceImpl deviceDataProcessServiceImpl;
|
||||||
|
@Autowired
|
||||||
|
private EmsDevicesSettingMapper emsDevicesSettingMapper;
|
||||||
|
@Autowired
|
||||||
|
private RedisCache redisCache;
|
||||||
|
@Autowired
|
||||||
|
private MqttPublisher mqttPublisher;
|
||||||
|
|
||||||
|
@Value("${mqtt.topic}")
|
||||||
|
private String topic;
|
||||||
|
@Value("${mqtt.siteId}")
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ModbusPoller(MqttLifecycleManager mqttLifecycleManager, ScheduledTask scheduledTask) {
|
||||||
|
this.mqttLifecycleManager = mqttLifecycleManager;
|
||||||
|
this.scheduledTask = scheduledTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pollAllDevices() {
|
||||||
|
if (!polling.compareAndSet(false, true)) {
|
||||||
|
log.warn("上一次轮询尚未完成,本次轮询跳过");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Path devicesDir = Paths.get(System.getProperty("user.dir"), "devices");
|
||||||
|
if (!Files.exists(devicesDir)) {
|
||||||
|
log.error("Devices目录不存在: {}", devicesDir);
|
||||||
|
polling.set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Path> jsonFiles = null;
|
||||||
|
try {
|
||||||
|
jsonFiles = Files.list(devicesDir)
|
||||||
|
.filter(path -> path.toString().endsWith(".json"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("modbusPoller.loadConfigs 获取设备配置文件失败: {}", devicesDir, e);
|
||||||
|
polling.set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按主机IP分组(同一网关的不同端口也归为一组,避免并发访问导致Connection Reset)
|
||||||
|
Map<String, List<DeviceConfig>> groupedByHost = new HashMap<>();
|
||||||
|
for (Path filePath : jsonFiles) {
|
||||||
|
DeviceConfig config = null;
|
||||||
|
try {
|
||||||
|
config = objectMapper.readValue(filePath.toFile(), DeviceConfig.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("modbusPoller.loadConfigs 解析设备配置文件失败: {}", filePath, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (config.isEnabled()) {
|
||||||
|
// 只按主机IP分组,确保同一网关的所有端口串行访问
|
||||||
|
String hostKey = config.getHost();
|
||||||
|
groupedByHost.computeIfAbsent(hostKey, k -> new ArrayList<>()).add(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用单线程 executor 串行执行所有主机的 Modbus 操作
|
||||||
|
// 将所有主机的设备按顺序串行处理,避免任何并发访问
|
||||||
|
Future<?> future = modbusExecutor.submit(() -> {
|
||||||
|
for (Map.Entry<String, List<DeviceConfig>> entry : groupedByHost.entrySet()) {
|
||||||
|
String hostKey = entry.getKey();
|
||||||
|
List<DeviceConfig> configs = entry.getValue();
|
||||||
|
for (DeviceConfig config : configs) {
|
||||||
|
try {
|
||||||
|
scheduledStart(config);
|
||||||
|
// 每次读取后等待200ms,给Modbus网关足够的处理时间
|
||||||
|
Thread.sleep(200);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
log.warn("Modbus轮询被中断");
|
||||||
|
return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("采集设备数据异常: {}", config.getDeviceName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("采集设备数据{}轮询任务执行完成", hostKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
future.get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
log.warn("Modbus轮询任务等待中断");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Modbus轮询任务执行异常", e);
|
||||||
|
} finally {
|
||||||
|
polling.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduledStart(DeviceConfig config) {
|
||||||
|
if (config.isEnabled()) {
|
||||||
|
log.info("Reading data from devices: {}", config.getDeviceName());
|
||||||
|
|
||||||
|
// 带重试的读取,最多重试2次
|
||||||
|
Map<String, Object> data = readWithRetry(config, 2);
|
||||||
|
|
||||||
|
List<String> rawValuEmptyList = new ArrayList<>();
|
||||||
|
// 在这里处理采集到的数据空
|
||||||
|
config.getTags().forEach(tag -> {
|
||||||
|
Object rawValue = data.get(tag.getKey());
|
||||||
|
if (rawValue != null) {
|
||||||
|
float value = 0;
|
||||||
|
if (rawValue instanceof Number) {
|
||||||
|
value = ((Number) rawValue).floatValue(); // 安全地转换为 float
|
||||||
|
} else {
|
||||||
|
log.error("tag:{},无法将数据转换为数字: {}", tag.getKey(), rawValue);
|
||||||
|
}
|
||||||
|
value = tag.getA() * value * value + tag.getK() * value + tag.getB();
|
||||||
|
|
||||||
|
int intValue = (int) value;
|
||||||
|
if (tag.getBit() != null) {
|
||||||
|
log.info("tag:{},bit:{},value:{}", tag.getKey(), tag.getBit(), value);
|
||||||
|
String binary = Integer.toBinaryString(intValue);
|
||||||
|
data.put(tag.getKey(), binary);
|
||||||
|
} else {
|
||||||
|
data.put(tag.getKey(), value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// data.put(tag.getKey(), rawValue);
|
||||||
|
// log.warn("tag:{},数据为空: {}", tag.getKey(), rawValue);
|
||||||
|
rawValuEmptyList.add("tag: " + tag.getKey() + ",数据为空: " + rawValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!rawValuEmptyList.isEmpty()) {
|
||||||
|
log.warn("设备 {} 数据为空: {}", config.getDeviceName(), JSON.toJSONString(rawValuEmptyList));
|
||||||
|
}
|
||||||
|
log.info("Data from {}: {}", config.getDeviceName(), data);
|
||||||
|
String deviceNumber = config.getDeviceNumber();
|
||||||
|
//处理数据并发送MQTT消息、保存Redis数据和数据入库
|
||||||
|
processingData(data, deviceNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带重试的读取方法
|
||||||
|
*/
|
||||||
|
private Map<String, Object> readWithRetry(DeviceConfig config, int maxRetries) {
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
|
||||||
|
for (int attempt = 0; attempt <= maxRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
ModbusMaster master = modbusProcessor.borrowMaster(config);
|
||||||
|
data = modbusProcessor.readDataFromDevice(config, master);
|
||||||
|
|
||||||
|
// 如果读取成功(有数据),直接返回
|
||||||
|
if (!data.isEmpty()) {
|
||||||
|
if (attempt > 0) {
|
||||||
|
log.info("设备 {} 第 {} 次重试成功", config.getDeviceName(), attempt);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取返回空数据,等待后重试
|
||||||
|
if (attempt < maxRetries) {
|
||||||
|
log.warn("设备 {} 读取返回空数据,等待1秒后重试 ({}/{})",
|
||||||
|
config.getDeviceName(), attempt + 1, maxRetries);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("设备 {} 读取异常 ({}/{}): {}",
|
||||||
|
config.getDeviceName(), attempt + 1, maxRetries, e.getMessage());
|
||||||
|
|
||||||
|
if (attempt < maxRetries) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有重试都失败
|
||||||
|
log.error("设备 {} 读取失败,已重试 {} 次", config.getDeviceName(), maxRetries);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processingData(Map<String, Object> data, String deviceNumber) {
|
||||||
|
if (CollectionUtils.isEmpty(data)) {
|
||||||
|
// 增加失败计数
|
||||||
|
int failureCount = deviceFailureCounts.getOrDefault(deviceNumber, 0) + 1;
|
||||||
|
deviceFailureCounts.put(deviceNumber, failureCount);
|
||||||
|
|
||||||
|
log.warn("设备 {} 数据读取失败,当前连续失败次数: {}", deviceNumber, failureCount);
|
||||||
|
|
||||||
|
// 连续6次失败触发报警
|
||||||
|
if (failureCount >= 6) {
|
||||||
|
addDeviceOfflineRecord(siteId, deviceNumber);
|
||||||
|
log.error("设备 {} 连续 {} 次未读取到数据,触发报警", deviceNumber, failureCount);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据读取成功,重置计数器
|
||||||
|
deviceFailureCounts.remove(deviceNumber);
|
||||||
|
// 读取到数据后告警自恢复
|
||||||
|
deleteDeviceOfflineRecord(siteId, deviceNumber);
|
||||||
|
|
||||||
|
// 发送MQTT消息、保存Redis数据和数据入库
|
||||||
|
Long timestamp = System.currentTimeMillis();
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("Data", data);
|
||||||
|
json.put("timestamp", timestamp);
|
||||||
|
json.put("Device", deviceNumber);
|
||||||
|
sendMqttMsg(json);
|
||||||
|
saveRedisData(json, deviceNumber);
|
||||||
|
saveDataToDatabase(data, deviceNumber, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMqttMsg(JSONObject json) {
|
||||||
|
try {
|
||||||
|
mqttPublisher.publish(topic, Collections.singletonList(json).toString(), 0);
|
||||||
|
} catch (MqttException e) {
|
||||||
|
log.error("MQTT消息发布失败: {}, reason code: {}", json.toJSONString(), e.getReasonCode() ,e);
|
||||||
|
}
|
||||||
|
log.info("已发送数据: {}", json.toJSONString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void saveRedisData(JSONObject obj, String deviceNumber) {
|
||||||
|
try {
|
||||||
|
// 存放mqtt原始每个设备最晚一次数据,便于后面点位获取数据
|
||||||
|
redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceNumber, obj);
|
||||||
|
// 存放每次同步数据,失效时间(同同步时间)-用于判断是否正常同步数据和保护策略查询
|
||||||
|
redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceNumber, obj, 1, TimeUnit.MINUTES);
|
||||||
|
log.info("数据已成功存储在Redis: {}", deviceNumber);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("无法在设备的Redis中存储数据: {}", deviceNumber, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveDataToDatabase(Map<String, Object> data, String deviceNumber, Long timestamp) {
|
||||||
|
deviceDataProcessServiceImpl.processingDeviceData(siteId, deviceNumber, JSON.toJSONString(data), DateUtils.convertUpdateTime(timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理设备连接失败的情况,更新设备状态为离线,添加报警记录
|
||||||
|
private void addDeviceOfflineRecord(String siteId, String deviceNumber) {
|
||||||
|
updateDeviceStatus(siteId, deviceNumber, DeviceRunningStatus.OFFLINE.getCode());
|
||||||
|
iEmsAlarmRecordsService.addDeviceOfflineRecord(siteId, deviceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理设备读取到数据的情况,更新设备状态为在线,报警记录自恢复
|
||||||
|
private void deleteDeviceOfflineRecord(String siteId, String deviceNumber) {
|
||||||
|
updateDeviceStatus(siteId, deviceNumber, DeviceRunningStatus.ONLINE.getCode());
|
||||||
|
iEmsAlarmRecordsService.deleteDeviceOfflineRecord(siteId, deviceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新设备状态为在线或离线
|
||||||
|
private void updateDeviceStatus(String siteId, String deviceNumber, String deviceStatus) {
|
||||||
|
EmsDevicesSetting emsDevicesSetting = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceNumber, siteId);
|
||||||
|
if (emsDevicesSetting != null && !Objects.equals(emsDevicesSetting.getDeviceStatus(), deviceStatus)) {
|
||||||
|
emsDevicesSetting.setDeviceStatus(deviceStatus);
|
||||||
|
emsDevicesSettingMapper.updateEmsDevicesSetting(emsDevicesSetting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getScheduledTaskInterval() {
|
||||||
|
SysJob query = new SysJob();
|
||||||
|
query.setInvokeTarget("modbusPoller.pollAllDevices");
|
||||||
|
List<SysJob> sysJobs = iSysJobService.selectJobList(query);
|
||||||
|
return Math.toIntExact(CronUtils.getNextExecutionIntervalMillis(sysJobs.get(0).getCronExpression()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,482 @@
|
|||||||
|
package com.xzzn.quartz.task;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.xzzn.common.annotation.SyncAfterInsert;
|
||||||
|
import com.xzzn.common.constant.RedisKeyConstants;
|
||||||
|
import com.xzzn.common.core.redis.RedisCache;
|
||||||
|
import com.xzzn.common.enums.AlarmLevelStatus;
|
||||||
|
import com.xzzn.common.enums.AlarmStatus;
|
||||||
|
import com.xzzn.common.enums.ProtPlanStatus;
|
||||||
|
import com.xzzn.common.enums.StrategyStatus;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsAlarmRecords;
|
||||||
|
import com.xzzn.ems.domain.EmsDevicesSetting;
|
||||||
|
import com.xzzn.ems.domain.EmsFaultIssueLog;
|
||||||
|
import com.xzzn.ems.domain.EmsFaultProtectionPlan;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRunning;
|
||||||
|
import com.xzzn.ems.domain.vo.ProtectionPlanVo;
|
||||||
|
import com.xzzn.ems.domain.vo.ProtectionSettingVo;
|
||||||
|
import com.xzzn.ems.mapper.EmsAlarmRecordsMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsFaultIssueLogMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
|
||||||
|
import com.xzzn.ems.service.IEmsFaultProtectionPlanService;
|
||||||
|
import com.xzzn.common.core.modbus.ModbusProcessor;
|
||||||
|
import com.xzzn.common.core.modbus.domain.DeviceConfig;
|
||||||
|
import com.xzzn.common.core.modbus.domain.WriteTagConfig;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警保护方案轮询
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
*/
|
||||||
|
@Component("protectionPlanTask")
|
||||||
|
public class ProtectionPlanTask {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ProtectionPlanTask.class);
|
||||||
|
@Resource(name = "scheduledExecutorService")
|
||||||
|
private ScheduledExecutorService scheduledExecutorService;
|
||||||
|
@Autowired
|
||||||
|
private IEmsFaultProtectionPlanService iEmsFaultProtectionPlanService;
|
||||||
|
@Autowired
|
||||||
|
private EmsAlarmRecordsMapper emsAlarmRecordsMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyRunningMapper emsStrategyRunningMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsFaultProtectionPlanMapper emsFaultProtectionPlanMapper;
|
||||||
|
@Autowired
|
||||||
|
private RedisCache redisCache;
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
@Autowired
|
||||||
|
private EmsDevicesSettingMapper emsDevicesSettingMapper;
|
||||||
|
@Autowired
|
||||||
|
private ModbusProcessor modbusProcessor;
|
||||||
|
@Autowired
|
||||||
|
private EmsFaultIssueLogMapper emsFaultIssueLogMapper;
|
||||||
|
|
||||||
|
public ProtectionPlanTask(IEmsFaultProtectionPlanService iEmsFaultProtectionPlanService) {
|
||||||
|
this.iEmsFaultProtectionPlanService = iEmsFaultProtectionPlanService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pollPlanList() {
|
||||||
|
Long planId = 0L;
|
||||||
|
try {
|
||||||
|
// 获取所有方案,轮询
|
||||||
|
List<EmsFaultProtectionPlan> planList = iEmsFaultProtectionPlanService.selectEmsFaultProtectionPlanList(null);
|
||||||
|
|
||||||
|
for (EmsFaultProtectionPlan plan : planList) {
|
||||||
|
planId = plan.getId();
|
||||||
|
String siteId = plan.getSiteId();
|
||||||
|
if (StringUtils.isEmpty(siteId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 保护前提
|
||||||
|
String protectionSettings = plan.getProtectionSettings();
|
||||||
|
final List<ProtectionSettingVo> protSettings = objectMapper.readValue(
|
||||||
|
protectionSettings,
|
||||||
|
new TypeReference<List<ProtectionSettingVo>>() {}
|
||||||
|
);
|
||||||
|
if (protSettings == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理告警保护方案
|
||||||
|
boolean isHighLevel = dealWithProtectionPlan(plan, protSettings);
|
||||||
|
if (isHighLevel) {
|
||||||
|
// 触发最高故障等级-结束循环
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("轮询失败,方案id为:{}", planId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理告警保护方案-返回触发下发方案时是否最高等级
|
||||||
|
// 需要同步云端
|
||||||
|
@SyncAfterInsert
|
||||||
|
private boolean dealWithProtectionPlan(EmsFaultProtectionPlan plan, List<ProtectionSettingVo> protSettings) {
|
||||||
|
logger.info("<轮询保护方案> 站点:{},方案ID:{}", plan.getSiteId(), plan.getId());
|
||||||
|
boolean isHighLevel = false;
|
||||||
|
|
||||||
|
String siteId = plan.getSiteId();
|
||||||
|
final Integer isAlertAlarm = plan.getIsAlert();
|
||||||
|
final Long status = plan.getStatus();
|
||||||
|
// 看方案是否启用,走不同判断
|
||||||
|
if (Objects.equals(status, ProtPlanStatus.STOP.getCode())) {
|
||||||
|
logger.info("<方案未启用> 站点:{},方案ID:{}", siteId, plan.getId());
|
||||||
|
// 未启用,获取方案的故障值与最新数据判断是否需要下发方案
|
||||||
|
if(checkIsNeedIssuedPlan(protSettings, siteId)){
|
||||||
|
if("3".equals(plan.getFaultLevel())){
|
||||||
|
isHighLevel = true;//最高故障等级
|
||||||
|
}
|
||||||
|
// 延时
|
||||||
|
final int faultDelay = plan.getFaultDelaySeconds().intValue();
|
||||||
|
ScheduledFuture<?> delayTask = scheduledExecutorService.schedule(() -> {
|
||||||
|
// 延时后再次确认是否仍满足触发条件(防止期间状态变化)
|
||||||
|
if (checkIsNeedIssuedPlan(protSettings, siteId)) {
|
||||||
|
// 判断是否需要生成告警
|
||||||
|
if (isAlertAlarm == 1) {
|
||||||
|
logger.info("<生成告警> 方案ID:{},站点:{}", plan.getId(), siteId);
|
||||||
|
EmsAlarmRecords alarmRecords = addAlarmRecord(siteId,plan.getFaultName(),
|
||||||
|
getAlarmLevel(plan.getFaultLevel()));
|
||||||
|
emsAlarmRecordsMapper.insertEmsAlarmRecords(alarmRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否有保护方案,有则通过modbus连接设备下发方案
|
||||||
|
String protPlanJson = plan.getProtectionPlan();
|
||||||
|
if (protPlanJson != null && !protPlanJson.isEmpty() && !"[]".equals(protPlanJson)) {
|
||||||
|
logger.info("<下发保护方案> 方案内容:{}", protPlanJson);
|
||||||
|
executeProtectionActions(protPlanJson,siteId,plan.getId(),plan.getFaultLevel()); // 执行Modbus指令
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新方案状态为“已启用”
|
||||||
|
logger.info("<方案已启用> 方案ID:{}", plan.getId());
|
||||||
|
plan.setStatus(ProtPlanStatus.RUNNING.getCode());
|
||||||
|
emsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(plan);
|
||||||
|
|
||||||
|
// 更新该站点策略为暂停状态
|
||||||
|
updateStrategyRunningStatus(siteId, StrategyStatus.SUSPENDED.getCode());
|
||||||
|
}
|
||||||
|
}, faultDelay, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info("<方案已启用> 站点:{},方案ID:{}", siteId, plan.getId());
|
||||||
|
// 已启用,则获取方案的释放值与最新数据判断是否需要取消方案
|
||||||
|
if(checkIsNeedCancelPlan(protSettings, siteId)){
|
||||||
|
// 延时,
|
||||||
|
int releaseDelay = plan.getReleaseDelaySeconds().intValue();
|
||||||
|
ScheduledFuture<?> delayTask = scheduledExecutorService.schedule(() -> {
|
||||||
|
// 判断是否已存在未处理告警,有着取消
|
||||||
|
if(isAlertAlarm == 1){
|
||||||
|
logger.info("<取消告警>");
|
||||||
|
EmsAlarmRecords emsAlarmRecords = emsAlarmRecordsMapper.getFailedRecord(siteId,
|
||||||
|
plan.getFaultName(),getAlarmLevel(plan.getFaultLevel()));
|
||||||
|
if(emsAlarmRecords != null){
|
||||||
|
emsAlarmRecords.setStatus(AlarmStatus.DONE.getCode());
|
||||||
|
emsAlarmRecordsMapper.updateEmsAlarmRecords(emsAlarmRecords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 更新方案状态为“未启用”
|
||||||
|
logger.info("<方案变更为未启用> 方案ID:{}", plan.getId());
|
||||||
|
plan.setStatus(ProtPlanStatus.STOP.getCode());
|
||||||
|
plan.setUpdateBy("system");
|
||||||
|
emsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(plan);
|
||||||
|
// 更新该站点策略为启用状态
|
||||||
|
updateStrategyRunningStatus(siteId, StrategyStatus.RUNNING.getCode());
|
||||||
|
}, releaseDelay, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isHighLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下发保护方案
|
||||||
|
private void executeProtectionActions(String protPlanJson, String siteId, Long planId, Integer faultLevel){
|
||||||
|
final List<ProtectionPlanVo> protPlanList;
|
||||||
|
try {
|
||||||
|
protPlanList = objectMapper.readValue(
|
||||||
|
protPlanJson,
|
||||||
|
new TypeReference<List<ProtectionPlanVo>>() {}
|
||||||
|
);
|
||||||
|
if (protPlanList == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历保护方案
|
||||||
|
for (ProtectionPlanVo plan : protPlanList) {
|
||||||
|
if (StringUtils.isEmpty(plan.getDeviceId()) || StringUtils.isEmpty(plan.getPoint())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 给设备发送指令记录日志,并同步云端
|
||||||
|
EmsFaultIssueLog faultIssueLog = createLogEntity(plan,siteId);
|
||||||
|
faultIssueLog.setLogLevel(faultLevel);
|
||||||
|
emsFaultIssueLogMapper.insertEmsFaultIssueLog(faultIssueLog);
|
||||||
|
|
||||||
|
// 通过modbus连接设备,发送数据
|
||||||
|
executeSinglePlan(plan,siteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("下发保护方案失败,方案id为:", planId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmsFaultIssueLog createLogEntity(ProtectionPlanVo plan,String siteId) {
|
||||||
|
EmsFaultIssueLog faultIssueLog = new EmsFaultIssueLog();
|
||||||
|
faultIssueLog.setLogId(UUID.randomUUID().toString());
|
||||||
|
faultIssueLog.setLogTime(new Date());
|
||||||
|
faultIssueLog.setSiteId(siteId);
|
||||||
|
faultIssueLog.setDeviceId(plan.getDeviceId());
|
||||||
|
faultIssueLog.setPoint(plan.getPoint());
|
||||||
|
faultIssueLog.setValue(plan.getValue());
|
||||||
|
faultIssueLog.setCreateBy("sys");
|
||||||
|
faultIssueLog.setCreateTime(new Date());
|
||||||
|
return faultIssueLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeSinglePlan(ProtectionPlanVo plan, String siteId) throws Exception {
|
||||||
|
String deviceId = plan.getDeviceId();
|
||||||
|
// 获取设备地址信息
|
||||||
|
EmsDevicesSetting device = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceId, siteId);
|
||||||
|
if (device == null || StringUtils.isEmpty(device.getIpAddress()) || device.getIpPort()==null) {
|
||||||
|
logger.warn("设备信息不完整,deviceId:{}", deviceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建设备配置
|
||||||
|
DeviceConfig config = new DeviceConfig();
|
||||||
|
config.setHost(device.getIpAddress());
|
||||||
|
config.setPort(device.getIpPort().intValue());
|
||||||
|
config.setSlaveId(device.getSlaveId().intValue());
|
||||||
|
config.setDeviceName(device.getDeviceName());
|
||||||
|
config.setDeviceNumber(device.getDeviceId());
|
||||||
|
|
||||||
|
// 构建写入标签配置
|
||||||
|
WriteTagConfig writeTag = new WriteTagConfig();
|
||||||
|
writeTag.setAddress(plan.getPoint());
|
||||||
|
writeTag.setValue(plan.getValue());
|
||||||
|
|
||||||
|
List<WriteTagConfig> writeTags = new ArrayList<>();
|
||||||
|
writeTags.add(writeTag);
|
||||||
|
config.setWriteTags(writeTags);
|
||||||
|
|
||||||
|
// 写入数据到设备
|
||||||
|
boolean success = modbusProcessor.writeDataToDeviceWithRetry(config);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
logger.error("写入失败,设备地址:{}", device.getIpAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验释放值是否取消方案
|
||||||
|
private boolean checkIsNeedCancelPlan(List<ProtectionSettingVo> protSettings, String siteId) {
|
||||||
|
BigDecimal releaseValue = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
StringBuilder conditionSb = new StringBuilder();
|
||||||
|
for (int i = 0; i < protSettings.size(); i++) {
|
||||||
|
ProtectionSettingVo vo = protSettings.get(i);
|
||||||
|
String deviceId = vo.getDeviceId();
|
||||||
|
String point = vo.getPoint();
|
||||||
|
releaseValue = vo.getFaultValue();
|
||||||
|
if(StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(point) || releaseValue == null
|
||||||
|
|| StringUtils.isEmpty(vo.getReleaseOperator())){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获取点位最新值
|
||||||
|
BigDecimal lastPointValue = getPointLastValue(deviceId, point, siteId);
|
||||||
|
logger.info("checkIsNeedCancelPlan 点位:{},最新值:{},比较方式:{},释放值:{}", point, lastPointValue, vo.getReleaseOperator(), releaseValue);
|
||||||
|
if(lastPointValue == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拼接校验语句-最新值+比较方式+故障值+与下一点位关系(最后一个条件后不加关系)
|
||||||
|
conditionSb.append(lastPointValue).append(vo.getReleaseOperator()).append(releaseValue);
|
||||||
|
if (i < protSettings.size() - 1) {
|
||||||
|
String relation = vo.getRelationNext();
|
||||||
|
conditionSb.append(" ").append(relation).append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// 执行比较语句
|
||||||
|
return executeWithParser(conditionSb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验故障值是否需要下发方案
|
||||||
|
private boolean checkIsNeedIssuedPlan(List<ProtectionSettingVo> protSettings, String siteId) {
|
||||||
|
BigDecimal faultValue = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
StringBuilder conditionSb = new StringBuilder();
|
||||||
|
for (int i = 0; i < protSettings.size(); i++) {
|
||||||
|
ProtectionSettingVo vo = protSettings.get(i);
|
||||||
|
String deviceId = vo.getDeviceId();
|
||||||
|
String point = vo.getPoint();
|
||||||
|
faultValue = vo.getFaultValue();
|
||||||
|
if(StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(point) || faultValue == null
|
||||||
|
|| StringUtils.isEmpty(vo.getFaultOperator())){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获取点位最新值
|
||||||
|
BigDecimal lastPointValue = getPointLastValue(deviceId, point, siteId);
|
||||||
|
logger.info("checkIsNeedIssuedPlan 点位:{},最新值:{},比较方式:{},故障值:{}", point, lastPointValue, vo.getFaultOperator(), faultValue);
|
||||||
|
if(lastPointValue == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拼接校验语句-最新值+比较方式+故障值+与下一点位关系(最后一个条件后不加关系)
|
||||||
|
conditionSb.append(lastPointValue).append(vo.getFaultOperator()).append(faultValue);
|
||||||
|
if (i < protSettings.size() - 1) {
|
||||||
|
String relation = vo.getRelationNext();
|
||||||
|
conditionSb.append(" ").append(relation).append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// 执行比较语句
|
||||||
|
return executeWithParser(conditionSb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal getPointLastValue(String deviceId, String point, String siteId) {
|
||||||
|
JSONObject mqttJson = redisCache.getCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceId);
|
||||||
|
if(mqttJson == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String jsonData = mqttJson.get("Data").toString();
|
||||||
|
if(StringUtils.isEmpty(jsonData)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map<String, Object> obj = JSON.parseObject(jsonData, new com.alibaba.fastjson2.TypeReference<Map<String, Object>>() {});
|
||||||
|
return StringUtils.getBigDecimal(obj.get(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新站点策略为启用
|
||||||
|
private void updateStrategyRunningStatus(String siteId, String status) {
|
||||||
|
// 获取是否有正在运行的策略,如果有则不更改
|
||||||
|
EmsStrategyRunning query = new EmsStrategyRunning();
|
||||||
|
query.setSiteId(siteId);
|
||||||
|
query.setStatus(StrategyStatus.RUNNING.getCode().equals(status) ? StrategyStatus.SUSPENDED.getCode() : StrategyStatus.RUNNING.getCode());
|
||||||
|
List<EmsStrategyRunning> strategyRunningList = emsStrategyRunningMapper.selectEmsStrategyRunningList(query);
|
||||||
|
if (CollectionUtils.isNotEmpty(strategyRunningList)) {
|
||||||
|
// 获取已存在并且状态为:未启用和已暂停的最晚一条策略,更新为已启用
|
||||||
|
strategyRunningList.forEach(emsStrategyRunning -> {
|
||||||
|
emsStrategyRunning.setStatus(status);
|
||||||
|
emsStrategyRunningMapper.updateEmsStrategyRunning(emsStrategyRunning);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新站点策略为启用
|
||||||
|
private void updateStrategyRunning(String siteId) {
|
||||||
|
// 获取是否有正在运行的策略,如果有则不更改
|
||||||
|
EmsStrategyRunning emsStrategyRunning = emsStrategyRunningMapper.getRunningStrategy(siteId);
|
||||||
|
if (emsStrategyRunning == null) {
|
||||||
|
// 获取已存在并且状态为:未启用和已暂停的最晚一条策略,更新为已启用
|
||||||
|
emsStrategyRunning = emsStrategyRunningMapper.getPendingStrategy(siteId);
|
||||||
|
emsStrategyRunning.setStatus(StrategyStatus.RUNNING.getCode());
|
||||||
|
emsStrategyRunningMapper.updateEmsStrategyRunning(emsStrategyRunning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmsAlarmRecords addAlarmRecord(String siteId, String content,String level) {
|
||||||
|
EmsAlarmRecords emsAlarmRecords = new EmsAlarmRecords();
|
||||||
|
emsAlarmRecords.setSiteId(siteId);
|
||||||
|
emsAlarmRecords.setAlarmContent(content);
|
||||||
|
emsAlarmRecords.setAlarmLevel(level);
|
||||||
|
emsAlarmRecords.setAlarmStartTime(new Date());
|
||||||
|
emsAlarmRecords.setStatus(AlarmStatus.WAITING.getCode());
|
||||||
|
emsAlarmRecords.setDeviceType("TCP");
|
||||||
|
emsAlarmRecords.setCreateBy("system");
|
||||||
|
emsAlarmRecords.setCreateTime(new Date());
|
||||||
|
return emsAlarmRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 故障等级-告警等级匹配
|
||||||
|
private String getAlarmLevel(Integer faultLevel) {
|
||||||
|
if (ObjectUtils.isEmpty(faultLevel) || faultLevel < 1 || faultLevel > 3) {
|
||||||
|
logger.warn("非法故障等级:{},默认返回普通告警", faultLevel);
|
||||||
|
return AlarmLevelStatus.EMERGENCY.getCode();
|
||||||
|
}
|
||||||
|
switch (faultLevel) {
|
||||||
|
case 1: return AlarmLevelStatus.GENERAL.getCode();
|
||||||
|
case 2: return AlarmLevelStatus.SERIOUS.getCode();
|
||||||
|
case 3: return AlarmLevelStatus.EMERGENCY.getCode();
|
||||||
|
default:
|
||||||
|
logger.error("未匹配的故障等级:{}", faultLevel);
|
||||||
|
return AlarmLevelStatus.EMERGENCY.getCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义表达式解析器(仅支持简单运算符和逻辑关系)
|
||||||
|
public boolean executeWithParser(String conditionStr) {
|
||||||
|
if (conditionStr == null || conditionStr.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 拆分逻辑关系(提取 && 或 ||)
|
||||||
|
List<String> logicRelations = new ArrayList<>();
|
||||||
|
Pattern logicPattern = Pattern.compile("(&&|\\|\\|)");
|
||||||
|
Matcher logicMatcher = logicPattern.matcher(conditionStr);
|
||||||
|
while (logicMatcher.find()) {
|
||||||
|
logicRelations.add(logicMatcher.group());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 拆分原子条件(如 "3.55>3.52")
|
||||||
|
String[] atomicConditions = logicPattern.split(conditionStr);
|
||||||
|
|
||||||
|
// 3. 解析每个原子条件并计算结果
|
||||||
|
List<Boolean> atomicResults = new ArrayList<>();
|
||||||
|
Pattern conditionPattern = Pattern.compile("(\\d+\\.?\\d*)\\s*([><]=?|==)\\s*(\\d+\\.?\\d*)");
|
||||||
|
for (String atomic : atomicConditions) {
|
||||||
|
Matcher matcher = conditionPattern.matcher(atomic.trim());
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
logger.error("无效的原子条件:{}", atomic);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double left = Double.parseDouble(matcher.group(1)); // 左值(最新值)
|
||||||
|
String operator = matcher.group(2); // 运算符
|
||||||
|
double right = Double.parseDouble(matcher.group(3)); // 右值(故障值)
|
||||||
|
|
||||||
|
// 执行比较
|
||||||
|
boolean result;
|
||||||
|
switch (operator) {
|
||||||
|
case ">":
|
||||||
|
result = left > right;
|
||||||
|
break;
|
||||||
|
case ">=":
|
||||||
|
result = left >= right;
|
||||||
|
break;
|
||||||
|
case "<":
|
||||||
|
result = left < right;
|
||||||
|
break;
|
||||||
|
case "<=":
|
||||||
|
result = left <= right;
|
||||||
|
break;
|
||||||
|
case "==":
|
||||||
|
result = left == right;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
atomicResults.add(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 组合原子结果(根据逻辑关系)
|
||||||
|
boolean finalResult = atomicResults.get(0);
|
||||||
|
for (int i = 0; i < logicRelations.size(); i++) {
|
||||||
|
String relation = logicRelations.get(i);
|
||||||
|
boolean nextResult = atomicResults.get(i+1);
|
||||||
|
if ("&&".equals(relation)) {
|
||||||
|
finalResult = finalResult && nextResult;
|
||||||
|
} else if ("||".equals(relation)) {
|
||||||
|
finalResult = finalResult || nextResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return finalResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,494 @@
|
|||||||
|
package com.xzzn.quartz.task;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.xzzn.common.core.modbus.ModbusProcessor;
|
||||||
|
import com.xzzn.common.core.modbus.domain.DeviceConfig;
|
||||||
|
import com.xzzn.common.core.modbus.domain.WriteTagConfig;
|
||||||
|
import com.xzzn.common.enums.ChargeStatus;
|
||||||
|
import com.xzzn.common.enums.DeviceCategory;
|
||||||
|
import com.xzzn.common.enums.SiteDevice;
|
||||||
|
import com.xzzn.common.enums.SocLimit;
|
||||||
|
import com.xzzn.common.enums.WorkStatus;
|
||||||
|
import com.xzzn.common.utils.DateUtils;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsAmmeterData;
|
||||||
|
import com.xzzn.ems.domain.EmsBatteryStack;
|
||||||
|
import com.xzzn.ems.domain.EmsDevicesSetting;
|
||||||
|
import com.xzzn.ems.domain.EmsPcsSetting;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyLog;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyTemp;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyTimeConfig;
|
||||||
|
import com.xzzn.ems.domain.vo.StrategyRunningVo;
|
||||||
|
import com.xzzn.ems.mapper.EmsAmmeterDataMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsBatteryStackMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsPcsSettingMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyLogMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyTempMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component("strategyPoller")
|
||||||
|
public class StrategyPoller {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(StrategyPoller.class);
|
||||||
|
|
||||||
|
private static final ConcurrentHashMap<Long, Boolean> strategyLocks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// SOC 上下限值,默认为0%-100%
|
||||||
|
private static final BigDecimal SOC_DOWN = new BigDecimal(0);
|
||||||
|
private static final BigDecimal SOC_UP = new BigDecimal(100);
|
||||||
|
// 逆变器功率下限值,默认为30kW
|
||||||
|
private static final BigDecimal ANTI_REVERSE_THRESHOLD = new BigDecimal(30);
|
||||||
|
// 逆变器下限值范围,默认为20%
|
||||||
|
private static final BigDecimal ANTI_REVERSE_RANGE_PERCENT = new BigDecimal(20);
|
||||||
|
// 逆变器功率上限值,默认为100kW
|
||||||
|
private static final BigDecimal ANTI_REVERSE_UP = new BigDecimal(100);
|
||||||
|
// PCS功率降幅,默认为10%
|
||||||
|
private static final BigDecimal ANTI_REVERSE_POWER_DOWN_PERCENT = new BigDecimal(10);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyRunningMapper emsStrategyRunningMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyTempMapper emsStrategyTempMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyTimeConfigMapper emsStrategyTimeConfigMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsBatteryStackMapper emsBatteryStackMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsDevicesSettingMapper emsDevicesMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsPcsSettingMapper emsPcsSettingMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsAmmeterDataMapper emsAmmeterDataMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyLogMapper emsStrategyLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private ModbusProcessor modbusProcessor;
|
||||||
|
|
||||||
|
@Resource(name = "modbusExecutor")
|
||||||
|
private ExecutorService modbusExecutor;
|
||||||
|
|
||||||
|
public void pollAllDevices() {
|
||||||
|
logger.info("开始执行运行策略数据轮询...");
|
||||||
|
List<StrategyRunningVo> strategyRunningVoList = emsStrategyRunningMapper.getPendingPollerStrategy(null);
|
||||||
|
strategyRunningVoList.forEach(strategyVo -> {
|
||||||
|
Long strategyId = strategyVo.getId();
|
||||||
|
if (strategyLocks.putIfAbsent(strategyId, true) == null) {
|
||||||
|
// 使用共享的modbusExecutor串行执行,避免与ModbusPoller并发访问导致通讯故障
|
||||||
|
modbusExecutor.submit(() -> {
|
||||||
|
try {
|
||||||
|
processData(strategyVo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("运行策略{}轮询异常", strategyVo.getId(), e);
|
||||||
|
} finally {
|
||||||
|
logger.info("运行策略{}轮询任务执行完成,释放锁", strategyVo.getId());
|
||||||
|
strategyLocks.remove(strategyId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
logger.info("策略{}已在处理中,跳过重复执行", strategyId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 处理获取到的运行策略数据,modbus发送指定的命令控制设备
|
||||||
|
private void processData(StrategyRunningVo strategyVo) {
|
||||||
|
logger.info("运行策略数据处理开始");
|
||||||
|
// 根据运行策略获取主副策略的模板数据
|
||||||
|
Long mainStrategyId = strategyVo.getMainStrategyId();
|
||||||
|
Long auxStrategyId = strategyVo.getAuxStrategyId();
|
||||||
|
String siteId = strategyVo.getSiteId();
|
||||||
|
// 处理主策略数据
|
||||||
|
if (mainStrategyId != null && StringUtils.isNotBlank(siteId)) {
|
||||||
|
dealStrategyCurveData(mainStrategyId, siteId);
|
||||||
|
}
|
||||||
|
// 处理副策略数据
|
||||||
|
if (auxStrategyId != null && StringUtils.isNotBlank(siteId)) {
|
||||||
|
dealStrategyCurveData(auxStrategyId, siteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("运行策略轮询处理结束");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dealStrategyCurveData(Long strategyId, String siteId) {
|
||||||
|
// 1.获取当前策略的所有模板
|
||||||
|
List<Map<String, String>> temps = emsStrategyTempMapper.getTempNameList(strategyId, siteId);
|
||||||
|
if (CollectionUtils.isEmpty(temps)) {
|
||||||
|
logger.info("当前站点: {}, 策略: {} 没有模板数据", siteId, strategyId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Map<String, String> temp : temps) {
|
||||||
|
// 2.查询当月配置的运行策略
|
||||||
|
String tempId = temp.get("templateId");
|
||||||
|
int month = LocalDateTime.now().getMonthValue();
|
||||||
|
List<EmsStrategyTimeConfig> timeConfigs = emsStrategyTimeConfigMapper.getTimeConfigByTempIdAndMonth(tempId, month);
|
||||||
|
if (CollectionUtils.isEmpty(timeConfigs)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
logger.info("当前站点: {}, 策略: {}, {}月配置模版:{}", siteId, strategyId, month, tempId);
|
||||||
|
// 3.查询当月配置的运行策略时间阶段数据
|
||||||
|
List<EmsStrategyTemp> powerConfig = emsStrategyTempMapper.selectStrategyTempByTempId(tempId);
|
||||||
|
if (CollectionUtils.isEmpty(powerConfig)) {
|
||||||
|
logger.info("当前站点: {}, 策略: {}, 模版:{} 未配置数据", siteId, strategyId, tempId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 4.遍历时间段数据,判断当前时间是否在时间段内,在时间段内的进行处理
|
||||||
|
for (EmsStrategyTemp emsStrategyTemp : powerConfig) {
|
||||||
|
if (emsStrategyTemp.getStartTime() == null || emsStrategyTemp.getEndTime() == null) {
|
||||||
|
logger.info("当前站点: {}, 策略: {}, 模版:{} 未配置时间阶段数据", siteId, strategyId, tempId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 判断当前时间是否在时间段内
|
||||||
|
if (!isTimeInRange(LocalTime.now(), emsStrategyTemp.getStartTime(), emsStrategyTemp.getEndTime())) {
|
||||||
|
logger.info("当前站点: {}, 策略: {}, 时间段:{} 不在时间段内", siteId, strategyId, emsStrategyTemp.getStartTime() + "-" + emsStrategyTemp.getEndTime());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 查询PCS设备信息
|
||||||
|
EmsDevicesSetting queryDevices = new EmsDevicesSetting();
|
||||||
|
queryDevices.setSiteId(siteId);
|
||||||
|
queryDevices.setDeviceCategory(DeviceCategory.PCS.getCode());
|
||||||
|
List<EmsDevicesSetting> pcsDeviceList = emsDevicesMapper.selectEmsDevicesSettingList(queryDevices);
|
||||||
|
if (CollectionUtils.isEmpty(pcsDeviceList)) {
|
||||||
|
logger.info("当前站点: {} 未配置PCS设备", siteId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 判断SOC上下限
|
||||||
|
if (isSocInRange(emsStrategyTemp)) {
|
||||||
|
BigDecimal avgChargeDischargePower = emsStrategyTemp.getChargeDischargePower().divide(new BigDecimal(pcsDeviceList.size()));
|
||||||
|
for (EmsDevicesSetting pcsDevice : pcsDeviceList) {
|
||||||
|
EmsPcsSetting pcsSetting = emsPcsSettingMapper.selectEmsPcsSettingByDeviceId(pcsDevice.getId());
|
||||||
|
if (pcsSetting == null || pcsSetting.getClusterNum() < 1) {
|
||||||
|
logger.info("当前站点: {}, PCS设备: {} 未获取电池簇数量", siteId, pcsDevice.getDeviceId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 功率默认放大10倍,平均功率值,根据电池簇数量进行平均分配
|
||||||
|
avgChargeDischargePower = avgChargeDischargePower.multiply(new BigDecimal(10)).divide(new BigDecimal(pcsSetting.getClusterNum()));
|
||||||
|
// 根据充电状态,处理数据
|
||||||
|
if (ChargeStatus.CHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
|
||||||
|
// 发送Modbus命令控制设备-充电
|
||||||
|
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.CHARGING, avgChargeDischargePower, emsStrategyTemp, false, null);
|
||||||
|
} else if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
|
||||||
|
boolean needAntiReverseFlow = false;
|
||||||
|
Integer powerDownType = null;
|
||||||
|
BigDecimal chargeDischargePower = avgChargeDischargePower;
|
||||||
|
// 查询策略运行日志
|
||||||
|
EmsStrategyLog lastStrategyLog = getLastStrategyLog(pcsDevice.getDeviceId(), emsStrategyTemp);
|
||||||
|
if (lastStrategyLog != null) {
|
||||||
|
// 如果当前时间段已经进入待机状态,则不处理
|
||||||
|
if (ChargeStatus.STANDBY.getCode().equals(lastStrategyLog.getChargeStatus())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chargeDischargePower = lastStrategyLog.getChargeDischargePower();
|
||||||
|
powerDownType = lastStrategyLog.getPowerDownType();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询电网电表的正向有功功率,36kW-50kW范围内,稳定运行,低于36kW,降功率,高于50kW,增加功率
|
||||||
|
EmsAmmeterData emsAmmeterData = emsAmmeterDataMapper.getLastData(emsStrategyTemp.getSiteId(), SiteDevice.LOAD.name());
|
||||||
|
if (emsAmmeterData == null || emsAmmeterData.getTotalActivePower() == null) {
|
||||||
|
logger.info("当前站点: {}, 未获取到最新电表数据", emsStrategyTemp.getSiteId());
|
||||||
|
} else {
|
||||||
|
// 判断是否需要防逆流
|
||||||
|
needAntiReverseFlow = isNeedAntiReverseFlow(emsAmmeterData.getTotalActivePower());
|
||||||
|
BigDecimal power = avgChargeDischargePower.multiply(ANTI_REVERSE_POWER_DOWN_PERCENT).divide(new BigDecimal(100));
|
||||||
|
if (needAntiReverseFlow) {
|
||||||
|
// 降功率
|
||||||
|
chargeDischargePower = chargeDischargePower.subtract(power);
|
||||||
|
powerDownType = 0;
|
||||||
|
} else {
|
||||||
|
// 判断是否需要增加功率,
|
||||||
|
if (powerDownType != null && emsAmmeterData.getTotalActivePower().compareTo(ANTI_REVERSE_UP) > 0) {
|
||||||
|
if (chargeDischargePower.compareTo(avgChargeDischargePower) == 0) {
|
||||||
|
// 功率增加到平均值则停止
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 增加功率
|
||||||
|
chargeDischargePower = chargeDischargePower.add(power);
|
||||||
|
powerDownType = 1;
|
||||||
|
needAntiReverseFlow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BigDecimal.ZERO.compareTo(chargeDischargePower) == 0) {
|
||||||
|
// 如果已经降功率到0,则设备直接待机
|
||||||
|
// 发送Modbus命令控制设备-待机
|
||||||
|
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, needAntiReverseFlow, powerDownType);
|
||||||
|
} else {
|
||||||
|
// 发送Modbus命令控制设备-放电
|
||||||
|
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.DISCHARGING, chargeDischargePower, emsStrategyTemp, needAntiReverseFlow, powerDownType);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 发送Modbus命令控制设备-待机
|
||||||
|
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, false, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 发送Modbus命令控制设备-待机
|
||||||
|
sendModbusCommand(pcsDeviceList, null, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, false, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void saveStrategyLog(String deviceId, BigDecimal chargeDischargePower, String chargeStatus,
|
||||||
|
EmsStrategyTemp strategyTemp, boolean needAntiReverseFlow, Integer powerDownType) {
|
||||||
|
EmsStrategyLog log = new EmsStrategyLog();
|
||||||
|
log.setStrategyId(strategyTemp.getStrategyId());
|
||||||
|
log.setTemplateId(strategyTemp.getTemplateId());
|
||||||
|
log.setSiteId(strategyTemp.getSiteId());
|
||||||
|
log.setDeviceId(deviceId);
|
||||||
|
log.setStartTime(strategyTemp.getStartTime());
|
||||||
|
log.setEndTime(strategyTemp.getEndTime());
|
||||||
|
log.setChargeDischargePower(chargeDischargePower);
|
||||||
|
log.setChargeStatus(chargeStatus);
|
||||||
|
log.setExecutionDate(DateUtils.toDate(LocalDateTime.now()));
|
||||||
|
log.setAntiReverse(needAntiReverseFlow ? 1 : 0);
|
||||||
|
log.setPowerDownType(powerDownType);
|
||||||
|
emsStrategyLogMapper.insertEmsStrategyLog(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<EmsStrategyLog> getStrategyLog(String deviceId, String chargeStatus,
|
||||||
|
EmsStrategyTemp strategyTemp, boolean needAntiReverseFlow) {
|
||||||
|
EmsStrategyLog query = new EmsStrategyLog();
|
||||||
|
query.setStrategyId(strategyTemp.getStrategyId());
|
||||||
|
query.setTemplateId(strategyTemp.getTemplateId());
|
||||||
|
query.setSiteId(strategyTemp.getSiteId());
|
||||||
|
query.setDeviceId(deviceId);
|
||||||
|
query.setStartTime(strategyTemp.getStartTime());
|
||||||
|
query.setEndTime(strategyTemp.getEndTime());
|
||||||
|
query.setChargeStatus(chargeStatus);
|
||||||
|
query.setExecutionDate(DateUtils.toDate(LocalDateTime.now()));
|
||||||
|
query.setAntiReverse(needAntiReverseFlow ? 1 : 0);
|
||||||
|
return emsStrategyLogMapper.selectEmsStrategyLogList(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmsStrategyLog getLastStrategyLog(String deviceId, EmsStrategyTemp strategyTemp) {
|
||||||
|
EmsStrategyLog query = new EmsStrategyLog();
|
||||||
|
query.setStrategyId(strategyTemp.getStrategyId());
|
||||||
|
query.setTemplateId(strategyTemp.getTemplateId());
|
||||||
|
query.setSiteId(strategyTemp.getSiteId());
|
||||||
|
query.setDeviceId(deviceId);
|
||||||
|
query.setStartTime(strategyTemp.getStartTime());
|
||||||
|
query.setEndTime(strategyTemp.getEndTime());
|
||||||
|
query.setExecutionDate(DateUtils.toDate(LocalDateTime.now()));
|
||||||
|
return emsStrategyLogMapper.getLastStrategyLog(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNeedAntiReverseFlow(BigDecimal totalActivePower) {
|
||||||
|
// 获取当前设定的防逆流阈值(30kW)
|
||||||
|
BigDecimal threshold = ANTI_REVERSE_THRESHOLD;
|
||||||
|
// 计算20%范围的上限(36kW)
|
||||||
|
BigDecimal upperLimit = threshold.multiply(ANTI_REVERSE_RANGE_PERCENT).divide(new BigDecimal(100)).add(threshold);
|
||||||
|
|
||||||
|
// 判断电网电表正向有功功率是否小于36kW(接近30kW的20%范围)
|
||||||
|
return totalActivePower.compareTo(upperLimit) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WriteTagConfig> getSwitchDeviceWriteTags(EmsPcsSetting pcsSetting, String workStatus) {
|
||||||
|
List<WriteTagConfig> writeTags = new ArrayList<>();
|
||||||
|
BigDecimal power;
|
||||||
|
|
||||||
|
if (WorkStatus.NORMAL.getCode().equals(workStatus)) {
|
||||||
|
// 开机先发送开机指令再发送有功功率给定值
|
||||||
|
WriteTagConfig writeTag = new WriteTagConfig();
|
||||||
|
writeTag.setAddress(pcsSetting.getPointAddress());
|
||||||
|
writeTag.setValue(pcsSetting.getStartCommand());
|
||||||
|
writeTags.add(writeTag);
|
||||||
|
|
||||||
|
power = pcsSetting.getStartPower();
|
||||||
|
} else {
|
||||||
|
// 关机
|
||||||
|
power = pcsSetting.getStopPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray array = JSON.parseArray(pcsSetting.getClusterPointAddress());
|
||||||
|
for (int i = 0; i < pcsSetting.getClusterNum(); i++) {
|
||||||
|
Object clusterPointAddress = array.get(i);
|
||||||
|
WriteTagConfig clusterWriteTag = new WriteTagConfig();
|
||||||
|
clusterWriteTag.setAddress(String.valueOf(clusterPointAddress));
|
||||||
|
// 电池簇PCS有功功率给定默认置0
|
||||||
|
if (power == null) {
|
||||||
|
power = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
clusterWriteTag.setValue(power);
|
||||||
|
writeTags.add(clusterWriteTag);
|
||||||
|
}
|
||||||
|
if (WorkStatus.STOP.getCode().equals(workStatus)) {
|
||||||
|
// 关机先发送有功功率给定值再发送关机指令
|
||||||
|
WriteTagConfig writeTag = new WriteTagConfig();
|
||||||
|
writeTag.setAddress(pcsSetting.getPointAddress());
|
||||||
|
writeTag.setValue(pcsSetting.getStopCommand());
|
||||||
|
writeTags.add(writeTag);
|
||||||
|
}
|
||||||
|
return writeTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WriteTagConfig> getWriteTags(EmsPcsSetting pcsSetting, BigDecimal chargeDischargePower) {
|
||||||
|
List<WriteTagConfig> writeTags = new ArrayList<>();
|
||||||
|
JSONArray array = JSON.parseArray(pcsSetting.getClusterPointAddress());
|
||||||
|
for (int i = 0; i < pcsSetting.getClusterNum(); i++) {
|
||||||
|
Object clusterPointAddress = array.get(i);
|
||||||
|
WriteTagConfig clusterWriteTag = new WriteTagConfig();
|
||||||
|
clusterWriteTag.setAddress(String.valueOf(clusterPointAddress));
|
||||||
|
clusterWriteTag.setValue(chargeDischargePower);
|
||||||
|
writeTags.add(clusterWriteTag);
|
||||||
|
}
|
||||||
|
return writeTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceConfig getDeviceConfig(String siteId, String deviceId, EmsDevicesSetting device, EmsPcsSetting pcsSetting, BigDecimal chargeDischargePower, int writeType) {
|
||||||
|
if (Objects.isNull(pcsSetting)) {
|
||||||
|
pcsSetting = emsPcsSettingMapper.selectEmsPcsSettingByDeviceId(device.getId());
|
||||||
|
if (pcsSetting == null) {
|
||||||
|
logger.info("当前站点: {}, PCS设备: {} 未找到对应PCS配置", siteId, deviceId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (device.getIpPort() == null || device.getSlaveId() == null) {
|
||||||
|
logger.info("当前站点: {}, PCS设备: {} 未配置IP端口或从站号", siteId, deviceId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DeviceConfig deviceConfig = new DeviceConfig();
|
||||||
|
deviceConfig.setDeviceNumber(device.getDeviceId());
|
||||||
|
deviceConfig.setDeviceName(device.getDeviceName());
|
||||||
|
deviceConfig.setSlaveId(device.getSlaveId().intValue());
|
||||||
|
deviceConfig.setHost(device.getIpAddress());
|
||||||
|
deviceConfig.setPort(device.getIpPort().intValue());
|
||||||
|
deviceConfig.setWriteTags(writeType == 0 ? getWriteTags(pcsSetting, chargeDischargePower) : getSwitchDeviceWriteTags(pcsSetting, device.getWorkStatus()));
|
||||||
|
return deviceConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendModbusCommand(List<EmsDevicesSetting> pcsDeviceList, EmsPcsSetting pcsSetting, ChargeStatus chargeStatus, BigDecimal chargeDischargePower,
|
||||||
|
EmsStrategyTemp emsStrategyTemp, boolean needAntiReverseFlow, Integer powerDownType) {
|
||||||
|
for (EmsDevicesSetting pcsDevice : pcsDeviceList) {
|
||||||
|
String siteId = pcsDevice.getSiteId();
|
||||||
|
String deviceId = pcsDevice.getDeviceId();
|
||||||
|
List<EmsStrategyLog> strategyLogList = getStrategyLog(deviceId, chargeStatus.getCode(), emsStrategyTemp, needAntiReverseFlow);
|
||||||
|
if (CollectionUtils.isNotEmpty(strategyLogList)) {
|
||||||
|
boolean isExist = true;
|
||||||
|
if (ChargeStatus.DISCHARGING.equals(chargeStatus) && needAntiReverseFlow) {
|
||||||
|
isExist = false;
|
||||||
|
}
|
||||||
|
if (isExist) {
|
||||||
|
logger.info("当前站点: {}, PCS设备: {} 当前时间段已存在策略执行记录,不再重复执行", siteId, deviceId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每次操作先判断设备工作状态
|
||||||
|
if (StringUtils.isEmpty(pcsDevice.getWorkStatus()) || WorkStatus.ABNORMAL.getCode().equals(pcsDevice.getWorkStatus())) {
|
||||||
|
// 设备故障,不发送指令
|
||||||
|
continue;
|
||||||
|
} else if (WorkStatus.STOP.getCode().equals(pcsDevice.getWorkStatus())) {
|
||||||
|
// 设备停机
|
||||||
|
if (ChargeStatus.STANDBY.equals(chargeStatus)) {
|
||||||
|
// 待机,则不写入功率值
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// 充、放电,则先开机设备
|
||||||
|
switchDevice(pcsDevice, pcsSetting, WorkStatus.NORMAL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsDevice, pcsSetting, chargeDischargePower, 0);
|
||||||
|
if (deviceConfig == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig);
|
||||||
|
if (!result) {
|
||||||
|
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, chargeStatus.getInfo());
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (ChargeStatus.STANDBY.equals(chargeStatus)) {
|
||||||
|
// 待机,先写功率值,再关机
|
||||||
|
if (!switchDevice(pcsDevice, pcsSetting, WorkStatus.STOP)) {
|
||||||
|
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, WorkStatus.STOP.getInfo());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 记录策略执行日志
|
||||||
|
saveStrategyLog(deviceId, chargeDischargePower, chargeStatus.getCode(), emsStrategyTemp, needAntiReverseFlow, powerDownType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//设备开关机
|
||||||
|
private boolean switchDevice(EmsDevicesSetting pcsDevice, EmsPcsSetting pcsSetting, WorkStatus workStatus) {
|
||||||
|
String siteId = pcsDevice.getSiteId();
|
||||||
|
String deviceId = pcsDevice.getDeviceId();
|
||||||
|
pcsDevice.setWorkStatus(workStatus.getCode());
|
||||||
|
DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsDevice, pcsSetting , null, 1);
|
||||||
|
if (deviceConfig == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig);
|
||||||
|
if (!result) {
|
||||||
|
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceConfig, workStatus.getInfo());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断当前时间是否在时间范围内
|
||||||
|
private static boolean isTimeInRange(LocalTime now, Date startTime, Date endTime) {
|
||||||
|
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
|
||||||
|
LocalTime startLocalTime = startTime.toInstant()
|
||||||
|
.atZone(zoneId)
|
||||||
|
.toLocalTime();
|
||||||
|
LocalTime endLocalTime = endTime.toInstant()
|
||||||
|
.atZone(zoneId)
|
||||||
|
.toLocalTime();
|
||||||
|
return now.equals(startLocalTime) || (now.isAfter(startLocalTime) && now.isBefore(endLocalTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断SOC上限和下限
|
||||||
|
private boolean isSocInRange(EmsStrategyTemp emsStrategyTemp) {
|
||||||
|
BigDecimal socDown = SOC_DOWN;
|
||||||
|
BigDecimal socUp = SOC_UP;
|
||||||
|
if (SocLimit.ON.getCode().equals(emsStrategyTemp.getSdcLimit())) {
|
||||||
|
socDown = emsStrategyTemp.getSdcDown();
|
||||||
|
socUp = emsStrategyTemp.getSdcUp();
|
||||||
|
}
|
||||||
|
// 查询电池堆(BMSD) SOC
|
||||||
|
EmsBatteryStack emsBatteryStack = emsBatteryStackMapper.getSiteSumStackInfo(emsStrategyTemp.getSiteId());
|
||||||
|
if (emsBatteryStack == null || emsBatteryStack.getStackSoc() == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 充电阶段判断SOC上限值
|
||||||
|
if (ChargeStatus.CHARGING.getCode().equals(emsStrategyTemp.getChargeStatus()) && emsBatteryStack.getStackSoc().compareTo(socUp) >= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 放电阶段判断SOC下限值
|
||||||
|
if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus()) && emsBatteryStack.getStackSoc().compareTo(socDown) <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -60,4 +60,25 @@ public class CronUtils
|
|||||||
throw new IllegalArgumentException(e.getMessage());
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回当前时间到下一次执行时间间隔的毫秒
|
||||||
|
*/
|
||||||
|
public static long getNextExecutionIntervalMillis(String cronExpression)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CronExpression cron = new CronExpression(cronExpression);
|
||||||
|
Date now = new Date();
|
||||||
|
Date nextExecution = cron.getNextValidTimeAfter(now);
|
||||||
|
Date nextExecution2 = cron.getNextValidTimeAfter(nextExecution);
|
||||||
|
|
||||||
|
return nextExecution2.getTime() - nextExecution.getTime();
|
||||||
|
}
|
||||||
|
catch (ParseException e)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,10 @@
|
|||||||
<groupId>com.xzzn</groupId>
|
<groupId>com.xzzn</groupId>
|
||||||
<artifactId>ems-common</artifactId>
|
<artifactId>ems-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.jaxb</groupId>
|
||||||
|
<artifactId>jaxb-runtime</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
import com.xzzn.common.annotation.Excel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警点位匹配数据对象 ems_alarm_match_data
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-09-22
|
||||||
|
*/
|
||||||
|
public class EmsAlarmMatchData extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** $column.columnComment */
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 告警点位 */
|
||||||
|
@Excel(name = "告警点位")
|
||||||
|
private String point;
|
||||||
|
|
||||||
|
/** 告警值 */
|
||||||
|
@Excel(name = "告警值")
|
||||||
|
private Long alarmData;
|
||||||
|
|
||||||
|
/** 告警描述 */
|
||||||
|
@Excel(name = "告警描述")
|
||||||
|
private String alarmDescription;
|
||||||
|
|
||||||
|
/** 站点id */
|
||||||
|
@Excel(name = "站点id")
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
/** 设备类型 */
|
||||||
|
@Excel(name = "设备类型")
|
||||||
|
private String deviceCategory;
|
||||||
|
|
||||||
|
public void setId(Long id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPoint(String point)
|
||||||
|
{
|
||||||
|
this.point = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPoint()
|
||||||
|
{
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlarmData(Long alarmData)
|
||||||
|
{
|
||||||
|
this.alarmData = alarmData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAlarmData()
|
||||||
|
{
|
||||||
|
return alarmData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlarmDescription(String alarmDescription)
|
||||||
|
{
|
||||||
|
this.alarmDescription = alarmDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlarmDescription()
|
||||||
|
{
|
||||||
|
return alarmDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId)
|
||||||
|
{
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSiteId()
|
||||||
|
{
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceCategory(String deviceCategory)
|
||||||
|
{
|
||||||
|
this.deviceCategory = deviceCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceCategory()
|
||||||
|
{
|
||||||
|
return deviceCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
.append("id", getId())
|
||||||
|
.append("point", getPoint())
|
||||||
|
.append("alarmData", getAlarmData())
|
||||||
|
.append("alarmDescription", getAlarmDescription())
|
||||||
|
.append("siteId", getSiteId())
|
||||||
|
.append("deviceCategory", getDeviceCategory())
|
||||||
|
.append("createBy", getCreateBy())
|
||||||
|
.append("createTime", getCreateTime())
|
||||||
|
.append("updateBy", getUpdateBy())
|
||||||
|
.append("updateTime", getUpdateTime())
|
||||||
|
.append("remark", getRemark())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@ import com.xzzn.common.annotation.Excel;
|
|||||||
* 告警记录对象 ems_alarm_records
|
* 告警记录对象 ems_alarm_records
|
||||||
*
|
*
|
||||||
* @author xzzn
|
* @author xzzn
|
||||||
* @date 2025-06-17
|
* @date 2025-06-29
|
||||||
*/
|
*/
|
||||||
public class EmsAlarmRecords extends BaseEntity
|
public class EmsAlarmRecords extends BaseEntity
|
||||||
{
|
{
|
||||||
@ -24,8 +24,8 @@ public class EmsAlarmRecords extends BaseEntity
|
|||||||
@Excel(name = "设备类型")
|
@Excel(name = "设备类型")
|
||||||
private String deviceType;
|
private String deviceType;
|
||||||
|
|
||||||
/** 告警等级 */
|
/** 告警等级:A-提示 B-一般 C-严重 D紧急 */
|
||||||
@Excel(name = "告警等级")
|
@Excel(name = "告警等级:A-提示 B-一般 C-严重 D紧急")
|
||||||
private String alarmLevel;
|
private String alarmLevel;
|
||||||
|
|
||||||
/** 告警内容 */
|
/** 告警内容 */
|
||||||
@ -42,21 +42,25 @@ public class EmsAlarmRecords extends BaseEntity
|
|||||||
@Excel(name = "告警结束时间", width = 30, dateFormat = "yyyy-MM-dd")
|
@Excel(name = "告警结束时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
private Date alarmEndTime;
|
private Date alarmEndTime;
|
||||||
|
|
||||||
/** 状态 */
|
/** 告警点位 */
|
||||||
@Excel(name = "状态")
|
@Excel(name = "告警点位")
|
||||||
|
private String alarmPoint;
|
||||||
|
|
||||||
|
/** 状态:0-待处理 1-已处理 2-处理中 */
|
||||||
|
@Excel(name = "状态:0-待处理 1-已处理 2-处理中")
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
/** 站点id */
|
/** 站点id */
|
||||||
@Excel(name = "站点id")
|
@Excel(name = "站点id")
|
||||||
private Long siteId;
|
private String siteId;
|
||||||
|
|
||||||
/** 设备唯一标识符 */
|
/** 设备唯一标识符 */
|
||||||
@Excel(name = "设备唯一标识符")
|
@Excel(name = "设备唯一标识符")
|
||||||
private Long deviceId;
|
private String deviceId;
|
||||||
|
|
||||||
/** 设备名称,用于标识设备 */
|
/** 工单号(规则:T+日期+6位随机) */
|
||||||
@Excel(name = "设备名称,用于标识设备")
|
@Excel(name = "工单号", readConverterExp = "规=则:T+日期+6位随机")
|
||||||
private String deviceName;
|
private String ticketNo;
|
||||||
|
|
||||||
public void setId(Long id)
|
public void setId(Long id)
|
||||||
{
|
{
|
||||||
@ -118,6 +122,16 @@ public class EmsAlarmRecords extends BaseEntity
|
|||||||
return alarmEndTime;
|
return alarmEndTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAlarmPoint(String alarmPoint)
|
||||||
|
{
|
||||||
|
this.alarmPoint = alarmPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlarmPoint()
|
||||||
|
{
|
||||||
|
return alarmPoint;
|
||||||
|
}
|
||||||
|
|
||||||
public void setStatus(String status)
|
public void setStatus(String status)
|
||||||
{
|
{
|
||||||
this.status = status;
|
this.status = status;
|
||||||
@ -128,34 +142,34 @@ public class EmsAlarmRecords extends BaseEntity
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSiteId(Long siteId)
|
public void setSiteId(String siteId)
|
||||||
{
|
{
|
||||||
this.siteId = siteId;
|
this.siteId = siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getSiteId()
|
public String getSiteId()
|
||||||
{
|
{
|
||||||
return siteId;
|
return siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeviceId(Long deviceId)
|
public void setDeviceId(String deviceId)
|
||||||
{
|
{
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getDeviceId()
|
public String getDeviceId()
|
||||||
{
|
{
|
||||||
return deviceId;
|
return deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeviceName(String deviceName)
|
public void setTicketNo(String ticketNo)
|
||||||
{
|
{
|
||||||
this.deviceName = deviceName;
|
this.ticketNo = ticketNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDeviceName()
|
public String getTicketNo()
|
||||||
{
|
{
|
||||||
return deviceName;
|
return ticketNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -167,6 +181,7 @@ public class EmsAlarmRecords extends BaseEntity
|
|||||||
.append("alarmContent", getAlarmContent())
|
.append("alarmContent", getAlarmContent())
|
||||||
.append("alarmStartTime", getAlarmStartTime())
|
.append("alarmStartTime", getAlarmStartTime())
|
||||||
.append("alarmEndTime", getAlarmEndTime())
|
.append("alarmEndTime", getAlarmEndTime())
|
||||||
|
.append("alarmPoint", getAlarmPoint())
|
||||||
.append("status", getStatus())
|
.append("status", getStatus())
|
||||||
.append("createBy", getCreateBy())
|
.append("createBy", getCreateBy())
|
||||||
.append("createTime", getCreateTime())
|
.append("createTime", getCreateTime())
|
||||||
@ -175,7 +190,7 @@ public class EmsAlarmRecords extends BaseEntity
|
|||||||
.append("remark", getRemark())
|
.append("remark", getRemark())
|
||||||
.append("siteId", getSiteId())
|
.append("siteId", getSiteId())
|
||||||
.append("deviceId", getDeviceId())
|
.append("deviceId", getDeviceId())
|
||||||
.append("deviceName", getDeviceName())
|
.append("ticketNo", getTicketNo())
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
2416
ems-system/src/main/java/com/xzzn/ems/domain/EmsAmmeterData.java
Normal file
2416
ems-system/src/main/java/com/xzzn/ems/domain/EmsAmmeterData.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,21 @@
|
|||||||
package com.xzzn.ems.domain;
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.xzzn.common.annotation.Excel;
|
||||||
import com.xzzn.common.core.domain.BaseEntity;
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import com.xzzn.common.annotation.Excel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 电池簇数据对象 ems_battery_cluster
|
* 电池簇数据对象 ems_battery_cluster
|
||||||
*
|
*
|
||||||
* @author xzzn
|
* @author xzzn
|
||||||
* @date 2025-06-22
|
* @date 2025-07-29
|
||||||
*/
|
*/
|
||||||
public class EmsBatteryCluster extends BaseEntity
|
public class EmsBatteryCluster extends BaseEntity
|
||||||
{
|
{
|
||||||
@ -20,16 +24,21 @@ public class EmsBatteryCluster extends BaseEntity
|
|||||||
/** */
|
/** */
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** 工作状态 */
|
/** 数据更新时间 */
|
||||||
@Excel(name = "工作状态")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@Excel(name = "数据更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date dataUpdateTime;
|
||||||
|
|
||||||
|
/** 工作状态:0-运行 1-停机 2-故障 */
|
||||||
|
@Excel(name = "工作状态:0-运行 1-停机 2-故障")
|
||||||
private String workStatus;
|
private String workStatus;
|
||||||
|
|
||||||
/** 与PCS通信状态 */
|
/** 与PCS通信状态:0-正常 1-通信中断 2-异常 */
|
||||||
@Excel(name = "与PCS通信状态")
|
@Excel(name = "与PCS通信状态:0-正常 1-通信中断 2-异常")
|
||||||
private String pcsCommunicationStatus;
|
private String pcsCommunicationStatus;
|
||||||
|
|
||||||
/** 与EMS通信状态 */
|
/** 与EMS通信状态:0-正常 1-通信中断 2-异常 */
|
||||||
@Excel(name = "与EMS通信状态")
|
@Excel(name = "与EMS通信状态:0-正常 1-通信中断 2-异常")
|
||||||
private String emsCommunicationStatus;
|
private String emsCommunicationStatus;
|
||||||
|
|
||||||
/** 簇电压 (V) */
|
/** 簇电压 (V) */
|
||||||
@ -74,11 +83,143 @@ public class EmsBatteryCluster extends BaseEntity
|
|||||||
|
|
||||||
/** 站点id */
|
/** 站点id */
|
||||||
@Excel(name = "站点id")
|
@Excel(name = "站点id")
|
||||||
private Long siteId;
|
private String siteId;
|
||||||
|
|
||||||
/** 设备唯一标识符 */
|
/** 设备唯一标识符 */
|
||||||
@Excel(name = "设备唯一标识符")
|
@Excel(name = "设备唯一标识符")
|
||||||
private Long deviceId;
|
private String deviceId;
|
||||||
|
|
||||||
|
/** 堆设备id */
|
||||||
|
@Excel(name = "堆设备id")
|
||||||
|
private String stackDeviceId;
|
||||||
|
|
||||||
|
/** 允许充电最大功率 */
|
||||||
|
@Excel(name = "允许充电最大功率")
|
||||||
|
private BigDecimal maxAllowedChargePower;
|
||||||
|
|
||||||
|
/** 允许放电最大功率 */
|
||||||
|
@Excel(name = "允许放电最大功率")
|
||||||
|
private BigDecimal maxAllowedDischargePower;
|
||||||
|
|
||||||
|
/** 允许充电最大电压 */
|
||||||
|
@Excel(name = "允许充电最大电压")
|
||||||
|
private BigDecimal maxAllowedChargeVoltage;
|
||||||
|
|
||||||
|
/** 允许放电最大电压 */
|
||||||
|
@Excel(name = "允许放电最大电压")
|
||||||
|
private BigDecimal maxAllowedDischargeVoltage;
|
||||||
|
|
||||||
|
/** 允许充电最大电流 */
|
||||||
|
@Excel(name = "允许充电最大电流")
|
||||||
|
private BigDecimal maxAllowedChargeCurrent;
|
||||||
|
|
||||||
|
/** 允许放电最大电流 */
|
||||||
|
@Excel(name = "允许放电最大电流")
|
||||||
|
private BigDecimal maxAllowedDischargeCurrent;
|
||||||
|
|
||||||
|
/** 组电压 */
|
||||||
|
@Excel(name = "组电压")
|
||||||
|
private BigDecimal batteryPackVoltage;
|
||||||
|
|
||||||
|
/** 组电流 */
|
||||||
|
@Excel(name = "组电流")
|
||||||
|
private BigDecimal batteryPackCurrent;
|
||||||
|
|
||||||
|
/** 模块温度 */
|
||||||
|
@Excel(name = "模块温度")
|
||||||
|
private BigDecimal batteryPackTemp;
|
||||||
|
|
||||||
|
/** 组SOC */
|
||||||
|
@Excel(name = "组SOC")
|
||||||
|
private BigDecimal batteryPackSoc;
|
||||||
|
|
||||||
|
/** 组SOH */
|
||||||
|
@Excel(name = "组SOH")
|
||||||
|
private BigDecimal batteryPackSoh;
|
||||||
|
|
||||||
|
/** 组绝缘电阻 */
|
||||||
|
@Excel(name = "组绝缘电阻")
|
||||||
|
private BigDecimal batteryPackInsulationResistance;
|
||||||
|
|
||||||
|
/** 平均单体电压 */
|
||||||
|
@Excel(name = "平均单体电压")
|
||||||
|
private BigDecimal avgCellVoltage;
|
||||||
|
|
||||||
|
/** 平均单体温度 */
|
||||||
|
@Excel(name = "平均单体温度")
|
||||||
|
private BigDecimal avgCellTemp;
|
||||||
|
|
||||||
|
/** 最高单体电压 */
|
||||||
|
@Excel(name = "最高单体电压")
|
||||||
|
private BigDecimal maxCellVoltage;
|
||||||
|
|
||||||
|
/** 最高单体电压对应点号 */
|
||||||
|
@Excel(name = "最高单体电压对应点号")
|
||||||
|
private String maxCellVoltageId;
|
||||||
|
|
||||||
|
/** 最低单体电压 */
|
||||||
|
@Excel(name = "最低单体电压")
|
||||||
|
private BigDecimal minCellVoltage;
|
||||||
|
|
||||||
|
/** 最低单体电压对应点号 */
|
||||||
|
@Excel(name = "最低单体电压对应点号")
|
||||||
|
private String minCellVoltageId;
|
||||||
|
|
||||||
|
/** 最高单体温度 */
|
||||||
|
@Excel(name = "最高单体温度")
|
||||||
|
private BigDecimal maxCellTemp;
|
||||||
|
|
||||||
|
/** 最高单体温度对应点号 */
|
||||||
|
@Excel(name = "最高单体温度对应点号")
|
||||||
|
private String maxCellTempId;
|
||||||
|
|
||||||
|
/** 最低单体温度 */
|
||||||
|
@Excel(name = "最低单体温度")
|
||||||
|
private BigDecimal minCellTemp;
|
||||||
|
|
||||||
|
/** 最低单体温度对应点号 */
|
||||||
|
@Excel(name = "最低单体温度对应点号")
|
||||||
|
private String minCellTempId;
|
||||||
|
|
||||||
|
/** 最高单体SOC */
|
||||||
|
@Excel(name = "最高单体SOC")
|
||||||
|
private BigDecimal maxCellSoc;
|
||||||
|
|
||||||
|
/** 最高单体SOC对应点号 */
|
||||||
|
@Excel(name = "最高单体SOC对应点号")
|
||||||
|
private String maxCellSocId;
|
||||||
|
|
||||||
|
/** 最低单体SOC */
|
||||||
|
@Excel(name = "最低单体SOC")
|
||||||
|
private BigDecimal minCellSoc;
|
||||||
|
|
||||||
|
/** 最低单体SOC对应点号 */
|
||||||
|
@Excel(name = "最低单体SOC对应点号")
|
||||||
|
private String minCellSocId;
|
||||||
|
|
||||||
|
/** 最高单体SOH */
|
||||||
|
@Excel(name = "最高单体SOH")
|
||||||
|
private BigDecimal maxCellSoh;
|
||||||
|
|
||||||
|
/** 最高单体SOH对应点号 */
|
||||||
|
@Excel(name = "最高单体SOH对应点号")
|
||||||
|
private String maxCellSohId;
|
||||||
|
|
||||||
|
/** 最低单体SOH */
|
||||||
|
@Excel(name = "最低单体SOH")
|
||||||
|
private BigDecimal minCellSoh;
|
||||||
|
|
||||||
|
/** 最低单体SOH对应点号 */
|
||||||
|
@Excel(name = "最低单体SOH对应点号")
|
||||||
|
private String minCellSohId;
|
||||||
|
|
||||||
|
/** 单次累计充电电量 */
|
||||||
|
@Excel(name = "单次累计充电电量")
|
||||||
|
private BigDecimal totalChargeEnergy;
|
||||||
|
|
||||||
|
/** 单次累计放电电量 */
|
||||||
|
@Excel(name = "单次累计放电电量")
|
||||||
|
private BigDecimal totalDischargeEnergy;
|
||||||
|
|
||||||
public void setId(Long id)
|
public void setId(Long id)
|
||||||
{
|
{
|
||||||
@ -90,6 +231,14 @@ public class EmsBatteryCluster extends BaseEntity
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Date getDataUpdateTime() {
|
||||||
|
return dataUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataUpdateTime(Date dataUpdateTime) {
|
||||||
|
this.dataUpdateTime = dataUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
public void setWorkStatus(String workStatus)
|
public void setWorkStatus(String workStatus)
|
||||||
{
|
{
|
||||||
this.workStatus = workStatus;
|
this.workStatus = workStatus;
|
||||||
@ -220,26 +369,356 @@ public class EmsBatteryCluster extends BaseEntity
|
|||||||
return currentSoc;
|
return currentSoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSiteId(Long siteId)
|
public void setSiteId(String siteId)
|
||||||
{
|
{
|
||||||
this.siteId = siteId;
|
this.siteId = siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getSiteId()
|
public String getSiteId()
|
||||||
{
|
{
|
||||||
return siteId;
|
return siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeviceId(Long deviceId)
|
public void setDeviceId(String deviceId)
|
||||||
{
|
{
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getDeviceId()
|
public String getDeviceId()
|
||||||
{
|
{
|
||||||
return deviceId;
|
return deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setStackDeviceId(String stackDeviceId)
|
||||||
|
{
|
||||||
|
this.stackDeviceId = stackDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStackDeviceId()
|
||||||
|
{
|
||||||
|
return stackDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAllowedChargePower(BigDecimal maxAllowedChargePower)
|
||||||
|
{
|
||||||
|
this.maxAllowedChargePower = maxAllowedChargePower;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxAllowedChargePower()
|
||||||
|
{
|
||||||
|
return maxAllowedChargePower;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAllowedDischargePower(BigDecimal maxAllowedDischargePower)
|
||||||
|
{
|
||||||
|
this.maxAllowedDischargePower = maxAllowedDischargePower;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxAllowedDischargePower()
|
||||||
|
{
|
||||||
|
return maxAllowedDischargePower;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAllowedChargeVoltage(BigDecimal maxAllowedChargeVoltage)
|
||||||
|
{
|
||||||
|
this.maxAllowedChargeVoltage = maxAllowedChargeVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxAllowedChargeVoltage()
|
||||||
|
{
|
||||||
|
return maxAllowedChargeVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAllowedDischargeVoltage(BigDecimal maxAllowedDischargeVoltage)
|
||||||
|
{
|
||||||
|
this.maxAllowedDischargeVoltage = maxAllowedDischargeVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxAllowedDischargeVoltage()
|
||||||
|
{
|
||||||
|
return maxAllowedDischargeVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAllowedChargeCurrent(BigDecimal maxAllowedChargeCurrent)
|
||||||
|
{
|
||||||
|
this.maxAllowedChargeCurrent = maxAllowedChargeCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxAllowedChargeCurrent()
|
||||||
|
{
|
||||||
|
return maxAllowedChargeCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAllowedDischargeCurrent(BigDecimal maxAllowedDischargeCurrent)
|
||||||
|
{
|
||||||
|
this.maxAllowedDischargeCurrent = maxAllowedDischargeCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxAllowedDischargeCurrent()
|
||||||
|
{
|
||||||
|
return maxAllowedDischargeCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryPackVoltage(BigDecimal batteryPackVoltage)
|
||||||
|
{
|
||||||
|
this.batteryPackVoltage = batteryPackVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getBatteryPackVoltage()
|
||||||
|
{
|
||||||
|
return batteryPackVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryPackCurrent(BigDecimal batteryPackCurrent)
|
||||||
|
{
|
||||||
|
this.batteryPackCurrent = batteryPackCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getBatteryPackCurrent()
|
||||||
|
{
|
||||||
|
return batteryPackCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryPackTemp(BigDecimal batteryPackTemp)
|
||||||
|
{
|
||||||
|
this.batteryPackTemp = batteryPackTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getBatteryPackTemp()
|
||||||
|
{
|
||||||
|
return batteryPackTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryPackSoc(BigDecimal batteryPackSoc)
|
||||||
|
{
|
||||||
|
this.batteryPackSoc = batteryPackSoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getBatteryPackSoc()
|
||||||
|
{
|
||||||
|
return batteryPackSoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryPackSoh(BigDecimal batteryPackSoh)
|
||||||
|
{
|
||||||
|
this.batteryPackSoh = batteryPackSoh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getBatteryPackSoh()
|
||||||
|
{
|
||||||
|
return batteryPackSoh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryPackInsulationResistance(BigDecimal batteryPackInsulationResistance)
|
||||||
|
{
|
||||||
|
this.batteryPackInsulationResistance = batteryPackInsulationResistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getBatteryPackInsulationResistance()
|
||||||
|
{
|
||||||
|
return batteryPackInsulationResistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvgCellVoltage(BigDecimal avgCellVoltage)
|
||||||
|
{
|
||||||
|
this.avgCellVoltage = avgCellVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAvgCellVoltage()
|
||||||
|
{
|
||||||
|
return avgCellVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvgCellTemp(BigDecimal avgCellTemp)
|
||||||
|
{
|
||||||
|
this.avgCellTemp = avgCellTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAvgCellTemp()
|
||||||
|
{
|
||||||
|
return avgCellTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCellVoltage(BigDecimal maxCellVoltage)
|
||||||
|
{
|
||||||
|
this.maxCellVoltage = maxCellVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxCellVoltage()
|
||||||
|
{
|
||||||
|
return maxCellVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCellVoltageId(String maxCellVoltageId)
|
||||||
|
{
|
||||||
|
this.maxCellVoltageId = StringUtils.fillThreeDigits(maxCellVoltageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMaxCellVoltageId()
|
||||||
|
{
|
||||||
|
return maxCellVoltageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCellVoltage(BigDecimal minCellVoltage)
|
||||||
|
{
|
||||||
|
this.minCellVoltage = minCellVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMinCellVoltage()
|
||||||
|
{
|
||||||
|
return minCellVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCellVoltageId(String minCellVoltageId)
|
||||||
|
{
|
||||||
|
this.minCellVoltageId = StringUtils.fillThreeDigits(minCellVoltageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMinCellVoltageId()
|
||||||
|
{
|
||||||
|
return minCellVoltageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCellTemp(BigDecimal maxCellTemp)
|
||||||
|
{
|
||||||
|
this.maxCellTemp = maxCellTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxCellTemp()
|
||||||
|
{
|
||||||
|
return maxCellTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCellTempId(String maxCellTempId)
|
||||||
|
{
|
||||||
|
this.maxCellTempId = StringUtils.fillThreeDigits(maxCellTempId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMaxCellTempId()
|
||||||
|
{
|
||||||
|
return maxCellTempId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCellTemp(BigDecimal minCellTemp)
|
||||||
|
{
|
||||||
|
this.minCellTemp = minCellTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMinCellTemp()
|
||||||
|
{
|
||||||
|
return minCellTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCellTempId(String minCellTempId)
|
||||||
|
{
|
||||||
|
this.minCellTempId = StringUtils.fillThreeDigits(minCellTempId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMinCellTempId()
|
||||||
|
{
|
||||||
|
return minCellTempId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCellSoc(BigDecimal maxCellSoc)
|
||||||
|
{
|
||||||
|
this.maxCellSoc = maxCellSoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxCellSoc()
|
||||||
|
{
|
||||||
|
return maxCellSoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCellSocId(String maxCellSocId)
|
||||||
|
{
|
||||||
|
this.maxCellSocId = StringUtils.fillThreeDigits(maxCellSocId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMaxCellSocId()
|
||||||
|
{
|
||||||
|
return maxCellSocId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCellSoc(BigDecimal minCellSoc)
|
||||||
|
{
|
||||||
|
this.minCellSoc = minCellSoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMinCellSoc()
|
||||||
|
{
|
||||||
|
return minCellSoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCellSocId(String minCellSocId)
|
||||||
|
{
|
||||||
|
this.minCellSocId = StringUtils.fillThreeDigits(minCellSocId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMinCellSocId()
|
||||||
|
{
|
||||||
|
return minCellSocId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCellSoh(BigDecimal maxCellSoh)
|
||||||
|
{
|
||||||
|
this.maxCellSoh = maxCellSoh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxCellSoh()
|
||||||
|
{
|
||||||
|
return maxCellSoh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCellSohId(String maxCellSohId)
|
||||||
|
{
|
||||||
|
this.maxCellSohId = StringUtils.fillThreeDigits(maxCellSohId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMaxCellSohId()
|
||||||
|
{
|
||||||
|
return maxCellSohId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCellSoh(BigDecimal minCellSoh)
|
||||||
|
{
|
||||||
|
this.minCellSoh = minCellSoh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMinCellSoh()
|
||||||
|
{
|
||||||
|
return minCellSoh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCellSohId(String minCellSohId)
|
||||||
|
{
|
||||||
|
this.minCellSohId = StringUtils.fillThreeDigits(minCellSohId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMinCellSohId()
|
||||||
|
{
|
||||||
|
return minCellSohId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalChargeEnergy(BigDecimal totalChargeEnergy)
|
||||||
|
{
|
||||||
|
this.totalChargeEnergy = totalChargeEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTotalChargeEnergy()
|
||||||
|
{
|
||||||
|
return totalChargeEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalDischargeEnergy(BigDecimal totalDischargeEnergy)
|
||||||
|
{
|
||||||
|
this.totalDischargeEnergy = totalDischargeEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTotalDischargeEnergy()
|
||||||
|
{
|
||||||
|
return totalDischargeEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
@ -264,6 +743,39 @@ public class EmsBatteryCluster extends BaseEntity
|
|||||||
.append("remark", getRemark())
|
.append("remark", getRemark())
|
||||||
.append("siteId", getSiteId())
|
.append("siteId", getSiteId())
|
||||||
.append("deviceId", getDeviceId())
|
.append("deviceId", getDeviceId())
|
||||||
|
.append("stackDeviceId", getStackDeviceId())
|
||||||
|
.append("maxAllowedChargePower", getMaxAllowedChargePower())
|
||||||
|
.append("maxAllowedDischargePower", getMaxAllowedDischargePower())
|
||||||
|
.append("maxAllowedChargeVoltage", getMaxAllowedChargeVoltage())
|
||||||
|
.append("maxAllowedDischargeVoltage", getMaxAllowedDischargeVoltage())
|
||||||
|
.append("maxAllowedChargeCurrent", getMaxAllowedChargeCurrent())
|
||||||
|
.append("maxAllowedDischargeCurrent", getMaxAllowedDischargeCurrent())
|
||||||
|
.append("batteryPackVoltage", getBatteryPackVoltage())
|
||||||
|
.append("batteryPackCurrent", getBatteryPackCurrent())
|
||||||
|
.append("batteryPackTemp", getBatteryPackTemp())
|
||||||
|
.append("batteryPackSoc", getBatteryPackSoc())
|
||||||
|
.append("batteryPackSoh", getBatteryPackSoh())
|
||||||
|
.append("batteryPackInsulationResistance", getBatteryPackInsulationResistance())
|
||||||
|
.append("avgCellVoltage", getAvgCellVoltage())
|
||||||
|
.append("avgCellTemp", getAvgCellTemp())
|
||||||
|
.append("maxCellVoltage", getMaxCellVoltage())
|
||||||
|
.append("maxCellVoltageId", getMaxCellVoltageId())
|
||||||
|
.append("minCellVoltage", getMinCellVoltage())
|
||||||
|
.append("minCellVoltageId", getMinCellVoltageId())
|
||||||
|
.append("maxCellTemp", getMaxCellTemp())
|
||||||
|
.append("maxCellTempId", getMaxCellTempId())
|
||||||
|
.append("minCellTemp", getMinCellTemp())
|
||||||
|
.append("minCellTempId", getMinCellTempId())
|
||||||
|
.append("maxCellSoc", getMaxCellSoc())
|
||||||
|
.append("maxCellSocId", getMaxCellSocId())
|
||||||
|
.append("minCellSoc", getMinCellSoc())
|
||||||
|
.append("minCellSocId", getMinCellSocId())
|
||||||
|
.append("maxCellSoh", getMaxCellSoh())
|
||||||
|
.append("maxCellSohId", getMaxCellSohId())
|
||||||
|
.append("minCellSoh", getMinCellSoh())
|
||||||
|
.append("minCellSohId", getMinCellSohId())
|
||||||
|
.append("totalChargeEnergy", getTotalChargeEnergy())
|
||||||
|
.append("totalDischargeEnergy", getTotalDischargeEnergy())
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,20 @@
|
|||||||
package com.xzzn.ems.domain;
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.xzzn.common.annotation.Excel;
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import com.xzzn.common.core.domain.BaseEntity;
|
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import com.xzzn.common.annotation.Excel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单体电池实时数据对象 ems_battery_data
|
* 单体电池实时数据对象 ems_battery_data
|
||||||
*
|
*
|
||||||
* @author xzzn
|
* @author xzzn
|
||||||
* @date 2025-06-25
|
* @date 2025-07-29
|
||||||
*/
|
*/
|
||||||
public class EmsBatteryData extends BaseEntity
|
public class EmsBatteryData extends BaseEntity
|
||||||
{
|
{
|
||||||
@ -56,15 +58,23 @@ public class EmsBatteryData extends BaseEntity
|
|||||||
|
|
||||||
/** 站点id */
|
/** 站点id */
|
||||||
@Excel(name = "站点id")
|
@Excel(name = "站点id")
|
||||||
private Long siteId;
|
private String siteId;
|
||||||
|
|
||||||
/** 设备唯一标识符 */
|
/** 设备唯一标识符 */
|
||||||
@Excel(name = "设备唯一标识符")
|
@Excel(name = "设备唯一标识符")
|
||||||
private Long deviceId;
|
private String deviceId;
|
||||||
|
|
||||||
/** 簇设备id */
|
/** 簇设备id */
|
||||||
@Excel(name = "簇设备id")
|
@Excel(name = "簇设备id")
|
||||||
private Long clusterDeviceId;
|
private String clusterDeviceId;
|
||||||
|
|
||||||
|
/** 单体电池内阻 */
|
||||||
|
@Excel(name = "单体电池内阻")
|
||||||
|
private BigDecimal interResistance;
|
||||||
|
|
||||||
|
/** 单体电池电流 */
|
||||||
|
@Excel(name = "单体电池电流")
|
||||||
|
private BigDecimal current;
|
||||||
|
|
||||||
public void setId(Long id)
|
public void setId(Long id)
|
||||||
{
|
{
|
||||||
@ -156,36 +166,54 @@ public class EmsBatteryData extends BaseEntity
|
|||||||
return dataTimestamp;
|
return dataTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSiteId(Long siteId)
|
public void setSiteId(String siteId)
|
||||||
{
|
{
|
||||||
this.siteId = siteId;
|
this.siteId = siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getSiteId()
|
public String getSiteId()
|
||||||
{
|
{
|
||||||
return siteId;
|
return siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeviceId(Long deviceId)
|
public void setDeviceId(String deviceId)
|
||||||
{
|
{
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getDeviceId()
|
public String getDeviceId()
|
||||||
{
|
{
|
||||||
return deviceId;
|
return deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClusterDeviceId(Long clusterDeviceId)
|
public void setClusterDeviceId(String clusterDeviceId)
|
||||||
{
|
{
|
||||||
this.clusterDeviceId = clusterDeviceId;
|
this.clusterDeviceId = clusterDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getClusterDeviceId()
|
public String getClusterDeviceId()
|
||||||
{
|
{
|
||||||
return clusterDeviceId;
|
return clusterDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInterResistance(BigDecimal interResistance)
|
||||||
|
{
|
||||||
|
this.interResistance = interResistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getInterResistance()
|
||||||
|
{
|
||||||
|
return interResistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getCurrent() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrent(BigDecimal current) {
|
||||||
|
this.current = current;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
@ -206,6 +234,8 @@ public class EmsBatteryData extends BaseEntity
|
|||||||
.append("siteId", getSiteId())
|
.append("siteId", getSiteId())
|
||||||
.append("deviceId", getDeviceId())
|
.append("deviceId", getDeviceId())
|
||||||
.append("clusterDeviceId", getClusterDeviceId())
|
.append("clusterDeviceId", getClusterDeviceId())
|
||||||
|
.append("interResistance", getInterResistance())
|
||||||
|
.append("current", getCurrent())
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,213 @@
|
|||||||
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
import com.xzzn.common.annotation.Excel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单体电池每日最新数据对象 ems_battery_data_daily_latest
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-07-17
|
||||||
|
*/
|
||||||
|
public class EmsBatteryDataDailyLatest extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 电池堆 */
|
||||||
|
@Excel(name = "电池堆")
|
||||||
|
private String batteryPack;
|
||||||
|
|
||||||
|
/** 电池簇 */
|
||||||
|
@Excel(name = "电池簇")
|
||||||
|
private String batteryCluster;
|
||||||
|
|
||||||
|
/** 单体编号 */
|
||||||
|
@Excel(name = "单体编号")
|
||||||
|
private String batteryCellId;
|
||||||
|
|
||||||
|
/** 电压 (V) */
|
||||||
|
@Excel(name = "电压 (V)")
|
||||||
|
private BigDecimal voltage;
|
||||||
|
|
||||||
|
/** 温度 (℃) */
|
||||||
|
@Excel(name = "温度 (℃)")
|
||||||
|
private BigDecimal temperature;
|
||||||
|
|
||||||
|
/** SOC (%) */
|
||||||
|
@Excel(name = "SOC (%)")
|
||||||
|
private BigDecimal soc;
|
||||||
|
|
||||||
|
/** SOH (%) */
|
||||||
|
@Excel(name = "SOH (%)")
|
||||||
|
private BigDecimal soh;
|
||||||
|
|
||||||
|
/** 日期:yyyy-MM-dd */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Excel(name = "日期:yyyy-MM-dd", width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
|
private Date dateDay;
|
||||||
|
|
||||||
|
/** 数据采集时间 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@Excel(name = "数据采集时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date dataTimestamp;
|
||||||
|
|
||||||
|
/** 站点id */
|
||||||
|
@Excel(name = "站点id")
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
/** 设备唯一标识符 */
|
||||||
|
@Excel(name = "设备唯一标识符")
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
/** 簇设备id */
|
||||||
|
@Excel(name = "簇设备id")
|
||||||
|
private String clusterDeviceId;
|
||||||
|
|
||||||
|
public void setBatteryPack(String batteryPack)
|
||||||
|
{
|
||||||
|
this.batteryPack = batteryPack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBatteryPack()
|
||||||
|
{
|
||||||
|
return batteryPack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryCluster(String batteryCluster)
|
||||||
|
{
|
||||||
|
this.batteryCluster = batteryCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBatteryCluster()
|
||||||
|
{
|
||||||
|
return batteryCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryCellId(String batteryCellId)
|
||||||
|
{
|
||||||
|
this.batteryCellId = batteryCellId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBatteryCellId()
|
||||||
|
{
|
||||||
|
return batteryCellId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVoltage(BigDecimal voltage)
|
||||||
|
{
|
||||||
|
this.voltage = voltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getVoltage()
|
||||||
|
{
|
||||||
|
return voltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemperature(BigDecimal temperature)
|
||||||
|
{
|
||||||
|
this.temperature = temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTemperature()
|
||||||
|
{
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoc(BigDecimal soc)
|
||||||
|
{
|
||||||
|
this.soc = soc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSoc()
|
||||||
|
{
|
||||||
|
return soc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoh(BigDecimal soh)
|
||||||
|
{
|
||||||
|
this.soh = soh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSoh()
|
||||||
|
{
|
||||||
|
return soh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateDay(Date dateDay)
|
||||||
|
{
|
||||||
|
this.dateDay = dateDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDateDay()
|
||||||
|
{
|
||||||
|
return dateDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataTimestamp(Date dataTimestamp)
|
||||||
|
{
|
||||||
|
this.dataTimestamp = dataTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDataTimestamp()
|
||||||
|
{
|
||||||
|
return dataTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId)
|
||||||
|
{
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSiteId()
|
||||||
|
{
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceId(String deviceId)
|
||||||
|
{
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId()
|
||||||
|
{
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClusterDeviceId(String clusterDeviceId)
|
||||||
|
{
|
||||||
|
this.clusterDeviceId = clusterDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClusterDeviceId()
|
||||||
|
{
|
||||||
|
return clusterDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
.append("batteryPack", getBatteryPack())
|
||||||
|
.append("batteryCluster", getBatteryCluster())
|
||||||
|
.append("batteryCellId", getBatteryCellId())
|
||||||
|
.append("voltage", getVoltage())
|
||||||
|
.append("temperature", getTemperature())
|
||||||
|
.append("soc", getSoc())
|
||||||
|
.append("soh", getSoh())
|
||||||
|
.append("dateDay", getDateDay())
|
||||||
|
.append("dataTimestamp", getDataTimestamp())
|
||||||
|
.append("createBy", getCreateBy())
|
||||||
|
.append("createTime", getCreateTime())
|
||||||
|
.append("updateBy", getUpdateBy())
|
||||||
|
.append("updateTime", getUpdateTime())
|
||||||
|
.append("remark", getRemark())
|
||||||
|
.append("siteId", getSiteId())
|
||||||
|
.append("deviceId", getDeviceId())
|
||||||
|
.append("clusterDeviceId", getClusterDeviceId())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,257 @@
|
|||||||
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.xzzn.common.annotation.Excel;
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单体电池天级数据对象 ems_battery_data_day
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2025-08-20
|
||||||
|
*/
|
||||||
|
public class EmsBatteryDataDay extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** $column.columnComment */
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 电池堆 */
|
||||||
|
@Excel(name = "电池堆")
|
||||||
|
private String batteryPack;
|
||||||
|
|
||||||
|
/** 电池簇 */
|
||||||
|
@Excel(name = "电池簇")
|
||||||
|
private String batteryCluster;
|
||||||
|
|
||||||
|
/** 单体编号 */
|
||||||
|
@Excel(name = "单体编号")
|
||||||
|
private String batteryCellId;
|
||||||
|
|
||||||
|
/** 电压 (V) */
|
||||||
|
@Excel(name = "电压 (V)")
|
||||||
|
private BigDecimal voltage;
|
||||||
|
|
||||||
|
/** 温度 (℃) */
|
||||||
|
@Excel(name = "温度 (℃)")
|
||||||
|
private BigDecimal temperature;
|
||||||
|
|
||||||
|
/** SOC (%) */
|
||||||
|
@Excel(name = "SOC (%)")
|
||||||
|
private BigDecimal soc;
|
||||||
|
|
||||||
|
/** SOH (%) */
|
||||||
|
@Excel(name = "SOH (%)")
|
||||||
|
private BigDecimal soh;
|
||||||
|
|
||||||
|
/** 数据采集时间 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Excel(name = "数据采集时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
|
private Date dataTimestamp;
|
||||||
|
|
||||||
|
/** 站点id */
|
||||||
|
@Excel(name = "站点id")
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
/** 设备唯一标识符 */
|
||||||
|
@Excel(name = "设备唯一标识符")
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
/** 簇设备id */
|
||||||
|
@Excel(name = "簇设备id")
|
||||||
|
private String clusterDeviceId;
|
||||||
|
|
||||||
|
/** 单体电池内阻 */
|
||||||
|
@Excel(name = "单体电池内阻")
|
||||||
|
private BigDecimal interResistance;
|
||||||
|
|
||||||
|
/** 天级时间维度 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Excel(name = "天级时间维度", width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
|
private Date dayTime;
|
||||||
|
|
||||||
|
/** 单体电池电流 */
|
||||||
|
@Excel(name = "单体电池电流")
|
||||||
|
private BigDecimal current;
|
||||||
|
|
||||||
|
public void setId(Long id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryPack(String batteryPack)
|
||||||
|
{
|
||||||
|
this.batteryPack = batteryPack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBatteryPack()
|
||||||
|
{
|
||||||
|
return batteryPack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryCluster(String batteryCluster)
|
||||||
|
{
|
||||||
|
this.batteryCluster = batteryCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBatteryCluster()
|
||||||
|
{
|
||||||
|
return batteryCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatteryCellId(String batteryCellId)
|
||||||
|
{
|
||||||
|
this.batteryCellId = batteryCellId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBatteryCellId()
|
||||||
|
{
|
||||||
|
return batteryCellId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVoltage(BigDecimal voltage)
|
||||||
|
{
|
||||||
|
this.voltage = voltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getVoltage()
|
||||||
|
{
|
||||||
|
return voltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemperature(BigDecimal temperature)
|
||||||
|
{
|
||||||
|
this.temperature = temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTemperature()
|
||||||
|
{
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoc(BigDecimal soc)
|
||||||
|
{
|
||||||
|
this.soc = soc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSoc()
|
||||||
|
{
|
||||||
|
return soc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoh(BigDecimal soh)
|
||||||
|
{
|
||||||
|
this.soh = soh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSoh()
|
||||||
|
{
|
||||||
|
return soh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataTimestamp(Date dataTimestamp)
|
||||||
|
{
|
||||||
|
this.dataTimestamp = dataTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDataTimestamp()
|
||||||
|
{
|
||||||
|
return dataTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId)
|
||||||
|
{
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSiteId()
|
||||||
|
{
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceId(String deviceId)
|
||||||
|
{
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId()
|
||||||
|
{
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClusterDeviceId(String clusterDeviceId)
|
||||||
|
{
|
||||||
|
this.clusterDeviceId = clusterDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClusterDeviceId()
|
||||||
|
{
|
||||||
|
return clusterDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInterResistance(BigDecimal interResistance)
|
||||||
|
{
|
||||||
|
this.interResistance = interResistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getInterResistance()
|
||||||
|
{
|
||||||
|
return interResistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDayTime(Date dayTime)
|
||||||
|
{
|
||||||
|
this.dayTime = dayTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDayTime()
|
||||||
|
{
|
||||||
|
return dayTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getCurrent() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrent(BigDecimal current) {
|
||||||
|
this.current = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
.append("id", getId())
|
||||||
|
.append("batteryPack", getBatteryPack())
|
||||||
|
.append("batteryCluster", getBatteryCluster())
|
||||||
|
.append("batteryCellId", getBatteryCellId())
|
||||||
|
.append("voltage", getVoltage())
|
||||||
|
.append("temperature", getTemperature())
|
||||||
|
.append("soc", getSoc())
|
||||||
|
.append("soh", getSoh())
|
||||||
|
.append("dataTimestamp", getDataTimestamp())
|
||||||
|
.append("createBy", getCreateBy())
|
||||||
|
.append("createTime", getCreateTime())
|
||||||
|
.append("updateBy", getUpdateBy())
|
||||||
|
.append("updateTime", getUpdateTime())
|
||||||
|
.append("remark", getRemark())
|
||||||
|
.append("siteId", getSiteId())
|
||||||
|
.append("deviceId", getDeviceId())
|
||||||
|
.append("clusterDeviceId", getClusterDeviceId())
|
||||||
|
.append("interResistance", getInterResistance())
|
||||||
|
.append("dayTime", getDayTime())
|
||||||
|
.append("current", getCurrent())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user