Spring Boot Jpa封裝快速構建Specification、OrderBy、Pageable的查詢條件
?
1、簡介
在我們使用JPA時,構建 Specification 查詢條件時重復代碼過多,而且需要大量的無效代碼。
2、工具類提供的方法
2.1、自動構建規范
/** * 自動構建規范 * * @param builder JapCriteriaBuilder * @param entity 實體 * @param <V> 實體類型 * @return Specification */ public <V> JpaCriteriaBuilder<T> autoBuilder(JpaCriteriaBuilder<T> builder, @NotNull V entity, @NotNull Class<T> clazz) { if (Objects.isNull(entity)) { throw new GlobalRuntimeException("實體不能為空"); } List<String> ignoreFields = List.of("serialVersionUID"); List<Field> 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; }
![]()
2.2 分組或過慮字段構建規范
2.3 添加等值查詢條件
/**
* 添加等值查詢條件
*
* @param field 字段
* @param value 值
* @param <V> 泛型
* @return JapCriteriaBuilder
*/
public <V> JpaCriteriaBuilder<T> equal(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.equal(root.get(field), value)
);
}
return this;
}
2.4 添加模糊查詢條件
/**
* 添加模糊查詢條件
*
* @param field 字段
* @param value 值
* @param <V> 泛型
* @return JapCriteriaBuilder
*/
public <V> JpaCriteriaBuilder<T> 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;
}
2.5 添加 in 查詢條件
/**
* 添加in查詢條件
*
* @param field 字段
* @param values 值
* @param <V> 泛型
* @return JapCriteriaBuilder
*/
public <V> JpaCriteriaBuilder<T> in(@NotNull String field, @NotNull List<V> values) {
if (CollectUtils.isNotEmpty(values)) {
specification = specification.and((root, query, criteriaBuilder) ->
root.get(field).in(values)
);
}
return this;
}
2.6 添加大于查詢條件
/**
* 添加大于查詢條件
*
* @param field 字段
* @param value 值
* @param <V> 泛型
* @return JapCriteriaBuilder
*/
public <V extends Comparable<? super V>> JpaCriteriaBuilder<T> greaterThan(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.greaterThan(root.get(field), value)
);
}
return this;
}
2.7 添加大于等于查詢條件
/**
* 添加大于等于查詢條件
*
* @param field 字段
* @param value 值
* @param <V> 泛型
* @return JapCriteriaBuilder
*/
public <V extends Comparable<? super V>> JpaCriteriaBuilder<T> greaterThanOrEqualTo(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.greaterThanOrEqualTo(root.get(field), value)
);
}
return this;
}
2.8 添加小于查詢條件
/**
* 添加小于查詢條件
*
* @param field 字段
* @param value 值
* @param <V> 泛型
* @return JapCriteriaBuilder
*/
public <V extends Comparable<? super V>> JpaCriteriaBuilder<T> lessThan(@NotNull String field, @NotNull V value) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.lessThan(root.get(field), value)
);
}
return this;
}
2.9 添加區間查詢條件
/**
* 添加區間查詢條件
*
* @param field 字段
* @param from 區間起始值
* @param to 區間結束值
* @param <V> 泛型
* @return JapCriteriaBuilder
*/
public <V extends Comparable<? super V>> JpaCriteriaBuilder<T> 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;
}
2.10 添加空查詢條件
/**
* 添加空查詢條件
*
* @param field 字段
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder<T> isNull(String field) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.isNull(root.get(field))
);
return this;
}
2.11 添加非空查詢條件
/**
* 添加非空查詢條件
*
* @param field 字段
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder<T> isNotNull(String field) {
specification = specification.and((root, query, criteriaBuilder) ->
criteriaBuilder.isNotNull(root.get(field))
);
return this;
}
2.12 添加關聯查詢條件
/**
* 添加關聯查詢條件
*
* @param joinField 關聯字段
* @param field 字段
* @param value 值
* @param joinType 關聯類型
* @param <X> 關聯實體類型
* @return JapCriteriaBuilder
*/
public <X> JpaCriteriaBuilder<T> joinEqual(String joinField, @NotNull String field, @NotNull Object value, JoinType joinType) {
if (isValidValue(value)) {
specification = specification.and((root, query, criteriaBuilder) -> {
Join<T, X> join = root.join(joinField, joinType);
return criteriaBuilder.equal(join.get(field), value);
});
}
return this;
}
2.13 添加自定義查詢條件
/**
* 添加自定義查詢條件
*
* @param condition 自定義查詢條件
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder<T> add(Function<Root<T>, Predicate> condition) {
specification = specification.and((root, query, criteriaBuilder) -> {
Predicate predicate = condition.apply(root);
return criteriaBuilder.and(predicate);
});
return this;
}
2.14 或查詢
/**
* 或查詢
*
* @param otherBuilder 其他查詢條件
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder<T> or(JpaCriteriaBuilder<T>... otherBuilder) {
// 創建一個新的 Specification 來存儲合并后的查詢條件
Specification<T> combinedSpecification = Specification.where(specification);
// 遍歷所有傳入的 JapCriteriaBuilder
for (JpaCriteriaBuilder<T> builder : otherBuilder) {
combinedSpecification = combinedSpecification.or(builder.build());
}
// 更新當前的 specification 為合并后的結果
specification = combinedSpecification;
return this;
}
2.15 頁碼
/**
* 頁碼
*
* @param page 頁碼
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder<T> page(int page) {
this.pageNumber = page;
return this;
}
2.16 每頁大小
/**
* 每頁大小
*
* @param size 每頁大小
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder<T> size(int size) {
this.pageSize = size;
return this;
}
2.17 排序
/**
* 排序
*
* @param field 字段
* @param direction 排序方向
* @return JapCriteriaBuilder
*/
public JpaCriteriaBuilder<T> orderBy(@NotNull String field, @NotNull Sort.Direction direction) {
if (direction != null) {
rawSortList.add(Sort.Order.by(field).with(direction));
}
return this;
}
2.18 構建分頁查詢條件
/**
* 構建分頁查詢條件
*
* @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)
);
}
2.19 構建查詢條件
/**
* 構建查詢條件
*
* @return Specification
*/
public Specification<T> build() {
return (root, query, cb) -> {
// 應用排序條件
if (!rawSortList.isEmpty()) {
List<Order> orders = rawSortList.stream()
.map(sortOrder -> {
Path<Object> path = root.get(sortOrder.getProperty());
return sortOrder.getDirection().isAscending() ? cb.asc(path) : cb.desc(path);
})
.collect(Collectors.toList());
query.orderBy(orders);
}
// 生成查詢條件
return specification.toPredicate(root, query, cb);
};
}
3 使用示例
3.1 使用自動構建規范
// 查詢條件
JpaCriteriaBuilder<WikiLicenseEntity> 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<WikiLicenseEntity> page = wikiLicenseRepository.findAll(builder.build(), builder.toPageable());
3.2 自定義添加查詢條件
// 查詢條件
JpaCriteriaBuilder<WikiLicenseEntity> builder = JpaCriteriaBuilder.Builder();
builder.equal(WikiLicenseDto.DELETED, IntegerConsts.ZERO);
builder.equal(WikiLicenseDto.STATUS, IntegerConsts.ONE);
JpaCriteriaBuilder<WikiLicenseEntity> builderKey = JpaCriteriaBuilder.Builder();
builderKey = builderKey.equal(WikiLicenseDto.KEY, license.getKey());
JpaCriteriaBuilder<WikiLicenseEntity> builderName = JpaCriteriaBuilder.Builder();
builderName = builderName.equal(WikiLicenseDto.NAME, license.getName());
// 添加或查詢
builder = builder.or(builderKey, builderName);
// 查詢數據
List<WikiLicenseEntity> licenseList = wikiLicenseRepository.findAll(builder.build());
4 總結
更多使用或者有更好的方法歡迎連續博主,完整的代碼可查看博主開源的框架:維基框架
Gitee:https://gitee.com/cdkjframework/wiki-framework
Github:https://github.com/cdkjframework/wiki-framework
若覺得博主的項目還不錯,希望你能給博主 star及fork。如果有其他需要了解的內容請留言,看到后會及時回復。
?

浙公網安備 33010602011771號