先说下什么是JPA吧,JPA其实是EJB3.0的一个规范,相信老程序员都知道啦,它是基于O/R映射的标准规范,目前最新版本是JPA2.1。既然是规范即只定义了标准规则,不提供实现,软件提供商按照标准进行实现,使用者只需要按照标准定义的方式进行使用即可(就像JDBC一样)。
今天的主角是Spring data JPA,它是spring data的一个分支,默认是使用Hibernate实现(当然还有EclipseLink、OpenJPA等都可以)。所以我们作为使用者只需要按照规范使用即可,如果需要深度的定制一些内容则研究一下源码,也没那么难(后续如果有空给大家写一遍自定义通用的Repository可以实现一些jpa默认实现里面不带有的根据用户传入的实体自动进行查询,类似mybaitis中的动态sql)。
废话不多说,先看步骤:
1、引入必要的包(maven必备,别告诉我你不会用)
2、配置JPA启动相关参数
3、编写实体(添加注解)
4、编写service和controller(业务简单可以直接省略service)
1、引入必要的包(maven必备,别告诉我你不会用)
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.pxk</groupId>
<artifactId>SpringBootDemo_JPA</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootDemo_JPA Maven Webapp</name>
<url>http://maven.apache.org</url>
<build>
<finalName>SpringBootDemo_JPA</finalName>
</build>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!--日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.18</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2、配置JPA启动相关参数
大家可能会有疑问了,为什么启动类里面看不到任何JPA的影子呢,因为只要我们引入spring-boot-starter-data-jpa,Spring Boot就会启动JPA的默认配置。
详见org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
package com.pxk.springboot;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import com.alibaba.druid.pool.DruidDataSource;
@SpringBootApplication
public class Application {
private final static Logger log=LoggerFactory.getLogger(Application.class);
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
//覆盖默认数据源 使用druid数据源
public DataSource dataSource() {
return new DruidDataSource();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
log.info("启动成功");
}
}
单写上面一个启动类还是不够的,还需要加入一些需要的配置参数到application.properties中
# 数据库访问配置
# 主数据源,默认的
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot_demo_jpa?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=pxk
server.port=8081
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8
spring.jpa.show-sql= true
## 建表方式
spring.jpa.properties.hibernate.hbm2ddl.auto=update
# 方言
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
3、编写实体(添加注解)
这里需要注意下,JPA实体注解,在Hibernate升级到4.0以后有一些变化,使用了javax的默认注解替代了Hiernate原本的注解,这里对使用老版本的朋友来说不注意就是一个小坑。至于注解的使用这里主要是主键的生成策略,属性如果不加注解name对应数据库的name字段,userName对应数据库的user_name。另外还有一些长度限制非空限定等都可以使用注解实现。(最好的一点可以直接结合Hibernate validator进行后台数据验证,数据完整性的保证--前台验证是不保险的【搞过爬虫的同学肯定知道,前端很脆弱的】)
package com.pxk.springboot.domain;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import com.fasterxml.jackson.annotation.JsonFormat;
@Entity
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Integer age;
private String passWord;
private String gender;
// json日期格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date regestDate;
// 默认构造函数不能少 ,如果没有会报ibatis.executor.ExecutorException: No constructor found
public User() {
super();
}
public User(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Date getRegestDate() {
return regestDate;
}
public void setRegestDate(Date regestDate) {
this.regestDate = regestDate;
}
}
4、编写service和controller(业务简单可以直接省略service)
UserServiceImpl.java
package com.pxk.springboot.serivce.imp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.pxk.springboot.dao.UserDao;
import com.pxk.springboot.domain.User;
import com.pxk.springboot.serivce.UserService;
@Service//注入成service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User getUser(String name) {
return new User(name);
}
@Override
public Page<User> findUserByPage(Pageable pageInfo) {
Page<User> list=userDao.findAll(new PageRequest(pageInfo.getPageNumber(), pageInfo.getPageSize()));
return list;
}
@Override
public User getUserById(Long id) {
return userDao.findOne(id);
}
@Override
public User updateUser(User user) {
return userDao.saveAndFlush(user);
}
@Override
public void deleteUser(User user) {
userDao.delete(user);
}
@Override
public User addUser(User user) {
return userDao.saveAndFlush(user);
}
}
UserController.java
如果看了我前一篇springboot 入门教程(5) 基于ssm框架的crud操作(后台部分-附源码)的同学肯定会发现这个后台无法和上一篇的前端整合在一起使用,为什么呢?就是因为我们前端用了Bootstap table,它自动发送的ajax请求参数和我们后台接受的参数名不统一,如果要实现整合提供两种思路
1、修改前端BootStrap table源码,优点是懂前端的修改起来简单,很快就改完了。缺点是修改源码意味着当BootStrap table升级后你不能很顺利的升级。
2、那肯定是修改后台咯,修改后台又有两种方式,一种是想前一篇一样,引入两个辅助分页的类,编写一个父类,进行统一的参数接收和结果集的转换。第二种就是硬编码,在controller的每个分页方法里面去手动实现一遍参数和结果集的转换。(当然第一种更适合了,后续有时间给大家补充上这一部分)
package com.pxk.springboot.conntroller;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.pxk.springboot.domain.User;
import com.pxk.springboot.serivce.UserService;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired // 依赖注入service
UserService userService;
@RequestMapping("/findUserByPage")
@ResponseBody
public Page<User> getStudents(Pageable pageInfo) {
return userService.findUserByPage(pageInfo);
}
@RequestMapping("/getUserById")
protected User getUserById(Long id) {
return userService.getUserById(id);
}
@RequestMapping("/deleteUser")
protected void deleteUser(Long id) {
User user = new User();
user.setId(id);
userService.deleteUser(user);
}
@RequestMapping(value="/addUser")
protected User addUser(User user) {
if(user.getId()!=null&&user.getId()!=0){
return userService.updateUser(user);
}else{
user.setRegestDate(new Date());
return userService.addUser(user);
}
}
}
代码都很简单没什么可介绍的了。
简单总结下:
其实小项目,用户并发量小的项目用JPA肯定比mybaitis快,而且逆向工程对开发这种小项目可以说是事半功倍。其实JPA还有很多高级特性,如:事务、自定义Repository,复杂的关联查询等等。后面有机会再介绍。
下集预告:Spring Boot 集成Jpa 和Shiro ,token方式实现 web和app鉴权