SpringBoot整合JPA(一)

298 阅读3分钟

前几节介绍了如何在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表已经自动创建,说明配置成功。

图片.png

一个增删改查的例子

创建JpaRepository

JpaRepository是Spring Data JPA中非常重要的类。它继承自SpringData的统一数据访问接口——Repository,实现了完整的增、删、改、查等数据操作方法。 创建JpaRepository非常简单,只需要定义一个JpaRepository接口的子类,然后加上@Repository注解就可以了。

@Repository
interface UserRepository :JpaRepository<User,Long>{
}

构建前端页面

界面是用bootstrap搭建的,比较简陋,凑合着看吧

图片.png

图片.png 就是一个简单的增删改查,页面数据是用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还有一些比较高级的操作,将在后续小节中逐步介绍。