开发DAO组件
作用:用来访问数据库
持久化技术:Spring Data, JPA, Mybaits,jOOQ 等
Spring Boot为常见持久化技术提供了支持。
现在使用 Spring Data JPA
Spring Data JPA
使用Spring Data JPA来访问数据库,需要再项目添加两个依赖:
1、Spring Boot Data JPA依赖,它会自动添加数据源的实现(用 springboot 提供的能自动配置和整合的Spring Boot Data JPA)
<!-- 添加 Spring Boot Data JPA 的 Starter 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2、MySQL数据库驱动依赖
<!-- mysql数据库驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
只要添加Spring Boot Data JPA的starter组件依赖,Spring Boot就会为你搞定整合spring data jpa的一切基础配置
创建配置文件,指定连接数据库的信息
创建一个配置文件 application.properties,就放在resources包下
# 数据库 URL
spring.datasource.url=jdbc:mysql://localhost:3306/数据库名?serverTimezone=UTC
spring.datasource.username=用户名
spring.datasource.password=密码
# 指定显示sql语句
spring.jpa.show-sql=true
# 指定根据实体自动建表
spring.jpa.generate-ddl=true
因为配置文件有配置这个功能:
指定根据实体自动建表 spring.jpa.generate-ddl=true
所以我们可以通过给Book类添加JPA注解,变成实体类。
问题:Java类和实体类有什么区别?
Java类: 是通用的,可以用于实现各种功能和逻辑
实体类: 是具有特定目的的类,用于表示领域模型中的具体实体,与数据持久化和数据库操作相关。
1、持久化能力: 实体类是指具有持久化能力的类,可以通过ORM(对象关系映射)技术将其映射到数据库表中,实现对象和数据库之间的数据交互。而普通类则通常不具备持久化的能力
2、注解: 实体类通常需要使用特定的注解(如JPA的@Entity注解)来进行标记,以便在持久化过程中进行映射和管理。而普通类不需要添加这些注解。
3、数据库映射: 实体类与数据库表之间存在一一对应或一对多的关系,实体类的属性通常与数据库表的字段相对应。而普通类则不需要与数据库表进行映射。
4、CRUD操作: 实体类通常可以通过ORM框架提供的API进行数据库的增删改查操作(CRUD操作)。而普通类不具备这些数据库操作的能力。
5、规范要求: 实体类在JPA等框架中有一些规范要求,如需要无参构造函数、需要主键等。而普通类没有这些规范要求。
6、实例化和使用: ava类可以被直接实例化和使用,用于封装数据和实现业务逻辑。而实体类一般需要通过ORM框架或者其他方式来创建和管理,以便与数据库进行交互。
如何把Java类变成实体类:
实体类通常需要使用特定的注解(如JPA的@Entity注解)来进行标记和配置,以便在持久化过程中进行映射和管理。而Java类没有这些特定的持久化注解
package cn.ljh.boot.domain;
import javax.persistence.*;
//通过添加JPA注解,把这个Java类变成实体类
@Entity //表明这个类是一个实体类
@Table(name = "book_inf") //把这个实体类映射到数据库的 book_inf 表
public class Book {
@Id //主键id
@GeneratedValue(strategy = GenerationType.IDENTITY) //指定主键生成策略
@Column(name = "book_id") //指定这个字段映射到数据库表的具体列名
private Integer id;
@Column(name = "book_name")
private String name;
@Column(name = "price")
private double price;
@Column(name = "author")
private String author;
后面我把price价格的修饰改成 bigdecimal 修饰类型
IDEA连接mysql
把Java类改成实体类后,运行项目,发现数据库自动生成 bool_inf 这张表了,对应的列也都生成了。
准备工作完成后,现在开发DAO组件
是基于 Spring Data 开发DAO组件,用spring data ,既可以访问sql数据库,也可以访问nosql数据库。
让DAO接口继承CrudRepository接口
Spring Data会为继承了CrudRepository接口的DAO接口自动为它动态生成实现类,并将该实现类的实例部署在Spring容器中。
此外,Spring Data还可动态为BookDao增加很多查询方法。
Spring Data不仅可以自动生成大量的CRUD方法,也能允许用户定义自定义的查询(sql、HQL),
甚至允许用户使用最底层API(EntityManager、DataSource、Connection……)
开发Dao组件,只需要创建一个BookDao 接口,然后去继承CrudRepository接口就可以了。
在service就可以注入这个BookDao 对象来用了,这时候的bookDao因为继承了CrudRepository接口,所以本身已经集成了很多sql操作
public interface BookDao extends CrudRepository<Book,Integer> {
}
通过代码可以看出,注入BookDao组件依赖后,这个bookDao就集成了很多sql操作。
比如简单的 save 保存,findAll 查询所有,deleteById根据id删除数据等。
下面的代码就是正式的业务逻辑,使用的就是基于spring boot data jpa 来实现数据库的数据持久化操作
//添加这个@Service注解,springboot就可以自动扫描这个Service组件的实现类,然后把这个类部署成容器中的bean。
@Service
@Transactional //事务控制
public class BookServiceImpl implements BookService {
//注入DAO组件,用有参构造器来注入
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao){
this.bookDao = bookDao;
}
//这个bookDao 因为继承了CrudRepository接口,所以本身已经集成了很多sql操作。
//添加书籍的方法
@Override
public Integer addBook(Book book) {
Book b = bookDao.save(book);
return b.getId();
}
//查看所有书籍的方法
@Override
public List<Book> getAllBooks() {
//要强制转换
List<Book> listBooks = (List<Book>) bookDao.findAll();
return listBooks;
}
//删除书籍的方法
@Override
public void deleteBookById(Integer id) {
bookDao.deleteById(id);
}
}
对应的前端页面也贴出来。有过一些功能修改,直接贴出来记录
bookForm.html添加书籍页面
<!DOCTYPE html>
<!-- HTML引入Thymeleaf ,导入命名空间 , 把thymeleaf的域名加进来就可以使用了-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>添加图书页面</title>
<!-- 导入 webjar 包中的 bootstrap 样式库 -->
<link rel="stylesheet" th:href="@{/webjars/bootstrap/4.6.0/css/bootstrap.css}">
</head>
<body>
<!-- class="container" :相当于类名,就是这个div模块的名字-->
<!-- class="alert alert-primary" : 警报框 -->
<div class="container">
<div id="addBookFailTips" th:if="${tip} != null">
<div th:text="${tip}" class="alert alert-primary" style="text-align: center">书籍添加失败显示的提示信息</div>
</div>
<h2>添加图书</h2>
<!-- TODO -->
<!-- submit提交表单的时候,就会走这个addBook方法 -->
<form method="post" th:action="@{/addBook}">
<div class="form-group row">
<label for="name" class="col-sm-3 col-form-label">图书名:</label>
<div class="col-sm-9">
<input type="text" id="name" name="name" class="form-control" placeholder="输入图书名">
</div>
</div>
<div class="form-group row">
<label for="author" class="col-sm-3 col-form-label">作者:</label>
<div class="col-sm-9">
<input type="text" id="author" name="author" class="form-control" placeholder="输入作者">
</div>
</div>
<div class="form-group row">
<label for="price" class="col-sm-3 col-form-label">价格:</label>
<div class="col-sm-9">
<input type="text" id="price" name="price" class="form-control" placeholder="输入价格">
</div>
</div>
<div class="form-group row">
<div class="col-sm-6 text-right">
<button id="add" type="submit" class="btn btn-primary">添加</button>
</div>
<div class="col-sm-1 ">
<button type="reset" class="btn btn-danger">重置</button>
</div>
<div class="col-sm-3 ">
<a th:href="@{/listBooks}">
<button type="button" class="btn btn-secondary" style="background-color: yellowgreen">查看书籍列表
</button>
</a>
</div>
</div>
</form>
</div>
<!--TODO 提示输入信息不能为空-->
<script>
// <!-- 如果书籍添加失败,那么在提示 2 秒后设置 div 为 none 进行隐藏 -->
// setTimeout(function() {
// document.getElementById("addBookFailTips").style.display = "none";
// }, 2000); // 2秒后隐藏
</script>
</body>
</html>
书籍列表页面 listBooks.html
<!DOCTYPE html>
<!-- HTML引入Thymeleaf ,导入命名空间 , 把thymeleaf的域名加进来就可以使用了-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>书籍列表页面</title>
<!-- 导入 webjar 包中的 bootstrap 样式库 -->
<link rel="stylesheet" th:href="@{/webjars/bootstrap/4.6.0/css/bootstrap.css}">
</head>
<body>
<!-- class="container" :相当于类名,就是这个div模块的名字-->
<!-- class="alert alert-primary" : 警报框 -->
<div class="container">
<table class="table table-hover">
<tr>
<th>书名</th>
<th>价格</th>
<th>作者</th>
<th>删除</th>
</tr>
<!-- 循环迭代 ${books}就是后端传来的集合数据, book就是循环后的变量 -->
<tr th:each="book: ${books}">
<td th:text="${book.name}">书名</td>
<td th:text="${book.price}">价格</td>
<td th:text="${book.author}">作者</td>
<td><a th:href="@{/deleteBook/} + ${book.id}">删除</a></td>
</tr>
</table>
</div>
<div class="container">
<a th:href="@{/bookForm}"><button type="button" style="background-color: beige">返回添加书籍</button></a>
</div>
</body>
</html>
实现页面:
bookForm页面
listBooks页面