本节主要介绍如何在Spring Boot中集成Spring Data JPA,服务层类开发,如何通过Spring Data JPA实现基本增删改查功能,以及自定义查询方法等内容。
引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.shrimpking</groupId>
<artifactId>demo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
继承JpaRepository
在pom.xml文件中引入依赖之后,我们在目录/src/main/java/com.shrimpking.repository下开发一个AvUserRepository类,
package com.shrimpking.repository;
import com.shrimpking.model.AvUser;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Collection;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:28
*/
public interface AvUserRepository extends JpaRepository<AvUser,String>
{
}
与此同时,我们需要在AvUser实体类下添加@Entity和@Id注解,具体代码如下:
package com.shrimpking.model;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/9 21:14
*/
@Data
@Entity
@Table(name = "av_user")
public class AvUser
{
@Id
private String id;
private String name;
private String password;
}
@Entity:每个持久化POJO类都是一个实体Bean,通过在类的定义中使用@Entity注解来进行声明。
@Table:声明此对象映射到数据库的数据表。该注释不是必需的,如果没有则系统使用默认值(实体的短类名)。
@Id:指定表的主键。
服务层类实现
AvUserService和AvUserServiceImpl类,它们分别存放在目录/src/main/java/com.shrimpking.service和/src/main/java/com.shrimpking.service.impl下。具体代码如下:
package com.shrimpking.service;
import com.shrimpking.model.AvUser;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.Collection;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:32
*/
public interface AvUserService
{
AvUser findById(String id);
List<AvUser> findAll();
AvUser save(AvUser avUser);
void delete(String id);
}
接口类AvUserService定义了4个接口,findById和findAll用来查询单个和所有数据,Delete用来删除数据,Save同时具备保存和更新数据的功能。接口实现类AvUserServiceImpl代码如下:
package com.shrimpking.service.impl;
import com.shrimpking.model.AvUser;
import com.shrimpking.repository.AvUserRepository;
import com.shrimpking.service.AvUserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:34
*/
@Service
public class AvUserServiceImpl implements AvUserService
{
@Resource
private AvUserRepository avUserRepository;
@Override
public AvUser findById(String id)
{
return this.avUserRepository.findById(id).get();
}
@Override
public List<AvUser> findAll()
{
return this.avUserRepository.findAll();
}
@Override
public AvUser save(AvUser avUser)
{
return this.avUserRepository.save(avUser);
}
@Override
public void delete(String id)
{
this.avUserRepository.deleteById(id);
}
}
@Service:Spring Boot会自动扫描到@Component注解的类,并把这些类纳入进Spring容器中管理。也可以用@Component注解,只是@Service注解更能表明该类是服务层类。
@Component:泛指组件,当组件不好归类的时候,可以使用这个注解进行标注。
@Repository:持久层组件,用于标注数据访问组件,即DAO组件。
@Resource:这个注解属于J2EE的,默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行查找。如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Autowired:这个注解是属于Spring的,默认按类型装配。默认情况下要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false),如果想使用名称装配可以结合@Qualifier注解进行使用。
增删改查分页简单实现
我们已经在服务层类AvUserService中开发完增删改查方法,这一节,我们将继续在类中添加分页接口,具体代码如下:
package com.shrimpking.service;
import com.shrimpking.model.AvUser;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.Collection;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:32
*/
public interface AvUserService
{
AvUser findById(String id);
List<AvUser> findAll();
AvUser save(AvUser avUser);
void delete(String id);
Page<AvUser> findAll(Pageable pageable);
}
Pageable:这是一个分页接口,查询时只需要传入一个Pageable接口的实现类,指定pageNumber和PageSize即可。pageNumber为第几页,而PageSize为每页大小。
Page:分页查询结果会封装在该类中,Page接口实现Slice接口,通过查看其源代码可知。通过调用getTotalPages和getContent等方法,可以方便获得总页数和查询的记录。
分页方法定义好之后,在类AvUserServiceImpl中实现该方法,具体代码如下:
package com.shrimpking.service.impl;
import com.shrimpking.model.AvUser;
import com.shrimpking.repository.AvUserRepository;
import com.shrimpking.service.AvUserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:34
*/
@Service
public class AvUserServiceImpl implements AvUserService
{
@Resource
private AvUserRepository avUserRepository;
@Override
public AvUser findById(String id)
{
return this.avUserRepository.findById(id).get();
}
@Override
public List<AvUser> findAll()
{
return this.avUserRepository.findAll();
}
@Override
public AvUser save(AvUser avUser)
{
return this.avUserRepository.save(avUser);
}
@Override
public void delete(String id)
{
this.avUserRepository.deleteById(id);
}
@Override
public Page<AvUser> findAll(Pageable pageable)
{
return this.avUserRepository.findAll(pageable);
}
}
自定义查询方法
我们除了使用JpaRepository接口提供的增删改查分页等方法之外,还可以自定义查询方法。下面在AvUserRepository类中添加几个自定义查询方法,具体代码如下:
package com.shrimpking.repository;
import com.shrimpking.model.AvUser;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Collection;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:28
*/
public interface AvUserRepository extends JpaRepository<AvUser,String>
{
List<AvUser> findByName(String name);
List<AvUser> findByNameLike(String name);
List<AvUser> findByIdIn(Collection<String> ids);
}
在AvUserRepository中,我们自定义了3个查询的方法。从代码可以看出,Spring Data JPA为我们约定了一系列的规范,只要按照规范编写代码,Spring Data JPA就会根据代码翻译成相关的SQL语句,进行数据库查询。比如,可以使用findBy、Like、In等关键字,其中findBy可以用read、readBy、query、queryBy、get、getBy来代替。关于查询关键字的更多内容,可以到官方网站(https://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/)查看,里面有详细的内容介绍,这里就不一一列举了。
AvUserRepository类中自定义查询方法开发完成之后,可分别在类AvUserService和类AvUserServiceImpl中调用它们。在AvUserService类中继续添加这3个方法,具体代码如下:
package com.shrimpking.service;
import com.shrimpking.model.AvUser;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.Collection;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:32
*/
public interface AvUserService
{
AvUser findById(String id);
List<AvUser> findAll();
AvUser save(AvUser avUser);
void delete(String id);
Page<AvUser> findAll(Pageable pageable);
List<AvUser> findByName(String name);
List<AvUser> findByNameLike(String name);
List<AvUser> findByIdIn(Collection<String> ids);
}
package com.shrimpking.service.impl;
import com.shrimpking.model.AvUser;
import com.shrimpking.repository.AvUserRepository;
import com.shrimpking.service.AvUserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:34
*/
@Service
public class AvUserServiceImpl implements AvUserService
{
@Resource
private AvUserRepository avUserRepository;
@Override
public AvUser findById(String id)
{
return this.avUserRepository.findById(id).get();
}
@Override
public List<AvUser> findAll()
{
return this.avUserRepository.findAll();
}
@Override
public AvUser save(AvUser avUser)
{
return this.avUserRepository.save(avUser);
}
@Override
public void delete(String id)
{
this.avUserRepository.deleteById(id);
}
@Override
public Page<AvUser> findAll(Pageable pageable)
{
return this.avUserRepository.findAll(pageable);
}
@Override
public List<AvUser> findByName(String name)
{
return this.avUserRepository.findByName(name);
}
@Override
public List<AvUser> findByNameLike(String name)
{
return this.avUserRepository.findByNameLike(name);
}
@Override
public List<AvUser> findByIdIn(Collection<String> ids)
{
return this.avUserRepository.findByIdIn(ids);
}
}
集成测试
package com.shrimpking;
import com.shrimpking.model.AvUser;
import com.shrimpking.repository.AvUserRepository;
import com.shrimpking.service.AvUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/10 15:55
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyTest
{
@Autowired
private AvUserService avUserService;
@Test
public void test(){
//查询所有数据
List<AvUser> userList = this.avUserService.findAll();
System.out.println("findAll:" + userList.size());
//通过name查询
List<AvUser> userList2 = this.avUserService.findByName("user1");
System.out.println("findByName:" + userList2.size());
Assert.isTrue(userList2.get(0).getName().equals("user1"),"error");
//通过name模糊查询
List<AvUser> userList3 = this.avUserService.findByNameLike("%user%");
System.out.println("findByNameLike:" + userList3.size());
Assert.isTrue(userList3.get(0).getName().equals("user1"),"error");
Assert.isTrue(userList3.get(1).getName().equals("user2"),"error");
//通过id列表查询数据
List<String> ids = new ArrayList<>();
ids.add("1");
ids.add("2");
List<AvUser> userList4 = this.avUserService.findByIdIn(ids);
System.out.println("findByIdIn:" + userList4.size());
//分页查询
PageRequest pageRequest = new PageRequest(0,10);
Page<AvUser> userList5 = this.avUserService.findAll(pageRequest);
System.out.println("page findAll: " + userList5.getTotalPages() + "," + userList5.getSize());
//新增数据
AvUser user3 = new AvUser();
user3.setId("3");
user3.setName("user3");
user3.setPassword("1234");
this.avUserService.save(user3);
//删除数据
//this.avUserService.delete("3");
}
}
Assert:添加Assert断言,在软件开发中是一种常用的调试方式。从理论上来说,通过Assert断言方式可以证明程序的正确性,在现在项目中被广泛使用,这是需要掌握的基本知识。Assert提供了很多好用的方法,比如isNull和isTrue等。