前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、简单进阶

1.1、QlExpressContext

public class QlExpressContext extends HashMap<String, Object> implements IExpressContext<String, Object> {

  @Getter
  private ApplicationContext applicationContext;

  public QlExpressContext() {
  }

  public QlExpressContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
  }

  public QlExpressContext(Map<String, Object> aProperties, 
                          ApplicationContext applicationContext) {
    super(aProperties);
    this.applicationContext = applicationContext;
  }

  public Object get(String key) {
    Object result = super.get(key);
    if (result == null 
        && applicationContext != null 
        && applicationContext.containsBean(key)) {
     
      result = applicationContext.getBean(key);
    }
    return result;
  }

  /**
     * 把key-value放到容器里面去
     *
     * @param key
     * @param value
     */
  @Override
  public Object put(String key, Object value) {
    return super.put(key, value);
  }
}

1.2、QlExpressRunner

package com.healerjean.proj.qlexpress;

import com.google.common.collect.Sets;
import com.healerjean.proj.qlexpress.dto.UserDTO;
import com.healerjean.proj.qlexpress.operator.OperatorDeparmentBelong;
import com.healerjean.proj.qlexpress.operator.OperatorNotBlank;
import com.healerjean.proj.qlexpress.service.UserService;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.instruction.op.OperatorBase;
import com.ql.util.express.instruction.op.OperatorMinMax;

import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 语法分析和计算的入口类
 *
 * @author zhangyujin
 * @date 2022/6/20  20:51.
 */
public class QlExpressRunner extends ExpressRunner {

  /**
     * 类是否已经加载
     */
  private AtomicBoolean isRunning = new AtomicBoolean(false);
  /**
     * 函数名称集合
     */
  private Set<String> allFunctionNames = Sets.newHashSet();

  public QlExpressRunner() {
    super(true, false);
    init();
  }

  private void init() {
    // 保证之初始化一次
    if (!isRunning.compareAndSet(false, true)) {
      return;
    }

    try {
      initFunctions();
      initFunctionOfClassMethods();
      initOperatorWithAlias();
      initMacros();
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage(), e);
    }

  }
  /**
     * 初始化函数
     */
  private void initFunctions() {
    addFunction("是否不为空", new OperatorNotBlank());
    addFunction("最小", new OperatorMinMax("min"));
    addFunction("最大", new OperatorMinMax("max"));
    addFunction("部门归属", new OperatorDeparmentBelong("部门归属"));
  }

  @Override
  public void addFunction(String name, OperatorBase op) {
    super.addFunction(name, op);
    if (isRunning != null && isRunning.get()) {
      allFunctionNames.add(name);
    }
  }

  /**
     * 初始化类中已知存在的方法
     *
     * @throws Exception 异常抛出
     */
  private void initFunctionOfClassMethods() throws Exception {
    addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs", new String[]{"double"}, null);
    addFunctionOfClassMethod("registerCheck", UserService.class.getName(), "registerCheck", new String[]{UserDTO.class.getName(), "boolean"}, null);
  }

  /**
     * 替换关键字初始化
     *
     * @throws Exception 异常抛出
     */
  private void initOperatorWithAlias() throws Exception {
    addOperatorWithAlias("如果", "if", null);
    addOperatorWithAlias("则", "then", null);
    addOperatorWithAlias("否则", "else", null);
  }

  /**
     * 初始化 自定义宏
     */
  private void initMacros() throws Exception {
    addMacro("用户是否注册", "registerCheck(userInfo, login)");
  }



}

1.3、ExpressManager

package com.healerjean.proj.qlexpress;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author zhangyujin
 * @date 2022/6/21  17:16.
 */
@Slf4j
@Component
public class ExpressManager implements ApplicationContextAware{

    private ApplicationContext applicationContext;


    /**
     * Spring重载方法
     * @param applicationContext Spring上下文对象
     * @throws BeansException 抛出异常
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 执行规则引擎
     * @param express 表达式
     * @param aProperties 上下文对象
     * @return 返回对象
     * @throws Exception 抛出异常
     */
    public Object execute(String express, Map<String, Object> aProperties) throws Exception {
        QlExpressRunner runner = new QlExpressRunner();
        QlExpressContext context = new QlExpressContext(aProperties, applicationContext);
        context.put("SYSTEM_VARIABLE_RUNNER", runner);
        return runner.execute(express, context, null, true, false);
    }

}

1.4、Operator

1.4.1、AbstractOperator

public abstract class AbstractOperator extends OperatorBase {

    public QlExpressContext getQlExpressContext(InstructionSetContext instructionSetContext){
        IExpressContext<String, Object> parent = instructionSetContext.getParent();
        if (parent instanceof InstructionSetContext) {
            return (QlExpressContext)((InstructionSetContext) parent).getParent();
        }
        return (QlExpressContext)parent;
    }
}

1.4.2、OperatorDeparmentBelong

public class OperatorDeparmentBelong extends AbstractOperator {

    public final static String SYSTEM_VARIABLE_DEPARTMENT = "DEPARTMENT_BELONG";

    public OperatorDeparmentBelong(String name) {
        this.name = name;
    }

    @Override
    public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
        if (list == null || list.length != 1){
            throw new IllegalArgumentException("[OperatorDeparmentBelong] 数据错误");
        }
        QlExpressContext context = super.getQlExpressContext(parent);
        if (!context.containsKey(SYSTEM_VARIABLE_DEPARTMENT)) {
            throw new IllegalArgumentException("[OperatorDeparmentBelong] 缺少 department_belong");
        }
        List<String> departments = (List<String>)context.get(SYSTEM_VARIABLE_DEPARTMENT);
        String department = (String)list.get(0).getObject(parent);
        boolean contains = departments.contains(department);
        return new OperateData(contains ? "是" : "否", String.class);
    }
}

1.4.3、OperatorNotBlank

public class OperatorNotBlank extends Operator {

    @Override
    public Object executeInner(Object[] params) throws Exception {
        return isNotBlank(params[0]) ? true : false;
    }

    private boolean isNotBlank(Object param) {
        if (param == null) {
            return false;
        }
        if (param instanceof String) {
            return StringUtils.isNotEmpty((String) param);
        }
        return true;
    }
}

1.5、Service

@Data
public class UserDTO {

    private Long id;

    private String name;
}

1.5.1、UserService

package com.healerjean.proj.qlexpress.service;

import com.healerjean.proj.qlexpress.dto.UserDTO;
import org.apache.commons.lang3.StringUtils;

/**
 * @author zhangyujin
 * @date 2022/6/21  21:13.
 */
public class UserService {

    /**
     * 判断用户是否注册
     *
     * @param userDTO 用户dto
     * @return 注册 true,未注册 false
     */
    public UserDTO registerCheck(UserDTO userDTO, boolean login) {
        if (login &&  StringUtils.endsWithIgnoreCase("HealerJean", userDTO.getName())) {
            userDTO.setId(1L);
            return userDTO;
        }
        return null;
    }
}

1.6、TestMain

package com.healerjean.proj.qlexpress;

import com.google.common.collect.Lists;
import com.healerjean.proj.qlexpress.dto.UserDTO;
import com.healerjean.proj.qlexpress.operator.OperatorDeparmentBelong;
import com.healerjean.proj.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangyujin
 * @date 2022/6/21  17:16.
 */
@Slf4j
public class TestMain {


    /**
     * 1、自定义function
     * @throws Exception 抛出异常
     */
    @Test
    public void test_function() throws Exception {
        ExpressManager expressManager = new ExpressManager();
        Map<String, Object> context = new HashMap<>();
        context.put(OperatorDeparmentBelong.SYSTEM_VARIABLE_DEPARTMENT, 
                    Lists.newArrayList("产品部", "研发部"));

        String express = "部门归属('商务部')";
        Object execute = expressManager.execute(express, context);
        log.info("[TestMain#test_function] 商务部 是否归属于部门:{}", 
                 JsonUtils.toJsonString(execute));

        express = "部门归属('研发部')";
        execute = expressManager.execute(express, context);
        log.info("[TestMain#test_function] 研发部 是否归属于部门:{}", 
                 JsonUtils.toJsonString(execute));
    }

    /**
     * 2、内置函数
     */
    @Test
    public void test_innner_function() throws Exception {
        ExpressManager expressManager = new ExpressManager();
        Map<String, Object> context = new HashMap<>();
        String express = "最大(1,2,5,4)";
        Object execute = expressManager.execute(express, context);
        log.info("[TestMain#test_innner_function] (1,2,5,4) 最大的是:{}", 
                 JsonUtils.toJsonString(execute));

    }

    /**
     * 3、验证 addFunctionOfClassMethod
     * @throws Exception 抛出异常
     */
    @Test
    public void test_addFunctionOfClassMethod() throws Exception {
        Map<String, Object> context = new HashMap<>();
        context.put("数字", -3);
        String express = "取绝对值(数字)";
        ExpressManager expressManager = new ExpressManager();
        Object execute = expressManager.execute(express, context);
        log.info("[TestMain#test] 取绝对值:{}", JsonUtils.toJsonString(execute));
    }

    /**
     * 3、验证addOperatorWithAlias
     */
    @Test
    public void test_addOperatorWithAlias() throws Exception {
        Map<String, Object> context = new HashMap<>();
        context.put("喜欢", 2);

        String express = "如果(喜欢 > 1) 则  {return 结婚;} 否则 {return 分手;}";
        ExpressManager expressManager = new ExpressManager();
        Object execute = expressManager.execute(express, context);
        log.info("[TestMain#test_addOperatorWithAlias] 恋爱状态:{}", 
                 JsonUtils.toJsonString(execute));
    }

    /**
     *
     */
    @Test
    public void test_addMacro() throws Exception {
        ExpressManager expressManager = new ExpressManager();
        UserDTO userDTO = new UserDTO();
        userDTO.setName("HealerJean");
        Map<String, Object> context = new HashMap<>();
        context.put("userInfo", userDTO);
        context.put("login", true);

        String express = "用户是否注册";
        Object execute = expressManager.execute(express, context);
        log.info("[TestMain#test_addMacro] name:{} 是否注册:{}", 
                 userDTO.getName(), 
                 JsonUtils.toJsonString(execute));

        userDTO.setName("zhang");
        execute = expressManager.execute(express, context);
        log.info("[TestMain#test_addMacro] name:{} 是否注册:{}", 
                 userDTO.getName(), 
                 JsonUtils.toJsonString(execute));

        userDTO.setName("liu");
        context.put("login", false);
        execute = expressManager.execute(express, context);
        log.info("[TestMain#test_addMacro] name:{} 是否注册:{}", 
                 userDTO.getName(), 
                 JsonUtils.toJsonString(execute));
    }

}

ContactAuthor