1

ExpressionParserSpring 有能力通过(Collection Selection)返回一个集合的子集。

例如,想象一个简单的类:

public Customer {
  private String name;
  private boolean vip;
  private boolean conferenceAttendee;
}

如果我有一个List<Customer>以前设置为StandardEvaluationContext变量的集合:evalContext.setVariable("customerList", customers); 我可以通过“选择表达式”检索 vip 为真的所有客户的子集<variable>.?[<selectionExpression>]

List<Customer> vipCustomers = 
       (List<Customer>)new SpelExpressionParser()
            .parseExpression("#customerList.?[vip]")
            .getValue(evalContext);

是否可以在选择表达式中作为联合 (vip || ConferenceAttendee) 或交集 (vip && ConferenceAttendee) 执行相同的逻辑,而无需调用evalContext.setVariable("customerList", vipCustomers)中间列表并执行第二个 parseExpression?

与此类似的东西:

// This doesn't work...
List<Customer> vipCustomers = 
       (List<Customer>)new SpelExpressionParser()
            .parseExpression("#customerList.?[vip || conferenceAttendee]")
            .getValue(evalContext);

我特别想了解我可以将哪些有效的选择表达式传递给 SpelExpressionParser 的 parseExpression,而不是其他类似的解决方案。

4

1 回答 1

3

你非常非常亲近。您可以使用 Spring 表达式语言中的OR 和 AND 逻辑运算符:

    customerList.add(new Customer("jim", true, false));
    customerList.add(new Customer("bob", false, true));
    customerList.add(new Customer("rob", true, true));

    List<Customer> vipCustomers =
            (List<Customer>)new SpelExpressionParser()
                    .parseExpression("#customerList.?[vip]")
                    .getValue(evalContext);
    System.out.println(vipCustomers);
    //[Customer{name='jim'}, Customer{name='rob'}]

    List<Customer> vipANDConfAttendeesCustomers =
            (List<Customer>)new SpelExpressionParser()
                    .parseExpression("#customerList.?[vip and conferenceAttendee]")
                    .getValue(evalContext);
    System.out.println(vipANDConfAttendeesCustomers);
    //[Customer{name='rob'}]        

    List<Customer> vipORConfAttendeesCustomers =
            (List<Customer>)new SpelExpressionParser()
                    .parseExpression("#customerList.?[vip or conferenceAttendee]")
                    .getValue(evalContext);
    System.out.println(vipORConfAttendeesCustomers);
    //[Customer{name='jim'}, Customer{name='bob'}, Customer{name='rob'}]        

编辑前 - 可以忽略,因为它不是真正的答案,而是建议

请允许我介绍另一种没有 Spring 的方法,它具有更多的功能感,并且可以很好地扩展,为复杂和/或交互提供更多的表现力。以下解决方案使用Guava 的谓词来表达查询需求的主要构建块:

    Predicate<Customer> isVip = new Predicate<Customer>() {
        @Override
        public boolean apply(Customer customer) {
            return customer.isVip();
        }
    };

    Predicate<Customer> isConferenceAttendee = new Predicate<Customer>() {
        @Override
        public boolean apply(Customer customer) {
            return customer.isConferenceAttendee();
        }
    };

然后将它们组合成更复杂的查询,涉及Predicates.andPredicates.or ,通过Iterables.filter过滤 Collection (一种迭代它们的功能方式):

Iterables.filter(customers, isVip);
Iterables.filter(customers, Predicates.and(isVip,isConferenceAttendee));
Iterables.filter(customers, Predicates.or(isVip,isConferenceAttendee));

基于名称是唯一标识客户的假设,带有一些自动生成的 equals/hashcode/toString 方法的完整工作示例:

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.List;

public class GuavaTest {

    public static void main(String ...args){

        Predicate<Customer> isVip = new Predicate<Customer>() {
            @Override
            public boolean apply(Customer customer) {
                return customer.isVip();
            }
        };

        Predicate<Customer> isConferenceAttendee = new Predicate<Customer>() {
            @Override
            public boolean apply(Customer customer) {
                return customer.isConferenceAttendee();
            }
        };

        List<Customer> customers = Lists.newArrayList();

        customers.add(new Customer("jim",true,false));
        customers.add(new Customer("bob",false,true));
        customers.add(new Customer("rob",true,true));

        System.out.println("Vips:\t"+Iterables.filter(customers, isVip));
        System.out.println("Vips && ConfAttendees:\t"+Iterables.filter(customers, Predicates.and(isVip,isConferenceAttendee)));
        System.out.print("Vips || ConfAttendees:\t"+Iterables.filter(customers, Predicates.or(isVip,isConferenceAttendee)));
    }
}

class Customer {
 private String name;
 private boolean vip;
 private boolean conferenceAttendee;

    Customer(String name, boolean vip, boolean conferenceAttendee) {
        this.name = name;
        this.vip = vip;
        this.conferenceAttendee = conferenceAttendee;
    }

    public String getName() {
        return name;
    }

    public boolean isVip() {
        return vip;
    }

    public boolean isConferenceAttendee() {
        return conferenceAttendee;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Customer customer = (Customer) o;

        if (name != null ? !name.equals(customer.name) : customer.name != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return name != null ? name.hashCode() : 0;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                '}';
    }
}
于 2012-11-15T00:20:26.767 回答