本文主要研究一下PowerJob的QueryConvertUtils
tech/powerjob/server/persistence/QueryConvertUtils.java
public class QueryConvertUtils {
public static <T> Specification<T> toSpecification(PowerQuery powerQuery) {
return (Specification<T>) (root, query, cb) -> {
List<Predicate> predicates = Lists.newLinkedList();
Field[] fields = powerQuery.getClass().getDeclaredFields();
try {
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
Object fieldValue = field.get(powerQuery);
if (fieldValue == null) {
continue;
}
if (fieldName.endsWith(PowerQuery.EQUAL)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.EQUAL);
predicates.add(cb.equal(root.get(colName), fieldValue));
} else if (fieldName.endsWith(PowerQuery.NOT_EQUAL)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.NOT_EQUAL);
predicates.add(cb.notEqual(root.get(colName), fieldValue));
} else if (fieldName.endsWith(PowerQuery.LIKE)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.LIKE);
predicates.add(cb.like(root.get(colName), convertLikeParams(fieldValue)));
} else if (fieldName.endsWith(PowerQuery.NOT_LIKE)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.NOT_LIKE);
predicates.add(cb.notLike(root.get(colName), convertLikeParams(fieldValue)));
} else if (fieldName.endsWith(PowerQuery.LESS_THAN)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.LESS_THAN);
predicates.add(cb.lessThan(root.get(colName), (Comparable)fieldValue));
} else if (fieldName.endsWith(PowerQuery.GREATER_THAN)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.GREATER_THAN);
predicates.add(cb.greaterThan(root.get(colName), (Comparable)fieldValue));
} else if (fieldName.endsWith(PowerQuery.LESS_THAN_EQUAL)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.LESS_THAN_EQUAL);
predicates.add(cb.lessThanOrEqualTo(root.get(colName), (Comparable)fieldValue));
} else if (fieldName.endsWith(PowerQuery.GREATER_THAN_EQUAL)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.GREATER_THAN_EQUAL);
predicates.add(cb.greaterThanOrEqualTo(root.get(colName), (Comparable)fieldValue));
} else if (fieldName.endsWith(PowerQuery.IN)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.IN);
predicates.add(root.get(colName).in(convertInParams(fieldValue)));
} else if (fieldName.endsWith(PowerQuery.NOT_IN)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.NOT_IN);
predicates.add(cb.not(root.get(colName).in(convertInParams(fieldValue))));
} else if (fieldName.endsWith(PowerQuery.IS_NULL)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.IS_NULL);
predicates.add(cb.isNull(root.get(colName)));
} else if (fieldName.endsWith(PowerQuery.IS_NOT_NULL)) {
String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.IS_NOT_NULL);
predicates.add(cb.isNotNull(root.get(colName)));
}
}
} catch (Exception e) {
log.warn("[QueryConvertUtils] convert failed for query: {}", query, e);
throw new PowerJobException("convert query object failed, maybe you should redesign your query object!");
}
if (powerQuery.getAppIdEq() != null) {
predicates.add(cb.equal(root.get("appId"), powerQuery.getAppIdEq()));
}
return query.where(predicates.toArray(new Predicate[0])).getRestriction();
};
}
private static String convertLikeParams(Object o) {
String s = (String) o;
if (!s.startsWith("%")) {
s = "%" + s;
}
if (!s.endsWith("%")) {
s = s + "%";
}
return s;
}
private static Object[] convertInParams(Object o) {
// FastJSON, 永远滴神!
return JSONArray.parseArray(JSONArray.toJSONString(o)).toArray();
}
}
QueryConvertUtils提供了toSpecification静态方法,用于将PowerQuery转换为jpa的Specification
public abstract class PowerQuery {
public static String EQUAL = "Eq";
public static String NOT_EQUAL = "NotEq";
public static String LIKE = "Like";
public static String NOT_LIKE = "NotLike";
public static String LESS_THAN = "Lt";
public static String LESS_THAN_EQUAL = "LtEq";
public static String GREATER_THAN = "Gt";
public static String GREATER_THAN_EQUAL = "GtEq";
public static String IN = "In";
public static String NOT_IN = "NotIn";
public static String IS_NULL = "IsNull";
public static String IS_NOT_NULL = "IsNotNull";
private Long appIdEq;
}
PowerQuery是个抽象类,定义了一系列操作符
tech/powerjob/common/request/query/JobInfoQuery.java
@Getter
@Setter
@Accessors(chain = true)
public class JobInfoQuery extends PowerQuery {
private Long idEq;
private Long idLt;
private Long idGt;
private String jobNameEq;
private String jobNameLike;
private String jobDescriptionLike;
private String jobParamsLike;
private List<Integer> timeExpressionTypeIn;
private List<Integer> executeTypeIn;
private List<Integer> processorTypeIn;
private String processorInfoEq;
private String processorInfoLike;
private List<Integer> statusIn;
private Long nextTriggerTimeGt;
private Long nextTriggerTimeLt;
private String notifyUserIdsLike;
private Date gmtCreateLt;
private Date gmtCreateGt;
private Date gmtModifiedLt;
private Date gmtModifiedGt;
private Integer dispatchStrategyEq;
private String tagEq;
}
JobInfoQuery继承了PowerQuery,它根据要查询的字段及操作定义了诸如idEq,idLt,idGt的属性
tech/powerjob/server/core/instance/InstanceService.java
public List<InstanceInfoDTO> queryInstanceInfo(PowerQuery powerQuery) {
return instanceInfoRepository
.findAll(QueryConvertUtils.toSpecification(powerQuery))
.stream()
.map(InstanceService::directConvert)
.collect(Collectors.toList());
}
InstanceService的queryInstanceInfo方法使用QueryConvertUtils.toSpecification(powerQuery)将powerQuery转换为Specification,再利用JpaSpecificationExecutor的findAll(Specification)进行查询
QueryConvertUtils提供了toSpecification静态方法,用于将PowerQuery转换为jpa的Specification,其约定query的属性以字段名+操作符构成,toSpecification根据这个规则来解析并转换为Specification,之后就可以利用jpa进行查询。