最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Jpa?Specification如何實(shí)現(xiàn)and和or同時使用查詢

 更新時間:2021年11月23日 09:41:31   作者:qq_41315539  
這篇文章主要介紹了Jpa?Specification如何實(shí)現(xiàn)and和or同時使用查詢,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

同時使用and和or的查詢

UserServiceImpl 類,service實(shí)現(xiàn)類

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
 
@Service
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private RongUserRepository rongUserRepository;
     //FriendNumResult  自定的返回類型
    //FriendNumParam  自定義的封裝參數(shù)的類型
    //RongUser  實(shí)體類型
    @Override
    public FriendNumResult friendNum(FriendNumParam friendNumParam) {
        FriendNumResult friendNumResult=new FriendNumResult();
 
        Specification<RongUser> specification = new Specification<RongUser>(){
 
            @Override
            public Predicate toPredicate(Root<RongUser> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //封裝and語句
                List<Predicate> listAnd = new ArrayList<Predicate>();
                //這里是hql,所以root.get(),方法里面必須是對應(yīng)的實(shí)體屬性
                listAnd.add(criteriaBuilder.equal(root.get("perLevel").as(Integer.class), friendNumParam.getPerLevel()));
                Predicate[] array_and=new Predicate[listAnd.size()];
                Predicate Pre_And = criteriaBuilder.and(listAnd.toArray(array_and));
 
                //封裝or語句
                List<Predicate> listOr = new ArrayList<Predicate>();
                listOr.add(criteriaBuilder.equal(root.get("fId").as(Integer.class), friendNumParam.getUid()));
                listOr.add(criteriaBuilder.equal(root.get("fId2").as(Integer.class), friendNumParam.getUid()));
                Predicate[] arrayOr = new Predicate[listOr.size()];
                Predicate Pre_Or = criteriaBuilder.or(listOr.toArray(arrayOr));
 
                return criteriaQuery.where(Pre_And,Pre_Or).getRestriction();
                //單獨(dú)使用  and 或者  or 時 返回
                //return criteriaBuilder.and(list.toArray());
            }
        };
        long num=this.rongUserRepository.count(specification);
        friendNumResult.setFriendNum(Integer.valueOf((int)num));
        return friendNumResult;
    }
}

RongUserRepository接口

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
//RongUser  自己的實(shí)體類型
public interface RongUserRepository extends JpaRepository<RongUser,Integer> , JpaSpecificationExecutor<RongUser> {
}

注意:使用Specification之前,RongUserRepository接口必須實(shí)現(xiàn)JpaSpecificationExecutor<RongUser>,RongUser對應(yīng)表的實(shí)體類

JPA 動態(tài)查詢之AND、OR結(jié)合使用

現(xiàn)在,我負(fù)責(zé)開發(fā)的項(xiàng)目中,使用JPA作為ORM框架。有了JPA,一行SQL都沒寫過。在昨天,有一個新的需求,需要進(jìn)行動態(tài)查詢,這個簡單。但是有一個地方需要AND、OR結(jié)合使用,這里,我將記錄下我的理解與寫法,希望能幫助到大家。

問題描述

需要根據(jù)條件進(jìn)行動態(tài)查詢,實(shí)現(xiàn)一條類似下文的語句:

SELECT *
FROM   table
WHERE  1 = 1
   if (a == 1)
        AND table.column1 = a
   if (b != null)
        AND table.column2 = b
   if (cList != null && cList.size() > 0)
        AND table.column3 IN cList
   if (d == 2 || dd == 2)
        AND (table.column4 = d OR table.column5 = dd)

上面是幾行偽代碼。意思是,幾個條件之間是AND連接,但是其中的部分條件,是使用OR連接的。

在我們的實(shí)際項(xiàng)目中,這個場景也是很常見的。這里,我將分享下具體的寫法。以我們項(xiàng)目中的例子為例。

代碼示例

JPA的動態(tài)查詢,這里我們使用的方式是:實(shí)現(xiàn) Specification 接口,自定義動態(tài)查詢邏輯。這也是我個人比較推薦的方式。JPA的使用、Specification 接口基礎(chǔ)知識這里我就不講了。有興趣的朋友可以查閱官方文檔學(xué)習(xí)。

下面,我們首先定義好我們的數(shù)據(jù)庫實(shí)體:

@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    /**
     * 用戶名
     */
    private String username;
    /**
     * 年齡
     */
    private Integer age;
    /**
     * 生日
     */
    private Date birthDay;
    /**
     * 刪除標(biāo)識; 0 - 未刪除,1 - 已刪除
     */
    private Integer deleteFlag;
}

然后定義好DAO層接口:

@Repository
public interface UserDAO extends JpaRepository<User, Long> {
    /**
     * 其實(shí),這個功能一般用作 list 接口使用,一般結(jié)合分頁查詢使用。這里,我不做介紹,看情況要不要后期加上教程
     */
    List<User> findAll(Specification<User> querySpec);
}

下面是前端傳過來的動態(tài)查詢的參數(shù)對象:

@Data
public class UserDTO {
    /**
     * 用戶名,用于模糊搜索
     */
    private String username;
    /**
     * 用戶ID,用于 In 查詢
     */
    private List<String> userIdList;
    /**
     * 用戶年齡,用于 OR In 查詢
     */
    private List<Integer> ageList;
    /**
     * 生日,開始
     */
    @JsonFormat(pattern = "yyyy-MM-dd", locale = "zh", timezone = "GMT+8")
    private Date birthDayBegin;
    /**
     * 生日,結(jié)束
     */
    @JsonFormat(pattern = "yyyy-MM-dd", locale = "zh", timezone = "GMT+8")
    private Date birthDayEnd;
}

然后,重要的地方來了,我們實(shí)現(xiàn) Specification 接口,定義查詢邏輯:

在實(shí)際代碼操作中,我會將這部分邏輯抽離為一個單獨(dú)的方法,使用lambda表達(dá)式完成,其實(shí)也就是匿名內(nèi)部類。

private Specification<User> getListSpec(UserDTO userDTO) {
    return (root, criteriaQuery, criteriaBuilder) -> {
        List<Predicate> predicateList = new ArrayList<>();
        // 未刪除標(biāo)識,只查詢未刪除的數(shù)據(jù)
        predicateList.add(criteriaBuilder.equal(root.get("deleteFlag"), 0));
        // 根據(jù) 用戶名 或 年齡List 查詢
        List<Predicate> usernameOrAgePredicate = new ArrayList<>();
        String username = userDTO.getUsername();
        if (!StringUtils.isEmpty(username)) {
            // 用戶名這里,用模糊匹配
            usernameOrAgePredicate.add(criteriaBuilder.like(root.get("username"), "%" + username + "%"));
        }
        List<Integer> ageList = userDTO.getAgeList();
        if (!CollectionUtils.isEmpty(ageList)) {
            // 下面是一個 IN查詢
            CriteriaBuilder.In<Integer> in = criteriaBuilder.in(root.get("age"));
            ageList.forEach(in::value);
            usernameOrAgePredicate.add(in);
        }
        /* 下面這一行代碼很重要。
         * criteriaBuilder.or(Predicate... restrictions) 接收多個Predicate,可變參數(shù);
         * 這多個 Predicate條件之間,是使用OR連接的;該方法最終返回 一個Predicate對象;
         */
        predicateList.add(criteriaBuilder.or(usernameOrAgePredicate.toArray(new Predicate[0])));
        // 用戶ID List,IN 查詢
        List<Integer> userIdList = reqDTO.getUserIdList();
        if (!CollectionUtils.isEmpty(userIdList)) {
            CriteriaBuilder.In<Integer> in = criteriaBuilder.in(root.get("id"));
            userIdList.forEach(in::value);
            predicateList.add(in);
        }
        // 生日時間段查詢
        Date birthDayBegin = reqDTO.getBirthDayBegin();
        Date birthDayEnd = reqDTO.getBirthDayEnd();
        if (birthDayBegin != null && birthDayEnd != null) {
            // DateUtils 是我自定義的一個工具類
            Date begin = DateUtils.startOfDay(birthDayBegin);
            Date end = DateUtils.endOfDay(birthDayEnd);
            predicateList.add(criteriaBuilder.greaterThanOrEqualTo(root.get("birthDay"), begin));
            predicateList.add(criteriaBuilder.lessThanOrEqualTo(root.get("birthDay"), end));
        }
        // 最終,使用AND 連接 多個 Predicate 查詢條件
        return criteriaBuilder.and(predicateList.toArray(new Predicate[0]));
    };
}

這樣,我們的動態(tài)查詢部分就構(gòu)建完畢了。具體怎么使用呢?如下:

Specification<User> querySpec = this.getListSpec(userDTO);
List<User> userList = userDAO.findAll(querySpec);

就這樣,我們就執(zhí)行了一次動態(tài)查詢,并獲取到了結(jié)果。

上面的動態(tài)查詢,實(shí)際上等價于下面的偽代碼:

SELECT * 
FROM   user 
WHERE  user.deleteFlag = 0 
AND    ( user.username like '%{username}%' OR user.age IN ageList )
AND    user.id IN userIdList
AND    user.birthDay > birthDayBegin AND user.birthDay < birthDayEnd ;

當(dāng)前,需要對應(yīng)值不為空,才會拼接相應(yīng)的AND條件。

至此,JPA 動態(tài)查詢之 AND OR結(jié)合使用,教程到這里就結(jié)束了。以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java如何獲取枚舉類型的值

    Java如何獲取枚舉類型的值

    這篇文章主要介紹了Java如何獲取枚舉類型的值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • java中url任意跳轉(zhuǎn)漏洞的解決

    java中url任意跳轉(zhuǎn)漏洞的解決

    URL任意跳轉(zhuǎn)漏洞是一種安全漏洞,它發(fā)生在應(yīng)用程序沒有正確地驗(yàn)證目標(biāo)URL,允許攻擊者將用戶重定向到惡意網(wǎng)站,本文就來介紹一下漏洞的解決修復(fù)方案,感興趣的可以了解一下
    2024-06-06
  • Mybatis 插件原理解析

    Mybatis 插件原理解析

    mybatis是一款優(yōu)秀的ORM開源框架,這個框架具有極強(qiáng)的靈活性,本文再次給大家介紹Mybatis 插件原理,感興趣的朋友一起看看吧
    2021-10-10
  • Java實(shí)題演練二叉搜索樹與雙向鏈表分析

    Java實(shí)題演練二叉搜索樹與雙向鏈表分析

    這篇文章主要介紹了Java二叉搜索樹與雙向鏈表,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達(dá)的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路
    2022-12-12
  • javaweb中Filter(過濾器)的常見應(yīng)用

    javaweb中Filter(過濾器)的常見應(yīng)用

    這篇文章主要介紹了javaweb中Filter的常見應(yīng)用,過濾器的使用方法,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Java使用Apache Commons高效處理CSV文件的操作指南

    Java使用Apache Commons高效處理CSV文件的操作指南

    在 Java 開發(fā)中,CSV(Comma-Separated Values,逗號分隔值)是一種常見的數(shù)據(jù)存儲格式,廣泛用于數(shù)據(jù)交換和簡單的存儲任務(wù),本文將介紹Java使用Apache Commons高效處理CSV文件的操作指南,需要的朋友可以參考下
    2025-03-03
  • Java開發(fā)中為什么要使用單例模式詳解

    Java開發(fā)中為什么要使用單例模式詳解

    單例對于大家來說并不陌生,但是在什么時候用單例呢?為什么要用呢?本文就帶大家了解一下為什么要使用單例,文中有非常詳細(xì)的介紹,需要的朋友可以參考下
    2021-06-06
  • Java中抽象類用法與注意點(diǎn)實(shí)例詳解

    Java中抽象類用法與注意點(diǎn)實(shí)例詳解

    這篇文章主要介紹了Java中抽象類用法與注意點(diǎn),結(jié)合實(shí)例形式詳細(xì)分析了java抽象類的定義、使用及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-08-08
  • MyBatis-Plus?分頁不生效的解決方法

    MyBatis-Plus?分頁不生效的解決方法

    本文主要介紹了MyBatis-Plus?分頁不生效的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • java.nio.file.WatchService?實(shí)時監(jiān)控文件變化的示例代碼

    java.nio.file.WatchService?實(shí)時監(jiān)控文件變化的示例代碼

    在?Java?語言中,從?JDK7?開始,新增了java.nio.file.WatchService類,用來實(shí)時監(jiān)控文件的變化,這篇文章主要介紹了java.nio.file.WatchService?實(shí)時監(jiān)控文件變化,需要的朋友可以參考下
    2022-05-05

最新評論

于都县| 襄垣县| 宣武区| 大方县| 台东县| 濉溪县| 西盟| 丽江市| 公安县| 闵行区| 安图县| 宁河县| 宁强县| 磐安县| 麻栗坡县| 苍梧县| 凌源市| 博野县| 黑水县| 泰兴市| 夹江县| 竹北市| 湘阴县| 准格尔旗| 南投市| 如皋市| 崇左市| 九台市| 博爱县| 舟曲县| 莒南县| 石楼县| 财经| 溆浦县| 廉江市| 姚安县| 龙里县| 定兴县| 安平县| 噶尔县| 高碑店市|