Java lambda 动态查询

Posted bosaidongmomo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java lambda 动态查询相关的知识,希望对你有一定的参考价值。

Java lambda 动态查询

提要

问题描述

我在 微软 REST API指南 中 了解到, 微软设计数据查询是按照如下方式来获取数据的。

示例:返回所有价格低于 $10.00 的产品

GET https://api.contoso.com/v1.0/products?$filter=price lt 10.00
操作符号描述示例
比较符
eqEqualcity eq ‘Redmond’
neNot equalcity ne ‘London’
gtGreater thanprice gt 20
geGreater than or equalprice ge 10
ltLess thanprice lt 20
leLess than or equalprice le 100
逻辑符
andLogical andprice le 200 and price gt 3.5
orLogical orprice le 3.5 or price gt 200
notLogical negationnot price le 3.5
组符号
( )Precedence grouping(priority eq 1 or city eq ‘Redmond’) and price gt 100

示例:名称等于“牛奶”的所有产品

GET https://api.contoso.com/v1.0/products?$filter=name eq 'Milk' 

示例:名称不等于“牛奶”的所有产品

http GET https://api.contoso.com/v1.0/products?$filter=name ne 'Milk

示例:名称为“牛奶”且价格低于 2.55 的所有产品:

GET https://api.contoso.com/v1.0/products?$filter=name eq 'Milk' and price lt 2.55

示例:所有名称为“牛奶”或价格低于 2.55 的产品:

http GET https://api.contoso.com/v1.0/products?$filter=name eq 'Milk'  or price lt 2.55

示例 :所有名称为“牛奶”或“鸡蛋”且价格低于 2.55 的产品:

http GET https://api.contoso.com/v1.0/products?$filter=(name eq 'Milk' or name eq 'Eggs') and price lt 2.55 

我在MSDN了解到
假设你有多个实体类型:

record Person(string LastName, string FirstName, DateTime DateOfBirth);
record Car(string Model, int Year);

对于这些实体类型中的任何一个,你都需要筛选并仅返回那些在其某个 string 字段内具有给定文本的实体。 对于 Person,你希望搜索 FirstName 和 LastName 属性:

string term = /* ... */;
var personsQry = new List<Person>()
    .AsQueryable()
    .Where(x => x.FirstName.Contains(term) || x.LastName.Contains(term));

但对于 Car,你希望仅搜索 Model 属性:

string term = /* ... */;
var carsQry = new List<Car>()
    .AsQueryable()
    .Where(x => x.Model.Contains(term));

尽管可以为 IQueryable 编写一个自定义函数,并为 IQueryable 编写另一个自定义函数。

关于C#的相关文档,您可以移步

C# 动态Linq 建立模糊查询通用工具类

但今天的重点是Java.

适用场景

先决条件

java 8

由于该方法使用反射处理查询lambda表达式,所以检索效率肯定没有使用JDBC连接数据库快。

我相信应该没有 后端工程师 直接把十万条数据一次性的交给 前端工程师 吧。

准备工作

maven库

		<dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>

准备数据集

实体类

@Data
public class Product extends Model 
    public Product(String name, BigDecimal price, Float fPrice, Double dPrice, Integer number) 
        this.name = name;
        this.price = price;
        this.fPrice = fPrice;
        this.dPrice = dPrice;
        this.number = number;

    
    private String name;
    private BigDecimal price;
    private Float fPrice;
    private Double dPrice;
    private Integer number;

    public String getName() 
        return name;
    

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

    public BigDecimal getPrice() 
        return price;
    

    public void setPrice(BigDecimal price) 
        this.price = price;
    

    public Float getfPrice() 
        return fPrice;
    

    public void setfPrice(Float fPrice) 
        this.fPrice = fPrice;
    

    public void setdPrice(Double dPrice) 
        this.dPrice = dPrice;
    

    public Integer getNumber() 
        return number;
    

    public void setNumber(Integer number) 
        this.number = number;
    

    public Double getdPrice() 
        return dPrice;
    

模拟获取方法

public List<Product> getProduct()
        List<Product> list = new ArrayList<>();

            list.add(new Product("水壶", BigDecimal.valueOf(8D), 5F, 9D, 3) 
            );
            list.add(new Product("电冰箱", BigDecimal.valueOf(1D), 4F, 10D, 3) 
            );
            list.add(new Product("空调", BigDecimal.valueOf(3D), 3F, 7D, 11) 
            );
            list.add(new Product("电热毯", BigDecimal.valueOf(4D), 2F, 8D, 77) 
            );
            list.add(new Product("暖气片", BigDecimal.valueOf(5D), 1F, 5D, 8) 
            );
        return list;
    

编写lambda表达式

		List<Product> products =  getProduct();
        Predicate<Product> isBottle = std -> "水壶".equals(std.getName());
        products.stream().filter(isBottle).collect(Collectors.toList());

细心的你一定能发现,这里的表达式可以乱写

products.stream().filter(isBottle.or(isBottle)).collect(Collectors.toList());

搭建框架

查询参数类

@Data
public class FilterParam 
    private String field;
    private String value;

封装表达式函数


public class FilterUtils<T> 
    // 转发类
    public List<T> filter(Predicate<T> predicate, List<T> list) 
        return list.stream().filter(predicate).collect(Collectors.toList());
    
    public Predicate<T> containsFilter(FilterParam param)
            return std -> 
                try 
                    return BeanUtils.getProperty(std,param.getField()).contains(param.getValue());
                 catch (IllegalAccessException e) 
                    e.printStackTrace();
                 catch (InvocationTargetException e) 
                    e.printStackTrace();
                 catch (NoSuchMethodException e) 
                    e.printStackTrace();
                
                return true;
            ;
    
    public Predicate<T> equalFilter(FilterParam param)
        return std -> 
            try 
                return BeanUtils.getProperty(std,param.getField()).equals(param.getValue());
             catch (IllegalAccessException e) 
                e.printStackTrace();
             catch (InvocationTargetException e) 
                e.printStackTrace();
             catch (NoSuchMethodException e) 
                e.printStackTrace();
            
            return true;
        ;
    
    public Predicate<T> notEqualFilter(FilterParam param)
        return std -> 
            try 
                return !BeanUtils.getProperty(std,param.getField()).equals(param.getValue());
             catch (IllegalAccessException e) 
                e.printStackTrace();
             catch (InvocationTargetException e) 
                e.printStackTrace();
             catch (NoSuchMethodException e) 
                e.printStackTrace();
            
            return true;
        ;
    
    public Predicate<T> greatThanFilter(FilterParam param)
        return std -> 
            try 
                BigDecimal field = new BigDecimal(BeanUtils.getProperty(std, param.getField()));
                BigDecimal value = new BigDecimal(param.getValue());
                return field.compareTo(value) == 1 ;
             catch (IllegalAccessException e) 
                e.printStackTrace();
             catch (InvocationTargetException e) 
                e.printStackTrace();
             catch (NoSuchMethodException e) 
                e.printStackTrace();
            
            return true;
        ;
    
    public Predicate<T> greatThanOrEqualFilter(FilterParam param)
        return std -> 
            try 
                BigDecimal field = new BigDecimal(BeanUtils.getProperty(std, param.getField()));
                BigDecimal value = new BigDecimal(param.getValue());
                return field.compareTo(value) == 1 || field.compareTo(value) == 0 ;
             catch (IllegalAccessException e) 
                e.printStackTrace();
             catch (InvocationTargetException e) 
                e.printStackTrace();
             catch (NoSuchMethodException e) 
                e.printStackTrace();
            
            return true;
        ;
    
    public Predicate<T> lessThanFilter(FilterParam param)
        return std -> 
            try 
                BigDecimal field = new BigDecimal(BeanUtils.getProperty(std, param.getField()));
                BigDecimal value = new BigDecimal(param.getValue());
                return field.compareTo(value) == -1 ;
             catch (IllegalAccessException e) 
                e.printStackTrace();
             catch (InvocationTargetException e) 
                e.printStackTrace();
             catch (NoSuchMethodException e) 
                e.printStackTrace();
            
            return true;
        ;
    
    public Predicate<T> lessThanOrEqualFilter(FilterParam param)
        return std -> 
            try 
                BigDecimal field = new BigDecimal(BeanUtils.getProperty(std, param.getField()));
                BigDecimal value = new BigDecimal(param.getValue());
                return field.compareTo(value) == -1 ||  field.compareTo(value) == 0;
             catch (IllegalAccessException e) 
                e.printStackTrace();
             catch (InvocationTargetException e) 
                e.printStackTrace();
             catch (NoSuchMethodException e) 
                e.printStackTrace();
            
            return true;
        ;
    

如何动态描述where语句?

name eq '暖气片' | ((name eq '水壶' & name eq '电冰箱') | name eq '电热毯') | name eq '水壶'

数据结构-栈

来点代码

public class QueryUtils<T> 

    private static Logger logger =
            LoggerFactory.getLogger(QueryUtils.class);
    FilterUtils<T> filterUtils = new FilterUtils<>();
    public List<T> getQuery(List<T> list,String queryParam)
        // 表达式 栈
        Stack<Predicate<T>> expressions = new Stack<Predicate<T>>();
        // 运算符 栈
        Stack<Character> stack = new Stack<>();
       
        StringBuilder express = new StringBuilder();
        queryParam =  queryParam.replaceAll(" and "," & ").replaceAll(" or "," | ");

        StringBuilder query = new StringBuilder(queryParam);
        do
            // 如果字符头部有 (
            if(query.charAt(0)=='(')
                stack.push('(');
                query.deleteCharAt(0);
            
            // 否则 读取字符串
            else
                // 如果读取到 | 或者 &
                // 那么 把运算符 和 表达式 如栈
                // 遇到运算符 |
                if(query.charAt(0) == 以上是关于Java lambda 动态查询的主要内容,如果未能解决你的问题,请参考以下文章

匠心小镇·随饮智能电热水瓶,凭什么颠覆“家庭饮水”场景?!

Java lambda 动态查询

Java lambda 动态查询

Java lambda 动态查询

动态构建Lambda表达式实现EF动态查询

Lambda表达式动态组装查询条件