怎么使用JPA+querydsl实现多条件动态查询
导读:本文共5929字符,通常情况下阅读需要20分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: JPA querydsl多条件动态查询相信很多人在做订单管理的时候会用到多条件的检索,比如说查询订单状态是已支付的,金额在100-200之间的商铺a的已完结的订单,这样的多条件。实现方式有多种,核心就一个if和判空。今天学习了querydsl,来具体回顾一下。首先是我做的效果图,我们主要看查询怎么实现的。介绍一下querydsl首先QueryDSL仅仅是一个通用... ...
目录
(为您整理了一些要点),点击可以直达。JPA querydsl多条件动态查询
相信很多人在做订单管理的时候会用到多条件的检索,比如说查询订单状态是已支付的,金额在100-200之间的商铺a的已完结的订单,这样的多条件。
实现方式有多种,核心就一个if和判空。今天学习了querydsl,来具体回顾一下。
首先是我做的效果图,我们主要看查询怎么实现的。
介绍一下querydsl
首先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,版本是一致的
<dependency> <groupId>com.querydsl</groupId> <artifactId>querydsl-jpa</artifactId> <version>4.2.1</version> </dependency> <dependency> <groupId>com.querydsl</groupId> <artifactId>querydsl-apt</artifactId> <version>4.2.1</version> </dependency>
然后是要配置一个插件来生成Q版的实体类,只有Q版的实体类才能参与querydsl的查询
<plugin> <groupId>com.querydsl</groupId> <artifactId>querydsl-maven-plugin</artifactId> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>jpa-export</goal> </goals> <configuration> <targetFolder>target/generated-sources/java</targetFolder> <packages>com.jerry.gamemarket.entity</packages> </configuration> </execution> </executions> </plugin>
<targetFolder>target/generated-sources/java</targetFolder>
这是生成Q版实体的目标文件夹
<packages>com.jerry.gamemarket.entity</packages>
这是把那些包下的实体生成Q版。
执行mvn compile之后,就能看到生成Q版实体类。
在编写具体的查询方法之前我们需要实例化EntityManager对象以及JPAQueryFactory对象,并且通过实例化控制器时就去实例化JPAQueryFactory对象,所以在启动类中引入一个Bean叫JPAQueryFactory加一个EntityManager参数,可以全局使用。
@Bean publicJPAQueryFactoryqueryFactory(EntityManagerentityManager){ returnnewJPAQueryFactory(entityManager); }
搜索条件实体类
packagecom.jerry.gamemarket.dto;importcom.jerry.gamemarket.enums.OrderStatusEnums;importcom.jerry.gamemarket.enums.PayStatusEnums;importlombok.Data;importorg.springframework.context.annotation.Bean;importjava.math.BigDecimal;/***authorby李兆杰*Date2018/11/28*/@DatapublicclassSearchOrderDTO{privateStringorderId;//privateStringid;privateStringbuyerName;privateStringbuyerPhone;privateStringbuyerAddress;privateStringcanteenName;privateBigDecimalmaxAmount;privateBigDecimalminAmount;privateIntegerorderStatus;//默认未支付privateIntegerpayStatus;privateIntegerpageNum=1;privateIntegerpageSize=10;}
动态搜索实现类中的方法,这里返回类型是 QueryResults,我们了解一下这个特殊的返回类型
看源码
results
是返回的list数据数组total
是总数offset
是从哪开始limit
是限制条数
////Sourcecoderecreatedfroma.classfilebyIntelliJIDEA//(poweredbyFernflowerdecompiler)//packagecom.querydsl.core;importcom.google.common.collect.ImmutableList;importjava.io.Serializable;importjava.util.List;importjavax.annotation.Nullable;publicfinalclassQueryResults<T>implementsSerializable{privatestaticfinallongserialVersionUID=-4591506147471300909L;privatestaticfinalQueryResults<Object>EMPTY=newQueryResults(ImmutableList.of(),9223372036854775807L,0L,0L);privatefinallonglimit;privatefinallongoffset;privatefinallongtotal;privatefinalList<T>results;publicstatic<T>QueryResults<T>emptyResults(){returnEMPTY;}publicQueryResults(List<T>results,@NullableLonglimit,@NullableLongoffset,longtotal){this.limit=limit!=null?limit.longValue():9223372036854775807L;this.offset=offset!=null?offset.longValue():0L;this.total=total;this.results=results;}publicQueryResults(List<T>results,QueryModifiersmod,longtotal){this(results,mod.getLimit(),mod.getOffset(),total);}publicList<T>getResults(){returnthis.results;}publiclonggetTotal(){returnthis.total;}publicbooleanisEmpty(){returnthis.results.isEmpty();}publiclonggetLimit(){returnthis.limit;}publiclonggetOffset(){returnthis.offset;}}
@OverridepublicQueryResults<OrderMaster>dymamicQuery(SearchOrderDTOsearchOrderDTO){QOrderMastero=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()));}returnquery.orderBy(o.createTime.desc()).offset((searchOrderDTO.getPageNum()-1)*searchOrderDTO.getPageSize()).limit(searchOrderDTO.getPageSize()).fetchResults();}
这些查询中包含了模糊查询,动态查询和分页
最后是Controller中的引用
@PostMapping("/searchorder")publicQueryResults<OrderMaster>findByCase(@RequestBodySearchOrderDTOsearchOrderDTO){QueryResults<OrderMaster>queryResults=orderService.dymamicQuery(searchOrderDTO);System.out.println(searchOrderDTO);System.out.println(queryResults.getResults());returnqueryResults;}
整个查询就完成了,怎么去渲染数据就看大家喜好了。
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比较直观
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
怎么使用JPA+querydsl实现多条件动态查询的详细内容,希望对您有所帮助,信息来源于网络。