package com.dy.pipIrrGlobal.command; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.dy.common.mw.protocol.Command; import com.dy.common.mw.protocol.CommandType; import com.dy.common.mw.protocol.Data; import com.dy.common.mw.protocol.p206V1.CodeV1; import com.dy.common.webUtil.BaseResponse; import com.dy.common.webUtil.BaseResponseUtils; import com.dy.pipIrrGlobal.command.dto.Param; import com.dy.pipIrrGlobal.command.enums.LastOperateENUM; import com.dy.pipIrrGlobal.command.result.CommandResultCode; import com.dy.pipIrrGlobal.daoBa.BaSettingsMapper; import com.dy.pipIrrGlobal.daoPr.PrCommonIntakesMapper; import com.dy.pipIrrGlobal.daoPr.PrControllerMapper; import com.dy.pipIrrGlobal.daoRm.RmCommandHistoryMapper; import com.dy.pipIrrGlobal.daoSe.SeVirtualCardMapper; import com.dy.pipIrrGlobal.pojoPr.PrCommonIntakes; import com.dy.pipIrrGlobal.pojoPr.PrController; import com.dy.pipIrrGlobal.pojoRm.RmCommandHistory; import com.dy.pipIrrGlobal.pojoSe.SeVirtualCard; import jakarta.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * @author ZhuBaoMin * @date 2024-05-30 15:45 * @LastEditTime 2024-05-30 15:45 * @Description 命令支撑类 */ public class ComSupport { //@Value("${mw.comSendUrl}") protected String comSendUrl; //protected static String controllerType = null; //protected static Integer projectNo = null; @Value("${project.projectNo}") protected Integer projectNo; @Value("${project.controllerType}") protected String controllerType; protected String commandTypeOuter = CommandType.outerCommand; // 存储实例化的 CompletableFuture 对象 protected static Map features = new HashMap<>(); //protected static Boolean setuped = false; @Autowired private RestTemplate restTemplate; @Autowired private BaSettingsMapper baSettingsMapper; @Autowired private PrControllerMapper prControllerMapper; @Autowired private RmCommandHistoryMapper rmCommandHistoryMapper; @Autowired private SeVirtualCardMapper seVirtualCardMapper; @Autowired private PrCommonIntakesMapper prCommonIntakesMapper; public static ComSupport comSupport; public ComSupport() { } /** * 引入BaSettingsMapper */ @PostConstruct public void init() { comSupport = this; comSupport.baSettingsMapper = this.baSettingsMapper; comSupport.prControllerMapper = this.prControllerMapper; } /** * 获取系统配置参数 */ //public void setUp() { // controllerType = comSupport.baSettingsMapper.getItemValue("controllerType"); // projectNo = Integer.parseInt(comSupport.baSettingsMapper.getItemValue("projectNo")); // setuped = true; //} /** * 生成订单号 * * @return */ public String generateOrderNo() { DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyMMddHHmmss"); LocalDateTime dateTime = LocalDateTime.now(); Random random = new Random(); String CHARACTERS = "0123456789"; StringBuilder sb = new StringBuilder(4); for (int i = 0; i < 4; i++) { int index = random.nextInt(CHARACTERS.length()); sb.append(CHARACTERS.charAt(index)); } return dtf.format(dateTime) + sb.toString(); } /** * 根据取水口ID或阀控器地址获取阀控器对象 * * @param intakeId * @return */ public JSONObject getRtu(Long intakeId, String rtuAddr) { PrController prController = prControllerMapper.getRtu(intakeId, rtuAddr); if (prController == null) { return null; } JSONObject job_rtu = new JSONObject(); job_rtu.put("rtuAddr", prController.getRtuAddr()); job_rtu.put("protocol", prController.getProtocol()); job_rtu.put("intakeId", prController.getIntakeId()); job_rtu.put("orgTag", prController.getOrgTag()); return job_rtu; } /** * 创建命令日志对象 * * @param comId 主键 * @param commandCode 功能码 * @param rtuAddr 阀控器地址 * @param protocol 通讯协议名称 * @param param 参数数据 * @param operator 操作员 * @return */ protected RmCommandHistory getComHistory(Long comId, String commandCode, String commandName, Long intakeId, String rtuAddr, String protocol, Object param, Long operator) { RmCommandHistory rmCommandHistory = new RmCommandHistory(); rmCommandHistory.setComId(comId); rmCommandHistory.setCommandCode(commandCode); //rmCommandHistory.setCommandName(CodeV202404.getCodeName(commandCode)); rmCommandHistory.setCommandName(commandName); rmCommandHistory.setIntakeId(intakeId); rmCommandHistory.setRtuAddr(rtuAddr); rmCommandHistory.setProtocol(protocol); rmCommandHistory.setParam((JSONObject) JSON.toJSON(param)); rmCommandHistory.setSendTime(new Date()); rmCommandHistory.setOperator(operator); return rmCommandHistory; } /** * 构造命令对象 * * @param comId 命令ID * @param commandCode 功能码 * @param rtuAddr RTU地址 * @param param 参数数据 * @return 构造好的命令对象 */ protected Command command(Long comId, String commandCode, String rtuAddr, String protocol, String rtuResultSendWebUrl, Object param) { Command com = new Command(); com.id = String.valueOf(comId); com.code = commandCode; com.rtuAddr = rtuAddr; com.protocol = protocol; com.type = commandTypeOuter; com.rtuResultSendWebUrl = rtuResultSendWebUrl; if(param != null) { com.param = param; } return com; } /** * 处理回调内容 * * @param comId * @return */ protected BaseResponse dealWithCallBack(Long comId, Command com) { CompletableFuture feature = new CompletableFuture<>(); features.put(comId, feature); try { // 发送命令 JSONObject response_SendCom = (JSONObject) JSON.toJSON(sendCom2Mw(com)); if (response_SendCom == null || !response_SendCom.getString("code").equals("0001")) { // 请求失败,RTU未上线,清除feature features.remove(comId); JSONObject job_param = response_SendCom.getJSONObject("content").getJSONObject("param"); return BaseResponseUtils.buildErrorMsg(job_param.getString("message")); } JSONObject resultData = feature.get(180, TimeUnit.SECONDS); features.remove(comId); Long commandId = resultData.getLong("commandId"); if (commandId.equals(comId)) { return BaseResponseUtils.buildSuccess(resultData); } else { return BaseResponseUtils.buildSuccess(); } } catch (InterruptedException e) { e.printStackTrace(); return BaseResponseUtils.buildFail(CommandResultCode.GET_RESULT_ERROR.getMessage()); } catch (ExecutionException e) { e.printStackTrace(); return BaseResponseUtils.buildFail(CommandResultCode.GET_RESULT_ERROR.getMessage()); } catch (TimeoutException e) { return BaseResponseUtils.buildSuccess(CommandResultCode.GET_RESULT_IN_ONE_MINUTE.getMessage()); } } /** * 发送命令 * * @return */ protected BaseResponse sendCom2Mw(Command com) { String url = UriComponentsBuilder.fromUriString(comSendUrl) .build() .toUriString(); HttpHeaders headers = new HttpHeaders(); HttpEntity httpEntity = new HttpEntity<>(com, headers); ResponseEntity response = null; try { // 通过Post方式调用接口 response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, BaseResponse.class); } catch (Exception e) { e.printStackTrace(); } if(response == null) { return BaseResponseUtils.buildErrorMsg("中间件调用失败"); } return response.getBody(); } /** * 构造命令、发送命令并处理请求结果及执行结果 * * @param po * @return */ protected BaseResponse dealWithCommandResult(Param po) { Long comId = po.getComId(); Byte comType = po.getComType(); String commandCode = po.getCommandCode(); String commandName = po.getCommandName(); Long intakeId = po.getIntakeId(); String rtuAddr = po.getRtuAddr(); String protocol = po.getProtocol(); Long vcId = po.getVcId(); Object param = po.getParam(); String rtuResultSendWebUrl = po.getRtuResultSendWebUrl(); Long operator = po.getOperator(); // 构造命令 Command com = command(comId, commandCode, rtuAddr, protocol, rtuResultSendWebUrl, param); // 创建命令日志对象并添加到数据库中 RmCommandHistory rmCommandHistory = getComHistory(comId, commandCode, commandName, intakeId, rtuAddr, protocol, param, operator); rmCommandHistoryMapper.insert(rmCommandHistory); comId = rmCommandHistory.getComId(); // 添加常用取水口或更新使用信息 addCommonIntake(operator, intakeId); /** * 处理回调 * feature准备就绪后发送命令 * 命令发送后立即阻塞等待回调 */ BaseResponse response_CallBack = dealWithCallBack(comId, com); // 回调异常 if (!response_CallBack.getCode().equals("0001")) { // 命令日志执行结果改为失败 rmCommandHistory = new RmCommandHistory(); rmCommandHistory.setComId(comId); rmCommandHistory.setResult((byte) 0); rmCommandHistoryMapper.updateByPrimaryKeySelective(rmCommandHistory); //return BaseResponseUtils.buildErrorMsg(response_CallBack.getContent().toString()); return BaseResponseUtils.buildErrorMsg(response_CallBack.getMsg()); } // 回调超时 if (response_CallBack.getContent().toString().equals(CommandResultCode.GET_RESULT_IN_ONE_MINUTE.getMessage())) { /** * 回调超时,暂时认为执行失败 * 命令置为失败 * 虚拟卡依旧保持使用中的状态 */ rmCommandHistory = new RmCommandHistory(); rmCommandHistory.setComId(comId); rmCommandHistory.setResult((byte) 0); rmCommandHistoryMapper.updateByPrimaryKeySelective(rmCommandHistory); return BaseResponseUtils.buildErrorMsg(CommandResultCode.GET_RESULT_IN_ONE_MINUTE.getMessage()); } /** * 如果是开关阀:更改虚拟卡状态:是否使用中、最后操作、最后操作时间 * 更新执行结果、返回结果时间、结果内容 * 返回回调内容 * ***************************** 虚拟卡使用状态不依赖开关阀意愿,依赖开关阀成功与否 */ //if (comType != null) { // SeVirtualCard virtualCard = new SeVirtualCard(); // virtualCard.setId(vcId); // if (comType == 1) { // virtualCard.setInUse((byte) 1); // } else { // virtualCard.setInUse((byte) 0); // } // virtualCard.setLastOperate(LastOperateENUM.OPEN_VALVE.getCode()); // virtualCard.setLastOperateTime(new Date()); // seVirtualCardMapper.updateByPrimaryKeySelective(virtualCard); //} // 如果是开发命令(92-平台开阀,91-小程序开阀),返回结果中添加阀控器地址、虚拟卡编号、订单号 //if(commandCode.equals("92") || commandCode.equals("97")) { if(commandCode.equals(CodeV1.cd_92) || commandCode.equals(CodeV1.cd_97) || commandCode.equals(CodeV1.cd_99) || commandCode.equals(CodeV1.cd_A0) || commandCode.equals(CodeV1.cd_A1) || commandCode.equals(CodeV1.cd_A2)) { JSONObject job_response = (JSONObject) JSON.toJSON(response_CallBack); JSONObject job_param = (JSONObject) JSON.toJSON(param); JSONObject job_data = job_response.getJSONObject("content").getJSONObject("data"); if(!job_data.getBoolean("success")) { // 开关阀失败,更新命令执行状态及虚拟卡状态 rmCommandHistory = new RmCommandHistory(); rmCommandHistory.setComId(comId); rmCommandHistory.setResult((byte) 0); rmCommandHistoryMapper.updateByPrimaryKeySelective(rmCommandHistory); // 开阀失败则解除占用,关阀失败则占用 if (comType != null) { SeVirtualCard virtualCard = new SeVirtualCard(); virtualCard.setId(vcId); if (comType == 1) { virtualCard.setInUse((byte) 0); virtualCard.setIntakeId(null); virtualCard.setOpenTime(null); } else { virtualCard.setInUse((byte) 1); virtualCard.setIntakeId(intakeId); } virtualCard.setLastOperate(LastOperateENUM.OPEN_VALVE.getCode()); virtualCard.setLastOperateTime(new Date()); seVirtualCardMapper.updateByPrimaryKeySelective(virtualCard); } response_CallBack.setCode("10003"); response_CallBack.setMsg(CommandResultCode.OPEN_CLOSE_FAIL.getMessage()); response_CallBack.setSuccess(false); }else { // 开关阀成功,更新命令执行状态及虚拟卡状态 rmCommandHistory = new RmCommandHistory(); rmCommandHistory.setComId(comId); rmCommandHistory.setResult((byte) 1); rmCommandHistoryMapper.updateByPrimaryKeySelective(rmCommandHistory); // 开阀成功则占用,关阀成功不占用 if (comType != null) { SeVirtualCard virtualCard = new SeVirtualCard(); virtualCard.setId(vcId); if (comType == 1) { virtualCard.setInUse((byte) 1); virtualCard.setIntakeId(intakeId); // 如果是计划开阀,从命令日志中获取计划时间,否则取当前时间 if(commandCode.equals(CodeV1.cd_A1) || commandCode.equals(CodeV1.cd_A2)) { // 计划开阀 Date openTime = null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { openTime = sdf.parse(rmCommandHistoryMapper.getTimeByCommId(comId)); }catch (ParseException e) { } virtualCard.setOpenTime(openTime); }else { // 非计划开阀 virtualCard.setOpenTime(new Date()); } } else { virtualCard.setInUse((byte) 0); virtualCard.setIntakeId(null); } virtualCard.setLastOperate(LastOperateENUM.OPEN_VALVE.getCode()); virtualCard.setLastOperateTime(new Date()); seVirtualCardMapper.updateByPrimaryKeySelective(virtualCard); } job_data.remove("success"); job_data.put("intakeId", intakeId); job_data.put("rtuAddr", rtuAddr); if(job_param != null) { job_data.put("vcNum", job_param.getString("icCardNo")); job_data.put("orderNo", job_param.getString("orderNo")); } response_CallBack = JSON.parseObject(job_response.toJSONString(), BaseResponse.class); } } // 回调返回的内容,回调结果写入命令日志表的任务由中间件完成 return response_CallBack; } /** * 添加常用取水口或更新使用信息 * @param intakeId * @return */ public Integer addCommonIntake(Long operatorId, Long intakeId) { PrCommonIntakes commonIntake = prCommonIntakesMapper.selectByOperatorAndIntake(operatorId, intakeId); if(commonIntake == null) { commonIntake = new PrCommonIntakes(); commonIntake.setOperatorId(operatorId); commonIntake.setIntakeId(intakeId); commonIntake.setLastUsedTime(new Date()); commonIntake.setUsageCount(1); return prCommonIntakesMapper.insert(commonIntake); } commonIntake.setLastUsedTime(new Date()); commonIntake.setUsageCount(commonIntake.getUsageCount() + 1); return prCommonIntakesMapper.updateByPrimaryKeySelective(commonIntake); } }