1.前言:由于项目用到了jpa,所以开始对jpa进行探究,本来,简单的模型,增删改查,继承
JpaRepository,就可以了,但是 遇到复杂的一对多,和多对多,分页等动态查询条件,就头疼了,下面就开始我的研究
(声明下哈:下面的是我做项目中摸索的,所以写的是伪代码,当中有些不对的,还请大家见谅)
1.环境:spring cloud + boot + idea + jpa
自己的接口继承JpaRepository 上,再继承 JpaSpecificationExecutor,在这个接口中,有几个方法
a.T findOne(Specification<T> var1)
b.List<T> findAll(Specification<T> var1)
c.Page<T> findAll(Specification<T> var1, Pageable var2)
d.List<T> findAll(Specification<T> var1, Sort var2);
e.long count(Specification<T> var1);
一般只用到动态条件的查询,就会使用 a 和 b 的方法, 分页查询 用到 b下面有个场景,1:一对多:(A 1:n B)class A{@Column("name = a_name")String aName;@OneToMany("mappedBy = a")List<B> bList;}class B{@Column("name = b_name")String bName;@ManyToOne@JoinColumn("name = a_id")A a;}注解:1.mappedBy = a,是在B 中定义的a,其次,这样就不会再生成一张维护表。2.JoinColumn,会在B生产的表中,多一个a的外键叫 a_id这时候,两张表的关系建成后,就开始动态条件查询:1.建立AInterface:Page<A> findAll(Pageable pageable,ADTO adto);注解:ADTO ,是传过来的条件封装成DTO,条件少的可以直接传字符串.2.建立实现类AInterfaceImpl implements AInterfacepublic Page<A> findAll(Pageable pageable,ADTO adto){//1.针对传过来的参数进行非空过滤,这边就忽略写了//2.利用ExampleMatcher 方法//如果你查询的条件,是等于的话,如下 第一行即可,不然即第二行:ExampleMatcher matcher = ExampleMatcher.matching();orExampleMatcher matcher = ExampleMatcher.matching().withMatcher("name 过滤不为空的参数",ExampleMatcher.GenericPropertyMatchers.contains());//这是针对name,进行模糊查询,多个继续往下添加//继续Example<A> AExample = Example.of(A,matcher);Page<A> aPage = ARepository.findAll(AExample,pageable);这样即可:这种的方法只适用于单表,并且有几个局限性1.传进来的参数,如果是 "",空字符串,必须转换为null,Example 才会忽略对它的查询,不然,Example会把它当做条件去查2.只适合单表查询,一旦出现多表关联,就无法使用,除非,你用了视图,把多张表的查询,建立成一个视图,在视图上进行查找3.针对Example的具体细节,大家可以百度,在这里我就不多说了。}既然Example 不能满足我们多表的查询,相信,大家也不太会使用,因此,接下来介绍的方法比较实用了继续实现我们的 AInterface}AInterfaceImpl implements AInterfacepublic Page<A> findAll(Pageable pageable,ADTO adto){//1.对adto 参数进行获取,String name = dto.getName();//2.声明一个List<Predicate> predicateList = new ArrayList<Predicate>();
Predicate 是用于动态条件查询,用到的必须对象,//定义一个 querySpecifi 内部类实现方法,里面封装了表关联和动态条件,Specification 大家可以百度具体的含义,我这边只是说我自己的用法,有些含义,我也不清楚,请见谅哈Specification querySpecifi = new Specification<Category>() {
@Override public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder){//条件判断
if(null != name)
{predicateList.add(criteriaBuilder.equal(root.get("name"),name));//这里简单解释下,我对上面的关键词和对象解释在 toPredicate 方法中,有三个参数,Root,criteriaQuery,CriteriaBuilder,1.root 是当前的根元素,里面的实现是根据反射技术生成,因此,root.get("A 定义的某个字段名称"),当前指向的就是A模型2.CriteriaQuery ,看名字,知道是个query查询的接口,里面封装了一下几个方法:select,where,groupby,having,orderingby...基本上是用于查询的方法,有条件的,可以进入源码查看。3.CriteriaBuilder,bulider里面也有些封装方法:createQuery,asc,desc,equal,等等,用于对条件进行操作,等于,大于,排序等等因此,上面的语句就是,root.get("name") 就是 A 类中的 name 属性, criteriaBuilder.equal(root.get("name"),name),就是A类中的name属性 == 所传的name,相等的条件。 然后加入 predicateList。最后,return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));这句意思就是,predicateList里面的所有条件,都是 and 操作,就类似,where and ...and ...
我上面定义的是predicateList ,多条件,如果是单个条件,就声明一个 Prediacate predicate = criteriaBuilder.equal(root.get("name"),name)}
}//最后分页结果查询,调用内部类的结果集Page<A> aList = aRepository.findAll(querySpecifi,pageable);return aList;}文笔有限,请大家多包涵,有问题或者建议,留言哈,//下一章说下,多对多的关系建立