aviator 使用案例

aviator 轻量级表达式引擎
需求: 每个检查项目都可以维护自己的指标,分为异常和正常指标,指标分为两种一种是数字形式的比较,一种是字符串形式的包含

pom

5.3.3

 
            com.googlecode.aviator
            aviator
        

案例

NormTypeEnum: 为指标枚举

  1. 值不是固定的,有可能是数字、浮点、字符串等,为了统一,计算相关的都去转为了BigDecimal
  2. 如果是包含,需要取出list对应的变量,所以需要正则去做拆分
@Getter
@AllArgsConstructor
public enum NormTypeEnum {

    COMPUTE("0", "计算","value", (pel) -> {
        Asserts.notBlank(pel, "计算表达式不能为空");
        Matcher matcher = RegexConstants.COMPUTE_REGEX_PATTERN.matcher(pel);
        return matcher.find();
    }),

    INCLUDE("1", "选择/匹配","list", (pel) -> {
        Asserts.notBlank(pel, "选择/匹配表达式不能为空");
        Matcher matcher = RegexConstants.INCLUDE_REGEX_PATTERN.matcher(pel);
        return matcher.find();
    });

    private final String code;

    private final String des;

    private final String var;

    private final Function<String, Boolean> beforeProcess;

    public static NormTypeEnum getByCode(String code) {
        NormTypeEnum[] values = values();
        for (NormTypeEnum item : values) {
            if (item.getCode().equals(code)) {
                return item;
            }
        }
        throw new UtilException(String.format("NormTypeEnum 获取枚举值失败,code: %s", code));
    }

    public static void main(String[] args) {
//        Matcher matcher = RegexConstants.INCLUDE_REGEX_PATTERN.matcher("contains(value, 20572537289314304@20572121830920192)");
//        NormTypeEnum.INCLUDE.getBeforeProcess().apply("");
//        System.err.println(matcher.find());

        Matcher matcher = Pattern.compile("\\d+").matcher("100<=value && value <= 300");

        while (matcher.find()){
            System.err.println(matcher.group());
        }
        System.err.println(matcher.groupCount());

    }
}


package com.qdp.health.utils;

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.Expression;
import com.qdp.common.core.exception.UtilException;
import com.qdp.health.enums.NormTypeEnum;
import com.qdp.health.enums.ResSignEnum;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 表达式解析工具类
 * @author : Betsy.
 * 2024-12-16 11:42
 */
@Slf4j
public class ExpressionUtils {

    private static final AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();

    public static Boolean validateMetrics(String normType, String evalStr, String value){
        log.info("validateMetrics ===> normType:{}, evalStr:{}", normType, evalStr);
        NormTypeEnum normTypeEnum = verify(normType, evalStr);
        String list = "";
        // 如果是匹配,处理参数
        if(normTypeEnum.getCode().equals(NormTypeEnum.INCLUDE.getCode())){
            // 需要将参数中的匹配值,处理出来
            Pattern pattern = Pattern.compile("\\((.*?)\\)"); // 匹配括号内的内容
            Matcher matcher = pattern.matcher(evalStr);
            if (matcher.find()) {
                String content = matcher.group(1);
                String[] split = content.split(",");
                list = split[0];
                evalStr=  evalStr.replaceAll(list, "list");
            }

        }
        System.err.println(evalStr);
        return eval(evalStr, getVariables(normTypeEnum, value, list));
    }

    public static String validateHighOrLow(String evalStr, String normType, String res){
        try{
            if(normType.equals(NormTypeEnum.COMPUTE.getCode())){
                BigDecimal resBg = new BigDecimal(res);
                Matcher matcher = Pattern.compile("\\d+").matcher(evalStr);
                int i = 0;
                String code = null;
                String low = "0";
                String high = "0";
                while (matcher.find()){
                    if(i==0){
                        low = matcher.group();
                    }else {
                        high = matcher.group();
                    }
                    i++;
                }
                if(resBg.compareTo(new BigDecimal(low)) < 0){
                    code = ResSignEnum.LOW.getCode();
                }else if(resBg.compareTo(new BigDecimal(high)) > 0){
                    code = ResSignEnum.HIGH.getCode();
                }
                return code;
            }else {
                log.info("当前指标不存在高低,不是计算属性: normType:{} , evalStr{}",normType,evalStr);
            }
        }catch (Exception e){
            log.info("验证指标高低异常, validateHighOrLow: {}", e.getMessage());
        }
        return null;
    }

    /**
    * 验证指标是否有效
    * @param normType {@link String}
    * @param evalStr {@link String}
    * @return {@link NormTypeEnum}
    */
    public static NormTypeEnum verify(String normType, String evalStr){
        log.info("verify ===> normType:{}, evalStr:{}", normType, evalStr);
        NormTypeEnum normTypeEnum = NormTypeEnum.getByCode(normType);
        Boolean isEffectiveNorm = normTypeEnum.getBeforeProcess().apply(evalStr);
        if(!isEffectiveNorm){
            throw new UtilException(String.format("当前指标( %s ) 无效", evalStr));
        }
        return normTypeEnum;
    }

    /**
    * 指标运算
    * @param evalStr {@link String}
    * @param variables {@link Map}
    * @return {@link Boolean}
    */
    public static Boolean eval(String evalStr, Map<String, Object> variables){
        log.info("variables:{}",variables);
        Expression compile = instance.compile(evalStr);
        return (Boolean) compile.execute(variables);
    }


    /***
    * 指标变量
    * @param normTypeEnum {@link NormTypeEnum}
    * @param value {@link String}
    * @param list {@link String}
    * @return {@link Map}
    */
    public static Map<String, Object> getVariables(NormTypeEnum normTypeEnum, String value, String list){
        Map<String, ? super Object> variables = new HashMap<>();
        if(normTypeEnum.getCode().equals(NormTypeEnum.INCLUDE.getCode())){
            // todo: 测试
            variables.put(normTypeEnum.getVar(), list.split(","));
            // todo: 值类型转换--优化 3 > val
//            variables.put(NormTypeEnum.COMPUTE.getVar(), new BigDecimal(value));
            variables.put(NormTypeEnum.COMPUTE.getVar(), value);
        }else {
            variables.put(normTypeEnum.getVar(), new BigDecimal(value));
        }
        return variables;
    }

    public static void main(String[] args) {
//        String str = "include(list,value)";
//        String strss = "3 <= value && value <= 5";
//        System.err.println(NormTypeEnum.COMPUTE.getBeforeProcess().apply(strss));
//        System.err.println(NormTypeEnum.INCLUDE.getBeforeProcess().apply(strss));
//        System.err.println("=========");
//        String[] split = str.split("\\(");
//        String[] split1 = split[1].split(",");
//        System.err.println(split[1]);
//        System.err.println(split1[0]);
//        List res = new ArrayList<>();
//        List params = new ArrayList<>();
//        res.add("admin");
//        res.add("test");
//        res.add("ruoyi");
//        params.add("admin");
//        params.add("ruoyi");

//        Pattern pattern = Pattern.compile("\\((.*?)\\)"); // 匹配括号内的内容
//        Matcher matcher = pattern.matcher("contains(value, 20572537289314304@20572121830920192)");
//        if (matcher.find()) {
//            String content = matcher.group(1); // 获取第一个匹配到的括号内的内容
//            System.out.println(content);
//        }

//        String str = "value >= 100 && value <= 300";
        String str = "include(value, 20572537289314304@20572121830920192)";
        Pattern pattern = Pattern.compile("\\((.*?)\\)"); // 匹配括号内的内容
        Matcher matcher = pattern.matcher(str);
        String list= "";
        if (matcher.find()) {
            String content = matcher.group(1);
            String[] split = content.split(",");
            list = split[split.length - 1];
            str =  str.replaceAll(list, "list");
        }
        System.err.println(str);
        Expression expression = instance.compile(str);
        List<String> res = new ArrayList<>();
        res.add("20572121830920192");
        res.add("20572537289314304");
        Map<String, ? super Object>  variables = new HashMap<>();
        variables.put("list", "20572537289314304");
        variables.put("value", res);
//        variables.put("list", new BigDecimal("80"));
        Object result1 = expression.execute(variables);
        System.out.println("Result 1: " + result1);
    }

}

你可能感兴趣的:(java排坑之路,java,后端)