springboot学习笔记5(JPA 实现分页、排序、返回map集合)

来源:互联网 发布:淘宝怎么给商品打折 编辑:程序博客网 时间:2024/06/08 11:24

   前言

    在相当长的一段时间里,实现应用程序的数据访问层非常麻烦。必须编写太多的模板代码来执行简单的查询,以及执行分页。Spring data  JPA旨在通过减少实际需要的工作量来显著改进数据访问层的实现。作为开发人员,您可以编写存储库接口,包括自定义查找程序方法。spring data JPA核心接口是Repository,其它所有接口都在此类的基础上进行了扩展。 下面是JPA关系图解图:


 熟悉JPA的几个API

     CurdRepository提供了增删改产方法,PagingAndSortingRepositroy增加了分页查询方法,JpaRepositroy又增加了实例查询方法。实际应用中可以有选择的继承上面接口即可。上面说过,jpa提供了封装查询数据库模板方法。下面就来一一介绍JPA给我们提供的模板方法:

CurdRepository 

 接口,提供增删改查基本的功能:

@NoRepositoryBeanpublic interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {<S extends T> S save(S entity);<S extends T> Iterable<S> save(Iterable<S> entities);T findOne(ID id);boolean exists(ID id);Iterable<T> findAll();Iterable<T> findAll(Iterable<ID> ids);long count();void delete(ID id);void delete(T entity);void delete(Iterable<? extends T> entities);void deleteAll();}

PagingAndSortingRepositroy

  接口 ,分页查询,和排序:

@NoRepositoryBeanpublic interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {       //分类查询Iterable<T> findAll(Sort sort);       //分页查询Page<T> findAll(Pageable pageable);}

JpaRepositroy

      接口,提供实例查询方法

@NoRepositoryBeanpublic interface JpaRepository<T, ID extends Serializable>extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {<S extends T> S saveAndFlush(S entity);void deleteInBatch(Iterable<T> entities);void deleteAllInBatch();T getOne(ID id);               //实例查询@Override<S extends T> List<S> findAll(Example<S> example);      //实例查询,分类排序@Override<S extends T> List<S> findAll(Example<S> example, Sort sort);}

SimpleRepository

     实现类,增加了事务注解,进行事务管理,这就不介绍了,讲到自定义封装基类的时候会用到,一般都不会继承使用这个类.

使用 

       自定义一个PersonRepository接口继承上述任何一个接口都可以。不需要在接口上加@Repository注解,也不需要写实现类,即可在service,controller层注入使用,是不是很简洁。对于一般的修改保存操作,只要直接调用JPA接口提供的方法就可以用了,这里就不在介绍了。

entity层 

 Person实体类:

@Entitypublic class Person {   private Integer id;     private String name;    private String password;  .....省略get set方法}

持久层

PersonRepository 接口

     下面介绍了JPA查询方法,条件查询,list集合查询,分页查询,排序查询,sql语句查询,指定字段查询,实例查询,基本上包含了实际开发中所需要的查询方法。

//省略了注释。public interface PersonRepository extends JpaRepository<Person, Integer> {       //自定义查询,AND为jpa 关键字,相当于(where x.lastname = ?1 and x.firstname = ?2)        jpa关键字应该都要熟悉        Person findByNameAndPassword(String name ,String password);        //指定字段查询,只返回name        PersonName   findById(Integer id);                  //排序查询,返回list集合        List<Person> findByNameAndPassword(String name ,String password,Sort sort);                  //分页查询 查询计算元素总个数总页数,数据多的情况下,代价是昂贵的        Page<Person> findByNameAndPassword(String name ,String password,Pageable pageable);         //分页查询,返回的是一个片段,它只知道下一片段或者上一片段是否可用。        Slice<Person> findByNameAndPassword(String name,Pageable pageable);          //sql查询。?后面数字,对应方法中参数位置。使用原生sql语句        @Query("select p from person as p where p.name = ?1 and p.password = ?2 ",nativeQuery = true)         Person myfind(String name ,String password);                //实例查询        Person findByExample(Example example)}

   说明: spring data JPA 提供两种查询方式,一种就是直接从方法名中派生中查询(需要遵循它的规范,见下文 JPA 查询语句关键字)上面的例子就是这种方式;另一种就是手动定义查询了(使用JPA 核心类 EntityManager,下文自定义查询会介绍)。

Controller 层

@RestController public class TestController  {    @Resource    private PersonRepository personRepository;        @GetMapping(value = "/test")  public String test(Integer personId){               Person  p = personRepository.findByNameAndPassword("张三","123");        //排序      List<Person> p1 = personRepository.findByNameAndPassword("张三","123",new Sort(Sort.Direction.ASC,"id"));      //分页      Page<Person> p2 = personRepository.findByNameAndPassword("张三","123", new PageRequest(1,10,new Sort("id")));             Person tempPerson=new Person();       tempPerson.setId(personId));       //通过实例查询        Person p3= personRepository.findByExample(Example.of(tempPerson))             return    p+"+"+ p1 "+"+p2.getTotalElements()+"+"+p3;}

JPA 查询语句关键字

KeywordSampleJPQL snippetAndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2Is,EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = 1?BetweenfindByStartDateBetween… where x.startDate between 1? and ?2LessThanfindByAgeLessThan… where x.age < ?1LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1GreaterThanfindByAgeGreaterThan… where x.age > ?1GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1AfterfindByStartDateAfter… where x.startDate > ?1BeforefindByStartDateBefore… where x.startDate < ?1IsNullfindByAgeIsNull… where x.age is nullIsNotNull,NotNullfindByAge(Is)NotNull… where x.age not nullLikefindByFirstnameLike… where x.firstname like ?1NotLikefindByFirstnameNotLike… where x.firstname not like ?1StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname descNotfindByLastnameNot… where x.lastname <> ?1InfindByAgeIn(Collection<Age> ages)… where x.age in ?1NotInfindByAgeNotIn(Collection<Age> age)… where x.age not in ?1TruefindByActiveTrue()… where x.active = trueFalsefindByActiveFalse()… where x.active = falseIgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame)

 自定义查询(返回map集合)

       上面的例子都是一些简单的查询,但实际开发中,我们可能会需要用到复杂的sq、连接查询或者需要查询结果只包含我们需要的字段。如果实体之间的关联关系都配置得当的话,JPA提供的方法也可以满足我们的需求。当然我们也可以自定义一个继承JPA的模板类,然后封装查询的方法:

BaseRepository

创建一个BaseRepository ,定义两个sq语句查询:


/** * repository 基类,封装自定义查询方法 * * @author  * @date 2017/5/12 8:32 * @Package com.base * @Version v1.0 */@NoRepositoryBean //该注解表示 spring 容器不会创建该对象public interface BaseRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>,JpaRepository<T,ID> {           /**     * sql查询     *     * @param sql     * @param args     * @return     */    List<Map> findAllByParams(String sql, Object... args);  /**     * sql分页查询     *     * @param sql     * @param args     * @return     */    Page<Map> findPageByParams(String sql, Pageable pageable, Object... args);}

BaseRepositoryImpl

BaseRepositoryImpl 类,实现BaseRepository 接口:

/** * @author  * @date 2017/5/12 8:32 * @Package com.base.impl * @Version v1.0 */public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {        //实体管理类,对持久化实体做增删改查,自动义sq操作模板所需要的核心类    public final EntityManager entityManager;    public BaseRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {        super(entityInformation, entityManager);        this.entityManager = entityManager;    }    @Override    @Transactional(rollbackFor = Exception.class)    public List<Map> findAllByParms(String sql, Object... args) {        //获取session        Session session = (Session) entityManager.getDelegate();        org.hibernate.Query q = session.createSQLQuery(sql);         //查询结果转map                q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);        int i = 0;        for (Object arg : args                ) {            q.setParameter(i++, arg);        }        return q.list();    }     @Override     @Transactional(rollbackFor = Exception.class)    public Page<Map> findPageByParams(String sql, Pageable pageable, Object... args) {        Session session = (Session) entityManager.getDelegate();        org.hibernate.Query q = session.createSQLQuery(sql);        q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);        int i = 0;        for (Object arg : args                ) {            q.setParameter(i++, arg);        }        List<Map> totalCount = q.list();        q.setFirstResult(pageable.getPageSize() * (pageable.getPageNumber() - 1));        q.setMaxResults(pageable.getPageSize());        List<Map> pageCount = q.list();        Page<Map> pages = new PageImpl<>(pageCount, pageable, totalCount.size());        return pages;    }}

PersonRepositroy

创建一个PersonRepositroy 继承BaseRepository,就可以直接使用定义的查询方法了:

/** * @author  * @date 2017/5/12 10:07 * @Package com.repository * @Version v1.0 */public interface PersonRepository extends BaseRepository<Person, Integer> {}

TestController 

@RestController public class TestController  {    @Resource    private PersonRepository personRepository;   @GetMapping(value = "/test")   public String test( ){        //订单表与用户表关联,通过用户ID查询该用户的所有订单,只获取订单编号和订单详情。       String sql="select o.no,o.detail from person as p inner join order as o on o.personid=p.id and p.id= ? "      Integer userId=11;      Page<Map>  orderLists = personRepository.findPageByParams(sql,new PageRequest(1,10),userId);  return   orderLists;}}


最后,在项目启动类上加一个注解,告诉springboot,我要使用JPA,请到repository包下去扫描我创建的repository 类,我的repository基类是BaseRepositoryImpl:

@EnableJpaRepositories(basePackages = {"com.repository"}, repositoryBaseClass = BaseRepositoryImpl.class)public class MybootApplication { public static void main(String[] args) {SpringApplication.run(MybootApplication.class, args);}}

这样启动项目,就可以进行对数据库访问了。上面的例子主要是解决如何使用sq语句对数据库操作,对于其他情况,大家可以自己尝试。