SpringData JPA(2)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: SpringData JPA(2)

7SpringData JPA快速入门

7.1 目标

本章节我们是实现的功能是搭建SpringData JPA环境,并实现一条数据的增删改查。

7.2 准备数据环境

--下面的操作让JPA自动生成表结构

7.3 创建java工程,导入坐标

<dependencies>
    <!-- 日志 -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <!-- 单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!-- Spring框架相关jar包 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.7</version>
    </dependency>
    <!--jpa-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.1.8.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>5.0.7.Final</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
</dependencies>

7.4 创建实体类

public class Article  implements Serializable {
    private Integer aid;
    private String title;
    private String author;
    private Date createTime;
  //省略set和get方法。。。
    //省略toString方法。。。
}    

7.5 在实体类中配置映射关系

@Entity//表示这是一个实体类
@Table(name = "article") //建立实体类和表的映射关系
public class Article implements Serializable {
    @Id//声明当前私有属性为主键
    @GeneratedValue(strategy = GenerationType.IDENTITY) //配置主键的生成策略
    private Integer aid;
    //声明类的属性跟数据表字段的对应关系,如果属性名称和字段名称一致,可省略
    @Column(name = "title")
    private String title;
    private String author;
    private Date createTime;
    //省略set和get方法。。。
    //省略toString方法。。。
}

7.6 编写dao接口

使用 Spring Data JPA操作数据库,只需要按照框架的规范提供 dao 接口,不需要提供在接口中定义方法,也不需要为接口提供实现类就能完成基本的数据库的增删改查等功能。

在 Spring Data JPA 中,对于定义符合规范的 Dao 层接口,我们只需要遵循以下几点就可以了:

  1. 创建一个 Dao 层接口,并实现 JpaRepository 和 JpaSpecificationExecutor
  2. 提供相应的泛型
/**
 * JpaRepository<实体类类型,主键类型>:用来完成基本 CRUD 操作
 * JpaSpecificationExecutor<实体类类型>:用于复杂查询(分页等查询操作)
 */
public interface ArticleDao extends JpaRepository<Article, Integer>,
    JpaSpecificationExecutor<Article> { 
}

7.7 添加Spring整合Jpa的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:jpa="http://www.springframework.org/schema/data/jpa"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
  <!-- 配置要扫描的包 -->
  <context:component-scan base-package="net.csdn" />
  <!-- 1.dataSource -->
  <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql:///springdata" />
    <property name="username" value="root" />
    <property name="password" value="adminadmin" />
  </bean>
  <!-- 2.EntityManagerFactory -->
  <bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <!-- 注入数据源 -->
    <property name="dataSource" ref="dataSource" />
    <!-- 指定实体类所在的包 -->
    <property name="packagesToScan" value="net.csdn.domain" />
    <!-- 指定jpa的实现提供者 -->
    <property name="persistenceProvider">
      <bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
    </property>
    <!--JPA供应商适配器 -->
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <!-- 是否生成DDL语句   是否自动建表 -->
        <property name="generateDdl" value="true" />
        <!-- 数据库厂商名称 -->
        <property name="database" value="MYSQL" />
        <!-- 数据库方言 -->
        <property name="databasePlatform" 
                          value="org.hibernate.dialect.MySQLDialect" />
        <!-- 是否显示SQL -->
        <property name="showSql" value="true" />
      </bean>
    </property>
  </bean>
  <!-- 3.事务管理器 -->
  <bean id="transactionManager" 
          class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
  </bean>
  <!-- 整合spring data jpa -->
  <!--spring 通过代理的方式为dao接口提供实现类,需要指明为哪些接口去产生代理类-->
  <jpa:repositories base-package="net.csdn.dao"
    transaction-manager-ref="transactionManager"
    entity-manager-factory-ref="entityManagerFactory" />
</beans>

7.8 测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ArticleDaoTest {
    @Autowired
    private ArticleDao articleDao;
    //新增
    @Test
    public void testSave() {
        Article article = new Article();
        article.setTitle("测试文章");
        article.setAuthor("oldlu");
        article.setCreateTime(new Date());
        articleDao.save(article);
    }
    //修改
    @Test
    public void testUpdate() {
        Article article = new Article();
        article.setTitle("测试文章1");
        article.setContent("测试内容");
        article.setAuthor("oldlu");
        article.setCreateTime(new Date());
        article.setAid(1);
        articleDao.save(article);
    }
    //根据Id查询
    @Test
    public void testFindByAid() {
        Optional<Article> optional = articleDao.findById(1);
        System.out.println(optional.get());
    }
    //查询所有
    @Test
    public void testFindAll() {
        List<Article> list = articleDao.findAll();
        for (Article article : list) {
            System.out.println(article);
        }
    }
    //删除
    @Test
    public void testdelete() {
        articleDao.deleteById(1);
    }
}

8 SpringData Jpa运行原理分析

8.1 SpringData中的几个重要接口

思考一个问题:自定义的接口中没有写任何的方法声明,那么测试类中调用的接口中的方法是哪来的呢?

自定义的接口继承了两个接口,方法肯定来自里面,追踪关系得到下面的继承关系
    Repository 标记接口:继承了此接口后会被Spring识别,进而可以在接口中声明一些满足规范的方法
        |
        |
    CrudRepository 实现了基本增删改查方法
        | 
        |
    PagingAndSortingRepository 实现了分页和排序的方法
        | 
        |
    JpaRepository 重写了几个查找和删除的方法
        | 
        |
    ArticleDao
  通过上面的继承关系,我们可以看到我们自定义的接口ArticleDao继承了一系列的Repository接口,而每一个接口都会给我们提供一部分的功能,这样继承下来,我们的ArticleDao不用任何的方法声明就拥有了很多的功能了。

8.2 SpringData Jpa底层运行原理

思考一个问题:我们找到了定义方法的接口,但并没有看到实现类,没有实现来就无法创建对象,那么真正干活的实现类到底在哪,它又是如何产生对象的呢?

下面我们通过debug的形式,寻找答案:

  1. 在运行时,Spring会使用JdkDynamicAopProxy为dao接口生成一个代理对象

20210120111909311.png

  1. 那么这个代理对象是根据那个类代理出来的呢?点击进入JdkDynamicAopProxy源码查看invoke方法,发现targetSource代理的是SimpleJpaRepository类

2021012011192332.png

通过对SimpleJpaRepository中代码的分析,我们看到最终执行保存的是EntityManager对象

20210120111936755.png

总结:使用SpringData JPA开发底层还是用的JPA的API,SpringData JPA只是对标准 JPA 操作进行了进一步封装,已达到简化了Dao层代码开发的目的。

8.3 SpringData Jpa 与 Jpa 及 Hibernate的关系

20210120111948681.png

9 SpringData JPA的多种查询方式

9.1 父接口方法查询

我们自定义的Dao接口可以使用它的父接口提供的方法,可以使用的方法如下图所示。

20210120111958688.png

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-jpa.xml")
public class SpringDataJpaQueryTest {
    @Autowired
    private ArticleDao articleDao;
    //主键查询
    @Test
    public void testFindById() {
        Optional<Article> optional = articleDao.findById(21);
        System.out.println(optional.get());
    }
    //查询所有
    @Test
    public void testFindAll() {
        List<Article> articles = articleDao.findAll();
        for (Article article : articles) {
            System.out.println(article);
        }
    }
    //查询所有---排序
    @Test
    public void testFindAllWithSort() {
        Sort sort = Sort.by(Sort.Order.desc("aid"));
        List<Article> articles = articleDao.findAll(sort);
        for (Article article : articles) {
            System.out.println(article);
        }
    }
    //查询所有---分页
    @Test
    public void testFindAllWithPage() {
        //从第几页(页数从0开始)开始查,每页多少条
        Pageable pageable = PageRequest.of(2,3);
        Page<Article> page = articleDao.findAll(pageable);
        for (Article article : page.getContent()) {
            System.out.println(article);
        }
    }
    //查询所有---分页和排序
    @Test
    public void testFindAllWithPageAndSort() {
        Sort sort = Sort.by(Sort.Order.desc("aid"));
        //从第几页(页数从0开始)开始查,每页多少条
        Pageable pageable = PageRequest.of(2,3,sort);
        Page<Article> page = articleDao.findAll(pageable);
        for (Article article : page.getContent()) {
            System.out.println(article);
        }
    }
}

9.2 方法命名规则查询

   顾名思义,方法命名规则查询就是根据方法的名字,就能创建查询。只需要按照SpringData JPA提供的方
法命名规则定义方法的名称,就可以完成查询工作。
   SpringData JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询.
   按照SpringData JPA定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。
public interface ArticleDao extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
    //根据标题查询
    List<Article> findByTitle(String title);
    //根据标题模糊查询
    List<Article> findByTitleLike(String title);
    //根据标题和作者查询
    List<Article> findByTitleAndAuthor(String title, String author);
    //根据ID范围查询
    List<Article> findByAidBetween(Integer starAid, Integer endAid);
    List<Article> findByAidLessThan(Integer endAid);
    List<Article> findByAidIn(List<Integer> aids);
    //根据创建时间之后查询
    List<Article> findByCreateTimeAfter(Date createTime);
关键字 例子 对应的JPQL语句
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ? 2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstnameIs, findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age ⇐ ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection age) … where x.age not in ?1
TRUE findByActiveTrue() … where x.active = true
FALSE findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = U

9.3 JPQL查询

   使用SpringData JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询。
  JPQL,全称是Java Persistence Query Language。JPQL语句是JPA中定义的一种查询语言,此种语言的用意是让开发者忽略数据库表和表中的字段,而关注实体类及实体类中的属性。
  它的写法十分类似于SQL语句的写法,但是要把查询的表名换成实体类名称,把表中的字段名换成实体类的属性名称。 
public interface ArticleDao extends JpaRepository<Article, Integer>, 
                  JpaSpecificationExecutor<Article> {
    //展示位置参数绑定
    @Query("from Article a where a.author=?1 and a.title=?2")
    List<Article> findByCondition1(String author, String title);
    //展示名字参数绑定
    @Query("from Article a where a.author=:author and a.title=:title")
    List<Article> findByCondition2(@Param("author") String author, 
                                   @Param("title") String title);
    //展示like模糊查询
    @Query("from Article a where a.title like %:title%")
    List<Article> findByCondition3(@Param("title") String title);
    //展示排序查询
    @Query("from Article a where a.title like %:title% order by aid desc")
    List<Article> findByCondition4(@Param("title") String title);
    //展示分页查询
    @Query("from Article a where a.title like %:title%")
    Page<Article> findByCondition5(Pageable pageable, @Param("title") String title);
    //展示传入集合参数查询
    @Query("from Article a where a.aid in :aids")
    List<Article> findByCondition6(@Param("aids") Collection<String> aids);
    //展示传入Bean进行查询(SPEL表达式查询)
    @Query("from Article a where a.author=:#{#article.author} and a.title=:#{#article.title}")
    Article findByCondition67(@Param("article") Article article);
}

9.4 本地SQL查询

//nativeQuery=true表示使用本地SQL查询
//基本不会使用,除非是出现非常复杂的业务情况导致SQL非常复杂,JPQL搞不定的时候
@Query("select * from article where title like ?1 and author = ?2",nativeQuery=true)
List<User> findAllByTitleAndAuthor(String title,String author);

9.5 Specifications动态查询

有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在 SpringData JPA 中可以通过 JpaSpecificationExecutor 接口查询。相比 JPQL,其优势是类型安全,更加的面向对象,缺点是书写比较麻烦。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ArticleDao4Test {
    @Autowired
    private ArticleDao articleDao;
    @Test
    public void test1() {
        List<Article> articles = articleDao.findAll(new Specification<Article>() {
            //查找title中含有“张三”,并且aid> 3的文章
            String myTitle = "张三";
            Integer myAid = 3;
            /**
             *
             * @param root  用于获取属性
             * @param cq    用于生成SQL 一般用不到
             * @param cb    用于追加添加条件
             * @return
             */
            @Override
            public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq, 
                                         CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                if (myTitle != null && !"".equals(myTitle)) {
                    Predicate predicate = 
                        cb.like(root.get("title").as(String.class), "%" + myTitle + "%");
                    predicates.add(predicate);
                }
                if (myAid != null) {
                    Predicate predicate =
                        cb.greaterThan(root.get("aid").as(Integer.class), myAid);
                    predicates.add(predicate);
                }
                return cb.and(predicates.toArray(new Predicate[]{}));
            }
        });
        for (Article article : articles) {
            System.out.println(article);
        }
    }
    //分页查询
    @Test
    public void test2() {
        int pageStart = 0;//起始页码
        int pageSize = 2;//每页条数
        Pageable pageable = PageRequest.of(pageStart, pageSize);
        Page<Article> pages = articleDao.findAll(new Specification<Article>() {
            @Override
            public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq,
                                         CriteriaBuilder cb) {
                //代表查询全部
                return null;
            }
        }, pageable);
        System.out.println("总记录数:" + pages.getTotalElements());
        System.out.println("总页数:" + pages.getTotalPages());
        System.out.println("当前页:" + pages.getNumber());
        for (Article article : pages.getContent()) {
            System.out.println(article);
        }
    }
    //分页+排序
    @Test
    public void test3() {
        int pageStart = 0;//起始页码
        int pageSize = 2;//每页条数
        //Sort.by(Sort.Order.desc("属性"))
        Pageable pageable = PageRequest.of(pageStart, pageSize,
                                           Sort.by(Sort.Order.desc("aid")));
        Page<Article> pages = articleDao.findAll(new Specification<Article>() {
            @Override
            public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq,
                                         CriteriaBuilder cb) {
                //代表查询全部
                return null;
            }
        }, pageable);
        System.out.println("总记录数:" + pages.getTotalElements());
        System.out.println("总页数:" + pages.getTotalPages());
        System.out.println("当前页:" + pages.getNumber());
        for (Article article : pages.getContent()) {
            System.out.println(article);
        }
    }
}

9.6 时间范围查询

需要判断的时间字段String即可,只不过需要格式相同

    @Override
    public Page<TaskPrint> findTaskPrintPage(TaskPrintQueryParam taskPrintQueryParam) {
        log.info("入参->" + taskPrintQueryParam.toString());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Specification<TaskPrint> spec = (Specification<TaskPrint>) (root, query, cb) -> {
            /*文件名称、申请人、打印人、打印状态(未打印、已打印、全部,默认字段未打印)、打印时间段,倒叙排列。*/
            Path<String> isFinished = root.get("isFinished");
            Path<String> createTime = root.get("createTime");
            Path<String> printerName = root.get("printerName");
            Path<String> fileName = root.get("fileName");
            Path<String> applicantName = root.get("applicantName");
            Predicate and = null;
            if (taskPrintQueryParam.getApplicantName() != null) {
                and = cb.and(cb.equal(applicantName, taskPrintQueryParam.getApplicantName()));
            }
            if (taskPrintQueryParam.getPrinterName() != null) {
                and = cb.and(cb.like(printerName, "%" + taskPrintQueryParam.getPrinterName() + "%"));
            }
            if (taskPrintQueryParam.getIsFinished() != null) {
                and = cb.and(cb.equal(isFinished, taskPrintQueryParam.getIsFinished()));
            }
            if (taskPrintQueryParam.getFileName() != null) {
                and = cb.and(cb.like(fileName, "%" + taskPrintQueryParam.getFileName() + "%"));
            }
            if (taskPrintQueryParam.getStartDate() != null || taskPrintQueryParam.getEndDate() != null) {
                Predicate p = null;
                try {
                /**
                时间范围查询,这里要注意时间格式
                */
                    if (taskPrintQueryParam.getStartDate()!=null&&taskPrintQueryParam.getEndDate()!=null){
                        p = cb.between(createTime, taskPrintQueryParam.getStartDate(), taskPrintQueryParam.getEndDate());
                    }
                    if (taskPrintQueryParam.getStartDate()==null){
                        p = cb.between(createTime, "1970-01-01 00:00:00", taskPrintQueryParam.getEndDate());
                    }
                    if (taskPrintQueryParam.getEndDate()==null){
                        Date date = new Date();// 获取当前时间
//                       log.info("现在时间->"+sdf.format(date));
                        p = cb.between(createTime, taskPrintQueryParam.getStartDate(), sdf.format(date));
                    }
                    and = cb.and(p);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return and;
        };
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        Pageable pageable = PageRequest.of(taskPrintQueryParam.getPageNum()-1, taskPrintQueryParam.getPageSize(), sort);
        org.springframework.data.domain.Page<TaskPrint> taskPrints = taskPrintRepository.findAll(spec, pageable);
        Page page = new Page();
        if (taskPrints!=null){
            taskPrints.getContent().forEach(taskPrint -> {
                FileInfo fileInfoByForeignId = fileInfoRepository.findFileInfoByForeignId(taskPrint.getId());
                if (fileInfoByForeignId != null) {
                    taskPrint.setFileInfo(fileInfoByForeignId);
                }
                Printer byPrinterName = printerRepository.findPrinterById(taskPrint.getPrinterId());
                if (byPrinterName != null) {
                    taskPrint.setPrinter(byPrinterName);
                }
                Device deviceById = deviceRepository.findDeviceById(taskPrint.getDeviceId());
                if (deviceById != null) {
                    taskPrint.setDevice(deviceById);
                }
            });
            page.setList(taskPrints.getContent());
            page.setCount((int) taskPrints.getTotalElements());
            page.setPageNum(taskPrintQueryParam.getPageNum());
            page.setPageSize(taskPrintQueryParam.getPageSize());
        }
        return page;
    }

9.7 AND OR条件查询

  /**
     * 分页查询
     */
    @ApiOperation(value = "2. 分页条件查询案件排期", notes = "2. 分页条件查询案件排期")
    @GetMapping("/list")
    public Object list(CaseSchedulingVO schedulingVO,
                       @RequestParam(required = false, defaultValue = "0") int pageNumber,
                       @RequestParam(required = false, defaultValue = "10") int pageSize) {
        //分页构造
        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        Page<CaseScheduling> pages = caseSchedulingRepository.findAll((Specification<CaseScheduling>) (root, cq, cb) -> {
            Path<String> caseNo = root.get("caseNo");
            Path<String> litignts = root.get("litignts");
            Path<String> caseReason = root.get("caseReason");
            Path<Integer> opened = root.get("opened");
            Path<Integer> isBurn = root.get("isBurn");
            Path<Integer> isMergedCasescheduling = root.get("isMergedCasescheduling");
            Path<Date> startTime = root.get("startTime");
            Path<Date> endTime = root.get("endTime");
            List<Predicate> adds = new ArrayList<>();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if (schedulingVO.getSearch() != null) {
                Predicate andCaseNo = cb.or(cb.equal(caseNo, schedulingVO.getSearch()));
                Predicate andLitignts = cb.or(cb.like(litignts, "%" + schedulingVO.getSearch() + "%"));
                Predicate andCaseReason = cb.or(cb.like(caseReason, "%" + schedulingVO.getSearch() + "%"));
                adds.add(cb.or(andCaseNo, andLitignts, andCaseReason));
            }
            if (schedulingVO.getOpened() != null) {
                Predicate andOpened = cb.and(cb.equal(opened, schedulingVO.getOpened()));
                adds.add(andOpened);
            }
            if (schedulingVO.getIsBurn() != null) {
                Predicate andIsBurn = cb.and(cb.equal(isBurn, schedulingVO.getIsBurn()));
                adds.add(andIsBurn);
            }
            if (schedulingVO.getStartTime() != null || schedulingVO.getEndTime() != null) {
                Predicate p = null;
                if (schedulingVO.getStartTime() != null && schedulingVO.getEndTime() != null) {
                    p = cb.between(startTime, schedulingVO.getStartTime(), schedulingVO.getEndTime());
                }
                if (schedulingVO.getStartTime() == null) {
                    Date date = new Date();
                    date.setTime(0);
                    p = cb.between(startTime, date, schedulingVO.getEndTime());
                }
                if (schedulingVO.getEndTime() == null) {
                    Date date = new Date();// 获取当前时间
//                       log.info("现在时间->"+sdf.format(date));
                    p = cb.between(endTime, schedulingVO.getStartTime(), date);
                }
                adds.add(p);
            }
            Predicate andisMergedCasesOne = cb.or(cb.equal(isMergedCasescheduling, 0));
            Predicate andisMergedCasesTwo = cb.or(cb.equal(isMergedCasescheduling, 2));
            adds.add(cb.or(andisMergedCasesOne, andisMergedCasesTwo));
            return cb.and(adds.toArray(new Predicate[]{}));
        }, pageable);
        return pages;
    }

9.7 时间范围过滤

 /**
     * 判断排期是否冲突
     * @param caseScheduling
     */
    public void   isConflictSchedule(CaseScheduling caseScheduling) {
        //查询时间段内是否有数据
        List<CaseScheduling> caseSchedulings = caseSchedulingRepository.findAll((Specification<CaseScheduling>) (root, cq, cb) -> {
            Path<Integer> isMergedCasescheduling = root.get("isMergedCasescheduling");
            Path<Date> startTime = root.get("startTime");
            Path<Date> endTime = root.get("endTime");
            List<Predicate> adds = new ArrayList<>();
            Predicate p1 ;
            Predicate p2 ;
            if (caseScheduling.getStartTime() != null || caseScheduling.getEndTime() != null) {
                /**
                 *         queryWrapper.le("start_time", endTime);
                 *         queryWrapper.ge("end_time", startTime);
                 */
                p1 = cb.lessThanOrEqualTo(startTime, caseScheduling.getEndTime());
                p2 = cb.greaterThanOrEqualTo(endTime, caseScheduling.getStartTime());
                adds.add(p1);
                adds.add(p2);
            }
            Predicate andisMergedCasesOne = cb.or(cb.equal(isMergedCasescheduling, 0));
            Predicate andisMergedCasesTwo = cb.or(cb.equal(isMergedCasescheduling, 2));
            adds.add(cb.or(andisMergedCasesOne, andisMergedCasesTwo));
            return cb.and(adds.toArray(new Predicate[]{}));
        });
        //如果检索到数据说明排期冲突
        if (!(caseSchedulings.isEmpty())){
            ConflictScheduling conflicscheduling=new ConflictScheduling();
            BeanUtils.copyProperties(caseScheduling,conflicscheduling);
            conflicschedulingRepository.save(conflicscheduling);
            CaseScheduling caseSchedulingConflics = caseSchedulings.get(0);
            throw new ServerException("排期时间冲突, 冲突的案件为:"+caseSchedulingConflics.getCaseNo()+"," +
                    "冲突的时间段为("+caseSchedulingConflics.getStartTime()+"~"+caseSchedulingConflics.getEndTime()+")");
        }
    }

9.8 条件排序

 List<Sort.Order> orders=new ArrayList<>();
        //开庭中优先级最高 ->未开庭 -> 开庭中最后
        orders.add(new Sort.Order(Sort.Direction.DESC,"isOpen"));
        // 从前到后
        orders.add(new Sort.Order(Sort.Direction.ASC,"startTime"));
        Pageable pageable = PageRequest.of(page, size,Sort.by(orders));

9.9 模糊查询(LIKE)

为了方便起见,service直接忽略,方便理解。

9.9.1 方法一使用自带方法

  1. Controller层:

方法参数如下,一定要加 “%”+name+“%”

@RestController
public class UserController {
    @Autowired
    private TeamRepository teamRepository;
    @GetMapping("/findByNameLike")
    public List<Team> findByNameLike(String name) {
        // 一定要加 "%"+参数名+"%"
        return teamRepository.findByNameLike("%"+name+"%");
    }
}
  1. Dao层:

一定要使用 JPA 规定的形式 findBy+参数名+Like(参数)

public interface TeamRepository extends JpaRepository<Team, String> {
    List<Team> findByNameLike(String name);

9.9.2 方法二使用sql

  1. Controller:

参数简单化

/**
 * @description:
 * @author: czx<15610554031@163.com>
 * @date: 2018/1/22 下午5:15
 * @version: V1.0
 */
@RestController
public class UserController {
    @Autowired
    private TeamRepository teamRepository;
    @GetMapping("/findByNameLike")
    public List<Team> findByNameLike(String name) {
        return teamRepository.findByNameLike(name);
    }
}
  1. Dao层:

需要自己定义SQL语句

/**
 * @description: 
 * @author: czx<15610554031@163.com>
 * @date: 2018/1/18 上午10:52
 * @version: V1.0
 */
public interface TeamRepository extends JpaRepository<Team, String> {
    @Query(value = "select t from Team t where t.name like %?1%")
    List<Team> findByNameLike(String name);

9.10 JPA自定义sql实现分页查询

CustomerRepository.java

@Query(nativeQuery = true, value = "select * from adm_sys_customer ORDER BY ?#{#pageable}",
countQuery = "select count(*) from adm_sys_customer")
Page<Customer> findAllByPageable(Pageable pageable);

CustomerServiceImpl.java

//调用自定义sql
Page<Customer> pageObjectList = customerRepos.findAllByPageable(pageService.getPageable(1, 1, null));

ORDER BY ?#{#pageable} 必须加,否则报错如果采用本地(nativeQuery = true)可以不加:

Caused by: org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException:

Cannot use native queries with dynamic sorting and/or pagination in …

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
SQL Java 数据库连接
JDBC DriverManager 详解
JDBC(Java Database Connectivity)是 Java 标准库中用于与数据库进行交互的 API。它允许 Java 应用程序连接到各种不同的数据库管理系统(DBMS),执行 SQL 查询和更新操作,以及处理数据库事务。在 JDBC 中,DriverManager 是一个关键的类,用于管理数据库驱动程序和建立数据库连接。本文将详细介绍 JDBC DriverManager 的用法,面向基础小白,帮助您快速入门 JDBC 数据库连接。
351 1
|
6月前
|
Linux
Linux系统ext4磁盘扩容实践指南
这个过程就像是给你的房子建一个新的储物间。你需要先找到空地(创建新的分区),然后建造储物间(格式化为ext4文件系统),最后将储物间添加到你的房子中(将新的分区添加到文件系统中)。完成这些步骤后,你就有了一个更大的储物空间。
545 10
|
7月前
|
机器学习/深度学习 自然语言处理 监控
深入探索:深度学习在时间序列预测中的强大应用与实现
时间序列分析是数据科学和机器学习中一个重要的研究领域,广泛应用于金融市场、天气预报、能源管理、交通预测、健康监控等多个领域。时间序列数据具有顺序相关性,通常展示出时间上较强的依赖性,因此简单的传统回归模型往往不能捕捉其中复杂的动态特征。深度学习通过其非线性建模能力和层次结构的特征提取能力,能够有效地捕捉复杂的时间相关性和非线性动态变化模式,从而在时间序列分析中展现出极大的潜力。
|
9月前
|
人工智能 自然语言处理 数据挖掘
从行业痛点到AI前沿:揭秘AGI时代企业培训的终极之选
近几年接触到的各类培训合作方越来越多,从国际咨询巨头、互联网科技培训平台,到本土独角兽型的专业培训公司;从专攻新技术与创新场景的培训团队,到深谙传统行业痛点的咨询顾问。作为一名在央企、国企、上市公司人力资源培训条线深耕多年的HR负责人,深知在这片竞争激烈的培训服务蓝海中,寻找高质、高效的合作伙伴并不简单,因为企业培训的逻辑正在悄然改变。
|
JSON C++ 数据格式
【VsCode】通过tasks.json中的problemMatcher属性的fileLocation子属性设定问题的输出内容
vscode 对于 json 文件的解析方式的开源代码部分. 摘录 文件目录设定部分的说明:
414 0
|
存储 Go 开发工具
go语言后端开发学习(二)——基于七牛云实现的资源上传模块
go语言后端开发学习(二)——基于七牛云实现的资源上传模块
169 0
|
监控 Devops jenkins
流行的软件质量保证体系工具
流行的软件质量保证体系工具
276 0
|
缓存 负载均衡 应用服务中间件
【2022】Nginx使用ngx_http_proxy_module模块实现七层反向代理
【2022】Nginx使用ngx_http_proxy_module模块实现七层反向代理
495 0
【2022】Nginx使用ngx_http_proxy_module模块实现七层反向代理
安装 xgboost 报错ERROR: Command "python setup.py egg_info" failed with error code 1 in /private/var/fold
安装 xgboost 报错ERROR: Command "python setup.py egg_info" failed with error code 1 in /private/var/fold
安装 xgboost 报错ERROR: Command "python setup.py egg_info" failed with error code 1 in /private/var/fold