springboot+jpa 整合与基本应用
什么是jpa
JPA (The Java Persistence API)是用于访问,持久化和管理 Java 对象/类与关系型数据库之间的数据交互的 Java 规范。JPA 被定义为EJB (Enterprise JavaBeans) 3.0规范的一部分,作为 EJB 2 CMP 实体 Bean 规范的替代。
注意,JPA 只是一个标准,只定义了一系列接口,而没有具体的实现。很多企业级框架提供了对 JPA 的实现,如 Spring 。因此 Spring 本身与 JPA 无关,只是提供了对 JPA 的支持,因此在 Spring 中你也会看到很多注解都是属于 javax.persistence 包的。
JPA 允许 POJO(Plain Old Java Objects)轻松地持久化,而不需要类来实现 EJB 2 CM P规范所需的任何接口或方法。 JPA 还允许通过注解或 XML 定义对象的关系映射,定义 Java 类如何映射到关系数据库表。 JPA 还定义了一个运行时 EntityManager API,用于处理对象的查询和管理事务。 同时,JPA 定义了对象级查询语言 JPQL,以允许从数据库中查询对象,实现了对数据库的解耦合,提高了程序的可移植性,而不具体依赖某一底层数据库。
JPA 是 Java 持久化规范中的一个最新版本。第一个版本是 OMG 持久性服务 Java 绑定,但这个一个失败的产品,甚至没有任何商业产品支持它。接下来的版本是 EJB 1.0 CMP Entity Beans,它已经非常成功地被大型 Java EE 提供程序(BEA,IBM)采用,但是它复杂性太高而且性能比较差。EJB 2.0 CMP 试图通过引入本地接口来减少 Entity Bean 的一些复杂性,但是大多数复杂性仍然存在,而且缺乏可移植性。
历史总是要向前发展的,种种的这些使得 EJB 3.0 规范将降低复杂性作为主要目标,这导致规范委员会沿着 JPA 的路径前进。 JPA 旨在统一 EJB 2 CMP,JDO,Hibernate,从目前来看,JPA 的确取得了成功。
目前大多数持久化供应商已经发布了 JPA 的实现,并被行业和用户采用。这些包括 Hibernate(由 JBoss 和 Red Hat 收购),TopLink(由 Oracle 收购)和 Kodo JDO(由 BEA 和 Oracle 收购)。其他支持 JPA 的产品包括 Cocobase(由 Thought Inc. 收购)和 JPOX。
Spring Boot JPA - 基本使用
导入jar
在pom.xml中加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
创建实体
@Entity
public class User{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String phone;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
Dao层接口
public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
User findByPhone(String phone);
User findByPhoneAndFlag(String phone, Integer flag);
User findByIdAndFlag(Integer userId, Integer flag);
User findByOpenIdAndFlag(String openId, Integer flag);
Page<User> findByFlag(Integer flag, Pageable pageable);
List<User> findByNewPersonAndFlagOrderByCreateTimeAsc(Integer isNewPerson, Integer flag);
User findById(Integer toBeFollowID);
List<User> findByFlagAndNewPerson(Integer flag, Integer isNewPerson, Pageable pageable);
List<User> findByNicenameIsLikeAndFlagAndNewPerson(String searchName, Integer flag, Integer isNewPerson, Pageable pageable);
}
spring data jpa 默认预先生成了一些基本的CURD的方法,例如:增、删、改等等
userDao.save(user); //保存一个对象
userDao.save(new List<User>); //保存多个对象
userDao.delete(user); //删除一个对象
userDao.delete(id); //通过id删除
userDao.deleteAll(); //删除所有
userDao.delete(new ArrayList<>()); //批量删除
userDao.findOne(id); //通过id获取
userDao.getOne(id); //通过id获取 不推荐使用
userDao.findAll(pageable); //分页查找所有
userDao.exists(id); //id是否存在
......
除此之外还提供了自定义方法名的方式查询(在userDao中)
User findByOpenIdAndFlag(String openId, Integer flag);
//等同于
SELECT * FROM 'user' WHERE open_id =?1 AND flag = ?2
具体的关键字,使用方法和生产成SQL如下表所示
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | where x.firstname = 1? |
Between | findByStartDateBetween | where x.startDate between 1? and ?2 |
LessThan | findByAgeLessThan | where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | where x.age >= ?1 |
After | findByStartDateAfter | where x.startDate > ?1 |
Before | findByStartDateBefore | where x.startDate < ?1 |
IsNull | findByAgeIsNull | where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | where x.age not null |
Like | findByFirstnameLike | where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | where x.firstname like ?1 |
EndingWith | findByFirstnameEndingWith | where x.firstname like ?1 |
Containing | findByFirstnameContaining | where x.firstname like ?1 |
OrderBy | findByAgeOrderByLastnameDesc | where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> age) | where x.age not in ?1 |
True | findByActiveTrue() | where x.active = true |
False | findByActiveFalse() | where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | where UPPER(x.firstame) = UPPER(?1) |
分页查询
直接在controller层封装好Pageable对象即可
@GetMapping("findBanners")
public Page<Banner> findBanners(@PageableDefault(sort = {"priority"}, direction=Sort.Direction.ASC) Pageable pageable)
注意: #ad1f1f
前端直接在请求的最后拼接上?page=0&size=10
如果前端不传page 和 size 这两个参数过来,那么@PageableDefault会默认为第1页开始,每页最大条数为10。需注意page为0时为第一页。
在service中调用即可
//返回给客户端的Page对象,其json格式为
{
"content": [],//数据内容
"first": true,//是否为第一页
"last": true,//是否为最后一页
"number": 0,//当前页码
"numberOfElements": 0,//当前页中的实际数据条数
"size": 0,//一页最大条数
"sort": { },//排序信息
"totalElements": 0,//总条数
"totalPages": 0//总页数
}
自定义分页
public Page<Banner> findBanners(int id){
int page = 1;
int size = 10;
Sort sort = new Sort(Sort.Direction.DESC,"priority");
Pageable pageable = new PageRequest(page,size,sort);
return bannserDao.findById(id,pageable);
}
动态查询
public Page<Admin> findAdminList(AdminCmsSearchVO adminCmsSearchVO, Pageable pageable) {
Specifications<Admin> spec = Specifications.where(commonSpecUtil.like("name", adminCmsSearchVO.getName()))
.and(commonSpecUtil.equal("clazzType", adminCmsSearchVO.getClazzType()))
.and(commonSpecUtil.equal("flag",ModelContants.AdminContant.FLAG_IS_TRUE));
return adminDao.findAll(spec, pageable);
}
//(此代码由建东提供)
package com.luwei.common.utils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
* Created by jdq on 2017/8/8.
*/
@Component
public class CommonSpecUtil<T> {
/**
* 精确匹配(equal)
*
* @param srcName 字段名
* @param targetProperty 匹配内容
* @return
*/
public Specification<T> equal(String srcName, Object targetProperty) {
if (targetProperty == null) {
return null;
}
return (root, query, cb) -> cb.equal(root.get(srcName), targetProperty);
}
/**
* 精确匹配(notEqual)
*
* @param srcName 字段名
* @param targetProperty 匹配内容
* @return
*/
public Specification<T> notEqual(String srcName, Object targetProperty) {
if (targetProperty == null) {
return null;
}
return (root, query, cb) -> cb.notEqual(root.get(srcName), targetProperty);
}
/**
* 模糊匹配(like)
*
* @param srcName 字段名
* @param targetProperty 匹配内容
* @return
*/
public Specification<T> like(String srcName, String targetProperty) {
if (StringUtils.isEmpty(targetProperty)) {
return null;
}
return (root, query, cb) -> cb.like(root.get(srcName), "%" + targetProperty + "%");
}
/**
* 日期范围匹配(timeBetween)
*
* @param srcName 字段名
* @param startTimeStr 开始时间
* @param endTimeStr 结束时间
* @return
*/
public Specification<T> timeBetween(String srcName, String startTimeStr, String endTimeStr) {
Date startTime, endTime;
if (StringUtils.isEmpty(startTimeStr)) {
startTime = DateUtils.getDate2("1970-01-01 00:00:00");
} else {
startTime = DateUtils.getDate2(startTimeStr + " 00:00:00");
}
if (StringUtils.isEmpty(endTimeStr)) {
endTime = new Date();
} else {
endTime = DateUtils.getDate2(endTimeStr + " 23:59:59");
}
return (root, query, cb) -> cb.between(root.get(srcName), startTime, endTime);
}
public Specification<T> parkingOrderTime(String srcName,String startTimeStr,String endTimeStr) {
Date startTime,endTime;
startTime=DateUtils.getDate2(DateUtils.tostartDayTime(startTimeStr));
endTime = DateUtils.getDate2(DateUtils.toEndDayTime(endTimeStr));
return (root, query, cb) -> cb.between(root.get(srcName), startTime,endTime);
}
/**
* 日期范围匹配(timeBetween)
*
* @param srcName 字段名
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
public Specification<T> timeBetween(String srcName, Date startTime, Date endTime) {
if (org.springframework.util.StringUtils.isEmpty(startTime)) {
return null;
}
if (org.springframework.util.StringUtils.isEmpty(endTime)) {
return null;
}
return (root, query, cb) -> cb.between(root.get(srcName), startTime, endTime);
}
/**
* 数值范围匹配(between)
*
* @param srcName 字段名
* @param start 开始
* @param end 结束
* @return
*/
public Specification<T> between(String srcName, Integer start, Integer end) {
if (org.springframework.util.StringUtils.isEmpty(start)) {
return null;
}
if (org.springframework.util.StringUtils.isEmpty(end)) {
return null;
}
return (root, query, cb) -> cb.between(root.get(srcName), start, end);
}
/**
* 大于等于(greaterThanOrEqualTo)
*
* @param srcName 字段名
* @param value 数值
* @return
*/
public Specification<T> greaterThanOrEqualTo(String srcName, Integer value) {
if (org.springframework.util.StringUtils.isEmpty(value)) {
return null;
}
return (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(srcName), value);
}
/**
* 小于等于(lessThanOrEqualTo)
*
* @param srcName 字段名
* @param value 数值
* @return
*/
public Specification<T> lessThanOrEqualTo(String srcName, Integer value) {
if (org.springframework.util.StringUtils.isEmpty(value)) {
return null;
}
return (root, query, cb) -> cb.lessThanOrEqualTo(root.get(srcName), value);
}
/**
* in条件帅选(in)
*
* @param srcName 字段名
* @param list 集合
* @return
*/
public Specification<T> in(String srcName, List<Integer> list) {
if (org.springframework.util.StringUtils.isEmpty(list)) {
return null;
}
return (root, query, cb) -> cb.and(root.get(srcName).in(list));
}
/**
* 不为空(isNotNull)
*
* @param srcName 字段名
* @return
*/
public Specification<T> isNotNull(String srcName) {
return (root, query, cb) -> cb.isNotNull(root.get(srcName));
}
/**
* 倒序(desc)
*
* @param srcName 字段名
* @return
*/
public Specification<T> desc(String srcName) {
return (root, query, cb) -> query.orderBy(cb.desc(root.get(srcName).as(Integer.class))).getRestriction();
}
/**
* 升序(asc)
*
* @param srcName 字段名
* @return
*/
public Specification<T> asc(String srcName) {
return (root, query, cb) -> query.orderBy(cb.asc(root.get(srcName).as(Integer.class))).getRestriction();
}
}
动态查找的条件:
1.adminDao要继承JpaSpecificationExecutor
2.CommonSpecUtil提供了各种匹配的方法。如equals,like,notEqual…
参考博客
部分引用于袁荻的博客
原文地址
广州芦苇科技Java开发团队
芦苇科技-广州专业互联网软件服务公司
抓住每一处细节 ,创造每一个美好
关注我们的公众号,了解更多
想和我们一起奋斗吗?lagou搜索“ 芦苇科技 ”或者投放简历到 [email protected] 加入我们吧
关注我们,你的评论和点赞对我们最大的支持