1. 程式人生 > >springboot+jpa 整合與基本應用

springboot+jpa 整合與基本應用

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
enter description here
2.CommonSpecUtil提供了各種匹配的方法。如equals,like,notEqual…

參考部落格

部分引用於袁荻的部落格
原文地址

廣州蘆葦科技Java開發團隊

蘆葦科技-廣州專業網際網路軟體服務公司

抓住每一處細節 ,創造每一個美好

關注我們的公眾號,瞭解更多

想和我們一起奮鬥嗎?lagou搜尋“ 蘆葦科技 ”或者投放簡歷到 [email protected] 加入我們吧

關注我們,你的評論和點贊對我們最大的支援