SpringDataJPA整合

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Spursxuezhu/article/details/101567171

1.什么是SpringDataJPA

springdata 这个项目 对于jpa进行封装,而形成一个springdatajpa的框架。封装之后,使用更加简单

1.1 SpringdataJpa的crud
用法:定义一个接口 继承 JpaRepository这个接口

新增/修改 save 通过有无id来判断是使用新增还是修改
employeeRepository.save(employee)

 //保存
    @Test
    public void testSave()throws Exception{
        Employee employee = new Employee();
        employee.setUsername("王嘉诚");
        employee.setAge(18);
        employee.setEmail("[email protected]");
        employee.setPassword("1111111");
        employeeRepository.save(employee);
    }

查询 findOne employeeRepository.findOne(id)

 //查询一条数据
    @Test
    public void testQueryOne()throws Exception{
        Employee employee = employeeRepository.findOne(273L);
        System.out.println(employee);
    }

修改

//修改
    @Test
    public void testSave1()throws Exception{
        Employee employee = new Employee();
        employee.setId(274L);
        employee.setUsername("王嘉鑫");
        employee.setAge(18);
        employee.setEmail("[email protected]");
        employee.setPassword("1111111");
        employeeRepository.save(employee);
    }

删除

//删除一条数据
    @Test
    public void testDelete()throws Exception{

            employeeRepository.delete(274L);
    }

查询所有

//查询所有
    @Test
    public void testSpringDataJpa()throws Exception{

        for (Employee employee : employeeRepository.findAll()) {
            System.out.println(employee);
        }
    }

1.2 Springdatajpa的分页和排序

 Sort sort = new Sort(Sort.Direction.DESC,"age");
   //分页和排序
   Pageable pageable = new PageRequest(0, 10,sort);
   Page<Employee> page = employeeRepository.findAll(pageable);

1.3 按照条件规则查询–只适合简单的查询

public interface EmployeeRepository extends JpaRepository<Employee,Long> {

    //按照规则条件进行查询 模糊查询
    public List<Employee> findByUsernameLike(String username);

    public List<Employee> findByUsername(String username);

    public List<Employee> findByAgeGreaterThan(Integer age);
}

应用场景:只适合简单的sql 比如只有个一两个条件可以使用

1.4 写jpql语句–Query注解式jpql

//Query注解查询
    @Query("select o from Employee o where o.id =(select max(p.id) from Employee p)")
    public Employee queryEmployee();

    //根据用户名和邮件查询员工 参数名称 建议写来一致
    @Query("select o from Employee o where o.username like ?1 and o.email like ?2")
    public List<Employee> queryEmployee1(String name ,String email);

    //@Param(username) 必须和 :username 一致 建议来都写来一致
    @Query("select o from Employee o where o.username like :username and o.email like :email")
    public List<Employee> queryEmployee2(@Param("username") String name ,@Param("email") String email);

    //原生SQL支持
    @Query(value = "select count(*) from employee ",nativeQuery = true)
    public Long queryCount();

1.5 JpaSpecificationExecutor 查询

JpaSpecificationExecutor:jpa提供的规范的执行者,作用可以用来动态的生成jpql语句来查询
完成一些复杂查询

@Test
    public void testJpaSpecificationExecutorAndPage()throws Exception{
        //Specification
        Specification specification = new Specification<Employee>(){
            //设置条件 给哪一列(username)设置条件
            //root
            public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path path1 = root.get("username"); //root 拿到要操作的字段
                //criteriaBuilder  用来构建的查询
                Predicate predicate1 = criteriaBuilder.like(path1, "%1%");

                Path path2 = root.get("age");
                Predicate predicate2 = criteriaBuilder.greaterThan(path2, 30);

                CriteriaQuery cq = criteriaQuery.where(predicate1, predicate2);
                return cq.getRestriction();
            }
        };
        // select o from Employee o where username like '%1%' and age > 30
        Sort sort = new Sort(Sort.Direction.DESC,"age");
        Pageable pageable = new PageRequest(0, 2, sort);

        Page<Employee> page = employeeRepository1.findAll(specification,pageable);
        List<Employee> employees = page.getContent();
        for (Employee employee : employees) {
            System.out.println(employee);
        }

    }

1.6 jpa-spe插件
jpa-spec这个插件 对应 JpaSpecificationExecutor 进行封装,封装出来之后,简化上面jpa规则查询的写法,更好用

使用:
​ (1)导入依赖包
(2)测试

5.3.1.单个条件查询

@Test
public void testSpecFind01() {
    Specification<Employee> spec = Specifications.<Employee>and().like("username", "%1%").build();
    List<Employee> emps = employeeRepository.findAll(spec);
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

5.3.2.多个条件查询

@Test
public void testSpecFind02() {
    Specification<Employee> spec = Specifications.<Employee>and().like("username", "%1%")
            .like("email","%2%").lt("age", 20).build();
    List<Employee> emps = employeeRepository.findAll(spec);
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

5.3.3.条件+排序分页功能

//条件集成+分页
@Test
public void testSpecFind03() {
    Specification<Employee> spec = Specifications.<Employee>and().like("username", "%1%").build();
    //排序 :第一个参数是排序的规则(DESC/ASC)  后面参数是排序的字符
    Sort sort = new Sort(Sort.Direction.DESC,"username");
    Pageable pageable = new PageRequest(0, 10,sort);

    Page<Employee> page = employeeRepository.findAll(spec, pageable);
    for (Employee emp : page) {
        System.out.println(emp);
    }
}

Query查询条件
6.1.BaseQuery:公共的分页条件

package cn.itsource.pss.query;
/**
 * 公共的条件与规范
 */
public abstract class BaseQuery {

    //当前页(从1开始)
    private int currentPage = 1;
    //每页条数
    private int pageSize = 10;

    //排序方式 ASC/DESC
    private String orderByType ="ASC";
    //排序字段
    private String orderByName;

    public int getCurrentPage() {
        return currentPage;
    }
    /**
     * 专门准备的方法,因为前台用户传的是从第1页开始,而我们后台分页又是从0开的
     * @return
     */
    public int getJpaPage() {
        return currentPage - 1;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }
    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
    public String getOrderByType() {
        return orderByType;
    }

    public void setOrderByType(String orderByType) {
        this.orderByType = orderByType;
    }

    public String getOrderByName() {
        return orderByName;
    }

    public void setOrderByName(String orderByName) {
        this.orderByName = orderByName;
    }
}

EmployeeQuery:Employee特有的一些条件

package cn.itsource.pss.query;

public class EmployeeQuery extends BaseQuery {

    private String username;//姓名
    private String email;//邮件
    private Integer age;//年龄

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

6.3.功能测试

//根据Query对象进行查询
@Test
public void testSpecFindByQuery() {
    //创建模块一个Query对象
    EmployeeQuery baseQuery = new EmployeeQuery();
//下面的都是测试的条件,可以任何放开进行测试
    //baseQuery.setUsername("1");
    //baseQuery.setAge(20);
    //baseQuery.setEmail("2");
    //baseQuery.setOrderByName("username");
    //baseQuery.setOrderByType("DESC");
    //baseQuery.setCurrentPage(2);
    //baseQuery.setPageSize(5);

	//like(条件boolean值,字段,值)
    Specification<Employee> spec = Specifications.<Employee>and()
            .like(StringUtils.isNotBlank(baseQuery.getUsername()), "username","%"+baseQuery.getUsername()+"%")
            .like(StringUtils.isNotBlank(baseQuery.getEmail()), "email","%"+baseQuery.getEmail()+"%")
            .lt(baseQuery.getAge()!=null, "age",baseQuery.getAge())
            .build();


    //这里确定是否需要排序
    Sort sort = null;
    if(baseQuery.getOrderByName()!=null){
        Sort.Direction desc = "DESC".equals(baseQuery.getOrderByType())?Sort.Direction.DESC:Sort.Direction.ASC;
        sort = new Sort(desc,baseQuery.getOrderByName());
    }
    Pageable pageable = new PageRequest(baseQuery.getJpaPage(), baseQuery.getPageSize(),sort);

    Page<Employee> page = employeeRepository.findAll(spec, pageable);
    for (Employee emp : page) {
        System.out.println(emp);
    }
}

6.4 创建Specification的流程放到Query里
BaseQuery中添加抽象方法

public abstract class BaseQuery {
...
//拿到查询的条件对象(由子类实现)
	public abstract Specification createSpecification();
//拿到排序的数据
	public Sort createSort() {
    		Sort sort = null;
    		if (StringUtils.isNotBlank(orderByName)) {
        		Sort.Direction type=  "ASC".equals(orderByType.toUpperCase())? Sort.Direction.ASC:Sort.Direction.DESC;
       		 sort = new Sort(type,orderByName);
    		}
    		return sort;
	}
...
}

EmployeeQuery中实现相应方法
(以后每一个Query要做高级查询都写在这个位置)

public class EmployeeQuery extends BaseQuery {
    ...
@Override
	public Specification createSpecification() {
    	//根据条件把数据返回即可
   	return  Specifications.<Employee>and()
            .like(StringUtils.isNotBlank(username), "username","%"+username+"%")
            .like(StringUtils.isNotBlank(email), "email","%"+email+"%")
            .lt(age!=null, "age",age)
            .build();
	}
...
}

在这里插入图片描述Spring Data Jpa扩展
在这里插入图片描述7.1.BaseRepository接口
直接创建BaseRepository来继承JpaRepository接口

package cn.itsource.pss.repository;

import cn.itsource.pss.query.BaseQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;

import java.io.Serializable;
import java.util.List;

/**
 * 自定义一个Repository,它是JpaRepository的功能基础上继承增强
 * 在上面添加@NoRepositoryBean标注,这样Spring Data Jpa在启动时就不会去实例化BaseRepository这个接口
Spring会自动扫描 最终会找到SimpleJpaRepository实现类,但是这个类没有下面的方法,所有添加该注解
 * @param <T>
 * @param <ID>
 */
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T>{
    //根据Query拿到分页对象(分页)
    Page findPageByQuery(BaseQuery baseQuery);

    //根据Query拿到对应的所有数据(不分页)
    List<T> findByQuery(BaseQuery baseQuery);

    //根据jpql与对应的参数拿到数据
    List findByJpql(String jpql,Object... values);
}

BaseRepositoryImpl功能实现

package cn.itsource.pss.repository;

import cn.itsource.pss.query.BaseQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.List;

/**
 * 实现父类中的三个方法
 * @param <T>
 * @param <ID>
 */
public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T,ID> {

    private final EntityManager entityManager;

    //必需要实现父类的这个构造器
    public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }

    @Override
    public Page findPageByQuery(BaseQuery baseQuery) {
        //第一步:拿到所有高级查询条件
        Specification spec = baseQuery.createSpecification();
        //第二步:拿到排序的值
        Sort sort = baseQuery.createSort();
        //第三步:根据条件查询分页数据并且返回
        Pageable pageable = new PageRequest(baseQuery.getJpaPage(), baseQuery.getPageSize(),sort);
        Page<T> page = super.findAll(spec, pageable);
        return page;
    }

    @Override
    public List<T> findByQuery(BaseQuery baseQuery) {
        //第一步:拿到所有高级查询条件
        Specification spec = baseQuery.createSpecification();
        //第二步:拿到排序的值
        Sort sort = baseQuery.createSort();
        //第三步:拿到数据返回
        return findAll(spec, sort);
    }

    @Override
    public List findByJpql(String jpql, Object... values) {
        //第一步:创建Query对象
        Query query = entityManager.createQuery(jpql);
        //第二步:把值设置到Query对象中去
        if (values!=null) {
            for (int i = 0; i < values.length; i++) {
                query.setParameter(i + 1, values[i]);
            }
        }
        //第三步:返回数据
        return query.getResultList();
    }
}

7.3.创建自定义创建自定义RepositoryFactoryBean

package cn.itsource.pss.repository;

import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;

import javax.persistence.EntityManager;
import java.io.Serializable;

public class BaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T,S,ID> {

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
          return new MyRepositoryFactory<T,ID>(entityManager); //注:这里创建是我们的自定义类
    }

    //继承JpaRepositoryFactory后,把返回的对象修改成我们自己的实现
    private static  class MyRepositoryFactory<T,ID extends Serializable>   extends JpaRepositoryFactory{
        private final EntityManager entityManager;
        /**
         * Creates a new {@link JpaRepositoryFactory}.
         *
         * @param entityManager must not be {@literal null}
         */
        public MyRepositoryFactory(EntityManager entityManager) {
            super(entityManager);
            this.entityManager = entityManager;
        }
	   //这里返回最后的功能对象
        @Override
        protected Object getTargetRepository(RepositoryInformation information) {
            return new BaseRepositoryImpl<T,ID>((Class<T>)information.getDomainType(),entityManager);
        }
	   //确定功能对象的类型
        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
    }

}

7.4.1.applicationContext.xml 中修改配置

<!-- Spring Data Jpa配置 ********************************************-->
<!-- base-package:扫描的包 -->
<jpa:repositories base-package="cn.itsource.pss.repository" transaction-manager-ref="transactionManager"
                  entity-manager-factory-ref="entityManagerFactory"
                  factory-class="cn.itsource.pss.repository.BaseRepositoryFactoryBean"
/>

7.4.2.继承BaseRepository

public interface EmployeeRepository extends BaseRepository<Employee,Long>{
}

7.5.测试扩展功能

//测试分页查询
@Test
public void testFindPageByQuery() {
    EmployeeQuery baseQuery = new EmployeeQuery();
    baseQuery.setUsername("1");
    //baseQuery.setAge(20);
    //baseQuery.setEmail("2");
    baseQuery.setOrderByName("username");
    baseQuery.setOrderByType("DESC");
    //baseQuery.setCurrentPage(2);
    baseQuery.setPageSize(5);
    Page<Employee> page = employeeRepository.findPageByQuery(baseQuery);
    for (Employee employee : page) {
        System.out.println(employee);
    }
}

//测试单独查询
@Test
public void findByQuery() {
    EmployeeQuery baseQuery = new EmployeeQuery();
    baseQuery.setUsername("1");
    //baseQuery.setAge(20);
    //baseQuery.setEmail("2");
    baseQuery.setOrderByName("username");
    baseQuery.setOrderByType("DESC");
    List<Employee> emps = employeeRepository.findByQuery(baseQuery);
    for (Employee employee : emps) {
        System.out.println(employee);
    }
}

//测试自定义JPQL
@Test
public void findByJpql() {
    List<Employee> emps = employeeRepository.findByJpql("select o from Employee o where username = ? and password = ?","admin","admin");
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

猜你喜欢

转载自blog.csdn.net/Spursxuezhu/article/details/101567171