Spring Data -Specification用法和常用查詢方法(in,join,equal等)
前言
在這一年里技術更新,從使用Mybatis轉為Spring Data,總體感受是終於不用在自己寫映射了,也可以少寫方法和對應字段了。接下來總結在工作中常用的查詢方式和方法,例如equal,join,in等。積少成多,在這里只收藏了用過查詢與方法(如果方法可以用得更有,有更多的用法和不足之處請聯系我)。
入門例子
controller層,這里是個簡單查詢獲取所有用戶並分頁
@GetMapping("/list")
@ApiOperation(value = "所有用戶列表")
public Result list(@RequestParam Map<String, Object> params) {
Page page = userService.queryPage(params);
return Result.ok().put("page", page);
}
接下對service層的實現,功能是實現關鍵字搜索,這里因為簡單並沒有單獨將Specification提出來,主要是對Specification接口有個大概的認識。
@Override
public page queryPage(Map<String, Object> params) {
//MapUtils方法用來取除params中的方法,來自於 org.apache.commons.collections.MapUtils;
String keyword = MapUtils.getSrting(params,"keyword");
Page page = sysUserRepository.findAll(new Specification<SysUserEntity>() {
@Override
public Predicate toPredicate(Root<SysUserEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotBlank(keyword)) {
List<Predicate> temp = new ArrayList<>();
for (String oneKeyword : keywordCopyStr) {
temp.add(criteriaBuilder.like(root.<String>get("mobile"), "%" + oneKeyword + "%"));
temp.add(criteriaBuilder.like(root.<String>get("trueName"), "%" + oneKeyword + "%"));
}
predicates.add(criteriaBuilder.or(temp.toArray(new Predicate[temp.size()])));
}
return criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
}
});
return page;
}
Repository層中為了支持這樣的查詢,sysUserRepository需要繼承JpaRepository(基本查詢),JpaSpecificationExecutor(分頁),這個接口是不需要再去實現的,到了Repository層就行,再對此進行擴充(比Mybatis簡單多了)。
public interface sysUserRepository extends JpaRepository<SysCaptchaEntity, String>, JpaSpecificationExecutor<SysCaptchaEntity> {
}
Repository層常用寫法
- 按着類字段查詢 按着類關系關聯查詢不需要寫語句的查詢就不在詳細講解,給個例子看看就行
//查詢第一個
EngineerVersionControl findTopByProjectIdAndOldOrderByVersionDesc(String projectId, int old);
//查詢存在
boolean existsByProjectId(String projectId);
//排序
List<EngineerVersionControl> findByProjectIdOrderByVersionDesc(String projectId);
- @Query語句查詢
一般不會做物理刪除,而是邏輯刪除。保存操作使用save或者saveAll方法
//更新 必有@Modifying,和使用hiberna一樣,HQL語句的寫法
@Transactional(rollbackFor = Exception.class)
@Modifying
@Query("update SysUserEntity u set u.isDelete = ?2 ,u.gmtModified= ?3 where u.id = ?1 ")
int deleteIsUpdate(String id, int deleted, Date date);
//查詢
@Query("select u from SysUserEntity u where u.id in ?1 and u.isDelete = 0 ")
Page<SysUserEntity> findAllUser(List<String> userIds, Pageable pageable);
//多表查詢
@Query(value = " select p from DictionaryEntity p , DictionaryContentEntity w " +
" Where w.ContentEntity.id = ?1 and p.id = w.DictionaryEntity.id and p.deleted = ?2 ORDER BY p.dictionary")
List<WebsiteDictionaryEntity> webOnwDictionary(String id,int isDeleted);
3.使用@Query實現寫sql語句的查詢
再spring data 中不僅有HQl語句,在功能太復雜的時候,可以使用sql語句進行本地查詢
@Query(value="select serve.* from service_serve serve " +
"left join company_info_user cominfo on serve.company_info_user_id=cominfo.company_info_user_id" +
" left join user_company company on cominfo.company_info_user_id=company.company_info_user_id " +
" left join employee employeeen3_ on company.user_company_id=employeeen3_.user_company_id " +
" left join user userentity4_ on employeeen3_.user_id=userentity4_.user_id " +
" where userentity4_.user_id=?1 and employeeen3_.activity_management_power=1" +
" order by serve.gmt_create desc " +
"limit ?2 , ?3 " ,nativeQuery = true)
List<ServiceServeEntity> queryByCompany(String userId,int startPoint,int endPoint);
4.@Param(value = “name”)查詢,這是兩種寫法。一種?,一種@Param()
@Query(value="select activity.* from service_activity activity " +
"left join company_info_user cominfo on activity.company_id=cominfo.company_info_user_id" +
" left join user_company company on cominfo.company_info_user_id=company.company_info_user_id " +
" left join employee employeeen3_ on company.user_company_id=employeeen3_.user_company_id " +
" left join user userentity4_ on employeeen3_.user_id=userentity4_.user_id " +
" where userentity4_.user_id=:userId and employeeen3_.service_management_power=1 and activity.status=:status" +
" order by activity.gmt_create desc " +
"limit :startPoint , :endPoint " ,nativeQuery = true)
List<ServiceActivityEntity> queryByCompanyAndStatus(@Param(value="userId")String userId,@Param(value="status")int status, @Param(value="startPoint")int startPoint, @Param(value="endPoint")int endPoint);
Specification 的用法
下面是個較為全面的例子,將一個較為復雜的查詢提取成一個方法。這個方法時使用and的方式拼接,接下來的每一個查詢都需要使用把finalConditions拼上,如同 finalConditions = criteriaBuilder.and(finalConditions, taskFastPre)。
public class TaskProjectSpecs {
public static Specification<Task> where(Map params, String userId, List<String> taskIds) {
//lambda表達式
return (Root<Task> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> {
//開始
Predicate finalConditions = criteriaBuilder.conjunction();
//提取參數
String taskFast = MapUtils.getString(params, "taskFast");
//lile 和join 用法 join可跟,JoinType.LEFT等
if (StringUtils.isNotBlank(taskFast)) {
Predicate taskFastPre = criteriaBuilder.like(root.join("taskType",JoinType.LEFT).<String>get("id"), "%" + taskFast + "%");
finalConditions = criteriaBuilder.and(finalConditions, taskFastPre);
}
//between用法
if ((null != createBegin) && (null != createEnd)) {
Predicate datePredicate = null;
if (createBegin.after(createEnd)) {
datePredicate = criteriaBuilder.between(root.get("gmtCreate"), createEnd, createBegin);
} else {
datePredicate = criteriaBuilder.between(root.get("gmtCreate"), createBegin, createEnd);
}
finalConditions = criteriaBuilder.and(finalConditions, datePredicate);
}
//equale
if (null != emergency && 0 != emergency) {
finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.equal(root.get("emergencyLevel"), emergency));
}
//大於 不等於
if (status != null) {
finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.greaterThan(root.get("startDate"), new Date()));
finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.notEqual(root.get("status"), 1));
}
// or
if (StringUtils.isNotBlank(keyword)) {
finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.or(
criteriaBuilder.like(root.get("taskName"), "%" + keyword + "%"),
criteriaBuilder.like(root.join("project").get("name"), "%" + keyword + "%"))
);
}
//in
if (taskIds.size() > 0) {
CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get("id"));
for (String id : taskIds) {
in.value(id);
}
finalConditions = criteriaBuilder.and(finalConditions, in);
}
return query.where(finalConditions).getRestriction();
};
}
}
上面的方法是and憑借,還有一種add的方法,本質一樣,都是構建query.where()查詢。
public class UserSpecs {
public static Specification<SysUserEntity> where(String keyword, Date createdAtBegin, Date createdAtEnd, List<String> userIds) {
return (Root<SysUserEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotBlank(keyword)) {
List<Predicate> temp = new ArrayList<>();
Set<String> keywordCopyStr = StringUtil.cutToArray(keyword);
for (String oneKeyword : keywordCopyStr) {
temp.add(cb.like(root.<String>get("mobile"), "%" + oneKeyword + "%"));
temp.add(cb.like(root.<String>get("trueName"), "%" + oneKeyword + "%"));
}
predicates.add(cb.or(temp.toArray(new Predicate[temp.size()])));
}
//未刪除
predicates.add(cb.equal(root.get("isDelete"), Constant.NOT_DELETED));
query.where(predicates.toArray(new Predicate[predicates.size()]));
return query.getRestriction();
};
}
}
return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
總結
基本將常用的都包含完了,以后遇到了新的寫法再更新上去。
</div>