如何创建通用mvel表达式

rjee0c15  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(377)

我正在为java对象编写通用mvel表达式。所以为了理解目的,我举了一个例子。

class Student {

   String name;

   String rollNo;

   List<Course> courses;
}

class Course {

   String courseName;

   String facultyName;

   String fee;

   String classRoom;
}

我可以写mvel表达式,如果我的查询是:检查一个学生是否给出了name和rollno

MVEL.eval(" name == 'XYZ' && rollNo == '3456' ", Student)

但如果问题是:检查一个学生是否在同一个教室参加了所有课程?

MVEL.eval(" courses[0].classRoom == 'A' ", Student);

但这只检查一门课的教室。但我想检查一个学生的所有课程是否都发生在a教室。我找不到任何资源来解决这个问题。我是mvel的新手。如果你有任何疑问,请问我。
谢谢您

eagi6jfj

eagi6jfj1#

要做到这一点需要几个步骤—您将需要使用mvel变量及其 foreach 接线员。
方法如下:

import org.mvel2.MVEL;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

public class App {
    public static void main(String[] args) {

        List<Course> courses = new ArrayList<>();
        courses.add(new Course("Math", "123"));
        courses.add(new Course("Physics", "123"));
        courses.add(new Course("Chemistry", "123"));

        Student student = new Student("XYZ", "3456", courses);

        // Check If a student has given name and rollNo:
        boolean b1 = MVEL.eval(" name == 'XYZ' && rollNo == '3456' ", student, Boolean.class);
        boolean b2 = MVEL.eval(" name == 'XYP' && rollNo == '3456' ", student, Boolean.class);
        //System.out.println(b1);
        //System.out.println(b2);

        // Check If a student attends all the courses in the same classroom:
        boolean allClassesInSameRoom = true;
        String prevRoom = null;

        Map vars = new HashMap();
        vars.put( "sameRoom", allClassesInSameRoom );
        vars.put( "prevRoom", prevRoom );

        String expression = String.join("\n", 
                "sameRoom = true;",
                "prevRoom = null;",
                "foreach (course : courses) {",
                "  if (sameRoom == true && prevRoom != null && course.classRoom != prevRoom) {",
                "    sameRoom = false;",
                "  }",
                "  prevRoom = course.classRoom;",
                "}",
                "sameRoom");

        allClassesInSameRoom = MVEL.eval(expression, student, vars, Boolean.class);

        System.out.println(allClassesInSameRoom);

    }

}

首先,我们定义两个java变量,这是mvel脚本所需要的。它们被传递给mvel eval 通过javaMap的操作员:

boolean allClassesInSameRoom = true;
String prevRoom = null;

Map<String, Object> vars = new HashMap<>();
vars.put( "sameRoom", allClassesInSameRoom );
vars.put( "prevRoom", prevRoom );

然后我们构建一个包含我们需要使用的mvel脚本的字符串:

String expression = String.join("\n", 
        "sameRoom = true;",
        "prevRoom = null;",
        "foreach (course : courses) {",
        "  if (sameRoom == true && prevRoom != null && course.classRoom != prevRoom) {",
        "    sameRoom = false;",
        "  }",
        "  prevRoom = course.classRoom;",
        "}",
        "sameRoom");

最后一行返回 sameRoom 变量。
这个 eval 语句集合我们需要的项:

allClassesInSameRoom = MVEL.eval(expression, student, vars, Boolean.class);

请注意 Course 类需要定义为 public :

public class Course {

    private final String courseName;
    private final String classRoom;

    public Course (String courseName, String classRoom) {
        this.courseName = courseName;
        this.classRoom = classRoom;
    }

    public String getCourseName() {
        return courseName;
    }

    public String getClassRoom() {
        return classRoom;
    }

}

可以将mvel脚本创建为模板,我认为这有助于避免像我在这里所做的那样,逐行构建java字符串的复杂过程。
这些加起来可能比简单地检查 student 对象而不使用mvel。但是mvel也支持函数和lambda表达式,所以可能有一些方法可以简化我的方法并简化mvel脚本。
更新
下面是一个更简洁的示例:

Map<String, String> rooms = new HashMap<>();
Map<String, Object> vars2 = new HashMap<>();
vars2.put( "rooms", rooms );

String expression2 = String.join("\n", 
        "foreach (course : courses) {",
        "  rooms.put(course.classRoom, course.classRoom);",
        "}",
        "(rooms.size() == 1) ? true : false;");

allClassesInSameRoom = MVEL.eval(expression2, student, vars2, Boolean.class);
System.out.println(allClassesInSameRoom);

在本例中,脚本将每个房间名称添加到Map中。重复的房间名称将具有相同的Map键,因此不会增加Map的大小。如果我们最终得到的Map只包含一个条目,那就意味着只有一个房间可供所有课程使用。
或者,您可以使用java(java 8或更高版本)计算学生课程列表中不同房间名称的数量:

import static java.util.stream.Collectors.toList;

...

long roomsCount = courses.stream()
        .map(Course::getClassRoom)    // get the room name from each course
        .collect(toList())            // build a list of these room names
        .stream().distinct().count(); // count the number of unique room names

这是一行代码。但由于您的目标是探索和理解mvel,所以这只是一个旁注。

相关问题