MVEL入门到使用

MVEL简介

MVEL为 MVFLEX Expression Language(MVFLEX表达式语言)的缩写,它是一种动态/静态的可嵌入的表达式语言和为Java平台提供Runtime(运行时)的语言。
最初是作为一个应用程序框架实用程序的语言开始,该项目现已发展完全独立。
MVEL通常用于执行用户(程序员)通过配置XML文件或注释等定义的基本逻辑。
它也可以用来解析简单的JavaBean表达式。Runtime(运行时)允许MVEL表达式通过解释执行或者预编译生成字节码后执行。
MVEL是一个基于java语法的表达式,为JAVA语言提供便捷灵活的动态性。MVEL吸收了大量的java语法,但是作为一个表达式语言,还是与java有很多不同之处,比如MVEL像正则表达式一样,有直接支持集合、数组、字符串的操作符。
除了表达式语言以外,MVEL还提供了用来配置和构造字符串的模板语言。
MVEL表达式主要有以下部分内容:

  • 属性表达式
  • 布尔表达式
  • 方法调用
  • 变量赋值
  • 函数定义

MVEL引入

<dependency>
	<groupId>org.mvel</groupId>
	<artifactId>mvel2</artifactId>
	<version>2.4.14.Final</version>
</dependency>

MVEL基本语法

属性表达式

基本使用

属性表达式是MVEL最常见的用途之一,通过他MVEL可以用来作为一个高性能易使用的反射优化器。
假设有一个user对象,属性有name,age。


public class User {

    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}```


  我们可以通过MVEL获取User 的值,如下:
  

```java
		User user = new User("zhangsan", 123);
        Map<String, Object> m = new HashMap<>();
        m.put("user",user);
        Object o = MVEL.eval("user.name",m);
        System.out.println(o);

也可以为user对象设置属性值:

        User user = new User("zhangsan", 11);
        Map<String, Object> m = new HashMap<>();
        m.put("user",user);
        MVEL.eval("user.age=22",m);
        System.out.println(user.getAge());

with语法

with可以为对象的多个属性赋值。
如为user的name和age同时赋值,语法如下:

with (user){
	name='张三',
	age=11
}

实例:

        User user = new User();
        Map<String,Object> m = new HashMap<>();
        m.put("user",user);
        MVEL.eval("with(user){name='张三',age=30}",m);

        System.out.println(user.getName());

布尔表达式

MVEL可以用来表达一个布尔表达式,比如user.name==‘zhangsan’ 。

MVEL的布尔表达式和JAVA一样有优先级,包括通过括号来控制执行顺序。

MVEL布尔表达式的操作符如下:

操作符说明
==等于
>大于
<小于
!=不等于
contains包含。如果左边的字符串包含右边的字符串内容,返回true
is/instanceof实例类型检查,如果实例类型是右边的类型,返回true
istrsim字符相似
sounds读音相似
~=正则表达式测试

举几个例子:
大于

        Map<String, Integer> m = new HashMap<>();
        m.put("a", 100);
        Object obj = MVEL.eval("a>10", m);
        System.out.println(obj);

读音相似性

        String composite = "'foobar' soundslike 'fubar'";
        Object obj = MVEL.eval(composite);
        System.out.println(obj);

复合表达式

在MVEL中,一段语句中可以写任意多个语句,每个语句以;隔开,最后一个语句没有分号。如以下这个语句:

statement1;statement2;statement3

例:

        String com = "a = a+10;a=+11";
        Map<String, Object> m = new HashMap<>();
        m.put("a", 0);
        Object obj = MVEL.eval(com, m);
        System.out.println(obj);

返回值

在MVEL中使用了输出最后值原则。
也就是说,虽然MVEL定义了return ,但是不一定用它,因为都一样。
比如下面的脚本:
a=10;b=(a=2)+10;a
这个脚本最后返回的值是a的值,也就是返回最后一个语句的值。

操作符

一元操作符

  • new:用来实例化对象,例如:new String(“foo”);
    也可以实例化自己定义的对象。例如:User obj = (User) MVEL.eval(“new com.mvel.pojo.User(‘hello’,11)”);
  • with:对单个对象执行多次操作。
  • assert:用一个AssertionError 断言一个值的对错,例:assert foo != null
  • isdef:用来判断一个变量在某个范围内是否定义,例:isdef variableName
  • !: 布尔取反操作符,例: !true == false

比较运算符

操作符说明示例
==比较两个值是否相等,与java的字符串内存地址比较不一样‘foo’==‘foo’
!=不等于
>大于
<小于
>=大于等于
<=小于等于
contains包含。如果左边的字符串包含右边的字符串内容,返回true
is/instanceof实例类型检查,如果实例类型是右边的类型,返回true
strsim字符相似性
sounds读音相似性
~=正则表达式测试

逻辑运算符

操作符说明示例
&&
||
or用于多个值进行逻辑或运算

数字运算符

包括加减乘除(+,-,*,/)等等

其他运算符

  • +,字符串连接运算,如:“foo” +“bar”

  • #,字符连接运算,如:1 # 2返回"12"

  • in,投影整个项目集合,如:(foo in list)

  • =,赋值运算符,如:var = “foobar”

MVEL对列表、数组、map的操作

在MVEL中,可以用非常简单的语法来描述列表,map,数组。

比如:map 在MVEL中的描述
[‘bob’,new User(‘bob’),‘jim’:new User(‘jim’)] 相当于:
Map m = new HashMap();
m.put(‘bob’,new User(‘bob’));
m.put(‘jim’,new User(‘jim’));

列表

用下面的格式描述:[item1,item2,item3] 如[“Jim”,“Bob”,“Tom”]

			  String expression = "['Jim','Bob','Tom']";
              List< String> l = (List<String>) MVEL. eval(expression);
               for(String str:l){
                     System. out.println(str);
              }

数组

数组用下面的格式描述:{itm1,itm2,itm3} 如:{“Jim”,“Bob”,“Tom”}

			  String expression = "{'Jim','Bob','Tom'}";
              Object str = MVEL.eval(expression);
              String[] newarray = null;
               if(str.getClass().isArray()){
                     System. out.println(String.valueOf(Array. get(str , 0)));
              }

Map

String expression = "['Bob' : new com.mvel.pojo.User('Bob'), 'Michael' : new com.mvel.pojo.User('Michael')]";
               Map o = (Map ) MVEL.eval(expression);
              User u = (User) o.get( "Bob");
              System. out.println(u.getName());

数组的强制转换

关于数组,需要知道的一个非常重要的方面是,它可以被强制转换成其它类型的数组,当你声明一个数组时,是不直接指定其类型的,但你可以通过将其传递给一个接收int[]类型参数的方法来指定。如:

foo.someMethod({1,2,3,4});在这种情况下,当MVEL发现目标方法接收的是一个int[],会自动的将{1,2,3,4}转换成int[]类型。

属性访问

在前面的文档中可以了解到MVEL可以访问到对象的属性。比如user.name可以相当于Java中的user.getName()。

Null-Safe Bean Navigation

有时,当你的表达式中会含有null元素时,这时就需要你进行一个为空判断,否则就会发生错误。当你使用null-safe操作符时你可以简化这个操作:user.?manager.name
它相当于:

if (user.manager != null) { 
	return user.manager.name; 
} else {
	 return null; 
}

集合

集合的遍历也可以通过简单的语法来实现:

  • List:可以像访问数组一样访问List,如:user[5],这等价与java代码中的user.get(5);
  • Map:Map的访问和访问数组也非常相似,不同的是,在访问Map时索引值可以是任意对象,如:user[“foobar”]这等价于java代码中的user.get(“foobar”);
    当Map的key是String类型时,还可以使用特殊的方式来访问,如:user.foobar,也就是允许你把map本身看成一个虚拟的对象,来访问其属性

控制流程

if else

MVEL中的if else 和Java中的语法一样。

String compoite = "if (a > 0) {System.out.println('Greater than zero!');}else if (a == -1) {System.out.println('Minus one!');}" +
                            "else { System.out.println('Something else!');}" ;
              String com = "a=a+3;a=a+4;a=a+5";
               Map m = new HashMap();
               m.put("a", 0);
              Object obj = MVEL. eval(com,m );
              System. out.println(obj);

三目运算

String expression = "foo>0?'大于0':'小于等于0'" ;
               Map m = new HashMap();
               m.put("foo", -11);
              Object obj = MVEL. eval(expression,m );
              System. out.println(obj);

三目运算符还支持嵌套,例如:var > 0 ? “Yes” : (var == -1 ? “Minus One!” : “No”)

迭代

String expression = "foreach (x : 9) {  System.out.println(x);} " ;
              MVEL. eval(expression);
       String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
              String expression = "foreach(el:str){System.out.println(el);}" ;
              Map<String, Object> m = new HashMap<String, Object>();
              m.put( "str", str);
              Object obj = MVEL.eval (expression,m);

目前也支持for关键字。

String expression =  "for(i=0;i<9;i++){System.out.println(i)}" ;
              MVEL. eval(expression);

do while / do until

do until的意义和do while正好相反

String expression = "do {System.out.println(i);i++;} while (i <10);" ;
               Map m = new HashMap();
               m.put("i", 1);
              Object obj = MVEL.eval (expression,m);
String expression = "do {System.out.println(i);i++;} until (i >10);" ;
               Map m = new HashMap();
               m.put("i", 1);
              Object obj = MVEL.eval (expression,m);

while / until

while (isTrue()) {
   doSomething();
}

until (isFalse()) {
   doSomething();
}

投影与交集

投影

投影是描述集合的方法之一,通过简单的语法你可以检索到集合中非常复杂的对象模型。

语法:in 比如:(foo in list)(对象属性 in 对象集合)
示例:

			  User u1 = new User("张三" );
              User u2 = new User("李四" );
              User u3 = new User("王二" );
              List<User> l = new ArrayList<User>();
              l.add(u1);
              l.add(u2);
              l.add(u3);
               Map vars = new HashMap();
               vars.put("users",l);
              String expression = "foo=(name in users);foo";
              Object obj = MVEL. eval(expression,vars );
              System. out.println(obj);

复杂示例:

			public class User {
                      private String name ;
                                 private Integer age ;
                      private Parent parent ;

                      public User(Parent parent) {
                      this.parent = parent;
                 }
                }
              User u1 = new User( new Parent("老大" ));
              User u2 = new User(new Parent("老二" ));
              User u3 = new User(new Parent("老三" ));
              List<User> l = new ArrayList<User>();
              l.add(u1);
              l.add(u2);
              l.add(u3);
               Map vars = new HashMap();
               vars.put( "users", l);
              String expression = "foo=(parent.name in users);foo" ;
              Object obj = MVEL. eval(expression, vars );
              System. out .println(obj);

投影可以支持嵌套投影,上面的脚本可以写成下面的形式:
foo=(name in (parent in users))

交集

我们可以根据投影这周方式获取交集,比如有一个User对象包含一个集合成员familyMembers,我们可以获取一个家庭成员姓名的集合:

familyMembers =(name in (familyMember in users))

过滤投影

MVEL提供通过if运算符构造的过滤条件来过滤投影,比如获取user集合中name 包含‘张’的用户,就可以使用过滤。
如下面的例子:

 			  User u1 = new User("张依依" );
              User u2 = new User("张尔尔" );
              User u3 = new User("老三" );
              List<User> l = new ArrayList<User>();
              l.add(u1);
              l.add(u2);
              l.add(u3);
               Map vars = new HashMap();
               vars.put("users", l);
              String expression = "($ in users if $.name contains '张')" ;
              Object obj = MVEL. eval(expression, vars );
              System. out.println(obj);

函数

函数定义

在MVEL中,定义函数用def或function关键字定义。
如:

def hello(){
     System.out.println("hello world");
}

function hello(){
     System.out.println("hello world");
}

参数与返回值

MVEL中的函数一样可以传参数,返回结果。如下面的函数:

def add(a,b){
     a+b;
}

add函数需要传两个参数 a 和b

因为MVEL遵循last-value-out原则,即输出最后值的原则,所以a+b的结果会被返回。也可以使用return关键字强制返回。

函数调用

函数在MVEL脚本文件中定义之后,在JAVA中的调用方法可以看下面的例子:
首先新建一个.el文件写MVEL脚本,test.el:

def add(a,b){
       a+b;
}  

Java代码如下

//获取脚本文件
                     File scriptFile = new File("src/com/mvel/test.el" );
                      VariableResolverFactory resolverFactory = new MapVariableResolverFactory();
                      //参数
                      Map map = new HashMap();
                      map.put("a", 11);
                      map.put("b", 12);
                     
                     MVEL. evalFile(scriptFile, ParserContext.create(), map);
                     Object obj = MVEL. eval("add(a,b);", map);

闭包

Lambda(匿名函数)

threshold = def (x) { x >= 10 ? x : 0 };
result = threshold(13);
System.out.println(result);

关于函数调用的其他内容

MVEL没有发现有自己的内置函数,比如其他的表达式语言如aviator中有获取日期的函数sysdate(),MVEL没有类似的东西。
但是发现MVEL可以调用JAVA中的一些类的方法,比如 Math的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

柳住

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

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

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

打赏作者

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

抵扣说明:

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

余额充值