千家信息网

Java中如何执行动态表达式语句前中后缀Ognl、SpEL、Groovy、Jexl3

发表于:2024-11-23 作者:千家信息网编辑
千家信息网最后更新 2024年11月23日,这篇文章主要介绍了Java中如何执行动态表达式语句前中后缀Ognl、SpEL、Groovy、Jexl3,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家
千家信息网最后更新 2024年11月23日Java中如何执行动态表达式语句前中后缀Ognl、SpEL、Groovy、Jexl3

这篇文章主要介绍了Java中如何执行动态表达式语句前中后缀Ognl、SpEL、Groovy、Jexl3,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

Ognl、SpEL、Groovy、Jexl3

在一些规则集或者工作流项目中,经常会遇到动态解析表达式并执行得出结果的功能。

规则引擎是一种嵌入在应用程序中的组件,它可以将业务规则从业务代码中剥离出来,使用预先定义好的语义规范来实现这些剥离出来的业务规则;规则引擎通过接受输入的数据,进行业务规则的评估,并做出业务决策。

工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。 工作流建模,即将工作流程中的工作如何前后组织在一起的逻辑和规则,在计算机中以恰当的模型表達并对其实施计算。 工作流要解决的主要问题是:为实现某个业务目标,利用计算机在多个参与者之间按某种预定规则自动传递文档、信息或者任务。

一、前中后缀简单描述

1、前缀、中缀、后缀表达式(逆波兰表达式)

最早接触的表达式解析是在上数据结构的时候,当时课设作业是 " 做一个简单的四则混合运算语句解析并计算结果 ",简单说就是计算器。

2、中缀表达式

将运算符写在两个操作数中间的表达式,称作中缀表达式。

中缀表达式是我们最熟悉和阅读最容易的表达式

比如:12 + 34 + 5 * 6 - 30 / 5

也就是我们常用的数学算式就是用中缀表达式表示的

3、后缀表达式

将运算符写在两个操作数之后的表达式称作后缀表达式。

12 34 + 5 6 * + 30 5 / -

前缀表达式需要从左往右读,遇到一个运算法,则从左边取 2 个操作数进行运算

从左到右读则可分为((12 34 + )(5 6 * )+ )(30 / 5) -

注:括号只是辅助,实际上没有

4、前缀表达式

前缀表达式是将运算符写在两个操作数之前的表达式。

前缀表达式需要从右往左读,遇到一个运算法,则从右边取 2 个操作数进行运算

12 + 34 + 5 * 6 - 30 / 5

- + + 12 34 * 5 6 / 30 5

中缀:12 + 34 + 5 * 6 - 30 / 5
后缀:12 34 + 5 6 * + 30 5 / -
前缀:- + + 12 34 * 5 6 / 30 5

二、OGNL

OGNL(Object-Graph Navigation Language的简称),对象图导航语言,它是一门表达式语言,除了用来设置和获取Java对象的属性之外,另外提供诸如集合的投影和过滤以及lambda表达式等。

引入依赖:

    ognl    ognl    3.2.18
MemberAccess memberAccess = new AbstractMemberAccess() {    @Override    public boolean isAccessible(Map context, Object target, Member member, String propertyName) {        int modifiers = member.getModifiers();        return Modifier.isPublic(modifiers);    }};OgnlContext context = (OgnlContext) Ognl.createDefaultContext(this,    memberAccess,    new DefaultClassResolver(),    new DefaultTypeConverter());context.put("verifyStatus", 1);Object expression = Ognl.parse_Expression("#verifyStatus == 1");boolean result =(boolean) Ognl.getValue(expression, context, context.getRoot());Assert.assertTrue(result);

三、SpEL

SpEL(Spring Expression Language),即Spring表达式语言。它是一种类似JSP的EL表达式、但又比后者更为强大有用的表达式语言。

ExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parse_Expression("#verifyStatus == 1");EvaluationContext context = new StandardEvaluationContext();context.setVariable("verifyStatus", 1);boolean result = (boolean) expression.getValue(context);Assert.assertTrue(result);

四、Jexl/Jexl3

引入依赖:

    org.apache.commons    commons-jexl3    3.1

执行简单的表达式:

JexlEngine jexl = new JexlBuilder().create();JexlContext jc = new MapContext();jc.set("verifyStatus", 1);JexlExpression expression = jexl.create_Expression("verifyStatus == 1");boolean result = (boolean) expression.evaluate(jc);Assert.assertTrue(result);

五、Groovy

Groovy 是一个很好的选择,其具备完备的 Groovy 和 Java 语法的解析执行功能。

引入依赖, 这个可以根据需要引入最新版本

    org.codehaus.groovy    groovy    2.5.6

执行表达式:

Binding binding = new Binding();binding.setVariable("verifyStatus", 1);GroovyShell shell = new GroovyShell(binding);boolean result = (boolean) shell.evaluate("verifyStatus == 1");Assert.assertTrue(result);

六、扩展

经常用 MyBatis 的一定用过动态语句

这里我们简化一下

该示例主要为了讲解,不一定好用, 其中 @if 与上面的 等效

select id, invite_code, phone, name from user where status = 1 @if(:inviteCode != null) { and invite_code = :inviteCode }

在处理这种 SQL 中,我们可以先用正则,将 @if 与 正常语句分割开

List results = StringUtil.matches(sql, "@if([\\s\\S]*?)}");

通过这种方式匹配到 @if(:inviteCode != null) { and invite_code = :inviteCode }

然后将需要执行计算的表达式与要拼接的 SQL 分离出

String text = "@if(:inviteCode != null) { and invite_code = :inviteCode }";List sqlFragment = StringUtil.matches(text, "\\(([\\s\\S]*?)\\)|\\{([\\s\\S]*?)\\}");

分离出

  • :inviteCode != null

  • and invite_code = :inviteCode

其中 :inviteCode != null 是需要动态处理的语句,对于 :inviteCode != null 我们需要识别出,那些是需要进行复制的变量名称

List sqlFragmentParam = StringUtil.matches(":inviteCode != null", "\\?\\d+(\\.[A-Za-z]+)?|:[A-Za-z0-9]+(\\.[A-Za-z]+)?");

得到 inviteCode,并通过某种方式找到对应的值,

具体代码,仅供参考:

JexlEngine jexl = new JexlBuilder().create();JexlContext jc = new MapContext();jc.set(":inviteCode", "ddddsdfa");JexlExpression expression = jexl.create_Expression(sqlExp);boolean needAppendSQL = (boolean) expression.evaluate(jc);

通过 needAppendSQL 来决定是否拼接 SQL, 这样一个简单的动态 SQL 就实现了,上面用的 Jexl 写的,你可以改成上面任意一种方案,这里只做演示

@Testpublic void testSQL() {  String sql = "select id, invite_code, phone, name \n"  + "from user \n"  + "where status = 1 \n"  + "@if(:inviteCode != null) { and invite_code = :inviteCode }";  Map params = new HashMap();params.put("inviteCode", "dd");  System.out.println(parseJexl(sql, params));}public String parseJexl(String jexlSql, Map params) {  // 判断是否包含 @if  List results = StringUtil.matches(jexlSql, "@if([\\s\\S]*?)}");  if (results.isEmpty()) {      return jexlSql;  }  JexlEngine jexl = new JexlBuilder().create();  JexlContext jc = new MapContext();  for (String e : results) {    List sqlFragment = StringUtil.matches(e, "\\(([\\s\\S]*?)\\)|\\{([\\s\\S]*?)\\}");    String sqlExp = sqlFragment.get(0).trim().substring(1, sqlFragment.get(0).length() - 1);    List sqlFragmentParam = StringUtil.matches(sqlExp, "\\?\\d+(\\.[A-Za-z]+)?|:[A-Za-z0-9]+(\\.[A-Za-z]+)?");    for (String param : sqlFragmentParam) {      String newSQLExp = "_" + param.substring(1);      sqlExp = sqlExp.replace(param, newSQLExp);      jc.set(newSQLExp, params.get(param.substring(1)));    }    JexlExpression expression = jexl.create_Expression(sqlExp);    Boolean needAppendSQL = (Boolean) expression.evaluate(jc);    if (needAppendSQL) {      jexlSql = jexlSql.replace(e, sqlFragment.get(1).trim().substring(1, sqlFragment.get(1).length() - 1));    } else {      jexlSql = jexlSql.replace(e, "");    }  }  return jexlSql;}

感谢你能够认真阅读完这篇文章,希望小编分享的"Java中如何执行动态表达式语句前中后缀Ognl、SpEL、Groovy、Jexl3"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

表达式 规则 运算 后缀 业务 工作 动态 语句 中缀 前缀 操作数 工作流 篇文章 语言 两个 运算符 之间 代码 功能 对象 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 java数据库事务怎么写 天融信是国内首家网络安全厂商 海淀区网络营销网络技术一体化 数据库的端到端安全性是什么 网络安全设备巡检 蚁安居网络技术有限公司工牌 疾病登记数据库 数据库版本太低怎么回事 ip网络技术+数据网络构建 服务器端的开发技术 游戏服务器出问题了游戏会怎么样 如何查看服务器管理端口 全球元器件数据库 32核的服务器集群节点应该 软件开发外包服务合同范本 阿里邮箱收件服务器 域服务器上的安全数据库 虚拟虚拟手机服务器地址端口号 网络安全目录 穿越火线黑屏服务器满了怎么办 删除数据库表的所有数据 简单介绍你对网络安全的认识 战争世界英雄无法连接服务器 julia操作数据库 对棱镜计划以及网络安全的看法 奥丁神叛手机端服务器繁忙 上海信息软件开发服务要多少钱 湖南数据软件开发价格服务标准 服务器怎么设置共享 网络安全为人民网络靠人民故事
0