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;
}
}