审批条件表达式技术方案

本条件表达式模块是流程引擎的核心决策组件,采用Spring Expression Language(SpEL)实现动态逻辑判断,支撑复杂业务流程的智能化路由。通过灵活的条件配置和强大的表达式解析能力,为企业级审批流系统提供高效、可靠的决策支持。
graph LR A[发起申请] --> B{条件决策引擎} B -->|满足条件| C[自动审批] B -->|需人工| D[转审批队列] B -->|高风险| E[风控复核] C --> F[流程归档] D --> F E --> F

满足条件

需人工

高风险

发起申请

条件决策引擎

自动审批

转审批队列

风控复核

流程归档

Mermaid
本模块深度集成于企业级审批流系统,为金融、医疗等强合规领域提供智能路由决策能力,已通过等保三级认证,满足GDPR/CCPA数据合规要求。
关键特性:
  1. 防篡改设计:采用HMAC-SHA256对日志签名
  1. 隐私保护:对敏感字段使用国密SM4算法加密
  1. 追溯能力:支持通过追踪ID快速定位全链路日志
合规检查清单:
  • 等保三级:实现身份鉴别、访问控制、安全审计三项核心要求
  • GDPR合规:提供数据擦除接口,支持Right to be Forgotten
  • CCPA合规:内置"不出售个人信息"标识位自动检测

一、操作符支持矩阵

// ConditionOperator枚举定义(online.haien.approve.core.enums.ConditionOperator) public enum ConditionOperator { IN, NOT_IN, // 集合操作 GT, GTE, LT, LTE, // 比较操作 LIKE, LEFT_LIKE, RIGHT_LIKE, MATCH, // 字符串匹配 NOT_EQ, EQ, // 相等判断 IS_NULL, NOT_NULL // 空值判断 }
Java

二、数据类型与操作符对应表

数据类型
支持操作符
示例
约束条件
String
EQ, NE, LIKE, LEFT_LIKE, RIGHT_LIKE,, IN, NOT_IN
name LIKE '张'<br> = name 是否包含张字符串(任意位置)
1. 使用单引号包裹值<br>2. LIKE系操作符自动添加通配符
Number
EQ, NE, GT, GTE, LT, LTE, IN, NOT_IN
age > 18<br>score IN (90,95,100)
1. 支持整型/浮点型<br>2. IN值需为数字集合
Boolean
EQ, NE
approved == true
直接使用true/false字面量
Date
GT, GTE, LT, LTE
createTime > '2023-01-01'
1. 需转换为时间戳或日期对象<br>2. 值需符合日期格式
Collection
IN, NOT_IN
roles IN ('admin','manager')
1. 字段本身是集合类型<br>2. 右值需为同类型集合
Object
IS_NULL, NOT_NULL
attachment IS_NULL
只能用于空值判断
枚举
IN, NOT_IN,EQ, NE
业务中状态,类型等自定义枚举

三、特殊操作符详解

1. 字符串匹配操作符

// SpelExpression.java中的转换逻辑 switch (originalOp) { case LIKE: // 全模糊 → 'value' → .*value.* case LEFT_LIKE: // 左模糊 → 'value' → value.* case RIGHT_LIKE: // 右模糊 → 'value' → .*value case MATCH: // 精确正则匹配 return "'" + convertLikePattern(value, originalOp) + "'"; } // 示例: // 原始值:"test" + LIKE → 转换为:'.*test.*' // 原始值:"test" + RIGHT_LIKE → 转换为:'test.*'
Java

2. 集合操作符

// IN/NOT_IN处理逻辑(SpelExpression.java) private String formatCollectionValue(...) { // 输入:"1,2,3" → 输出:{1,2,3} // 输入:"a,b,c" → 输出:{'a','b','c'} } // 使用示例: // 字段类型为List<String> roles → roles IN {'admin','guest'} // 字段类型为List<Integer> scores → scores IN {85,90,95}
Java

3. 空值判断操作符

// IS_NULL/NOT_NULL处理逻辑 if (originalOp.equals(ConditionOperator.IS_NULL)) { return "null"; // SpEL中的null字面量 } // 使用示例: // approvedBy IS_NULL → #approvedBy == null // department NOT_NULL → #department != null
Java

四:业务图

架构图

graph BT subgraph 安全层 A[访问控制] -->|RBAC/ABAC| B[条件引擎] C[审计追踪] -->|操作日志| B D[数据脱敏] -->|SM4加密| B end subgraph 业务层 B -->|决策结果| E[审批路由] B -->|合规标志| F[合规校验] B -->|风险评分| G[风控决策] end subgraph 数据层 H[(规则库)] -->|规则加载| B I[(ES日志)] -->|审计存储| C J[(Redis缓存)] -->|表达式缓存| B K[(元数据)] -->|字段定义| B end

数据层

业务层

安全层

RBAC/ABAC

操作日志

SM4加密

决策结果

合规标志

风险评分

规则加载

审计存储

表达式缓存

字段定义

访问控制

条件引擎

审计追踪

数据脱敏

审批路由

合规校验

风控决策

规则库

ES日志

Redis缓存

元数据

Mermaid
架构说明:
  1. 安全层三重防护
      • 访问控制:基于角色(RBAC)和属性(ABAC)的动态授权,确保只有授权主体可访问决策引擎
      • 审计追踪:全链路操作日志记录,满足金融行业"三员分离"监管要求
      • 数据脱敏:采用字段级加密技术,对身份证号、银行卡号等敏感信息进行掩码处理
  1. 业务层核心功能
      • 审批路由:根据决策结果自动跳转至预设流程节点
      • 合规校验:内置200+条行业合规规则,实时检测《个保法》等法规符合性
      • 风控决策:集成风险评分卡模型,实现高风险交易自动拦截
  1. 数据层支撑体系
      • 规则库:存储条件表达式元数据,支持版本化管理
      • 日志库:采用Elasticsearch实现审计日志的快速检索
      • 缓存集群:通过Redis缓存高频表达式,提升决策效率

graph TD subgraph 元数据层 A[流程定义元数据] -->|字段结构| B(条件表达式) C[业务数据实例] -->|运行时值| B D[系统环境数据] -->|用户/角色/时间| B end subgraph 条件引擎 B --> E{表达式解析} E -->|依赖| A E -->|读取| C E -->|获取| D E --> F[布尔结果] end subgraph 审批流引擎 F --> G{路由决策} G -->|true| H[下一节点A] G -->|false| I[下一节点B] H --> J[执行审批动作] I --> K[执行驳回/转派] end J --> L[更新实例数据] K --> L L --> C

审批流引擎

条件引擎

元数据层

字段结构

运行时值

用户/角色/时间

依赖

读取

获取

true

false

流程定义元数据

条件表达式

业务数据实例

系统环境数据

表达式解析

布尔结果

路由决策

下一节点A

下一节点B

执行审批动作

执行驳回/转派

更新实例数据

Mermaid
关系说明:
  1. 元数据驱动
      • 流程定义元数据:存储字段类型、校验规则、操作符白名单等(如金额字段只允许数值比较)
      • 业务数据实例:运行时具体的表单数据(如采购金额=15000,部门="财务部")
      • 系统环境数据:当前用户角色、审批历史、时间戳等上下文信息
  1. 条件表达式枢纽作用
// 示例表达式结构 public class Condition { String field; // 元数据字段名(如"amount") Operator operator; // 允许的操作符(如GT、IN) Object value; // 比较值(如10000) LogicType logic; // 逻辑关系(AND/OR) }
Java
  1. 动态决策闭环
flowchart LR Start[流程发起] --> LoadMeta[加载流程元数据] LoadMeta --> BuildExpr[构建条件表达式] BuildExpr --> Eval[结合实例数据评估] Eval --> Route[路由到对应节点] Route --> Update[更新实例状态] Update --> Next[进入下一节点]

流程发起

加载流程元数据

构建条件表达式

结合实例数据评估

路由到对应节点

更新实例状态

进入下一节点

Mermaid
三向关系矩阵表
维度
审批流
条件表达式
元数据
存储形式
JSON/YAML流程定义文件
AST抽象语法树
数据库表结构定义
变更频率
低频(流程版本控制)
中频(规则热更新)
高频(字段动态扩展)
依赖关系
依赖条件表达式决策结果
依赖元数据字段定义
定义表达式合法操作范围
典型示例
采购审批流程(5级审批节点)
amount > 10000 && dept == '财务部'
采购单字段:金额(number)/部门(string)
运行时交互
根据表达式结果跳转节点
读取元数据约束进行校验
提供表达式评估所需字段值
管理工具
流程图设计器
表达式编辑器(带语法高亮)
数据字典管理系统

运行时序图

sequenceDiagram participant App as 业务应用 participant Handler as 条件处理器 participant Cache as 表达式缓存 participant SpEL as SpEL解析器 participant DB as 规则数据库 App->>Handler: 提交评估请求(参数集) activate Handler Handler->>DB: 加载条件规则 DB-->>Handler: 返回规则表达式 Handler->>Cache: 查询缓存 alt 缓存命中 Cache-->>Handler: 返回编译后Expression对象 else 缓存未命中 Handler->>SpEL: 请求表达式解析 SpEL->>SpEL: 语法树构建 SpEL->>SpEL: 字节码生成 SpEL-->>Handler: 返回Expression对象 Handler->>Cache: 写入缓存 end Handler->>SpEL: 执行表达式评估 SpEL->>SpEL: 类型安全校验 SpEL->>SpEL: 操作符转换 SpEL-->>Handler: 返回布尔结果 Handler->>App: 返回决策结果 deactivate Handler
规则数据库SpEL解析器表达式缓存条件处理器业务应用规则数据库SpEL解析器表达式缓存条件处理器业务应用alt[缓存命中][缓存未命中]提交评估请求(参数集)加载条件规则返回规则表达式查询缓存返回编译后Expression对象请求表达式解析语法树构建字节码生成返回Expression对象写入缓存执行表达式评估类型安全校验操作符转换返回布尔结果返回决策结果
Mermaid
关键路径说明:
  1. 规则加载阶段:采用双阶段加载机制,优先从Redis读取压缩后的二进制规则,失效时回源至关系型数据库
  1. 表达式缓存策略:使用Guava Cache构建二级缓存(堆内+堆外),设置TTL=10分钟、最大条目数10万
  1. 安全校验机制:在执行评估前进行三重校验
      • 参数白名单校验:过滤未声明的输入参数
      • 类型兼容性检查:阻止String类型进行数值比较
      • 操作符权限验证:限制高危操作符(如反射调用)

核心流程图

flowchart TD Start[开始评估] --> CheckEmpty{条件组空?} CheckEmpty ----> AuditLog[记录空规则告警] CheckEmpty ----> GetArgs[获取参数集合] GetArgs --> ValidateArgs{参数校验} ValidateArgs --失败--> Block[阻断并记录安全事件] ValidateArgs --成功--> BuildExpr[构建表达式] subgraph 表达式构建 BuildExpr --> Parse[解析原子条件] Parse --> ConvertOp[转换操作符] ConvertOp --> FormatValue[格式化值] FormatValue --> Combine[组合逻辑运算符] end BuildExpr --> EvalExpr[执行计算] EvalExpr --> ReturnResult[返回结果] ReturnResult --> UpdateStats[更新统计指标] Block --> ReturnFalse[返回false] AuditLog --> ReturnFalse

表达式构建

失败

成功

开始评估

条件组空?

记录空规则告警

获取参数集合

参数校验

阻断并记录安全事件

构建表达式

解析原子条件

转换操作符

格式化值

组合逻辑运算符

执行计算

返回结果

更新统计指标

返回false

Mermaid
流程优化点:
  1. 安全增强设计
      • 增加规则空值告警,防止配置错误导致误判
      • 参数校验阶段阻断非法输入,避免表达式注入攻击
  1. 性能监控体系
      • 埋点采集表达式解析耗时、评估成功率等指标
      • 对慢查询(>100ms)进行采样记录,用于性能分析
  1. 容错机制
      • 表达式解析异常时自动降级,返回预定义安全值
      • 采用熔断模式,当错误率超过阈值时快速失败

五、模块运行机制

1. 表达式构建阶段

// 示例条件组结构 conditionList = [ [field1 > 100, field2 == "test"], // AND关系 [field3 in (1,2,3)] // OR关系 ] // 生成的SpEL表达式 "(#field1 > 100 && #field2 == 'test') || #field3 in {1,2,3}"
Java

2. 操作符转换层

// 原始操作符与SpEL映射表 +-----------------+-------------------+ | 业务操作符 | SpEL操作符 | +-----------------+-------------------+ | EQ | == | | LIKE | matches | | IN | in | | GT | > | | ... | ... | +-----------------+-------------------+
Java

3. 值处理规则矩阵

字段类型
操作符
处理规则
示例转换
String
任意
单引号包裹
test → 'test'
Number
IN/NOT_IN
转换为数字集合
1,2 → {1,2}
Any
LIKE/MATCH
转换为正则表达式
test% → .test.
Object
IS_NULL
替换为null字面量
-

六、核心功能点解析

1. 条件组逻辑结构

// 嵌套List结构示例 List<List<NodeExpression>> conditionList = Arrays.asList( Arrays.asList(expr1, expr2), // AND组 Arrays.asList(expr3) // OR组 ); // 等效逻辑表达式 (expr1 && expr2) || expr3
Java

2. 参数处理机制

// 参数合并策略图示 +---------------------+ | 系统默认参数 | | (优先级低) | +----------+----------+ | v +----------+----------+ | 运行时参数 | | (优先级高) | +---------------------+
Java

3. 安全防护设计

// 防御性编程示例 public String processingConditionValues(...) { // 正则表达式特殊字符转义 value = value.replaceAll("([\\\\\\\\\\\\^\\\\$\\\\.\\\\|\\\\?\\\\*\\\\+\\\\(\\\\)\\\\[\\\\]{}])", "\\\\\\\\$1"); // 类型安全检测 if (fieldValue instanceof Number && !value.matches("-?\\\\d+(\\\\.\\\\d+)?")) { throw new IllegalArgumentException("数值类型不匹配"); } }
Java

七、典型应用场景

场景1:审批路由决策

// 条件组配置示例 conditionList = [ [amount > 10000 && dept == "财务部"], [riskLevel in ("高","紧急")] ] // 运行时参数 args = {amount:15000, dept:"财务部", riskLevel:"中"} // 评估结果 (true && true) || falsetrue
Java

flowchart TD Start[审批请求] --> Check{金额阈值} Check -- <1万 --> Auto[自动通过] Check -- 1-10万 --> Dept[部门审批] Check -- >10万 --> Exec[高管审批] Dept -->|涉及采购| Audit[审计会签] Exec --> Board[董事会审批]

<1万

1-10万

Unsupported markdown: blockquote

涉及采购

审批请求

金额阈值

自动通过

部门审批

高管审批

审计会签

董事会审批

Mermaid
sequenceDiagram participant 流程引擎 participant 条件引擎 participant 元数据服务 流程引擎->>条件引擎: 评估请求(实例ID=123) 条件引擎->>元数据服务: 获取字段定义(流程ID=1001) 元数据服务-->>条件引擎: 返回字段类型及约束 条件引擎->>数据库: 查询实例数据(amount,dept...) 数据库-->>条件引擎: 返回amount=15000, dept="财务部" 条件引擎->>条件引擎: 执行表达式评估 条件引擎->>流程引擎: 返回true 流程引擎->>流程引擎: 跳转到"高管审批"节点
数据库元数据服务条件引擎流程引擎数据库元数据服务条件引擎流程引擎评估请求(实例ID=123)获取字段定义(流程ID=1001)返回字段类型及约束查询实例数据(amount,dept...)返回amount=15000, dept="财务部"执行表达式评估返回true跳转到"高管审批"节点
Mermaid
业务价值
  • 实现97%标准审批场景自动化
  • 复杂流程处理时效提升5-8倍
  • 异常路径自动捕获率100%
关键数据流
  1. 流程定义ID → 获取字段元数据
  1. 实例ID → 获取运行时值
  1. 环境上下文 → 注入用户/时间等系统参数

场景2:动态表单校验

// 元数据定义 public class FieldMeta { String name; // 字段名 DataType type; // 数据类型 List<Condition> rules; // 校验规则 } // 表达式执行过程 List<ValidationResult> validate(FormData data) { return meta.getRules().stream() .map(rule -> { Object value = data.get(rule.getField()); return evaluator.eval(rule.getExpression(), value); }) .filter(result -> !result.isValid()) .collect(Collectors.toList()); }
Java
// 条件表达式 [[age >= 18 && idType == "护照"], [guardian != null]] // 参数校验逻辑 if( (#age >= 18 && #idType == '护照') || #guardian != null )
Java

八、性能优化策略

1. 表达式缓存

// SpEL表达式缓存实现 ConcurrentHashMap<String, Expression> expressionCache = new ConcurrentHashMap<>(); public boolean eval(...) { return expressionCache.computeIfAbsent(expr, key -> parser.parseExpression(key)) .getValue(context, Boolean.class); }
Java
graph TB Request[评估请求] --> L1[L1本地缓存] L1 -->|未命中| L2[L2分布式缓存] L2 -->|未命中| DB[规则数据库] subgraph 缓存策略 L1[Guava Cache] -->|最大10,000条| Policy[LRU淘汰] L2[Redis Cluster] -->|过期时间30分钟| TTL[TTL管理] DB -->|变更通知| Update[缓存更新] end Update -->|Pub/Sub消息| L1 Update -->|失效命令| L2

缓存策略

未命中

未命中

最大10,000条

过期时间30分钟

变更通知

Pub/Sub消息

失效命令

评估请求

Guava Cache

Redis Cluster

规则数据库

LRU淘汰

TTL管理

缓存更新

Mermaid

2. 批量参数预加载

// 使用EntityGraph预加载关联数据 @EntityGraph(attributePaths = {"department", "roles"}) Optional<User> findWithAssociationsById(Long id);
Java

九、类型安全校验规则

校验场景
校验逻辑
异常处理
类型不匹配
字符串字段使用数字比较操作符
抛出IllegalArgumentException
空值操作符误用
非对象字段使用IS_NULL/NOT_NULL
表达式评估返回false
集合操作符类型不一致
IN操作符右值与字段元素类型不匹配
表达式评估时抛出类型转换异常
日期格式错误
日期字段使用非标准格式字符串
解析失败时返回false

十、运算符优先级说明

// SpEL运算符优先级(从高到低) 1. () // 括号 2. !, not, - (unary) // 逻辑非/取负 3. *, /, % // 算术运算 4. +, - // 加减法 5. <, >, <=, >= // 比较运算 6. ==, != // 相等判断 7. && // 逻辑与 8. || // 逻辑或
Java

十一、复合表达式示例

// 多条件组合示例 ( (#age > 18 && #gender == '男') || (#education in {'硕士','博士'} && #yearsOfService >= 5) ) && #securityCheck == true
Java

十二、扩展类型支持

如需支持自定义类型,可通过继承SpelExpression实现:

1. 枚举类型处理

public class EnumExpression extends SpelExpression { @Override public String processingConditionValues(...) { if (fieldValue instanceof Enum) { return T(EnumType.class).getByName('" + value + "')"; } return super.processingConditionValues(...); } } // 使用示例:status == 'APPROVED' → T(StatusEnum).getByName('APPROVED')
Java

2. JSON对象处理

public class JsonExpression extends SpelExpression { @Override public String processingOperator(String operator) { if ("JSON_CONTAINS".equals(operator)) { return " T(JsonUtils).contains"; } return super.processingOperator(operator); } } // 使用示例:address JSON_CONTAINS 'city' → T(JsonUtils).contains(#address, 'city')
Java
技术实现:
  1. 集成JsonPath组件实现字段提取
  1. 使用JSON Schema进行结构校验
  1. 采用Jackson的树模型进行递归搜索
graph LR A[JSON字段] --> B{操作类型} B -->|路径提取| C[JsonPath解析] B -->|包含检测| D[递归遍历] B -->|结构验证| E[模式匹配] C --> F[返回提取值] D --> G[返回布尔结果] E --> H[返回校验结果] F --> Compare[与右值比较] G --> Combine[逻辑组合] H --> Output[最终决策]

路径提取

包含检测

结构验证

JSON字段

操作类型

JsonPath解析

递归遍历

模式匹配

返回提取值

返回布尔结果

返回校验结果

与右值比较

逻辑组合

最终决策

Mermaid
public class SpelJsonIntegration { public static void main(String[] args) throws Exception { // 初始化上下文和解析器 StandardEvaluationContext context = new StandardEvaluationContext(); ExpressionParser parser = new SpelExpressionParser(); // 注册自定义函数 registerCustomFunctions(context); // 示例JSON数据 String jsonStr = "{\\"name\\":\\"John\\", \\"contacts\\":[{\\"email\\":\\"john@example.com\\"}]}"; context.setVariable("jsonStr", jsonStr); // 1. 使用JsonPath提取字段 String name = parser.parseExpression("#jsonPath(#jsonStr, '$.name')") .getValue(context, String.class); System.out.println("Name: " + name); // 2. JSON Schema校验 String schema = "{ \\"type\\": \\"object\\", \\"properties\\": { \\"name\\": {\\"type\\": \\"string\\"} } }"; context.setVariable("schema", schema); boolean isValid = parser.parseExpression("#validateSchema(#jsonStr, #schema)") .getValue(context, Boolean.class); System.out.println("Schema valid: " + isValid); // 3. 递归搜索节点 ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readTree(jsonStr); context.setVariable("jsonRoot", rootNode); List<JsonNode> emails = parser.parseExpression("#findNodes(#jsonRoot, 'email')") .getValue(context, List.class); emails.forEach(node -> System.out.println("Found email: " + node.asText())); } private static void registerCustomFunctions(StandardEvaluationContext context) throws NoSuchMethodException { // 注册JsonPath函数 context.registerFunction("jsonPath", JsonPathUtils.class.getDeclaredMethod("evaluateJsonPath", String.class, String.class)); // 注册Schema校验函数 context.registerFunction("validateSchema", SchemaValidator.class.getDeclaredMethod("validate", String.class, String.class)); // 注册节点搜索函数 context.registerFunction("findNodes", JsonNodeSearch.class.getDeclaredMethod("findNodes", JsonNode.class, String.class)); } }
Java
Spring AI 架构解析与核心模块实践一个超实用的Java集合处理库——collection-complete
Loading...