Springboot+jpa之 Specification複雜查詢1:搜索功能

Specification: jpa的條件構造器

實現複雜查詢,使用Repository,需要實現JpaSpecificationExecutor接口       

public interface UserDao extends JpaRepository<User, Long>,JpaSpecificationExecutor<User> {
}
userDao.findAll(new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) { }
        });

Root查詢結果的一個實體對象,也就是查詢結果返回的主要對象

CriteriaQuery(javax.persistence.criteria.CriteriaQuery<T>):

這個是JPA標準,用於構建查詢條件,裏面的方法爲各種查詢方式,如:distinct、select、where、groupby、having、orderby等

CriteriaBuilder(javax.persistence.criteria.CriteriaBuilder):

用來進行函數操作,此接口很多都是返回Predicate接口的,其中包含:between(範圍之間)、gt(大於),lt(小於),not(非)等操作.

JPA標準中Hibernate的兩個實現方法

   1.and(org.hibernate.ejb.criteria.CriteriaBuilderImpl.and(Predicate...)) :將各個條件作爲and來拼接,進行查詢;
    2.or (org.hibernate.ejb.criteria.CriteriaBuilderImpl.or(Predicate...)):將各條件作爲or來拼接,進行查詢。

這兩個方法都有一個關鍵的接口:Predicate(javax.persistence.criteria.Predicate);是Expression(javax.persistence.criteria.Expression<Boolean>)的子接口。這個接口作爲關聯各種Predicate的核心操作接口。

 

1.定義一個Predicate數組,和一個臨時Predicate數組,

List<Predicate> predicates = new ArrayList<>();
List<Predicate> temp = new ArrayList<>();

2.將查詢條件添加到臨時Predicate數組當中

temp.add(criteriaBuilder.like(userName,"%"+ user.getUserName()+"%"));
temp.add(criteriaBuilder.equal(phone,user.getPhone()));

3.再將臨時數組用or或者and將查詢條件拼接起來放到Predicate數組當中

predicates.add(criteriaBuilder.or(temp.toArray(new Predicate[temp.size()])));

4.最後將list轉爲數組執行查詢

query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();

簡單來說:

Root:查詢的實體類(user實體類)
CriteriaQuery:構建查詢條件,查詢哪些字段,排序是什麼
CriteriaBuilder:字段之間是什麼關係,如何生成一個查詢條件,進行函數操作;
Predicate(Expression):單獨每一條查詢條件的詳細描述。(條件)

 

實際例子:User表按條件查詢

實體類

package com.association.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.persistence.*;
import java.util.Date;

/**
 * 用戶表
 */
@Entity
@Data
@Table(name="user")
public class User extends BaseEntity {

    /** 用戶ID */
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id
    private Long userId;

    /** 用戶名 */
    private String userName;

    /** 手機*/
    private String phone;

    /** 狀態 1:停用 0:正常*/
    private String status;

    /** 開始時間 */
    @JsonIgnore
    private String beginTime;

    /** 結束時間 */
    @JsonIgnore
     private String endTime;

}

Dao層

@Repository
public interface UserDao extends JpaRepository<User, Long>,JpaSpecificationExecutor<User> {

}

Controller層

@RestController
@RequestMapping("/api/user")
public class UserController extends BaseController {

 @Autowired
    UserService userService;

  //region  獲取用戶列表
    /**
     * 獲取用戶列表
     */
    @GetMapping("/list")
    public TableDataInfo listUser(User user)
    {
        startPage();

        List<User> list = userService.selectUserList(user);

        //表格分頁數據
        return getDataTable(list);
    }
    //endregion

}

service層

/**
 * 用戶 業務層
 */
public interface UserService
{
    /**
     * 根據條件分頁查詢用戶列表
     * 
     * @param user 用戶信息
     * @return 用戶信息集合信息
     */
    public List<User> selectUserList(User user);

    /**
     * 根據搜索條件查詢用戶列表
     * 
     * @param user 用戶信息
     * @return 用戶信息集合信息
     */
    List<User> findByDynamicCases(User user);

}

serviceImpl(service實現層)

/**
 * 用戶 業務層處理
 *
 * @author baozi
 */
@Service
public class UserServiceImpl implements UserService {

   //日誌
  private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

  @Autowired
  private UserDao userDao;

    //region 根據條件分頁查詢用戶列表

    /**
     * 根據條件分頁查詢用戶列表
     *
     * @param user 用戶信息
     * @return 用戶信息集合信息
     */
    @Override
    public List<User> selectUserList(User user) {

        //查詢條件:1.用戶姓名 2.用戶電話 3.用戶狀態 4.創建時間範圍

        //如果條件都爲null則查詢全部
        if (StringUtils.isNull(user.getUserName()) && StringUtils.isNull(user.getStatus())
                && StringUtils.isNull(user.getPhone())
                && StringUtils.isEmpty(user.getBeginTime())
                && StringUtils.isEmpty(user.getEndTime())) {
            return userDao.findAll();
        } else {
            return findByDynamicCases(user);
        }
    }
    //endregion

    //region 查詢:按條件進行動態查詢

    /**
     * 按條件進行動態查詢
     * 查詢條件:1.用戶姓名
     * 2.用戶手機
     * 3.用戶狀態
     * 4.用戶創建時間範圍
     * @return
     */
    public List<User> findByDynamicCases(User user) {
        return  userDao.findAll(new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {

                Path userName = root.get("userName");
                Path phone = root.get("phone");
                Path status = root.get("status");
                Path createTime = root.get("createTime");

                List<Predicate> predicates = new ArrayList<>();
                List<Predicate> temp = new ArrayList<>();

                if (user.getUserName() != null) {
                    temp.add(criteriaBuilder.like(userName,"%"+ user.getUserName()+"%"));
                }
                if (user.getPhone() != null) {
                    temp.add(criteriaBuilder.equal(phone,user.getPhone()));
                }
                if (user.getStatus() != null) {
                    temp.add(criteriaBuilder.equal(status,user.getStatus()));
                }
                if (user.getBeginTime() != null
                        && user.getEndTime()!= null
                        &&StringUtils.isNotEmpty(user.getBeginTime())
                        &&StringUtils.isNotEmpty(user.getEndTime())){
                    temp.add(criteriaBuilder.between(createTime, DateUtils.parseDate(user.getBeginTime()), DateUtils.parseDate(user.getEndTime())));
                }

                predicates.add(criteriaBuilder.or(temp.toArray(new Predicate[temp.size()])));
                return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        });
    }
    //endregion


}

表格分頁


@Data
public class TableDataInfo implements Serializable
{
    private static final long serialVersionUID = 1L;

    /** 總記錄數 */
    private long total;

    /** 列表數據 */
    private List<?> rows;

    /** 消息狀態碼 */
    private int code;

    /** 消息內容 */
    private int msg;

    /**
     * 表格數據對象
     */
    public TableDataInfo()
    {
    }

    /**
     * 分頁
     * 
     * @param list 列表數據
     * @param total 總記錄數
     */
    public TableDataInfo(List<?> list, int total)
    {
        this.rows = list;
        this.total = total;
    }


}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章