一、系统介绍
该系统包括两个模版,分别为规则配置是否正确校验以及规则过滤校验。
二、技术实现
1.RuleEngine
filter 方法判断规则是否满足,用的算法是逆波兰表示法。
validate方法会判断规则配置是否正确,用的算法是dfs。
public class RuleEngine{
/**
* 规则项配置
*/
@Autowired
private Map<String, RuleItem> ruleItemMap;
/**
* 规则命中校验
*/
public boolean filter(Rule rule, RuleContext context) {
String ruleExpression = rule.getExpression();
Stack<Character> opStack = new Stack<>();
Stack<Boolean> resStack = new Stack<>();
Set<Character> opChSet = Set.of('(', ')', '&', '|');
int i = 0;
// 处理右括号
while (i < ruleExpression.length()) {
char ch = ruleExpression.charAt(i);
switch (ch) {
case ')':
while (opStack.peek() != '(') {
Character opChar = opStack.peek();
if (opChar == '&') {
boolean right = resStack.pop();
boolean left = resStack.pop();
resStack.push(left && right);
} else if (opChar == '|') {
boolean right = resStack.pop();
boolean left = resStack.pop();
resStack.push(left || right);
}
opStack.pop();
}
break;
case '(':
case '&':
case '|':
opStack.push(ch);
i++;
break;
default: // 操作数 放入结果
int j = i;
while (j < ruleExpression.length() && !opChSet.contains(ruleExpression.charAt(j))) {
j++;
}
String rule = ruleExpression.substring(i, j);
resStack.push(ruleItemMap.get(rule).filter(ruleContext));
i = j;
}
}
// 处理结果
while (!opStack.isEmpty()) {
Character opChar = opStack.peek();
if (opChar == '&') {
boolean right = resStack.pop();
boolean left = resStack.pop();
resStack.push(left && right);
} else if (opChar == '|') {
boolean right = resStack.pop();
boolean left = resStack.pop();
resStack.push(left || right);
}
opStack.pop();
}
return resStack.pop();
}
default String rootRulePath();
/**
* 规则配置校验
*/
public PathError validate(Rule rule) {
PathError pathError = PathError.of(null, rule.getClass().getSimpleName());
for (Map.Entry<String, RuleItem> entry : rule.getRuleItems()) {
String ruleItemPath = entry.getKey();
RuleItem ruleItem = entry.getValue();
PathError ruleItemError = ruleItem.validate();
if (ruleItemError != null) {
return pathError.with(ruleItemError);
}
}
return null;
}
}
2.UserCenterRegistryActivityRule
UserCenterRegistryActivityRule是用户中心注册活动对应规则,对应rule expression为 userGroup & channelRule
class UserCenterRegistryActivityRule extends Rule{
@Overrider
public Map<String, RuleItem> getRuleItems(){
return Map.of("userGroup", new UserGroupItem(), "channelRule", new ChannelRuleItem());
}
@Override
public String getRuleExpression(){
return "userGroup&channelRule";
}
}
3.RuleItem
RuleItem 是规则项定义,UserGroupRuleItem 是具体的RuleItem,会判断用户组是否命中。
class UserGroupRuleItem extends RuleItem{
private List<String> groupsLimit;
/**
* 判断规则配置
*/
@Override
public PathError validate(){
PathError pathError = PathError.of(null, getClass().getSimpleClassName());
if (groupsLimit == null || groupsLimit.size() == 0){
return pathError.withPath("groupsLimit").withError("groupsLimit不能为空");
}
return null;
}
/**
* 判断规则命中
*/
public boolean check(RuleContext context){
UserService userService = SpringUtil.getBean(UserService.class);
// 判断用户是否符合用户组规则
List<String> userGroups = userService.getUserGroups(context.getUser().getUserId());
if (groupsLimit.stream().anyMatch(userGroups::contains)){
return true;
}
retrun false;
}
}