Spring Boot 之 Spring Data JPA 三(

作者: 孙亖 | 来源:发表于2017-12-21 08:38 被阅读120次

    Specifications 的思路来自于“领域驱动设计”的概念,通过可编程的方式实现查询的where语句。我们今天就来写一个Specification的例子。

    一、首先建立一个Spring Boot 工程

    我们使用的IDE是InteliJ IDEA,开发语言是Kotlin,


    项目信息

    Spring 的工程特性选择了JPA、Rest Repository和一种数据库支持(这里是MySql)


    项目工程特性
    新建项目没有什么可说的,接下来我们正式进入编码:

    二、编写一个实体类来记录数据

    我们使用一个Record实体来保存数据,包含了名称和值,代码如下:

    package cn.techcave.demo.jpa3.domain
    
    import javax.persistence.Entity
    import javax.persistence.GeneratedValue
    import javax.persistence.GenerationType
    import javax.persistence.Id
    
    @Entity
    class Record(
            /**
             * 主键
             */
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            var id:Long? = null,
            /**
             * 名称
             */
            var name:String? = null,
            /**
             * 值
             */
            var value:Double? = null
    )
    

    三、通过接口实现Specification的支持

    要使我们的Repository支持Specification查询,需要在Repository中继承JpaSpecificationExecutor接口,代码如下:

    package cn.techcave.demo.jpa3.repository
    
    import cn.techcave.demo.jpa3.domain.Record
    import org.springframework.data.jpa.repository.JpaRepository
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor
    import org.springframework.stereotype.Repository
    
    @Repository
    interface RecordRepo:JpaRepository<Record, Long>, JpaSpecificationExecutor<Record>{
    }
    

    四、通过JPA 2 的criteria API实现Specifications查询

    Repository支持了Specifications查询,我们在代码中实现查询,如下代码所示:

    package cn.techcave.demo.jpa3.service
    
    import cn.techcave.demo.jpa3.domain.Record
    import cn.techcave.demo.jpa3.repository.RecordRepo
    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.stereotype.Service
    import java.time.LocalDate
    import javax.persistence.criteria.CriteriaBuilder
    import javax.persistence.criteria.Root
    import org.springframework.data.jpa.domain.Specification
    import org.springframework.data.jpa.domain.Specifications.where
    import javax.persistence.criteria.CriteriaQuery
    import javax.persistence.criteria.Predicate
    
    
    @Service
    class RecordService {
        @Autowired
        lateinit var recordRepo: RecordRepo
    
        fun nameLike(name:String): Specification<Record> {
            return object : Specification<Record> {
                override fun toPredicate(root: Root<Record>, query: CriteriaQuery<*>,
                                         builder: CriteriaBuilder): Predicate {
                    return builder.like(root.get("name"),"%$name%")
                }
            }
        }
    
        fun filterByName(name:String) = recordRepo.findAll(nameLike(name))
    
        fun filterByNames(n1:String, n2:String) :List<Record> {
            return recordRepo.findAll(where(nameLike(n1)).or(nameLike(n2)))
        }
        fun findAll() = recordRepo.findAll()
    }
    

    上面的代码中,我们首先编写nameLike方法,返回一个基于名称的Specification查询。然后我们在filterByName中执行此查询。Specification还可以进行组合条件的查询,例如filterByNames方法,我们用or组合了两个nameLike的Specification。

    五、测试

    我们用REST发布我们的查询功能,代码如下:

    package cn.techcave.demo.jpa3.web
    
    import cn.techcave.demo.jpa3.service.RecordService
    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.web.bind.annotation.GetMapping
    import org.springframework.web.bind.annotation.RestController
    
    @RestController
    class RecordController {
        
        @Autowired
        lateinit var recordSvc:RecordService
        
        @GetMapping("findAll")
        fun findAll() = recordSvc.findAll()
        
        @GetMapping("findByName")
        fun findByName(name:String) = recordSvc.filterByName(name)
    
        @GetMapping("findByNames")
        fun findByNames(n1:String, n2:String) = recordSvc.filterByNames(n1, n2)
    }
    

    然后,我们在这里手工做一些数据用于测试:

    测试数据

    用Postman调用REST接口,首先是findAll,可以看到所有数据被查询出来了:

    findAll结果

    然后findByName,包含查询参数name的值被查询出来了:


    findByName结果

    findByNames,这里测试或验收的是组合查询,两个组合条件都是包含名称,当然也可以使用其他查询条件:


    findByNames组合查询结果

    原文地址

    相关文章

      网友评论

        本文标题:Spring Boot 之 Spring Data JPA 三(

        本文链接:https://www.haomeiwen.com/subject/fvgswxtx.html