com.feingto.cloud.data.jpa.specification.bean.Condition Maven / Gradle / Ivy
package com.feingto.cloud.data.jpa.specification.bean;
import com.feingto.cloud.kit.reflection.BeanConvertKit;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.util.WebUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.feingto.cloud.data.jpa.specification.bean.RuleGroup.UnionOperator.AND;
import static com.feingto.cloud.data.jpa.specification.bean.RuleGroup.UnionOperator.OR;
/**
* 查询参数过滤规则
*
* JSON格式:
* {"conditions":[{"groups":[{"rules":[{"property":"id.sn","op":"EQ","value":"001"},{"property":"enabled","op":"EQ","value":"ENABLED"}],"op":"and"}],"rules":[{"property":"type","op":"EQ","value":1}],"op":"or"}],"rules":[{"property":"status","op":"EQ","value":1}],"op":"and"}
*
* @author longfei
*/
@Data
@Accessors(chain = true)
public class Condition implements Serializable {
private static final long serialVersionUID = 4950188917289587920L;
/**
* 查询参数前缀
*/
private static final String SEARCH_PREFIX = "search_";
/**
* 查询参数分隔符
*/
private static final String SEARCH_DELIMITER = "_";
/**
* 全部运算符
*/
private static final List OPERATORS = Stream.of(Rule.Operator.values())
.map(Enum::name)
.collect(Collectors.toList());
private List conditions = new ArrayList<>();
private List groups = new ArrayList<>();
private List rules = new ArrayList<>();
/**
* 操作符(AND 或者 OR)
*/
private RuleGroup.UnionOperator op;
/**
* group by
* 此属性不支持 Oracle, Oracle select 出来的字段必须在 group by 后边出现.
*
* Oracle group by @Query 使用说明:
* 返回单属性集合 List: @Query("select e.setProperty from Entity e group by e.setProperty")
* 返回多属性集合 List: @Query("select new Entity(e.property1, e.property2) from Entity e group by e.property1, e.property2"), 必须要有public Entity(String property1, String property2)构造函数.
*/
private List groupByNames = new ArrayList<>();
/**
* 是否去重
*/
private boolean distinct;
/**
* 备注
*/
private String remark;
public static Condition build() {
return new Condition();
}
/**
* request参数转换为查询规则
* 参数名示例:
* search_EQ_status
* search_LIKE_username_OR_realName
* search_NEQ_groups.id_OR_ISNULL_groups.id
*/
public static Condition build(HttpServletRequest request) {
Condition condition = Condition.build();
Optional.ofNullable(request)
.ifPresent(req -> WebUtils.getParametersStartingWith(req, SEARCH_PREFIX).entrySet().stream()
.filter(entry -> !ObjectUtils.isEmpty(entry.getValue()))
.forEach(entry -> parseParameter(condition, entry.getKey(), (String) entry.getValue())));
return condition;
}
/**
* 解析参数, 提取 AND/OR 并转换为查询规则
*
* @param condition Condition
* @param paramName 参数名
* @param paramValue 参数值
*/
private static void parseParameter(Condition condition, String paramName, String paramValue) {
String[] names = StringUtils.splitByWholeSeparator(paramName, SEARCH_DELIMITER);
if (names.length == 0) {
return;
}
List operators = new ArrayList<>();
RuleGroup.UnionOperator unionOperator = null;
int i = 0;
for (String name : names) {
if (OPERATORS.contains(name)) {
operators.add(Rule.Operator.valueOf(name));
} else if (OR.name().equals(name) || AND.name().equals(name)) {
unionOperator = RuleGroup.UnionOperator.valueOf(name);
} else if (CollectionUtils.isNotEmpty(operators)) {
condition.getRules().add(new Rule()
.setProperty(name)
.setOp(i < operators.size()
? operators.get(i)
: operators.get(operators.size() - 1))
.setValue(paramValue.contains(",")
? Arrays.asList(paramValue.split(","))
: paramValue.trim()));
i++;
}
}
if (OR.equals(unionOperator)) {
condition.or();
} else {
condition.and();
}
}
public Condition eq(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.EQ).setValue(value));
return this;
}
public Condition ne(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.NEQ).setValue(value));
return this;
}
public Condition slike(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.SLIKE).setValue(value));
return this;
}
public Condition elike(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.ELIKE).setValue(value));
return this;
}
public Condition like(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.LIKE).setValue(value));
return this;
}
public Condition gt(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.GT).setValue(value));
return this;
}
public Condition lt(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.LT).setValue(value));
return this;
}
public Condition gte(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.GTE).setValue(value));
return this;
}
public Condition lte(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.LTE).setValue(value));
return this;
}
public Condition between(String property, Object lo, Object hi) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.GT).setValue(lo));
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.LT).setValue(hi));
return this;
}
public Condition in(String property, Collection> values) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.IN).setValue(values));
return this;
}
public Condition notIn(String property, Collection> values) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.NIN).setValue(values));
return this;
}
public Condition isEmpty(String property) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.ISEMPTY));
return this;
}
public Condition isNotEmpty(String property) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.ISNOTEMPTY));
return this;
}
public Condition isNull(String property) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.ISNULL));
return this;
}
public Condition isNotNull(String property) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.ISNOTNULL));
return this;
}
public Condition isBoolean(String property, Object value) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.ISBOOLEAN).setValue(value));
return this;
}
public Condition isTrue(String property) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.ISTRUE));
return this;
}
public Condition isFalse(String property) {
this.rules.add(new Rule().setProperty(property).setOp(Rule.Operator.ISFALSE));
return this;
}
public Condition and() {
return this.setRule(AND);
}
public Condition or() {
return this.setRule(OR);
}
public Condition AND() {
return this.setRuleGroup(AND);
}
public Condition OR() {
return this.setRuleGroup(OR);
}
public Condition setRule(RuleGroup.UnionOperator op) {
if (CollectionUtils.isNotEmpty(this.rules)) {
this.groups.add(new RuleGroup()
.setRules(BeanConvertKit.convert(this.rules, Rule.class))
.setOp(op));
this.rules.clear();
}
return this;
}
public Condition setRuleGroup(RuleGroup.UnionOperator op) {
if (CollectionUtils.isNotEmpty(this.groups)) {
this.conditions.add(new Condition()
.setGroups(BeanConvertKit.convert(this.groups, RuleGroup.class))
.setRules(BeanConvertKit.convert(this.rules, Rule.class))
.setOp(op));
this.groups.clear();
this.rules.clear();
} else {
this.op(op);
}
return this;
}
public Condition op(RuleGroup.UnionOperator operator) {
this.op = operator;
return this;
}
public Condition distinct() {
this.distinct = true;
return this;
}
public Condition groupBy(String property) {
this.groupByNames.add(property);
return this;
}
}