网站建设录哪个科目,图片网站怎么做排名,搜狗推广找谁,昆明专业网站建设公司在实际工作中#xff0c;有哪些场景会用到自定义 Repository 呢#xff0c;这里列出几种实际在工作中的应用案例。
1. 逻辑删除场景
可以用到上面说的两种实现方式#xff0c;如果有框架级别的全局自定义 Respository 那就在全局实现里面覆盖默认 remove 方法#xff0c;…在实际工作中有哪些场景会用到自定义 Repository 呢这里列出几种实际在工作中的应用案例。
1. 逻辑删除场景
可以用到上面说的两种实现方式如果有框架级别的全局自定义 Respository 那就在全局实现里面覆盖默认 remove 方法这样就会统一全部只能使用逻辑删除。但是一般是自定义一个特殊的删除Respository让大家去根据不同的domain业务逻辑去选择使用此接口即可。
2. 当有业务场景要覆盖 SimpleJpaRepository 默认实现的时候
这种一般是具体情况具体分析的一般实现特殊化的自定义 Respository 即可。
3. UUID 与 ID 的情况
经常在实际生产中会有这样的场景对外暴露的是 UUID 查询方法而对内呢暴露的是 Long 类型的 ID这时候我们就可以自定义一个 FindByIDOrUUID 的底层实现方法在自定义的 Respository 接口里面。
4. 使用 Querydsl
Spring Data JPA 里面还帮我们做了 QuerydslJpaRepository 用来支持 Querydsl 的查询方法当我们引入 Querydsl 的时候 Spring 就会自动帮我们把 SimpleJpaRepository 的实现切换到 QuerydslJpaRepository 的实现。
5. 动态查询条件
由于 Data JPA 里面的 query method 或者 query 注解不支持动态查询条件正常情况下将动态条件写在 manager 或者 service 里面。这个时候如果是针对资源的操作并且和业务无关的查询的时候可以放在自定义 Repository 里面有个缺点就是不能使用 SimpleJpaRepository里面的很多优秀的默认是实现方法在实际工作中还是放在 service 和 manager 中多一些只是给大家举个例子知道有这么回事就行。实例如下
//我们假设要根据条件动态查询订单
public interface OrderRepositoryCustom {PageOrder findAllByCriteria(OrderCriteria criteria); // 定义一个订单的定制化Repository查询方法当然实际生产过程中这里面可能不止一个方法。
}public class OrderRepositoryImpl implements OrderRepositoryCustom { PersistenceContextEntityManager entityManager; /*** 一个动态条件的查询方法*/public ListOrder findAllByCriteria(OrderCriteria criteria) {// 查询条件列表final ListString andConditions new ArrayListString();final MapString, Object bindParameters new HashMapString, Object();// 动态绑定参数和要查询的条件if (criteria.getId() ! null) {andConditions.add(o.id :id);bindParameters.put(id, criteria.getId());}if (!CollectionUtils.isEmpty(criteria.getStatusCodes())) {andConditions.add(o.status.code IN :statusCodes);bindParameters.put(statusCodes, criteria.getStatusCodes());}if (andConditions.isEmpty()) {return Collections.emptyList();}// 动态创建queryfinal StringBuilder queryString new StringBuilder();queryString.append(SELECT o FROM Order o);// 动态拼装条件IteratorString andConditionsIt andConditions.iterator();if (andConditionsIt.hasNext()) {queryString.append( WHERE ).append(andConditionsIt.next());}while (andConditionsIt.hasNext()) {queryString.append( AND ).append(andConditionsIt.next());}// 添加排序queryString.append( ORDER BY o.id);// 创建 typed query.final TypedQueryOrder findQuery entityManager.createQuery(queryString.toString(), Order.class);// 绑定参数for (Map.EntryString, Object bindParameter : bindParameters.entrySet()) {findQuery.setParameter(bindParameter.getKey(), bindParameter.getValue());}//返回查询结果。return findQuery.getResultList();}
}
//实际中此种就比较少用了大家知道有这么回事真是遇到特殊场景必须要用了可以用此方法实现。
6. 扩展 JpaSpecificationExecutor 使其更加优雅
当我们动态查询的时候经常会出现下面的代码逻辑写起来老是感觉有点不是特别优雅且有点重复的感觉
PageRequest pr new PageRequest(page - 1, rows, Direction.DESC, id);Page pageData memberDao.findAll(new Specification() {Overridepublic Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {ListPredicate predicates new ArrayList();if (isNotEmpty(userName)) {predicates.add(cb.like(root.get(userName), % userName %));}if (isNotEmpty(realName)) {predicates.add(cb.like(root.get(realName), % realName %));}if (isNotEmpty(telephone)) {predicates.add(cb.equal(root.get(userName), telephone));}query.where(predicates.toArray(new Predicate[0]));return null;}}, pr);
使用了自定义的复杂查询我们可以做到如下效果
Page pageData userDao.findAll(new MySpecificationUser().and(Cnd.like(userName, userName),Cnd.like(realName, realName),Cnd.eq(telephone, telephone)
).asc(id), pr);
如果对 Spring MVC 比较熟悉的话可以更进一步把其查询提交和规则直接封装到 HandlerMethodArgumentResolver 里面把参数自动和规则匹配起来。
我们可以对如下代码进行参考感觉实现的还不错此段代码可以作参考只是实现的还有点不完整如下
/*** 扩展Specification* param T*/
public class MySpecificationT implements SpecificationT {/*** 属性分隔符*/private static final String PROPERTY_SEPARATOR .;/*** and条件组*/ListCnd andConditions new ArrayList();/*** or条件组*/ListCnd orConditions new ArrayList();/*** 排序条件组*/ListOrder orders new ArrayList();Overridepublic Predicate toPredicate(RootT root, CriteriaQuery? cq, CriteriaBuilder cb) {Predicate restrictions cb.and(getAndPredicates(root, cb));restrictions cb.and(restrictions, getOrPredicates(root, cb));cq.orderBy(getOrders(root, cb));return restrictions;}public MySpecification and(Cnd... conditions) {for (Cnd condition : conditions) {andConditions.add(condition);}return this;}public MySpecification or(CollectionCnd conditions) {orConditions.addAll(conditions);return this;}public MySpecification desc(String property) {this.orders.add(Order.desc(property));return this;}public MySpecification asc(String property) {this.orders.add(Order.asc(property));return this;}private Predicate getAndPredicates(RootT root, CriteriaBuilder cb) {Predicate restrictions cb.conjunction();for (Cnd condition : andConditions) {if (condition null) {continue;}Path? path this.getPath(root, condition.property);if (path null) {continue;}switch (condition.operator) {case eq:if (condition.value ! null) {if (String.class.isAssignableFrom(path.getJavaType()) condition.value instanceof String) {if (!((String) condition.value).isEmpty()) {restrictions cb.and(restrictions, cb.equal(path, condition.value));}} else {restrictions cb.and(restrictions, cb.equal(path, condition.value));}}break;case ge:if (Number.class.isAssignableFrom(path.getJavaType()) condition.value instanceof Number) {restrictions cb.and(restrictions, cb.ge((PathNumber) path, (Number) condition.value));}break;case gt:if (Number.class.isAssignableFrom(path.getJavaType()) condition.value instanceof Number) {restrictions cb.and(restrictions, cb.gt((PathNumber) path, (Number) condition.value));}break;case lt:if (Number.class.isAssignableFrom(path.getJavaType()) condition.value instanceof Number) {restrictions cb.and(restrictions, cb.lt((PathNumber) path, (Number) condition.value));}break;case ne:if (condition.value ! null) {if (String.class.isAssignableFrom(path.getJavaType()) condition.value instanceof String !((String) condition.value).isEmpty()) {restrictions cb.and(restrictions, cb.notEqual(path, condition.value));} else {restrictions cb.and(restrictions, cb.notEqual(path, condition.value));}}break;case isNotNull:restrictions cb.and(restrictions, path.isNotNull());break;}}return restrictions;}private Predicate getOrPredicates(RootT root, CriteriaBuilder cb) {// 相同的逻辑 Need TODOreturn null;}private Listjavax.persistence.criteria.Order getOrders(RootT root, CriteriaBuilder cb) {Listjavax.persistence.criteria.Order orderList new ArrayList();if (root null || CollectionUtils.isEmpty(orders)) {return orderList;}for (Order order : orders) {if (order null) {continue;}String property order.getProperty();Sort.Direction direction order.getDirection();Path? path this.getPath(root, property);if (path null || direction null) {continue;}switch (direction) {case ASC:orderList.add(cb.asc(path));break;case DESC:orderList.add(cb.desc(path));break;}}return orderList;}/*** 获取Path** param path Path* param propertyPath 属性路径* return Path*/private X PathX getPath(Path? path, String propertyPath) {if (path null || StringUtils.isEmpty(propertyPath)) {return (PathX) path;}String property StringUtils.substringBefore(propertyPath, PROPERTY_SEPARATOR);return getPath(path.get(property), StringUtils.substringAfter(propertyPath, PROPERTY_SEPARATOR));}/*** 条件*/public static class Cnd {Operator operator;String property;Object value;public Cnd(String property, Operator operator, Object value) {this.operator operator;this.property property;this.value value;}/*** 相等** param property* param value* return*/public static Cnd eq(String property, Object value) {return new Cnd(property, Operator.eq, value);}/*** 不相等** param property* param value* return*/public static Cnd ne(String property, Object value) {return new Cnd(property, Operator.ne, value);}}/*** 排序*/GetterSetterpublic static class Order {private String property;private Sort.Direction direction Sort.Direction.ASC;/*** 构造方法** param property 属性* param direction 方向*/public Order(String property, Sort.Direction direction) {this.property property;this.direction direction;}/*** 返回递增排序** param property 属性* return 递增排序*/public static Order asc(String property) {return new Order(property, Sort.Direction.ASC);}/*** 返回递减排序** param property 属性* return 递减排序*/public static Order desc(String property) {return new Order(property, Sort.Direction.DESC);}}/*** 运算符*/GetterSetterpublic enum Operator {/*** 等于*/eq( ),/*** 不等于*/ne( ! ),/*** 大于*/gt( ),/*** 小于*/lt( ),/*** 大于等于*/ge( ), /*** 不为Null*/isNotNull( is not NULL );Operator(String operator) {this.operator operator;}private String operator;}
}
7. 与之类似的解决方案还有 RSQL 的解决方案可以参考Git_Hub上的此开源项目。
RSQLRESTful Service Query Language是 Feed Item Query Language (FIQL) 的超集是一种 RESTful 服务的查询语言。这里我们使用 rsql-jpa 来实践它依赖 rsql-parser 来解析 RSQL 语法然后将解析后的 RSQL 转义到 JPA 的 Specification。
maven 的地址如下
dependencygroupIdcom.github.tennaito/groupIdartifactIdrsql-jpa/artifactIdversion2.0.2/version
/dependency
GitHub 文档地址详见这里。如果要立志做优秀的架构师Spring Data JPA 的实现还是非常好的包括开源的生态等也非常好。