一步一步学 Spring Boot 2 (三)

第3章: 集成 Spring Data JPA

本章主要介绍SpringDataJPA 核心接口以及集成关系、在Spring Boot中集成Spring Data JPA 以及如何通过 DataJPA 实现增删改查及自定义查询等。

3.1 Spring Data JPA 介绍

本章主要介绍Spring Data JPA 是什么、Spring Data JPA 核心接口Repository、核心接口间的继承关系图。

3.1.1 Spring Data JPA介绍

JPA(Java Persistence API)是Sun官方提出的Java持久化规范。所谓规范,即只定义标准规则,不提供实现。而JPA的主要实现有Hibernate、EclipseLink、OpenJPA等。JPA是一套规范,不是一套产品。Hibernate是一套产品,如果这些产品实现了JPA规范,那我们可以称其为JPA的实现产品。
Spring Data JPA是Spring Data的一个子项目,通过提供基于JPA的 Repository 极大地减少了 JPA作为数据访问方案的代码量,通过 Spring Data JPA 框架,开发者可以省略实现持久层业务逻辑的工作,唯一要做的就是声名持久层的接口,其他都交给Spring Data JPA 来完成。

3.1.2 核心接口 Repository

Spring Data JPA 最顶层的接口是Repository,该接口是所有Repository类的父类。具体代码如下:

package org.springframework.data.repository;
import java.io.Serializable;
public interface Repository<T,ID extends Serializable>{

}

Repository 类下没有任何接口,只有一个空类。Repository接口的子类有CrudRepository、PagingAndSortingRepository、JpaRepository 等。其中,CrabRepository类提供了基本的增删改查等接口,PaingAndSortingRepository类提供了基本的分页和排序等接口,JpaRepository类是CrabRepository类和PaingAndSortingRepository类的子类,继承了它们的所有接口。所以在真实的项目当中,我们都是通过实现JpaRepository或者其子类进行基本的数据库操作。JpaRepository的具体代码如下:

@NoRepositoryBean
public interface JpaRepository extends PaingAndSortingRepository<T,ID>{
	List<T> findAll();
	List<T> findAll(Sort var1);
	List<T> findAll(Iterable var1);
	<S extends T> List<S> save(Iterable<S> var1);
	void flush();
	<S extends T> S saveAndFlush(S var1);
    void deleteInBatch(Iterable<T> var1);
    void deleteInBatch();
    T getOne(ID var1);
    <S extends T> List<S> findAll(Example<S> var1);	
	<S extends T> List<S> findAll(Example<S> var1,Sort var2);
}
  • @NoRepositoryBean:使用该注解标明此接口不是一个Repository Bean。
3.1.3 接口继承关系图

Repository接口间的继承关系如图所示,通过该继承图可以清楚地知道接口间的继承关系。在项目中,我们一般都是实现JpaRepository类,加上自己定义的业务方法来完成业务开发。在这里插入图片描述

3.2 集成 Spring Data JPA

本节主要介绍如何在Spring Boot 中集成 Spring Data JPA,服务层类开发,如何通过 Spring Data JPA 实现基本的增、删、改、查功能,以及自定义查询方法等内容。

3.2.1 引入依赖

在 Spring Boot 中集成 Spring Data JPA,首先需要在pom.xml文件引入所需的依赖,具体代码如下:

<dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

在之前的章节中,我们已经在开发工具中安装好了Maven Helper插件,所以大家可以通过该插件查看目前引入的所有依赖,如图所示:
在这里插入图片描述

3.2.2 继承JpaRepository

在pom.xml文件中引入依赖之后,我们在目录/src/main/java/com.example.demo.repository下开发一个AyUserRepository类,如图所示,代码如下:
在这里插入图片描述

public interface AyUserRepository extends JpaRepository<AyUser,String>{

}

在此同时,我们需要在AyUser实体类下面添加@Entity和@Id注解,具体代码如下:

@Entity
@Table(name = "ay_user")
public class AyUser {
   //主键
   @Id
   private String id;
   //用户名
   private String name;
   //密码
   private String password;
}

在这里插入图片描述

  • @Entity:每一个持久化POJO类都是一个实体Bean,通过在类的定义中使用@Entity注解来进行声名。
  • @Table:声名此对象映射到数据库的数据表。该注释不是必须的,如果没有,系统就会使用默认值(实体的短类名)。
  • @Id:指定表的主键。
3.2.3 服务层类实现

我们在my-spring-boot项目下继续开发服务层接口类和实现类:AyUserService和AyUserServiceImpl类,分别存放在目录/src/main/java/com.example.demo.service和/src/main/java/com/example.demo.service.Impl下。具体代码如下:

public interface AyUserService {
  AyUser findById(String id);
  List<AyUser> findAll();
  AyUser save(AyUser ayUser);
  void delete(String id);
}

接口类AyUserService定义了4个接口,findById和findAll用来查询单个和所有数据,delete用来删除数据,save同时具备保存和更新数据的功能,接口实体类AyUserServiceImpl 的代码如下:


@Service
public class AyUserServiceImpl implements AyUserService {
    @Resource
    private AyUserRepository ayUserRepository;
    
    @Override
    public AyUser findById(String id){
        return ayUserRepository.findById(id).get();
    }
    @Override
    public List<AyUser> findAll() {
        return ayUserRepository.findAll();
    }
    @Override
    public AyUser save(AyUser ayUser) {
        return ayUserRepository.save(ayUser);
    }
    @Override
    public void delete(String id) {
        ayUserRepository.deleteById(id);
    }
}
  • @Service:Spring Boot 会自动扫描到@Component 注解的类,并把这些类纳入Spring容器中管理。也可以用@Component注解,只是@Service注解更能表明该类是服务层类。
  • @Component:泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
  • @Repository:持久层组件,用于标注数据访问组件,即DAO组件。
  • @Resource:这个注解属于J2EE,默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定的name属性,当注解写在字段上时,就默认取字段名进行查找。。如果注解写在setter方法上,就默认去属性名进行装配,当找不到与名称匹配的bean时,才按照类型进行装配。但需要注意的是,name属性一旦指定,就只会按照名称进行装配。具体代码如下:
@Resource(name = "ayUserRepository")
private AyUserRepository ayUserRepository;
  • @Autowired:这个注解属于Spring,默认按类型装配。默认情况下,要求依赖对象必须存在,如果要允许null值,那么可以设置它的required属性为false,如果@Autowired(required=false);如果想使用名称装配,那么可以结合@Qualifier注解使用。具体代码如下:
@Autowired
@Qualifier("ayUserRepository")
private AyUserRepository ayUserRepository;
3.2.4 增删改查分页简单实现

前面已经在服务层类AyUserService开发完增删改查方法,这一节将继续在类中添加分页接口,具体代码如下:


//用户服务层接口
public interface AyUserService {
	AyUser findById(String id);
	List<AyUser> findAll();
	AyUser save(AyUser ayUser);
	void delete(String id);
	//分页
	Page<AyUser> findAll(Pageable pageable);
	
}
  • Pageable:这是一个分页接口,查询时只需要传入一个Pageable接口的实现类,指定pageNumber和pageSize即可。pageNumber为第几页,而pageSize为每页的大小。
  • Page:分类查询结果会封装在 该类中,page接口实现Slice接口,通过查看其代码源可知。我们通过调用getTotalPages和getContent等方法可以很方便地获得总页数和查询的记录。Page接口和Slice接口源代码如下:

public interface Page<T> extends Slice<T> {
	int getTotalPages();
	long getTotalElements();
	<S>Page<S> map(Converter<? super T, ? extends S> var1);
}


public interface Slice<T> extends Iterable<T> {
	int getNumber();
	int getSize();
	int getNumberOfElements();
	List<T> getContent();
	boolean hasContent();
	Sort getSort();
	boolean isFirst();//第一个
	boolean isLast();//持续
	boolean hasNext();//下一页
	boolean hasPrevious();//上一页
	boolean nextPageable();
	Pegaable previousPageable();
	<S> Slice<S> map(Converter<? super T, ? extends S> var1);
}

分页方法定义好之后,在类AyUserServiceImpl中实现该方法,具体代码如下:

@Override
public Page<AyUser> findAll(Pageable pageable){
    return ayUserRepository.findAll(pageable);
}
3.2.5 自定义查询方法

我们除了使用JpaRepository接口提供的增删改查分页等方法之外,我们还可以自定义查询方法。在AyUserRepository类中添加几个自定义查询方法,具体代码如下:

//用户Repository
public interface AyUserRepository extends JpaRepository<AyUser,String>{
//通过名字相等查询,参数为name
//相当于:select u from ay_user u where u.name=?1

List<AyUser> findByName(String name);
//通过名字like查询,参数为name
//相当于:select u from ay_user u where u.name like ?1
List<AyUser> findByNameLike(String name);
//通过主键id集合查询,参数为id集合
//相当于:select u from ay_user u where id in (?,?,?)
//@param ids
List<AyUser> findByIdIn(Collection<String> ids);
}

在AyUserRepository中自定义了3个查询的方法。从代码可以看出,Spring Data JPA 为我们约定了一系列规范,只要按照规范编写代码,Spring Data JPA 就会根据代码翻译成相关的SQL语句,进行数据库查询。比如可以使用 findBy,Like,In等关键字,其中findBy可以用read、readby、query、queryBy、get、getBy来代替。关于查询关键字的更多内容,大家可以到官方网站查看,里面有详细的内容介绍,这里就不一一列举了。
AyUserRepository类中的自定义查询方法开发完成之后,分别在类AyUserService和AyUserServiceImpl中调用它们。
AyUserService继续添加这3个方法,具体代码如下:

List<AyUser> findByName(String name);
List<AyUser> findByNameLike(String name);
List<AyUser> findByIdIn(Collection<String> ids);

AyUserServiceImpl类添加这3个方法,具体代码如下:

@Override
public List<AyUser> findByName(String name){
   return ayUserRepository.findByName(name);
}
@Override
public List<AyUser> findByNameLiek(String name){
   return ayUserRepository.findByNameLiek(name);
}
@Override
public List<AyUser> findIdIn(Collection<String> ids){
   return ayUserRepository.findIdIn(ids);
}

温馨提示:@Override 注解不可以去掉,他可以帮助我们效验接口方法是否被误改。

3.3 集成测试

3.3.1 测试用例开发

在测试类MySpringBootApplicationTests中添加如下代码:

 @Resource
    private AyUserService ayUserService;

    @Test
    public void testRepository(){
        //查询所有数据
        List<AyUser> userList =  ayUserService.findAll();
        System.out.println("findAll(查看所有) :" + userList.size());
        //通过name查询数据
        List<AyUser> userList2 = ayUserService.findByName("阿鸡");
        System.out.println("findByName(查询名字) :" + userList2.size());
        Assert.isTrue(userList2.get(0).getName().equals("阿鸡"),"data error!");
        //通过name模糊查询数据
        List<AyUser> userList3 = ayUserService.findByNameLike("%鸡%");
        System.out.println("findByNameLike(查看含有鸡的名字有几个) :" + userList3.size());
        Assert.isTrue(userList3.get(0).getName().equals("阿鸡"),"data error!");
        //通过id列表查询数据
        List<String> ids = new ArrayList<String>();
        ids.add("1");
        ids.add("2");
//        ids.add("3");
//        ids.add("4");
//        ids.add("5");
//        ids.add("6");
        List<AyUser> userList4 = ayUserService.findByIdIn(ids);
        System.out.println("findByIdIn() :" + userList4.size());
        //分页查询数据
        Pageable pageable = PageRequest.of(0,10);
        Page<AyUser> userList5 =  ayUserService.findAll(pageable);
        System.out.println("page findAll(查看页数):" + userList5.getTotalPages() + "/" + userList5.getSize());
        //新增数据
        AyUser ayUser = new AyUser();
        ayUser.setId("3");
        ayUser.setName("test");
        ayUser.setPassword("123");
        ayUserService.save(ayUser);
        //删除数据
        ayUserService.delete("3");
    }
  • Assert:添加Assert断言在软件开发中是一种常用的调试方式。从理论上来说,通过Assert断言方式可以证明程序的正确性,现在在项目中被广泛使用,这是大家需要掌握的基本知识。Assert提供了很多好用的方法,比如isNull、isTrue等。
3.3.2 测试

通过运行3.3.1节的单元测试用例,我们可以在控制台看到如下打印信息:
在这里插入图片描述

通过上面的打印信息可以看出,Spring Boot 集成 Spring Data JPA 已经成功,同时代码中的所有Assert断言全部通过,说明增删改查分页以及自定义方法都可以正常运行。

猜你喜欢

转载自blog.csdn.net/qq_43791614/article/details/108367995