Spring Data JPA示例
在这个Spring Data JPA示例中,我们将使用Spring Web MVC创建一个Rest Web服务,使用的JPA实现是Hibernate,DB是MySQL。
Spring Data JPA
Spring data JPA是对JPA的Spring Data存储库支持。
通过在我们使用的持久性存储(JPA,NoSQL,JDBC等)上使用Spring Data Repository抽象,可以显着减少实现那些持久性存储的数据访问层所需的样板代码数量。
作为开发人员,我们只需要编写存储库接口,包括自定义查找器方法(如果有),Spring就会自动为这些数据访问方法提供实现。
Maven依赖
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.theitroad</groupId> <artifactId>SpringJPAProject</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>SpringJPA</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>5.1.8.RELEASE</spring.version> <spring.data>2.1.10.RELEASE</spring.data> <hibernate.jpa>5.4.3.Final</hibernate.jpa> <mysql.version>8.0.17</mysql.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring data JPA --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>${spring.data}</version> </dependency> <dependency> <groupId>com.fasterxml.Hymanson.core</groupId> <artifactId>Hymanson-databind</artifactId> <version>2.9.6</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.jpa}</version> </dependency> <!-- MySQL Driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> </dependencies> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <release>11</release> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.1</version> <configuration> <warSourceDirectory>WebContent</warSourceDirectory> </configuration> </plugin> </plugins> </build> </project>
为Spring核心,Spring上下文以及Spring Web和Spring数据JPA添加了依赖项。
当使用Hibernate JPA实现时,添加了Hibernate的依赖关系。
MySQL连接器用于从Java应用程序连接到MySQL DB。
对于以JSON发送的Web服务响应,需要Hymanson数据绑定。
项目结构
完整实施此Spring Data JPA示例的项目结构如下
数据库表查询
可以使用以下查询创建用于此Spring数据JPA的MySQL DB表。
CREATE TABLE `emp` ( `id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(45) DEFAULT NULL, `last_name` varchar(45) DEFAULT NULL, `department` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Spring Data JPA示例–模型类
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="emp") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(name="first_name") private String firstName; @Column(name="last_name") private String lastName; @Column(name="department") private String dept; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getDept() { return dept; } public void setDept(String dept) { this.dept = dept; } @Override public String toString() { return "Id= " + getId() + " First Name= " + getFirstName() + " Last Name= " + getLastName() + " Dept= "+ getDept(); } }
这是与DB中的emp表相对应的模型类。
@Entity注释指定此模型类为实体。
@Table注释指定实体的主表。
@Id注释指定实体的主键。
@GeneratedValue指定主键生成策略,在这种情况下,该策略是自动递增的。
@Column注释指定该字段的映射表列名称。
Spring Data JPA示例–存储库
import java.util.List; import org.springframework.data.repository.CrudRepository; import com.theitroad.springproject.model.Employee; public interface EmployeeRepository extends CrudRepository<Employee, Integer> { List<Employee> findByLastName(String lastName); }
EmployeeRepository接口扩展了CrudRepository,它使用域类来管理(在这种情况下为Employee),并且将域类的id类型作为类型参数。
这就是CRUD功能所需的所有数据访问代码,无需编写实现此接口的类。
自定义存储库继承的CrudRepository为所管理的实体类提供了复杂的CRUD功能。 CrudRepository接口中的某些方法。
<S扩展T> S save(S实体)–保存给定的实体。
T findOne(ID primaryKey)–返回由给定ID标识的实体。
Iterable <T> findAll()–返回所有实体。
Long count()–返回实体数。
void delete(Tentity)–删除给定的实体。
boolean exist(ID primaryKey)–指示是否存在具有给定ID的实体。
我们还可以编写可自动生成的自定义查询,也可以将查询编写为"命名查询"或者在存储库中使用@Query注释。如我们所见,在我们的存储库界面中,有一个findByLastName()方法。对于以" find"," count"," remove"," delete"之类的名称开头的方法,Spring框架通过解析方法名称并将其与实体类中的属性进行匹配可以自动生成正确的查询。
请参阅本文中的在Spring Data JPA中使用@NamedQuery注释的示例Spring Data JPA @NamedQuery注释示例
请参阅本文中的在Spring Data JPA中使用@Query注释的示例Spring Data JPA @Query注释示例
Spring Data JPA示例–服务类
在服务层,我们将称为DAO层方法。由于我们只需要一个用于存储Spring数据的存储库,因此我们将从服务类中调用存储库的方法。请注意,必须将存储库实例注入服务类中。
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.theitroad.springproject.dao.EmployeeRepository; import com.theitroad.springproject.model.Employee; @Service public class EmployeeService { @Autowired private EmployeeRepository repository; public Employee getEmployeeById(int id) { return repository.findById(id).get(); } public List<Employee> getAllEmployees(){ return (List<Employee>) repository.findAll(); } public void deleteEmployeeById(int id){ repository.deleteById(id); } public Employee addEmployee(Employee emp) { return repository.save(emp); } public List<Employee> getEmployeeByLastName(String lastName) { return repository.findByLastName(lastName); } }
Spring Data JPA示例–控制器类
使用Rest控制器类,我们会将路径映射到要为请求调用的方法。
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import com.theitroad.springproject.model.Employee; import com.theitroad.springproject.service.EmployeeService; @RestController @RequestMapping("/employee") public class EmployeeController { @Autowired EmployeeService empService; @GetMapping("/{id}") public Employee getEmployeeById(@PathVariable int id) { return empService.getEmployeeById(id); } @GetMapping public List<Employee> getAllEmployees(){ return empService.getAllEmployees(); } @DeleteMapping("/{id}") @ResponseStatus(HttpStatus.OK) public void deleteEmployeeById(@PathVariable int id){ empService.deleteEmployeeById(id); } @PostMapping @ResponseStatus(HttpStatus.CREATED) public Employee addEmployee(@RequestBody Employee emp) { return empService.addEmployee(emp); } @GetMapping("/lastname/{lastName}") public List<Employee> getEmployeeByLastName(@PathVariable String lastName) { return empService.getEmployeeByLastName(lastName); } }
Spring Data JPA示例–配置
在此Spring数据JPA示例中,使用Java配置,因此使用@Configuration注释对类进行注释。
为了设置数据源,将从属性文件中读取数据库属性。使用@PropertySource注释配置属性文件的路径。
@EnableJpaRepositories注释启用JPA存储库。带有注释的值提供了用于扫描存储库的软件包。
@EnableTransactionManagement注释启用Spring的注释驱动的事务管理功能。
在此Java配置类中,我们设置了EntityManagerFactory并将Hibernate用作持久性提供程序。
import java.util.Properties; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableJpaRepositories("com.theitroad.springproject.dao") @EnableTransactionManagement @PropertySource("classpath:config/db.properties") public class JPAConfig { @Autowired private Environment env; @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); factory.setPackagesToScan("com.theitroad.springproject.model"); factory.setDataSource(dataSource()); factory.setJpaProperties(hibernateProperties()); return factory; } @Bean public DataSource dataSource() { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName(env.getProperty("db.driverClassName")); ds.setUrl(env.getProperty("db.url")); ds.setUsername(env.getProperty("db.username")); ds.setPassword(env.getProperty("db.password")); return ds; } Properties hibernateProperties() { Properties properties = new Properties(); properties.setProperty("hibernate.dialect", env.getProperty("hibernate.sqldialect")); properties.setProperty("hibernate.show_sql", env.getProperty("hibernate.showsql")); return properties; } @Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager txManager = new JpaTransactionManager(); txManager.setEntityManagerFactory(entityManagerFactory().getObject()); return txManager; } }
如果我们使用的是XML配置,则用于启用JPA存储库的配置为
<jpa:repositories base-package="com.theitroad.springproject.dao"/>
db.properties文件
db.driverClassName=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:3306/theitroad db.username= db.password= hibernate.sqldialect=org.hibernate.dialect.MySQLDialect hibernate.showsql=true
要使用Java config而不是web.xml设置网络应用程序,我们需要以下类。
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class WebConfigInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // TODO Auto-generated method stub return null; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] {WebConfig.class}; } @Override protected String[] getServletMappings() { return new String[] {"/"}; } }
@Configuration @EnableWebMvc @ComponentScan(basePackages = "com.theitroad.springproject") public class WebConfig implements WebMvcConfigurer{ }
部署Spring Data JPA应用程序
右键单击项目,然后选择"运行方式– Maven构建",提供目标为全新安装。如果构建成功,则将应用程序打包为战争,可以将其部署在像Tomcat这样的Web容器上,然后测试该应用程序。
为了测试RESTful Web服务,使用了Postman rest客户端。
新增员工
请注意,所选的请求是POST,URL是http:// localhost:8080 / SpringJPAProject / employee
数据以JSON格式作为请求正文发送。在响应中添加了员工数据回发。
获取所有员工
通过ID删除员工
按姓获取员工
我们也可以直接从浏览器发送请求,就像完成此请求一样。