1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package com.dy.pipIrrRemote.monitor.common;
 
import com.alibaba.fastjson2.JSONObject;
import com.dy.common.mw.protocol.Command;
import com.dy.common.util.IDLongGenerator;
import com.dy.common.webUtil.BaseResponse;
import com.dy.common.webUtil.BaseResponseUtils;
import com.dy.pipIrrGlobal.command.ComResultWait;
import com.dy.pipIrrGlobal.pojoPr.PrController;
import com.dy.pipIrrGlobal.pojoRm.RmCommandHistory;
import com.dy.pipIrrRemote.common.dto.DtoBase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.validation.BindingResult;
import org.springframework.web.client.RestTemplate;
 
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
 
/**
 * @Author: liurunyu
 * @Date: 2025/5/9 14:53
 * @Description
 */
public abstract class ComCtrl {
 
    @Autowired
    protected Environment env ;
 
    @Autowired
    protected RestTemplate restTemplate ;
 
    @Value("${mw.waitMwRtnResultTimeout}")
    protected int waitMwRtnResultTimeout ;
 
    @Value("${mw.rtuCallbackUrl_rm}")
    protected String rtuResultSendWebUrl;
 
    @Value("${project.projectNo}")
    protected Integer projectNo;
 
    @Value("${project.controllerType}")
    protected String controllerType;
 
    //控制器对象
    protected PrController ctrlPo ;
    //异步等待器
    protected CompletableFuture<JSONObject> feature;
    //命令名称
    protected String comName ;
    //命令日志id
    protected Long comId ;
 
    /**
     * 发送命令前-1:验证
     * @param comSv
     * @param comCode
     * @param dto
     * @param bindingResult
     * @return
     */
    public BaseResponse<Object> pre1(ComSv comSv, String comCode, DtoBase dto, BindingResult bindingResult) {
        if (bindingResult != null && bindingResult.hasErrors()) {
            return BaseResponseUtils.buildError(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }
        String msg = this.checkDto(dto) ;
        if(msg != null){
            return BaseResponseUtils.buildError("服务端出错," + msg) ;
        }
        return  null ;
    }
 
    /**
     * 发送命令前-2:获得数据
     * @param comSv
     * @param comCode
     * @param dto
     * @param bindingResult
     * @return
     */
    public BaseResponse<Object> pre2(ComSv comSv, String comCode, DtoBase dto, BindingResult bindingResult) {
        //得到控制器对象
        ctrlPo = comSv.getRtu(dto.getIntakeId());
        if (ctrlPo == null) {
            return BaseResponseUtils.buildError("服务端出错,从数据库中未得到控制器数据") ;
        }
        //检查协议
        String msg = comSv.checkProtocol(ctrlPo) ;
        if(msg != null) {
            return BaseResponseUtils.buildError("服务端出错," + msg) ;
        }
        //得到功能码对应的命令名称
        comName = comSv.getCommandName(comCode, ctrlPo) ;
        if(comName == null) {
            return BaseResponseUtils.buildError("服务端出错,未得到功能码对应命令名称") ;
        }
        return  null ;
    }
    /**
     * 发送命令前-3:保存命令日志
     * @param comSv sv对象
     * @param intakeId 取水口ID
     * @param operator 当前用登录用户id(操作人)
     * @param comCode 功能码
     * @param param 命令参数
     * @return
     */
    public BaseResponse<Object> pre3(ComSv comSv, Long intakeId, Long operator, String comCode, CdParameter param) {
        comId = new IDLongGenerator().generate();
        //生成并保存命令日志
        RmCommandHistory po = comSv.saveComHistoryPo(comId,
                ctrlPo.getProtocol(),
                comCode, comName,
                intakeId,
                ctrlPo.getRtuAddr(),
                param,
                operator);
        if(po == null){
            return BaseResponseUtils.buildError("服务端出错,未能生成并保存命令日志") ;
        }
        return  null ;
    }
    /**
     * 发送命令前-4:准备Feature
     * @return
     */
    public void pre4() {
        feature = new CompletableFuture<>();
        ComResultWait.put(comId, feature);
    }
 
    /**
     * 发送命令
     * @param comSv
     * @param com
     * @return
     */
    public BaseResponse<Object> doSend(ComSv comSv, Command com){
        //得到通信中间件发送命令的web URL
        String rqUrl = comSv.get2MwRequestUrl(env, comSv.ContextComSend) ;
        //向通信中间件发送web请求
        BaseResponse res = comSv.sendPostRequest2Mw(restTemplate, rqUrl, com) ;
        //处理通信中间件对web请求的响应
        String msg = comSv.dealMwDealResponse(res) ;
        if(msg != null) {
            return BaseResponseUtils.buildError(msg) ;
        }else{
            return null ;
        }
    }
 
    /**
     * 发送命令后
     * @return
     */
    public BaseResponse<Object> after(String comCode) {
        try{
            //等待通信中间件通知控制器执行命令上行数据(命令结果)
            JSONObject resultData = feature.get(waitMwRtnResultTimeout, TimeUnit.SECONDS);
            return BaseResponseUtils.buildSuccess(this.createRtnMsg(comCode, resultData));
        }catch (Exception e){
            return BaseResponseUtils.buildFail("等待通信中间件通知命令结果超时");
        }
    }
 
    /**
     * 发送命令最后
     * @return
     */
    public void end(){
        try {
            //最后清除CompletableFuture缓存
            if(ComResultWait.contain(comId)){
                ComResultWait.remove(comId);
            }
        }catch (Exception ee){}
    }
 
    /**
     * 验证
     * @param dto
     * @return
     */
    protected abstract String checkDto(DtoBase dto) ;
 
 
    /**
     * 生成命令返回信息
     */
    protected abstract String createRtnMsg(String code, JSONObject resultData);
}