java集成groovy

44 篇文章 1 订阅
9 篇文章 2 订阅

java集成groovy,实现页面化可编写脚本并执行

groovy教程
https://www.w3cschool.cn/groovy

GroovyExtendScript - 自定义扩展函数类

import groovy.lang.Script;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * groovy函数扩展
 */
public class GroovyExtendScript extends Script {

    @Override
    public Object run() {
        Method[] methods = GroovyExtendScript.class.getDeclaredMethods();
        StringBuilder sb = new StringBuilder();
        for (Method method : methods) {
            sb.append(method);
        }
        return sb.substring(0, sb.length() - 1);
    }

    // 求和
    public static Object sum(Number... args) {
        double rst = 0;
        for (Number arg : args) {
            rst = rst + Double.valueOf(arg.toString());
        }
        return round(rst);
    }
    public static Object sum(List<? extends Number> args) {
        double rst = 0;
        for (Number arg : args) {
            rst = rst + Double.valueOf(arg.toString());
        }
        return round(rst);
    }
    public static Object sum(Set<? extends Number> args) {
        double rst = 0;
        for (Number arg : args) {
            rst = rst + Double.valueOf(arg.toString());
        }
        return round(rst);
    }

    private static double round(double num) {
        return round(num, 4);
    }
    private static double round(double num, int decimal) {
        if(num == 0) {
            return 0.0;
        }
        return Double.valueOf(String.format("%." + decimal + "f", num));
    }

}

GroovySupport - groovy执行类

import com.fintell.tools.report.CommonUtils;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.groovy.control.CompilerConfiguration;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class GroovySupport {
    private static final Object lock = new Object();
    private static final GroovyShell shell;
    // 初始化最大缓存大小
    private static volatile int CACHE_SIZE = 200;
    // 最大缓存大小
    private static final int MAX_CACHE_SIZE = 5000;
    // 缓存扩充,增加的步长
    private static int CACHE_STEP_SIZE = 50;
    // 上一次清空缓存时间,默认为项目启动时间
    private static volatile Long LAST_CLEAR_TIME = System.currentTimeMillis();
    // 两次清空的缓存间隔在多少分钟内,则认为需要缓存扩充,如X分钟内如果再次清空,则认为需要扩充缓存
    private static int CACHE_INTERVAL_MINUTES = 60;
    // 定义缓存
    private static Map<String, Script> cache = new ConcurrentHashMap<>();
    static {
        CompilerConfiguration cfg = new CompilerConfiguration();
        cfg.setScriptBaseClass(GroovyExtendScript.class.getName());
        shell = new GroovyShell(cfg);
    }

    public static Object parseExprNoTrans(String expr, Map<String, Object> map) {
        Binding binding = new Binding(map);
        Script script = getScriptFromCache(expr);
        script.setBinding(binding);
        return script.run();
    }

    public static Object parseExpr(String expr, Map<String, Object> map) {
        // 对数据进行转换 (数值型处理)
       trans(map);
        Binding binding = new Binding(map);
        Script script = getScriptFromCache(expr);
        script.setBinding(binding);
        Object result = script.run();
        if (isFloat(result)) {
            return round(Double.parseDouble(result.toString()));
        }
        return result;
    }

    /**
     * 获取groovy
     */
    private static Script getScriptFromCache(String expr) {
        // 尝试从缓存获取......
        Script scriptCache = cache.get(expr);
        if (scriptCache != null) {
            return scriptCache;
        }
        // 获取失败,进行加工获取
        synchronized (lock) {
            // 再次判断缓存中是否有数据
            scriptCache = cache.get(expr);
            if (scriptCache != null) {
                return scriptCache;
            }
            // 判断缓存是否需要进行清空处理,如果已清空,打印日志处理......
            if (clearCache()) {
                log.info("groovy进行缓存清空,当前缓存大小[{}]...", CACHE_SIZE);
            }
            // 如果清空了缓存或者缓存中未获取到,则进行缓存
            Script script = shell.parse(expr);
            cache.put(expr, script);
            return script;
        }
    }

    /**
     * 清空缓存
     */
    private static boolean clearCache() {
        // 判断缓存中的数据是否已经大于最大数据,如不大于,则不进行缓存清空
        if (cache.size() < CACHE_SIZE) {
            return false;
        }
        // 若缓存中的数据大于允许的最大缓存,则直接清空处理
        if (cache.size() > MAX_CACHE_SIZE) {
            log.info("groovy缓存大小[{}]大于最大允许的缓存大小[{}],进行缓存清空处理...", cache.size(), MAX_CACHE_SIZE);
            cache.clear();
            LAST_CLEAR_TIME = System.currentTimeMillis();
            return true;
        }
        try {
            // 获取本次清空和上次清空的时间间隔
            long nowTime = System.currentTimeMillis();
            // 获取本次清空缓存时间和上次清空缓存时间的间隔(分钟)
            long intervalMinutes = (nowTime - LAST_CLEAR_TIME) / (60 * 1000);
            // 如果本次清空和上次清空的间隔小于等于配置的缓存间隔,则认为缓存需要扩充,进行缓存扩充
            if (intervalMinutes <= CACHE_INTERVAL_MINUTES) {
                log.info("groovy缓存扩充,扩充前缓存大小[{}],扩充后缓存大小[{}],当前间隔差[{}]分钟,缓存间隔差[{}]...", CACHE_SIZE, CACHE_SIZE + CACHE_STEP_SIZE, intervalMinutes, CACHE_INTERVAL_MINUTES);
                CACHE_SIZE += CACHE_STEP_SIZE;
                LAST_CLEAR_TIME = System.currentTimeMillis();
                return false;
            }
            // 如果本次清空和上次清空的间隔大于配置的缓存间隔,则进行缓存清空
            cache.clear();
            LAST_CLEAR_TIME = System.currentTimeMillis();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 对数据进行转换
     */
    private static void trans(Map<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return;
        }
        // 对数据进行转换
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value == null || CommonUtils.isEmpty(value)) {
                continue;
            }
            if (isInt(value)) {
                try {
                    map.put(key, Long.parseLong(String.valueOf(value)));
                }catch (Exception e){

                }
            } else if (isFloat(value)) {
                try {
                    map.put(key, Double.parseDouble(String.valueOf(value)));
                }catch (Exception e){

                }
            }
        }
    }

    /**
     * 判断是否为double类型
     */
    private static final Pattern patternFloat = Pattern.compile("[-\\+]?\\d+(\\.\\d+)");
    private static boolean isFloat(Object param){
        if (CommonUtils.isEmpty(param)) {
            return false;
        }
        Matcher isNum = patternFloat.matcher(param.toString());
        return isNum.matches();
    }
    /**
     * 判断是否为int类型
     */
    private static final Pattern patternInt = Pattern.compile("-?\\d+");
    private static boolean isInt(Object param){
        if (CommonUtils.isEmpty(param)) {
            return false;
        }
        Matcher isNum = patternInt.matcher(param.toString());
        return isNum.matches();
    }

    private static double round(double num) {
        if(num == 0) {
            return 0.0;
        }
        return Double.valueOf(String.format("%.4f", num));
    }

}

CustomUtil - 工具类,可不使用

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 自定义变量工具类
 */
public class CustomUtil {

    /**
     * 验证变量是否存在
     * @param logicParams : 变量逻辑中的变量列表
     * @param dbParams : 从数据库查询到的变量列表
     */
    public static void checkParamIsHave(Set<String> logicParams, Set<String> dbParams) throws Exception {
        if ((logicParams == null || logicParams.isEmpty()) && (dbParams == null || dbParams.isEmpty())) {
            return;
        }
        if (logicParams.size() == dbParams.size()) {
            return;
        }
        for (String logicParam : logicParams) {
            if (!dbParams.contains(logicParam)) {
                throw new Exception("变量[" + logicParam + "]不存在!");
            }
        }
        return;
    }

    /**
     * 获取变量逻辑的变量值
     * @param paramLogic : 变量逻辑
     */
    static final Pattern pattern = Pattern.compile("\\$\\{([^}]*)\\}"); // (\\{[^}]*?\\})
    public static Set<String> getParmsByLogic(String paramLogic){
        Set<String> params = new HashSet<>();
        Matcher matcher = pattern.matcher(paramLogic);
        while (matcher.find()) {
            params.add(matcher.group(1));
        }
        return params;
    }

}

GroovyTest - 测试类

import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.*;

public class GroovyTest {

    public static void main(String[] args) {
        // 验证变量是否都存在
        Set<String> logicParams = CustomUtil.getParmsByLogic("${REBM_ZCVB_XBVB_BAVA_MCQ2}+${REBZ_BAVA_MDQ3}");
        Set<String> dbParams = new HashSet<>();
        dbParams.add("REBM_ZCVB_XBVB_BAVA_MCQ2");
        try {
            CustomUtil.checkParamIsHave(logicParams, dbParams);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }

        // 数据定义
        HashMap<String, Object> params = new HashMap<String, Object>() {
            {
                put("a", 1);
                put("b", 2);
                put("c", 3);
                put("d", 4);
            }
        };

        // 表达式计算
        System.err.println("sum=" + GroovySupport.parseExpr("sum(a,b,c,d)", params));

        // 区间值测试
        String rangeTest = "def res = ${a};" +
                "if(res >= 0 && res < 10){" +
                "   return \"L1\";" +
                "}else if(res >= 10 && res < 20){" +
                "   return \"L2\";" +
                "}else if(res >= 20 && res < 30){" +
                "   return \"L3\";" +
                "}else{" +
                "   return 0;" +
                "}";
        System.err.println("rangeTest=" + GroovySupport.parseExpr(rangeTest.replace("${a}","a"), params));

        // 枚举值测试
        String enumTest = "def res = a + b;" +
                "switch(res){" +
                "   case 1:" +
                "      return \"L1\";" +
                "   case 2: " +
                "      return \"L2\";" +
                "   case 3: " +
                "      return \"L3\";" +
                "   default:" +
                "      return 0;" +
                "}";
        System.err.println("enumTest=" + GroovySupport.parseExpr(enumTest, params));

        // 验证json解析集合
        List<Score> scores = new ArrayList<>();
        scores.add(new Score(10,20));
        scores.add(new Score(30,40));
        Student student = new Student(29, "anyf", null, scores);
        System.err.println(JSON.toJSON(student));
        params.put("json", JSON.toJSON(student));
        String jsonTest = "" +
                "def res = 0;" +
                "def scores = json.scores;" +
                "for(e in scores){" +
                "   if(e.math > 5){" +
                "       res++;" +
                "   };" +
                "};" +
                "return res;";
        System.err.println("jsonTest=" + GroovySupport.parseExpr(jsonTest, params));

        // 验证json空值处理
        String jsonTestNull = "" +
                "def defaultValue = -999;" +
                "try { " +
                "   return json.loan.msg;" +
                "} catch(NullPointerException e1) {" +
                "   return defaultValue;" +
                "}";
        System.err.println("jsonTestNull=" + GroovySupport.parseExpr(jsonTestNull, params));

    }

}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Student{
    private Integer age;
    private String name;
    private Loan loan;
    List<Score> scores;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Score{
    private Integer math;
    private Integer english;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Loan{
    private String msg;
}

HTML集成CodeMirror CodeMirror下载地址

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小安灬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值