前几节介绍了如何在springboot中使用MyBatis,MyBatis虽然很大程度上减轻了操作数据库的难度,但是依然需要编写一些必要的SQL语句。而JPA作为一套数据持久化的标准规范,由于其自带持久化API可以使开发人员不用编写复杂的SQL语句,专注于业务功能的开发。本小节内容主要介绍在SpringBoot中如何集成JPA完成数据持久化操作。
添加依赖
新建项目的时候选择SpringDataJPA依赖,此时便会在pom.xml中自动添加依赖,或者在pom.xml中手动添加依赖,由于要进行数据库操作,所以MySql的依赖也是必须的。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
配置数据库和JPA
添加JPA和数据库依赖后需要在application.properties中配置JPA和MySql。
#mysql
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root123
#JPA
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
mysql部分主要是jdbc的链接信息,数据库用户名和密码等信息。JPA部分有几个常用的属性,
- spring.jpa.show-sql 是否打印SQL语句
- spring.jpa.generate-ddl是否使用jpa 层面对数据表的生成策略,默认false
- spring.jpa.database 指定数据库
- spring.jpa.database-platform 指定数据库的存储引擎
创建表结构
在使用MyBatis或者JdbcTemplate的时候需要使用sql或者可视化工具手动创建表结构,而在JPA中只要定义一个实体类就可以了。定义一个User实体类,User既是类名又是表名。
@Entity
@Table(name = "user")
data class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long,
@Column(length = 3)
var number:Int,
@Column(length = 64)
var name:String,
@Column(length = 20)
var age:String
)
@Entity表示该提示类对应数据库中的表。
@Table用来将实体类注注解到表中,并且可以定义表名。
@Id表示字段在表中是唯一标识,也就是主键。
@GeneratedValue用来描述主键的自增策略,默认AUTO表示有程序控制生成主键。IDENTITY表示主键由数据库生成,ID自增。SEQUENCE表示通过数据库序列产生主键,使用@SequenceGenerator指定序列名称。TABLE表示通过特定的数据库表产生主键。
测试验证
前面的工作完成了数据库的基本配置,下面验证一下配置是否有效。通过可视化工具创建一个空的数据库test,然后启动项目,如果控制台没有报错,并且user表已经自动创建,说明配置成功。
一个增删改查的例子
创建JpaRepository
JpaRepository是Spring Data JPA中非常重要的类。它继承自SpringData的统一数据访问接口——Repository,实现了完整的增、删、改、查等数据操作方法。 创建JpaRepository非常简单,只需要定义一个JpaRepository接口的子类,然后加上@Repository注解就可以了。
@Repository
interface UserRepository :JpaRepository<User,Long>{
}
构建前端页面
界面是用bootstrap搭建的,比较简陋,凑合着看吧
就是一个简单的增删改查,页面数据是用Thymeleaf渲染的,表单样式用的是bootstrap的模态框,数据提交也是用的Thymeleaf。
- 前端页面代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
</head>
<body>
<script>
function f(obj) {
//打开模态框
$("#myModal").modal("show");
//检索列表中的数据,向模态框传值
var id = $(obj).parent().parent().find("td:eq(0)").text();
var number = $(obj).parent().parent().find("td:eq(1)").text();
var name=$(obj).parent().parent().find("td:eq(2)").text();
var age=$(obj).parent().parent().find("td:eq(3)").text();
$("#username").val(name);
$("#number").val(number);
$("#age").val(age);
$("#id").val(id);
}
</script>
<div class="container mt-3" th:with="age=0">
<div class="container text-end">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#myModal">增加</button>
</div>
<div th:if="${not #lists.isEmpty(stus)}">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>学号</th>
<th>用户名</th>
<th>年龄</th>
<th>操作</th>
</tr>
</thead>
<tbody class="tbody" id="tbody">
<tr th:each="student : ${stus}">
<td th:text="${student.id}">id</td>
<td th:text="${student.number}">number</td>
<td th:text="${student.name}">name</td>
<td th:text="${student.age}">age</td>
<td>
<a class="btn btn-primary" onclick="f(this)">编辑</a>
<!-- data-bs-toggle="modal" data-bs-target="#myModal"-->
<a class="btn btn-secondary ml-0" th:href="${'/del/' + student.id}">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 模态框 -->
<div class="modal fade modal-dialog modal-dialog-centered" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<!-- 模态框头部 -->
<div class="modal-header">
<h4 class="modal-title">添加学生</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<!-- 模态框内容 -->
<div class="modal-body">
<!--th:object="${user}将表单和thymeleaf绑定-->
<form id="form" th:object="${user}" th:action="@{/add}" th:method="POST">
<div class="mb-3 mt-1" hidden>
<label for="id" class="form-label">ID:</label>
<input type="text" th:field="*{id}" class="form-control" id="id" placeholder="id" name="id">
</div>
<div class="mb-3 mt-1">
<label for="username" class="form-label">姓名:</label>
<input type="text" th:field="*{name}" class="form-control" id="username" placeholder="姓名" name="name">
</div>
<div class="mb-3">
<label for="number" class="form-label">学号:</label>
<input type="number" th:field="*{number}" class="form-control" id="number" placeholder="学号" name="number">
</div>
<div class="mb-3">
<label for="age" class="form-label">年龄:</label>
<input type="number" th:field="*{age}" class="form-control" id="age" placeholder="年龄" name="age">
</div>
<div class="container text-center">
<button type="submit" class="btn btn-primary" data-bs-dismiss="modal">添加
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!--<script src="https://libs.baidu.com/jquery/3.6.0/jquery.min.js" type="text/javascript"></script>-->
</body>
</html>
增加和修改的弹框是用的bootstrap的模态框,关于模态框可以参考另一篇文章bootstrap模态框。
构建Controller
@Controller
class JpaController {
@Resource
private lateinit var userRepository: UserRepository
// 获取所有数据
@GetMapping("/user")
fun getUser(model:ModelMap):String{
val list=userRepository.findAll()
model.addAttribute("stus",list)
model.addAttribute("user",User())
return "index"
}
// 增加或者修改内容
// 由于JPA没有提供update方法,可以才用先把数据查出来,重新设置值,然后再保存的方式
// 这种情况下执行的sql就是update
@PostMapping("/add")
fun addUser(@ModelAttribute user: User?):String{
user?.run {
return if (id==0L){
userRepository.save(user)
"redirect:/user"
}else{
var u:User?=userRepository.findById(user.id).get()
if (u!=null){
u.id=user.id
u.name=user.name
u.number=user.number
u.age=user.age
userRepository.save(u)
}else{
userRepository.save(user)
}
"redirect:/user"
}
}
return "redirect:/user"
}
//删除
@RequestMapping("/del/{id}")
fun delUser(@PathVariable id:Long):String{
userRepository.deleteById(id)
return "redirect:/user"//重定向
}
}
总结
本小节简单介绍了SpringBoot如何集成JPA,并且结合Thymeleaf初步实现了一个简单的增删改查页面,其实JPA还有一些比较高级的操作,将在后续小节中逐步介绍。