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
操作符号 | 描述 | 示例 |
---|---|---|
比较符 | ||
eq | Equal | city eq ‘Redmond’ |
ne | Not equal | city ne ‘London’ |
gt | Greater than | price gt 20 |
ge | Greater than or equal | price ge 10 |
lt | Less than | price lt 20 |
le | Less than or equal | price le 100 |
逻辑符 | ||
and | Logical and | price le 200 and price gt 3.5 |
or | Logical or | price le 3.5 or price gt 200 |
not | Logical negation | not 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#的相关文档,您可以移步
但今天的重点是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 动态查询的主要内容,如果未能解决你的问题,请参考以下文章