jpa多条件查询,jpa 动态查询条件

  jpa多条件查询,jpa 动态查询条件

  

目录

JPAquerydsl多条件动态查询介绍querydsl看看源码SpringdatJPA和querydsl什么是SpringdatJPA?什么是QueryDSL?@Mapper实体-模型映射项目整体流程查询JPArepositoryImplejparepository写一个存储库继承jparepository后spring-data-jpa的相关语法

 

  00-1010我相信很多人在做订单管理的时候都会用到多条件搜索,比如查询A店订单状态为已支付,金额在100到200之间的已完成订单,这样的多条件。

  实现的方式有很多种,核心就是一个if和null判断。今天学了querydsl,下面详细复习一下。

  首先,效果图是我做的。我们主要看查询是如何实现的。

  00-1010首先,QueryDSL只是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查询。

  其次,Querydsl可以通过一套通用的查询API,为用户构建适合不同类型ORM框架或SQL的查询语句,也就是说,QueryDSL是基于各种ORM框架和SQL的通用查询框架。

  然后,在QueryDSL的帮助下,可以在任何支持的ORM框架或SQL平台上以通用API的方式构建查询。目前,QueryDSL支持的平台包括JPA、JDO、SQL、Java Collections、RDF、Lucene和Hibernate Search。

  开始开发 ,首先是pom依赖

  这里增加了两个关于querydsl的依赖,jpa和apt,版本一致。

  dependencygroupid com . querydsl/groupid artifactidquerydsl-JPA/artifactidVersion 4 . 2 . 1/version/dependencydependencycgroupid com . querydsl/Groupartifactidquerydsl-apt/artifactidVersion 4 . 2 . 1/version/dependency然后要配置一个插件来生成Q版本的实体类。只有Q版本的实体类才能参与QueryDSL的查询。

  plugingroupid com . querydsl/groupid artifactidquerydsl-maven-plugin/artifactidexecutionexecutionphasegenerate-sources/phasegoalsgoaljpa-export/goalsconfigurationtargetFoldertarget/generated-sources/Java/targetfolderpackagescom . Jerry . game market . entity/packages/configuration/execution/Executions/plugingtargetfoldertarget/generated-sources/Java/target folder这是用于生成Qversion实体的目标文件夹。

  Packagescom.jerry.gamemarket.entity/packages将在这些包下生成实体的Q版本。

  执行mvn编译后,可以看到生成的Q版本实体类。

  在编写具体的查询方法之前,我们需要实例化EntityManager对象和JPAquiryFactory对象,在实例化控制器时实例化JPAquiryFactory对象。因此,在startup类中引入了一个名为JPAquiryFactory的Bean和一个EntityManager参数,可以全局使用。

  @

  Beanpublic JPAQueryFactory queryFactory(EntityManager entityManager){return new JPAQueryFactory(entityManager);}搜索条件实体类

  

package com.jerry.gamemarket.dto;import com.jerry.gamemarket.enums.OrderStatusEnums;import com.jerry.gamemarket.enums.PayStatusEnums;import lombok.Data;import org.springframework.context.annotation.Bean;import java.math.BigDecimal;/** * author by 李兆杰 * Date 2018/11/28 */@Datapublic class SearchOrderDTO { private String orderId; // private String id; private String buyerName; private String buyerPhone; private String buyerAddress; private String canteenName; private BigDecimal maxAmount; private BigDecimal minAmount; private Integer orderStatus; // 默认未支付 private Integer payStatus; private Integer pageNum = 1; private Integer pageSize=10;}

动态搜索实现类中的方法,这里返回类型是 QueryResults,我们了解一下这个特殊的返回类型

 

  

 

  

看源码

results是返回的list数据数组total是总数offset是从哪开始limit是限制条数

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.querydsl.core;import com.google.common.collect.ImmutableList;import java.io.Serializable;import java.util.List;import javax.annotation.Nullable;public final class QueryResults<T> implements Serializable { private static final long serialVersionUID = -4591506147471300909L; private static final QueryResults<Object> EMPTY = new QueryResults(ImmutableList.of(), 9223372036854775807L, 0L, 0L); private final long limit; private final long offset; private final long total; private final List<T> results; public static <T> QueryResults<T> emptyResults() { return EMPTY; } public QueryResults(List<T> results, @Nullable Long limit, @Nullable Long offset, long total) { this.limit = limit != null ? limit.longValue() : 9223372036854775807L; this.offset = offset != null ? offset.longValue() : 0L; this.total = total; this.results = results; } public QueryResults(List<T> results, QueryModifiers mod, long total) { this(results, mod.getLimit(), mod.getOffset(), total); } public List<T> getResults() { return this.results; } public long getTotal() { return this.total; } public boolean isEmpty() { return this.results.isEmpty(); } public long getLimit() { return this.limit; } public long getOffset() { return this.offset; }}
 @Override public QueryResults<OrderMaster> dymamicQuery(SearchOrderDTO searchOrderDTO) { QOrderMaster o = QOrderMaster.orderMaster; JPAQuery<OrderMaster> query = jpaQueryFactory.select(o).from(o); if (!StringUtils.isEmpty(searchOrderDTO.getOrderId())){ query.where(o.orderId.like(searchOrderDTO.getOrderId())); } if (!StringUtils.isEmpty(searchOrderDTO.getBuyerName())){ query.where(o.buyerName.like("%"+searchOrderDTO.getBuyerName()+"%")); } if (!StringUtils.isEmpty(searchOrderDTO.getBuyerPhone())){ query.where(o.buyerPhone.eq(searchOrderDTO.getBuyerPhone())); } if (searchOrderDTO.getMaxAmount()!=null && searchOrderDTO.getMinAmount()!=null){ query.where(o.orderAmount.goe(searchOrderDTO.getMinAmount())); } if (searchOrderDTO.getMaxAmount()!=null && searchOrderDTO.getMinAmount()!=null){ query.where(o.orderAmount.loe(searchOrderDTO.getMaxAmount())); } if (searchOrderDTO.getOrderStatus()!=null){ query.where(o.orderStatus.eq(searchOrderDTO.getOrderStatus())); } if (searchOrderDTO.getPayStatus()!=null){ query.where(o.payStatus.eq(searchOrderDTO.getPayStatus())); } return query.orderBy(o.createTime.desc()) .offset((searchOrderDTO.getPageNum()-1)*searchOrderDTO.getPageSize()) .limit(searchOrderDTO.getPageSize()) .fetchResults(); }

这些查询中包含了模糊查询,动态查询和分页

 

  最后是Controller中的引用

  

@PostMapping("/searchorder") public QueryResults<OrderMaster> findByCase(@RequestBody SearchOrderDTO searchOrderDTO){ QueryResults<OrderMaster> queryResults=orderService.dymamicQuery(searchOrderDTO); System.out.println(searchOrderDTO); System.out.println(queryResults.getResults()); return queryResults; }

整个查询就完成了,怎么去渲染数据就看大家喜好了。

 

  

 

  

springdataJPA和querydsl

 

  

什么是SpringDataJPA?什么是QueryDSL?

SpringDataJPA是对JPA使用的封装(JPA是java持久层api)

 

  QueryDSL是基于各种ORM(对象关系映射)上的一个通用框架。使用其API类库,可以写出java代码的sql

  

 

  

@Mapper 实体-模型映射

在mapper上使用注解 @Mapper(componentModel = "spring", uses = {})

 

  用于映射dto和entity 自动生成mapper实现 完成相互转化

  如果dto和entity中的属性名不匹配,需要增加注解

  

@Mappings({@Mapping(source = "entity.name", target = "dto属性名")})

 

  

项目整体流程

服务后台中rest包下对外暴露提供restful接口,具体类中引入代理层,该代理层实现dto以及dao层的处理(注入service以及自动生成的mapper映射),由mapper处理dto与entity之间的相互转化,service层操作db(操作方式为jpa)

 

  

 

  

疑问

代理类中,为什么要通过在构造方法上增加@Autowired注解对mapper和service进行初始化,而不是对要注入的成员变量上增加@Autowired注解,采用构造方法的方式有何优点?

 

  通过相关资料找到其答案:java变量初始化的顺序为:静态变量或静态语句块–>实例变量或初始化语句块–>构造方法–>@Autowired 如果该类中有增加构造方法时,执行构造方法时,成员变量还没有初始化,此时会报错,如果没有构造方法可以在成员变量上增加@Autowired注解来初始化变量。为了避免构造方法初始化的时候,成员变量还没有初始化,所以建议在构造方法上增加@Autowired注解。

  项目中QueryDSL仅用于生成q类,并没有用java代码格式的sql呀?为什么只用了spring-data-jpa?

  

 

  

JpaRepository

spring-data-jpa简介,spring整合各种第三方框架,命名格式为spring-data-*,spring整合jpa造就了spring-data-jpa。

 

  repository就是持久层,相当于dao、mapper等,项目中定义各种repository继承JpaRepository就可以使用基本的CRUD。

  

 

  CrudRepository该接口是spring整合jpa的二级接口,此接口提供了普通的CRUD操作,后续新增PagingAndSortingRepository接口,提供findAll方法的重载方法(支持分页),QueryByExampleExecutor优雅的解决了空指针问题,后续优化为JpaRepository接口,该接口对上个接口方法进行优化,返回值更广泛。

  

 

  

SimpleJpaRepository

该类是JpaRepository接口的具体实现,CRUD操作就是由该类提供的。包括四个成员变量JpaEntityInformation、PersistenceProvider、CrudMethodMetadata、EntityManager。 前三个成员变量是为了获取拼接sql,EntityManager执行该sql。相当于session、sqlSession等

 

  

 

  

写一个Repository继承JpaRepository之后

可以写其实现类,但是不需要implements关键字去实现,spring-data-jpa会自动识别其关系,也可以不写实现类,在运行时期,SimpleJpaRepository该类就是其实现类,如果写了自定义实现类,就会执行实现类中的逻辑

 

  

 

  

spring-data-jpa的相关语法

 

  对于多表查询 需要用到Specification匿名内部类,重写其方法。感觉遇到多表查询还是写sql比较直观

  以上为个人经验,希望能给大家一个参考,也希望大家多多支持盛行IT。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: