一、简介:
springData,显然也是spring家族的,data,顾名思义,它就是操作数据的一个框架。jpa,全称为Java persistence api,是用来管理java ee 或Java se环境中的持久化、以及对象关系映射的api,hibernate就是它的一个实现。当jpa遇上springData,就是见证奇迹的时候!它们俩在一起,dao层我们基本上无需再写代码,只需定义接口就可以了,一般的实现都不用我们写了,我们只需调用即可。
二、JPA核心概念:
1、实体:
实体表示关系数据库中的表,每个实体实例对应该表中的一条记录,实体类应该有标识其为实体的注解,还应该有唯一的对象标识符,简单主键或复合主键。
2、关系:
关系无外乎一下几种:
一对一: @OneToOne
一对多: @OneToMany
多对一: @ManyToOne
多对多: @ManyToMany
3、EntityManager:
这个就相当于hibernate的session、mybatis的sqlsessionFactory,定义用于与持久性上下文进行交互的方法。
三、springboot集成jpa案例:
本案例使用gradle构建,前端使用thymeleaf,数据库用到了H2和mysql,使用jpa完成crud操作。
1、添加依赖:
build.gradle:
buildscript { ext { springBootVersion = '1.5.2.RELEASE' } //自定义版本 ext['thymeleaf.version'] = '3.0.3.RELEASE' ext['thymeleaf-layout-dialect.version'] = '2.2.0' ext['hibernate.version'] = '5.2.8.Final' repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' group = 'com.zhu' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { //jpa依赖 compile('org.springframework.boot:spring-boot-starter-data-jpa') compile('org.springframework.boot:spring-boot-starter-web') //thymeleaf依赖 compile('org.springframework.boot:spring-boot-starter-thymeleaf') //mysql驱动 compile('mysql:mysql-connector-java:6.0.5') //H2数据库 runtime('com.h2database:h2:1.4.193') testCompile('org.springframework.boot:spring-boot-starter-test') }
2、配置thymeleaf、H2和jpa:
application.properties:
#thymeleaf相关配置 spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.cache=false spring.thymeleaf.mode=HTML5 #启用h2控制台 spring.h2.console.enabled=true #jpa相关配置 spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update
注意:
这里没有配置mysql,先演示H2数据库的用法;
spring.jpa.hibernate.ddl-auto
的值有以下几个:
create
---- 每次运行该程序,没有表格会新建表格,表内有数据会清空;
create-drop
---- 每次程序结束的时候会清空表;
update
---- 每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新;
validate
---- 运行程序会校验数据与数据库的字段类型是否相同,不同会报错。
所以一般情况下用update
就行了。
3、实体层:
User.java:
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity // 标识这个类是实体 public class User { @Id // 标识主键 @GeneratedValue(strategy=GenerationType.IDENTITY) //自增策略 private Long id; private String name; private String email; }
注意:
这里省略了set、get方法以及构造方法;
这样自动建表时表中字段与属性名一致,比如name属性对应数据库表中字段也是name,如果要自定义,可以用在属性上用@Column()
注解;
表名默认与实体类名一致,可以在类上加@Table()
注解来自定义
。
4、dao层:
UserDao.java:
public interface UserDao extends CrudRepository<User, Long> { }
注意:
第一:
这个就是简单的实现crud操作,所以继承CrudRepository
即可,其它接口如下:
(1)、Repository
:
标记型接口,表示任何继承它的类都是仓库接口类。
(2)、CrudRepository
:
包含了10种crud方法。
(3)、PagingAndSortingRepository
:
除了10中crud方法外,多了分页和排序。
(4)、JpaRepository
:
比(3)又多了一些其他的常用方法。
所以在项目开发中继承JpaRepository
就行了。
第二:
springData Jpa 还可以自定义方法,只要符合命名规范,就不用我们自己实现。比如要根据用户名和密码查询用户,就可以定义一个findByNameAndPwd()
方法,直接调用就行,不需要自己实现。命名规范如下图:
第三:
其实这里取名UserDao
不太好,dao
是Data Access Objects
的缩写,意思为数据访问对象,这里使用Jpa,根据命名规范应该叫做UserRepository
,就像mybatis中应该叫做UserMapper
一样。
第四:
jpa没有直接提供分页方法,若是要分页,请看下面的例子:
接口中的方法:
Page<User> findByAge(int age, Pageable pageable);
调用时:
Pageable pageable = PageRequest.of(page,size); Page<User> result = UserRepository.findByAge(20,pageable);
上述代码表示分页查询age为20的的User。先要构建一个Pageable对象,传入分页信息,再把pageable对象传入查询方法中。
5、service层:
因为本案例service层并无其他逻辑,所以直接省略。
6、controller层:
UserController.java:
@RestController @RequestMapping("/users") public class UserController { @Autowired private UserDao userDao; /** * 查询所有用户 * * @param model * @return */ @GetMapping public ModelAndView list(Model model) { model.addAttribute("userList", userDao.findAll()); model.addAttribute("title", "用户管理"); return new ModelAndView("user/list", "userModel", model); } /** * 根据id查询用户 * * @param id * @param model * @return */ @GetMapping("{id}") public ModelAndView view(@PathVariable("id") Long id, Model model) { User user = userDao.findOne(id); model.addAttribute("user", user); model.addAttribute("title", "查看用户"); return new ModelAndView("user/view", "userModel", model); } /** * 获取创建表单页面 * * @param model * @return */ @GetMapping("/form") public ModelAndView createForm(Model model) { model.addAttribute("user", new User()); model.addAttribute("title", "创建用户"); return new ModelAndView("user/form", "userModel", model); } /** * 保存或更新用户 * * @param user * @return */ @PostMapping public ModelAndView saveOrUpdateUser(User user) { user = userDao.save(user); return new ModelAndView("redirect:/users"); } /** * 删除用户 * * @param id * @return */ @GetMapping("/delete/{id}") public ModelAndView delete(@PathVariable("id") Long id) { userDao.delete(id); return new ModelAndView("redirect:/users");// 重定向到list页面 } /** * 获取修改用户的界面 * * @param id * @param model * @return */ @GetMapping("/modify/{id}") public ModelAndView modify(@PathVariable("id") Long id, Model model) { User user = userDao.findOne(id); model.addAttribute("user", user); model.addAttribute("title", "修改用户"); return new ModelAndView("user/form", "userModel", model); } }
从上面的代码可以看到,虽然dao层只是简单的继承了CrudRepository,没有做任何实现,但是我们在controller层调用时却可以使用findOne、findAll、delete、save
方法,底层已经帮我们实现这些方法了,我们只需调用就行了。
7、前端:
页头:header.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <meta charset="UTF-8"> <title>thymeleaf in action</title> </head> <body> <div th:fragment="header"> <h1>Thymeleaf in action</h1> <a href="/users" >首页</a> </div> </body> </html>
页脚:footer.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <meta charset="UTF-8"> <title>thymeleaf in action</title> </head> <body> <div th:fragment="footer"> <a href="#" >邮箱</a> </div> </body> </html>
form.html:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <meta charset="UTF-8"> <title>thymeleaf in action</title> </head> <body> <div th:replace="~{fragments/header :: header}"></div> <h3 th:text="${userModel.title}">test</h3> <form action="/users" th:action="@{/users}" method="POST" th:object="${userModel.user}"> <input type="hidden" name="id" th:value="*{id}"> 名称:<br> <input type="text" name="name" th:value="*{name}"><br> 邮箱:<br> <input type="text" name="email"th:value="*{email}"> <input type="submit" value="提交"> </form> <div th:replace="~{fragments/footer :: footer}"></div> </body> </html>
list.html:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <meta charset="UTF-8"> <title>thymeleaf in action</title> </head> <body> <!-- 引用头部信息 --> <!-- 在fragments下的header文件下有名为header的片段 --> <div th:replace="~{fragments/header :: header}"></div> <h3 th:text="${userModel.title}"></h3> <div> <a href="/users/form.html" th:href="@{/users/form}">创建用户</a> </div> <table border="1"> <thead> <tr> <td>ID</td> <td>Email</td> <td>Name</td> </tr> </thead> <tbody> <tr th:if="${userModel.userList.size()} eq 0"> <td colspan="3">没有用户信息</td> </tr> <tr th:each="user : ${userModel.userList}"> <td th:text="${user.id}"></td> <td th:text="${user.email}"></td> <td ><a th:href="@{'/users/'+${user.id}}" th:text="${user.name}"></a></td> </tr> </tbody> </table> <div th:replace="~{fragments/footer :: footer}"></div> </body> </html>
view.html:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <meta charset="UTF-8"> <title>thymeleaf in action</title> </head> <body> <div th:replace="~{fragments/header :: header}"></div> <h3 th:text="${userModel.title}">test</h3> <div> <p><strong>ID:</strong><span th:text="${userModel.user.id}"></span></p> <p><strong>Name:</strong><span th:text="${userModel.user.name}"></span></p> <p><strong>Email:</strong><span th:text="${userModel.user.email}"></span></p> </div> <div> <a th:href="@{'/users/delete/'+${userModel.user.id}}">删除</a> <a th:href="@{'/users/modify/'+${userModel.user.id}}">修改</a> </div> <div th:replace="~{fragments/footer :: footer}"></div> </body> </html>
8、测试:
创建用户:
用户列表:
点击用户名字还可以进行删除和修改操作,这里不再截图。接下来说说H2数据库。
9、H2数据库:
H2数据库是一个内存数据库,数据保存在内存中,项目一重启数据就没了。且其无需安装任何服务或者客户端,要在项目中使用也不用怎么配置,直接添加其依赖即可。那么如何查看数据是否保存到了H2数据库中呢?它提供了一个网页版控制台,网址为http://localhost:8080/h2-console
,这个控制台默认是不启用的,所以刚才在application.properties中加上了spring.h2.console.enabled=true
配置。开启后,访问该网址就会出现如下界面:
点击connect就可以查看到数据:
注意,如果你首次登录http://localhost:8080/h2-console
,JDBC URL显示的不是jdbc:h2:mem:testdb
,就要改成这个,否则进去看不到数据。
如果使用了H2数据库后还想使用MySQL,只需要在appication.properties中加上其配置即可,如下:
#配置MySQL数据源 spring.datasource.url=jdbc:mysql:///blog?useSSL=false&serverTimezone=GMT spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=# spring.datasource.password=#
H2数据库会自动检测你有没有配置其他数据库,如果配置了,H2就会退出江湖,如果把mysql的配置注释掉了,H2就会重出江湖。
值得注意的是:如果你的MySQL驱动用的是6.0以上的版本,要像上面一样在jdbc的url中添加serverTimezone=GMT
,否则会报错。
总结:
springData Jpa十分强大,有了它,dao层几乎不需要自己写了。上面的案例只是演示了简单的crud,其他方法以及自定义方法老铁们也可以试一试。还有这个项目是基于gradle的,基于maven的也是一样的开发方法,只是添加依赖的方式不同而已。
以上内容属于个人笔记整理,如有错误,欢迎批评指正!