查控预警规则的链式调度

今日心得:

做别人不能做的事情,不敢做的事情,有难度的事情,本身就是一种自信,不管结果怎么样,不要怕,也不要觉得别人不会的我也不会,就是因为别人不会,我才有机会挑战不可能,才能体现我的价值.

需求场景

资金查控是一个应用工具软件,实现从执法办调取案件数据和卡号信息,在本系统内发起申请单,向公安部API发起查控申请,通过异步异地文件交互的方式获取结果.系统是给基层民警办案提供的协查工具,经过上级单位审批提交给公安部统一协调,由银行执行查控结果返回.

执法监督-查控预警模块设计,是民警基于线上系统长时间运行后,对业务运维上提出的新思考,在业务进行时,存在一些不合法的使用场景,于是民警提出了一个excel表格来记录业务违反规则的场景,希望我们系统能提供自动判断违规使用的查控申请,并将案件和账号及违规内容记录到预警内容,提供给省厅民警进行核查.这个规则列表是根据业务进行后会补充的,也会有调整的.甚至会启停.

问题清单 是否可通过现有资金查控平台监督 现有资金查控平台工作要求或无法通过平台监督原因 资金查控平台执法监督功能改造措施 执法监督设计逻辑 (粗体要求系统开发)
规则1 xxx xxxxx ccccc

思考

当时第一次接到这个需求的时候,我没有多想,就是在业务代码中增加拦截规则匹配,基本实现思路就是流水式代码.当我实现了其中几个规则之后,我发现代码越来越难维护,因为每个规则流程都要经历查询待办的案件数据,对案件中的几个关键指标根据规则的业务逻辑进行匹配,如果匹配上就增加案件的预警记录,然后标记该案件在在该规则上的执行任务状态,我要记录很多个执行状态,代码越来越难维护.

经过反复的思考业务场景的特点, 数据源是案件编号—>获取案件编号—>调用规则匹配—->标记规则完成.其他的规则控制逻辑相同,规则逻辑不同.而且这些规则都需要匹配完成, 这就是一个典型的责任链模式, 责任处理器就是规则处理,这个处理器抽象有两个方法,一个是处理匹配规则,一个是设置下一个处理器.然后我从定时调度任务开启一个任务线程获取待处理的案件列表,经过规则处理器之后,将结果写入到案件列表状态.

设计代码如下:

1
2
3
4
5
6
7
8
IHandler.java //链式规则处理接口
RequestHandler.java//链式规则处理抽象类
ChainFactoryBuilder.java//组链,初始化链路bean,执行链式调用
FlwsValidateHandler.java//业务规则实例
Request.java //请求对象 包含案件对象
RequestType.java //规则枚举
IScheduleExecutor.java //任务接口 获取数据/执行任务/结束任务
ScheduleExecutorTask.java //任务接口实现
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/**

\* ClassName: ChainFactoryBuilder

\* Description:组链,初始化链路bean,执行链式调用

*

\* @author shengfq

\* @date: 2023/3/11 11:08 上午

*/

@Service

public class ChainFactoryBuilder {

private IHandler chain;

@Autowired

FlwsValidateHandler flwsValidateHandler;

@Autowired

public ChainFactoryBuilder(){

​ buildChain();

}

/**

\* TODO 构建责任链处理器链路

\* 如果有新的规则添加,则设置

\* handler.setNext(next);

\* 目前只有FlwsValidateHandler

\* */

@PostConstruct

private void buildChain() {

​ IHandler head=flwsValidateHandler;

//TODO 构建责任链处理器链路,新增的责任处理器要在此处上链

// head.setNext(iHandler);

​ chain=head;

}

/**

\* 压栈处理

\* */

public void makeRequest(List<Request> requests) {

if(CollectionUtil.isNotEmpty(requests)){

​ requests.stream().forEach(item->{

​ chain.handleRequest(item);

​ });

​ }

}



}



public interface IHandler {

/**

\* 处理请求

\* */

void handleRequest(Request req);

/**

\* 设置下一个处理器

\* */

void setNext(IHandler next);

}



/**

\* 责任链处理器抽象类

\* 定义公共执行方法的实现

\* @author sheng

\* @date 2023-03-11

\* */

public abstract class RequestHandler implements IHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
private IHandler next;
@Override

public void setNext(IHandler next) {

this.next = next;

}


/**

\* Request handler

*/

@Override

public void handleRequest(Request req) {

if (next != null && !req.isHandled()) {

next.handleRequest(req);

}

}



protected void printHandling(Request req) {

LOGGER.info("{} 处理规则 \"{}\"", this, req);

}

@Override

public abstract String toString();

}

/**

*请求对象 包含案件对象

*/

@Data

public class Request {



private final RequestType requestType;



private final YjAjxxtjInfo yjAjxxtjInfo;



private boolean handled;



public Request(final RequestType requestType, final YjAjxxtjInfo yjAjxxtjInfo) {

this.requestType = Objects.requireNonNull(requestType);

this.yjAjxxtjInfo = Objects.requireNonNull(yjAjxxtjInfo);

}



public RequestType getRequestType() {

return requestType;

}



public void markHandled() {

this.handled = true;

}



public boolean isHandled() {

return this.handled;

}





@Override

public String toString() {

return requestType.getDesc();

}

}





/**

*枚举规则匹配

\* @author shengfq

\* @date 2023-03-09

*/

@Getter

public enum RequestType {

WLADJZH,

WCXYEDJZH,

DJFFZSAZH,

DJJECGSAJE,

CFDJZH,

CADJ,

WABFSSXZ,

WYFJSJDZH,

CXWGZH,

FLWSNRQS;

}



/**

\* 定时任务执行器接口

\* */

public interface IScheduleExecutor {

/**

\* 获取待查的案件信息

\* */

List<Request> begin(YjAjxxtjInfo ajxxtjInfo);

/**

\* 责任链处理规则

\* */

void handler(List<Request> requests);

/**

\* 将结果更新到统计记录表

\* yj_ajxxtj_info

\* */

int end(YjAjxxtjInfo request);

}



/**

\* 定时任务类

\* */

@Slf4j

@Service

public class ScheduleExecutorTask implements IScheduleExecutor {

@Autowired

YjAjxxtjInfoService yjAjxxtjInfoService;

@Autowired

ChainFactoryBuilder chainFactoryBuilder;

/**

*TODO 给目标案件添加预警规则匹配

*/

@Override

public List<Request> begin(YjAjxxtjInfo ajxxtjInfo) {

​ log.info("获取待处理的案件信息 ajxxtjInfo{} ",ajxxtjInfo);

​ List<Request> requests=new ArrayList<>();

//法律文书校验规则处理

​ Request request=new Request(RequestType.FLWSNRQS,ajxxtjInfo);

//TODO 有后续规则通过 新增 Request对象规则加入规则队列

​ requests.add(request);

return requests;

}

/**

\* 责任链处理规则

\* */

@Override

public void handler(List<Request> requests){

​ log.info("开始执行规则匹配");

​ chainFactoryBuilder.makeRequest(requests);

}



/**

\* 将结果更新到统计记录表

\* yj_ajxxtj_info

*/

@Override

public int end(YjAjxxtjInfo ajxxtjInfo) {

​ log.info("完成预警规则匹配");

int result=0;

if(ajxxtjInfo!=null){

​ YjAjxxtjInfo update=new YjAjxxtjInfo();

​ update.setAjbh(ajxxtjInfo.getAjbh());

​ update.setSfyj(QueryParamEnum.SFYJ_YES);

​ result=yjAjxxtjInfoService.updateByAjbh(update);

​ }

return result;

}

}



/**

*

\* FlwsValidateHandler

*法律文书内容校验处理器

*/

@Slf4j

@Service

public class FlwsValidateHandler extends RequestHandler{

@Autowired

ZjckFlwsService zjckFlwsService;

@Override

public void handleRequest(Request req) {

if(req.getRequestType()==RequestType.FLWSNRQS && !req.isHandled()){

//规则匹配后的处理

}

super.handleRequest(req);

}

}

实现心得

代码实现相对简单,但是将业务逻辑规则和控制任务代码进行了抽象隔离,符合OOP中的单一职责和开闭原则.控制线程还能很方便的放入到线程池中进行并发执行,提高了系统运行效率.也是将业务逻辑和控制逻辑解耦思想的体现.