在我们使用JPA时,构建 Specification 查询条件时重复代码过多,而且需要大量的无效代码。
/**
* 自动构建规范
*
* @param builder JapCriteriaBuilder
* @param entity 实体
* @param 实体类型
* @return Specification
*/
public JpaCriteriaBuilder autoBuilder(JpaCriteriaBuilder builder, @NotNull V entity, @NotNull Class clazz) {
if (Objects.isNull(entity)) {
throw new GlobalRuntimeException("实体不能为空");
}
List ignoreFields = List.of("serialVersionUID");
List fields = getDeclaredFields(clazz);
for (Field field : fields) {
if (field == null || Modifier.isStatic(field.getModifiers())) {
continue;
}
try {
field.setAccessible(Boolean.TRUE);
Object value = ReflectionUtils.getFieldValue(entity, field.getName());
if (StringUtils.isNullAndSpaceOrEmpty(value) || ignoreFields.contains(field.getName())) {
continue;
}
builder = builder.equal(field.getName(), value);
} catch (Exception e) {
LOG.error(e, "自动构建规范异常");
}
}
// 分页数据
String pageSize = "pageSize", pageIndex = "pageIndex";
Object value = ReflectionUtils.getFieldValue(entity, pageIndex);
if (StringUtils.isNotNullAndEmpty(value)) {
builder = builder.page(ConvertUtils.convertInt(value));
}
// 页码大小
value = ReflectionUtils.getFieldValue(entity, pageSize);
if (StringUtils.isNotNullAndEmpty(value)) {
builder = builder.size(ConvertUtils.convertInt(value));
}
// 返回结果
return builder;
}
/**
* 自动构建规范
*
* @param builder JapCriteriaBuilder
* @param entity 实体
* @param ignoreFields 对应字段
* @param groupFields 分组字段
* @param 实体类型
* @return Specification
*/
public JpaCriteriaBuilder autoBuilder(JpaCriteriaBuilder builder, @NotNull V entity, @NotNull Class clazz, List ignoreFields, List... groupFields) {
if (Objects.isNull(entity)) {
throw new GlobalRuntimeException("实体不能为空");
}
if (ignoreFields == null) {
ignoreFields = CollectUtils.toList();
}
if (groupFields == null) {
groupFields = new List[IntegerConsts.ZERO];
}
if (CollectUtils.isEmpty(ignoreFields) || CollectUtils.isEmpty(groupFields)) {
return autoBuilder(builder, entity, clazz);
}
// 分页数据
String pageSize = "pageSize", pageIndex = "pageIndex";
Integer size = null, index = null;
Object intValue = ReflectionUtils.getFieldValue(entity, pageIndex);
if (StringUtils.isNotNullAndEmpty(intValue)) {
index = ConvertUtils.convertInt(intValue);
}
// 页码大小
intValue = ReflectionUtils.getFieldValue(entity, pageSize);
if (StringUtils.isNotNullAndEmpty(intValue)) {
size = ConvertUtils.convertInt(intValue);
}
List fields = getDeclaredFields(clazz);
List> groupFieldsList = new ArrayList<>();
for (int i = IntegerConsts.ZERO; i < groupFields.length; i++) {
List groupField = groupFields[i];
List fieldList = fields.stream()
.filter(field -> groupField.contains(field.getName()))
.toList();
if (CollectUtils.isEmpty(fieldList)) {
continue;
}
JpaCriteriaBuilder criteria = CopyUtils.copyProperties(builder, JpaCriteriaBuilder.class);
assert criteria != null;
for (Field field : fieldList) {
if (field == null || Modifier.isStatic(field.getModifiers())) {
continue;
}
field.setAccessible(Boolean.TRUE);
String fieldName = field.getName();
if (ignoreFields.contains(fieldName)) {
continue;
}
Object value = ReflectionUtils.getFieldValue(entity, pageIndex);
if (StringUtils.isNullAndSpaceOrEmpty(value)) {
if (pageIndex.equals(field.getName())) {
index = ConvertUtils.convertInt(value);
} else if (pageSize.equals(field.getName())) {
size = ConvertUtils.convertInt(value);
} else {
criteria = criteria.equal(field.getName(), value);
}
}
}
groupFieldsList.add(criteria);
}
// 构建最终数据
JpaCriteriaBuilder result = builder.or(groupFieldsList.toArray(new JpaCriteriaBuilder[IntegerConsts.ZERO]));
if (index != null && size != null) {
result.page(index).size(size);
}
// 返回结果
return result;
}
/**
* 添加等值查询条件
*
* @param field 字段
* @param value 值
* @param 泛型
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder equal(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.equal(root.get(field), value)
);
}
return this;
}
/**
* 添加模糊查询条件
*
* @param field 字段
* @param value 值
* @param 泛型
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder like(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) -> {
String pattern = StringUtils.PERCENT + value + StringUtils.PERCENT;
return criteriaBuilder.like(root.get(field), pattern);
});
}
return this;
}
/**
* 添加in查询条件
*
* @param field 字段
* @param values 值
* @param 泛型
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder in(@NotNull String field, @NotNull List values) {
if (CollectUtils.isNotEmpty(values)) {
specification = specification.and((root, query, criteriaBuilder) ->
root.get(field).in(values)
);
}
return this;
}
/**
* 添加大于查询条件
*
* @param field 字段
* @param value 值
* @param 泛型
* @return JapCriteriaBuilder
*/
public > JpaCriteriaBuilder greaterThan(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.greaterThan(root.get(field), value)
);
}
return this;
}
/**
* 添加大于等于查询条件
*
* @param field 字段
* @param value 值
* @param 泛型
* @return JapCriteriaBuilder
*/
public > JpaCriteriaBuilder greaterThanOrEqualTo(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.greaterThanOrEqualTo(root.get(field), value)
);
}
return this;
}
/**
* 添加小于查询条件
*
* @param field 字段
* @param value 值
* @param 泛型
* @return JapCriteriaBuilder
*/
public > JpaCriteriaBuilder lessThan(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.lessThan(root.get(field), value)
);
}
return this;
}
/**
* 添加区间查询条件
*
* @param field 字段
* @param from 区间起始值
* @param to 区间结束值
* @param 泛型
* @return JapCriteriaBuilder
*/
public > JpaCriteriaBuilder between(@NotNull String field, @NotNull V from, V to) {
if (from != null && to != null) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.between(root.get(field), from, to)
);
}
return this;
}
/**
* 添加空查询条件
*
* @param field 字段
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder isNull(String field) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.isNull(root.get(field))
);
return this;
}
/**
* 添加非空查询条件
*
* @param field 字段
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder isNotNull(String field) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.isNotNull(root.get(field))
);
return this;
}
/**
* 添加关联查询条件
*
* @param joinField 关联字段
* @param field 字段
* @param value 值
* @param joinType 关联类型
* @param 关联实体类型
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder joinEqual(String joinField, @NotNull String field, @NotNull Object value, JoinType joinType) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) -> {
Join join = root.join(joinField, joinType);
return criteriaBuilder.equal(join.get(field), value);
});
}
return this;
}
/**
* 添加自定义查询条件
*
* @param condition 自定义查询条件
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder add(Function, Predicate> condition) {
specification = specification.and((root, query, criteriaBuilder) -> {
Predicate predicate = condition.apply(root);
return criteriaBuilder.and(predicate);
});
return this;
}
/**
* 或查询
*
* @param otherBuilder 其他查询条件
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder or(JpaCriteriaBuilder... otherBuilder) {
// 创建一个新的 Specification 来存储合并后的查询条件
Specification combinedSpecification = Specification.where(specification);
// 遍历所有传入的 JapCriteriaBuilder
for (JpaCriteriaBuilder builder : otherBuilder) {
combinedSpecification = combinedSpecification.or(builder.build());
}
// 更新当前的 specification 为合并后的结果
specification = combinedSpecification;
return this;
}
/**
* 页码
*
* @param page 页码
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder page(int page) {
this.pageNumber = page;
return this;
}
/**
* 每页大小
*
* @param size 每页大小
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder size(int size) {
this.pageSize = size;
return this;
}
/**
* 排序
*
* @param field 字段
* @param direction 排序方向
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder orderBy(@NotNull String field, @NotNull Sort.Direction direction) {
if (direction != null) {
rawSortList.add(Sort.Order.by(field).with(direction));
}
return this;
}
/**
* 构建分页查询条件
*
* @return Pageable
*/
public Pageable toPageable() {
if (CollectUtils.isEmpty(rawSortList)) {
throw new GlobalRuntimeException("分页查询必须指定排序条件");
}
return PageRequest.of(
Objects.requireNonNullElse(pageNumber, IntegerConsts.ZERO),
Objects.requireNonNullElse(pageSize, IntegerConsts.FIFTEEN),
Sort.by(rawSortList)
);
}
/**
* 构建查询条件
*
* @return Specification
*/
public Specification build() {
return (root, query, cb) -> {
// 应用排序条件
if (!rawSortList.isEmpty()) {
List orders = rawSortList.stream()
.map(sortOrder -> {
Path
// 查询条件
JpaCriteriaBuilder builder = JpaCriteriaBuilder.Builder();
builder = builder.autoBuilder(builder, license);
// 排序
builder = builder.orderBy(WikiLicenseDto.ADD_TIME, Sort.Direction.DESC);
// 分页
builder = builder .page(license.getPageIndex() - IntegerConsts.ONE)
.size(license.getPageSize());
// 查询分页数据
Page page = wikiLicenseRepository.findAll(builder.build(), builder.toPageable());
// 查询条件
JpaCriteriaBuilder builder = JpaCriteriaBuilder.Builder();
builder.equal(WikiLicenseDto.DELETED, IntegerConsts.ZERO);
builder.equal(WikiLicenseDto.STATUS, IntegerConsts.ONE);
JpaCriteriaBuilder builderKey = JpaCriteriaBuilder.Builder();
builderKey = builderKey.equal(WikiLicenseDto.KEY, license.getKey());
JpaCriteriaBuilder builderName = JpaCriteriaBuilder.Builder();
builderName = builderName.equal(WikiLicenseDto.NAME, license.getName());
// 添加或查询
builder = builder.or(builderKey, builderName);
// 查询数据
List licenseList = wikiLicenseRepository.findAll(builder.build());
更多使用或者有更好的方法欢迎连续博主,完整的代码可查看博主开源的框架:维基框架
Gitee:https://gitee.com/cdkjframework/wiki-framework
Github:https://github.com/cdkjframework/wiki-framework
若觉得博主的项目还不错,希望你能给博主 star及fork。如果有其他需要了解的内容请留言,看到后会及时回复。