1、基于drools规则引擎实现的动态创建规则语法生成结果如下:
package com.drools.rule.req
import com.drools.rule.req.LoginActionReq
rule login_rule_1
when
$s:LoginActionReq(loginNum==1)
then
$s.amount=10;
update($s);
end
代码实现:
public class RuleReq {
//LOGIN、登陆,PAY、支付
private String actionType;
//LOGIN_NUM、登陆了次数,LOGON_TIME、登陆时间
//PAY_NUM、支付次数,PAY_TYPE、支付类型
private String subActionType;
//次数
private Integer num;
//开始时间
private Date beginTime;
//结束时间
private Date endTime;
//金额
private Integer amount;
public String getActionType() {
return actionType;
}
public void setActionType(String actionType) {
this.actionType = actionType;
}
public String getSubActionType() {
return subActionType;
}
public void setSubActionType(String subActionType) {
this.subActionType = subActionType;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public Date getBeginTime() {
return beginTime;
}
public void setBeginTime(Date beginTime) {
this.beginTime = beginTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
}
public class LoginActionReq extends ActionReq{
//LOGIN_NUM、登陆了次数,LOGON_TIME、登陆时间
private String loginActionType;
//登陆次数
private Integer loginNum;
//登陆时间
private Date loginTime;
//增加积分金额
public Integer amount;
public boolean flag;
public String getLoginActionType() {
return loginActionType;
}
public void setLoginActionType(String loginActionType) {
this.loginActionType = loginActionType;
}
public Integer getLoginNum() {
return loginNum;
}
public void setLoginNum(Integer loginNum) {
this.loginNum = loginNum;
}
public Date getLoginTime() {
return loginTime;
}
public void setLoginTime(Date loginTime) {
this.loginTime = loginTime;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
public interface BaseRuleBuild<T extends RuleReq>{
DrlContext.Builder BUILDER = new DrlContext.Builder();
default DrlContext getDrlContext(T ruleReq){
setPackage();
setImport();
setRuleId(ruleReq);
setExpireDate(ruleReq);
setSalience(ruleReq);
setActivationGroup(ruleReq);
setWhenAndThen(ruleReq);
return BUILDER.build();
}
default void setPackage(){
BUILDER.setDrlPackage("package com.drools.rule.req \n");
}
void setImport();
void setRuleId(T ruleReq);
default void setExpireDate(T ruleReq){
BUILDER.setDataExpires(
new StringBuilder()
.append(DATE_EFFECTIVE)
.append(BLANK)
.append("\"")
.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(ruleReq.getBeginTime()))
.append("\"")
.append(WRAP)
.append(DATE_EXPIRES)
.append(BLANK)
.append("\"")
.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(ruleReq.getEndTime()))
.append("\"")
.append(WRAP).toString());
}
void setSalience(T ruleReq);
void setActivationGroup(RuleReq ruleReq);
void setWhenAndThen(RuleReq ruleReq);
}
@Service
public class LoginRuleBuild implements BaseRuleBuild<RuleReq> , InitializingBean{
@Override
public void setImport() {
BUILDER.setDrlImport("import com.drools.rule.req.LoginActionReq \n");
//BUILDER.setDrlImport("global java.util.ArrayList result \n");
}
@Override
public void setRuleId(RuleReq ruleReq) {
BUILDER.setDrlRuleId(new StringBuilder().append(RULE).append(BLANK).append("login_rule_id").append(WRAP).toString());
}
@Override
public void setSalience(RuleReq ruleReq) {
BUILDER.setSalience(
new StringBuilder()
.append(SALIENCE)
.append(BLANK)
.append(100)
.append(BLANK)
.append(WRAP).toString());
}
@Override
public void setActivationGroup(RuleReq ruleReq) {
BUILDER.setActivationGroup(
new StringBuilder()
.append(ACTIVATION_GROUP)
.append(BLANK)
.append("\"")
.append("LOGIN-GROUP-001")
.append("\"")
.append(BLANK)
.append(WRAP).toString());
}
@Override
public void setWhenAndThen(RuleReq ruleReq) {
StringBuilder stringBuilder = new StringBuilder();
switch (UserLoginActionEnum.get(ruleReq.getSubActionType())){
case LOGIN_NUM:
stringBuilder = getLoginNumWhenAndThen(ruleReq);
break;
case LOGIN_TIME:
//stringBuilder = getLoginTimeThen(ruleReq);
break;
default:
break;
}
BUILDER.setDrlWhenAndThen(stringBuilder.toString());
}
private StringBuilder getLoginNumWhenAndThen(RuleReq ruleReq) {
//这里提出另一种思路,如果when then条件比较复杂这样写必将导致这个方法膨胀的很厉害
//可以设计一个drl模板文件加载到程序里面每次新增规则的时候动态替换里面的内容就好
//什么时候有时间我再按这种思路实现一个
//或者哪位小伙伴想做可以微信 yaoyaowuyuanqi 联系我给你开放修改权限
return new StringBuilder().append(WHEN)
.append(WRAP)
.append(BLANK)
.append("$s:LoginActionReq(")
.append("loginNum").append("==").append(""+ruleReq.getNum()+"")
.append(")")
.append(BLANK)
.append(WRAP)
.append(THEN)
.append(WRAP)
.append(BLANK)
.append("$s.setAmount(" + ruleReq.getAmount() + ");")
//.append("result.add(\" hello world !\");")
.append(WRAP)
.append(BLANK)
.append("update($s);")
.append(WRAP)
.append(END);
}
@Override
public void afterPropertiesSet() throws Exception {
RuleBuildFactory.registerService(UserAction.UserActionEnum.LOGIN.name(), this);
}
}
public class RuleBuildFactory {
private static Map<String, BaseRuleBuild> buildService = new ConcurrentHashMap<>();
private static Map<String, List<String>> rulesMap = new ConcurrentHashMap<>();
public static void registerService(String actionType, BaseRuleBuild baseRuleBuild){
buildService.putIfAbsent(actionType, baseRuleBuild);
}
public static BaseRuleBuild getBuildService(String actionType){
return buildService.get(actionType);
}
public static void addRules(String subActionType, String ruleContext){
if(rulesMap.containsKey(subActionType)){
rulesMap.get(subActionType).add(ruleContext);
return;
}
List<String> ruleContextList = new ArrayList<String>();
ruleContextList.add(ruleContext);
rulesMap.putIfAbsent(subActionType, ruleContextList);
}
public static List<String> getRules(String subActionType){
return rulesMap.get(subActionType);
}
}
@RestController
@RequestMapping("/rule")
public class CreateDrlController {
@Resource
private RuleService ruleService;
@RequestMapping(value = "/create", method = RequestMethod.POST)
public Boolean create(@RequestBody RuleReq ruleReq){
return ruleService.create(ruleReq);
}
@RequestMapping(value = "/login/action/execute", method = RequestMethod.POST)
public Boolean execute(@RequestBody LoginActionReq actionReq){
return ruleService.execute(actionReq);
}
}
@Service
public class RuleServiceImpl implements RuleService {
@Resource
private RuleExecute ruleExecute;
@Override
public Boolean create(RuleReq ruleReq) {
BaseRuleBuild baseRuleBuild = RuleBuildFactory.getBuildService(ruleReq.getActionType());
DrlContext drlContext = baseRuleBuild.getDrlContext(ruleReq);
//在实际项目中 drlContext.toString() 个内容需要落库存储并做一些防重验证等逻辑
RuleBuildFactory.addRules(ruleReq.getSubActionType(), drlContext.toString());
System.out.println(drlContext.toString());
return true;
}
@Override
public Boolean execute(LoginActionReq loginActionReq) {
//这里需要去数据库查询出用户的登录次数,这里测试方便就用传过来的值
loginActionReq.setLoginNum(loginActionReq.getLoginNum());
List<String> rulesContext = RuleBuildFactory.getRules(loginActionReq.getLoginActionType());
ActionReq actionReq = ruleExecute.execute(rulesContext, loginActionReq);
System.out.println(JSONObject.toJSONString(actionReq));
return true;
}
}
最后使用postman body json 参数 {"actionType":"LOGIN","subActionType":"LOGIN_NUM","num":"1","amount":"10","beginTime":"2020-01-01 00:00:00","endTime":"2030-01-01 00:00:00"}
调用 /rule/create 即可得到如下结果:
package com.drools.rule.req
import com.drools.rule.req.LoginActionReq
rule login_rule_1
when
$s:LoginActionReq(loginNum==1)
then
$s.amount=10;
update($s);
end
调用 /rule/login/action/execute body json 参数 {"loginActionType":"LOGIN_NUM","loginNum":"1"} 即可看到执行结果
有问题可加微信
本案例已提交,有兴趣的可加微信获取
补充一句,加微信别老是您您您的,都是打工人,不必这么客气,我也才18啊哈哈
也请大家关注下博客谢谢