摘要
本文主要介绍了JPA开发步骤实战,包括添加JPA依赖、领域Domain模型设计、创建Java实体类、配置数据库连接、创建Repository接口、service类、Application类、Controller类,提供RPC调用接口,进行JPA接口测试以及启动Springboot应用服务等内容,旨在帮助开发者掌握JPA开发流程。
1. 添加JPA依赖
在 pom.xml
文件中添加 JPA 和 MySQL 的依赖。如下文件提供一个参考:
<?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>
<groupId>com.zhuangxiaoyan</groupId>
<artifactId>springboot_jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_jpa</name>
<description>springboot_jpa</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
<mysql-connector-verison>5.1.49</mysql-connector-verison>
<lombok-version>1.18.30</lombok-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MySQL JDBC依赖,用来连接数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-verison}</version>
</dependency>
<!-- Lombok注解 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.zhuangxiaoyan.springboot.jpa.SpringbootJpaApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2. 领域Domain模型设计
-- springboot_jpa.`user` definition
CREATE TABLE `user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`email` varchar(100) NOT NULL,
`name` varchar(100) NOT NULL,
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modify` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='user表';
3. 创建Java实体类
package com.zhuangxiaoyan.springboot.jpa.domian.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* User
*
* @author xjl
* @version 2025/01/13 23:07
**/
@Entity
@Table(name = "user")
@Data
@EqualsAndHashCode
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private int id;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private LocalDateTime gmtCreate;
@Column(nullable = false)
private LocalDateTime gmtModify;
// 在实体第一次持久化到数据库时(即插入时),设置 gmtCreate 和 gmtModify
@PrePersist
public void prePersist() {
LocalDateTime now = LocalDateTime.now();
if (gmtCreate == null) {
gmtCreate = now;
}
if (gmtModify == null) {
gmtModify = now;
}
}
// 在实体每次更新时,更新 gmtModify
@PreUpdate
public void preUpdate() {
gmtModify = LocalDateTime.now();
}
}
4. 配置数据库连接配置
在 application.properties
或 application.yml
中配置数据源。
server:
port: 8080 # 设置应用程序运行端口
servlet:
context-path: /api # 设置应用程序的上下文路径
spring:
application:
name: springboot-mybatis-app # 设置 Spring Boot 应用程序的名称
datasource:
driver-class-name: com.mysql.jdbc.Driver # MySQL数据库驱动
url: jdbc:mysql://192.168.3.13:3306/springboot_jpa?useSSL=false&serverTimezone=UTC&characterEncoding=utf8&connectTimeout=10000&socketTimeout=10000 # 数据库连接URL
username: root # 数据库用户名
password: root # 数据库密码
hikari: # 配置 Hikari 数据源连接池(Spring Boot 2 默认使用 HikariCP)
minimum-idle: 5 # 最小空闲连接数
maximum-pool-size: 10 # 最大连接池大小
idle-timeout: 30000 # 空闲连接的最大生命周期(毫秒)
connection-timeout: 30000 # 连接超时时间(毫秒)
pool-name: HikariCP # 连接池名称
jackson:
serialization:
fail-on-empty-beans: false # 禁用 Jackson 序列化空 JavaBean 错误
thymeleaf:
cache: false # 开启/关闭 Thymeleaf 模板缓存
messages:
basename: messages # 配置国际化消息文件路径(messages.properties)
logging:
level:
root: INFO # 设置根日志级别
org.apache.ibatis: DEBUG # 设置根mybatis的日志级别
org.springframework.web: DEBUG # 设置 Spring Web 的日志级别
com.zhuangxiaoyan.springboot: DEBUG # 设置自定义包的日志级别
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" # 设置日志输出格式
5. 创建Repository接口
UserRepository需要继承的JPARepository接口或者CrudRepository接口
package com.zhuangxiaoyan.springboot.jpa.domian.repository;
import com.zhuangxiaoyan.springboot.jpa.domian.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
* UserRepository
*
* @author xjl
* @version 2025/01/13 23:14
**/
public interface UserRepository extends CrudRepository<User, Integer> {
/**
* 根据邮箱查询用户
*
* @param email
* @return
*/
Optional<User> findByEmail(String email);
}
6. 创建service类
package com.zhuangxiaoyan.springboot.jpa.domian.service;
import com.zhuangxiaoyan.springboot.jpa.domian.model.User;
import com.zhuangxiaoyan.springboot.jpa.domian.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* UserDomainService
*
* @author xjl
* @version 2025/01/13 23:12
**/
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
/**
* 判断邮箱是否唯一
*
* @param email
* @return
*/
public boolean isEmailUnique(String email) {
return userRepository.findByEmail(email).isPresent();
}
/**
* 创建用户
*
* @param user
* @return
*/
public User createUser(User user) {
if (userRepository.findByEmail(user.getEmail()).isPresent()) {
throw new IllegalArgumentException("Email already exists");
}
return userRepository.save(user);
}
/**
* 查询所有用户
*
* @return
*/
public List<User> getAllUsers() {
return (List<User>) userRepository.findAll();
}
/**
* 根据 ID 查询用户
*
* @param id
* @return
*/
public Optional<User> getUserById(int id) {
return userRepository.findById(id);
}
/**
* 更新用户
*
* @param id
* @param updatedUser
* @return
*/
public User updateUser(int id, User updatedUser) {
return userRepository.findById(id).map(user -> {
user.setName(updatedUser.getName());
user.setEmail(updatedUser.getEmail());
return userRepository.save(user);
}).orElseThrow(() -> new IllegalArgumentException("User not found"));
}
/**
* 删除用户
*
* @param id
*/
public void deleteUser(int id) {
if (!userRepository.existsById(id)) {
throw new IllegalArgumentException("User not found");
}
userRepository.deleteById(id);
}
}
7. 创建Application类
package com.zhuangxiaoyan.springboot.jpa.application;
import com.zhuangxiaoyan.springboot.jpa.domian.model.User;
import com.zhuangxiaoyan.springboot.jpa.domian.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* UserApplication
*
* @author xjl
* @version 2025/01/13 23:44
**/
@Service
public class UserManagerApplication {
@Autowired
private UserService userService;
/**
* 这一层主要是业务层,相关处理逻辑
*/
public User userCreateBusiness(User user) {
return userService.createUser(user);
}
/**
* 这一层主要是业务层,相关处理逻辑
*/
public List<User> getUserAll() {
return userService.getAllUsers();
}
}
8. 创建Controller类
package com.zhuangxiaoyan.springboot.jpa.interfaces.controller;
import com.zhuangxiaoyan.springboot.jpa.domian.model.User;
import com.zhuangxiaoyan.springboot.jpa.domian.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* UserController
*
* @author xjl
* @version 2025/01/13 23:27
**/
@RestController
@RequestMapping("/users")
public class UserManagerController {
@Autowired
private UserService userService;
// 创建用户
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User createdUser = userService.createUser(user);
return ResponseEntity.ok(createdUser);
}
// 获取所有用户
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.getAllUsers();
return ResponseEntity.ok(users);
}
// 根据 ID 获取用户
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable int id) {
return userService.getUserById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// 更新用户
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable int id, @RequestBody User user) {
User updatedUser = userService.updateUser(id, user);
return ResponseEntity.ok(updatedUser);
}
// 删除用户
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable int id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
9. 提供RPC调用接口
package com.zhuangxiaoyan.springboot.jpa.interfaces.facade;
/**
* UserManagerFacade 提供远程调用GRPC 服务
*
* @author xjl
* @version 2025/01/13 23:01
**/
public interface UserManagerFacade {
}
10. JPA接口测试
package com.zhuangxiaoyan.springboot.jpa.application;
import com.zhuangxiaoyan.springboot.jpa.SpringbootJpaApplication;
import com.zhuangxiaoyan.springboot.jpa.domian.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* UserMangerApplicationTest 测试类
*
* @author xjl
* @version 2025/01/14 08:54
**/
@SpringBootTest(classes = SpringbootJpaApplication.class)
public class UserMangerApplicationTest {
@Autowired
private UserManagerApplication userMangerApplication;
@Test
public void testCreateUser() {
User user = new User();
user.setName("xjl-test");
user.setEmail("xjl-test@163.com");
userMangerApplication.userCreateBusiness(user);
}
@Test
public void testGetUserAll() {
userMangerApplication.getUserAll().forEach(System.out::println);
}
}
11. Springboot启动服务
package com.zhuangxiaoyan.springboot.jpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootJpaApplication.class, args);
}
}
12. 参考代码
Hera-Mybatis: 主要介绍的Mybatis的相关的原理和实践方案。 - Gitee.com