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下载地址