JPA不定项分页查询初学者分享

  

  初学JPA,遇见分页查询需求:不定项、模糊、排序要求,如果没有不定项的需求,会很容易搞定:直接findByClassNameLikeAndParentIdAndHide(),传入分页参数Pageable就可以搞定,但是加上不定项只能自己手动写sql,手忙脚乱,网上查询了各位大神的文章,经整理实践,得出以下两种实现方式。Controller层我只写了参数合法性验证,Model层不需要写任何代码,service层代码如下:

    /**
     * 分页查询系统分类列表(方法一)
     *
     * @param className
     * @param parentId
     * @param hide
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Transactional
    public ResultMap getList(String className, Integer parentId, Integer hide, int pageNum, int pageSize) {
        //返回结果
        ResultMap resultMap = new ResultMap();

        StringBuilder jpql = new StringBuilder(" from SysClass s where 1=1 ");
        List<Object> args = new ArrayList<>();//参数集合

        int i = 0;//参数位置标记
        //模糊查询
        if(className != null){
//            jpqlBuilder.append(" and s.className like %" + className + "% ");  //存在sql注入风险
            jpql.append(" and s.className like CONCAT('%',?").append(i).append(",'%') ");
            args.add(className);
            i++;
        }
        //指定查询
        if(parentId != null){
            jpql.append(" and s.parentId = ?").append(i).append(" ");
            args.add(parentId);
            i++;
        }
        //controller层中对参数hide进行了验证,确保为0~2的整数,数据库中只保存0、1,全部查询参数为2
        if(hide != 2){
            jpql.append(" and s.hide = ?").append(i).append(" ");
            args.add(hide);
        }
        //拼接排序方式
        String orderJpql = " order by s.sort desc ,s.classId ";

        //列表查询
        Query query = em.createQuery(jpql.toString() + orderJpql );
        //加入参数
        for(int j = 0; j < args.size(); j++){
            query.setParameter(j,args.get(j));
        }
        //加入分页信息
        query.setFirstResult((pageNum - 1) * pageSize);
        query.setMaxResults(pageSize);

        List<SysClass> sysClassList = query.getResultList();
        //结果处理,将需要展示的字段返回前端
        List<JSONObject> resultList = new ArrayList<>();
        for(SysClass sysClass :sysClassList){
            //自定义工具类,将对象中需要返回的字段以json形式返回
            resultList.add(Util.getCustomInfo(sysClass));
        }
        resultMap.put("data", resultList);

        //查询总数量
        String countJpql = "select count(s.classId) ";
        Query countQuery = em.createQuery(countJpql + jpql.toString());
        //加入参数
        for(int j = 0; j < args.size(); j++){
            countQuery.setParameter(j,args.get(j));
        }
        List<Object> countResult = countQuery.getResultList();

        //分页信息处理
        int total = Integer.valueOf(countResult.get(0).toString());
        int totalPage = total/pageSize;
        if( total%pageSize !=0 ){
            totalPage++;
        }

        //将查询结果填入结果集中
        resultMap.put("pageNum", pageNum);
        resultMap.put("pageSize", pageSize);
        resultMap.put("total",total);
        resultMap.put("totalPage", totalPage);

        return resultMap;
    }

以下为方法二:

   /**
     * 分页查询系统分类列表(方法二)
     *
     * @param className
     * @param parentId
     * @param hide
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Transactional
    public ResultMap getList(String className, Integer parentId, Integer hide, int pageNum, int pageSize) {
        //返回结果
        ResultMap resultMap = new ResultMap();

        CriteriaBuilder cb = em.getCriteriaBuilder();  //获取CriteriaBuilder实体类
        CriteriaQuery<Tuple> criteriaQuery = cb.createTupleQuery();//列表查询
        CriteriaQuery<Tuple> criteriaQueryCount = cb.createTupleQuery();//统计查询
        Root<SysClass> root = criteriaQuery.from(SysClass.class);   //列表查询的实体对象
        Root<SysClass> rootCount = criteriaQueryCount.from(SysClass.class);   //统计查询的实体对象

        //加载查询的列
        criteriaQuery.multiselect(
                root.get("classId").alias("classId"),
                root.get("className").alias("className"),
                root.get("icon").alias("icon"),
                root.get("parentId").alias("parentId")
        );

        //加载查询统计的内容
        criteriaQueryCount.multiselect(
                cb.count(rootCount.get("classId")).alias("total")  //统计查询总条数,作为页面信息返回
        );

        //条件集合
        List<Predicate> predicates = new ArrayList<>();
        //设定查询条件
        if (className != null) { //模糊搜索
            Path<String> classNamePath = root.get("className");
            predicates.add(cb.like(classNamePath.as(String.class), "%" + className + "%"));
        }
        if (parentId != null) {  //匹配搜索
            Path<Integer> parentIdPath = root.get("parentId");
            predicates.add(cb.equal(parentIdPath.as(Integer.class), parentId));
        }
        if (hide != 2) {   //0.查询隐藏内容 1.查询显示隐藏内容 2.查询全部内容(不加查询条件)
            Path<Integer> hidePath = root.get("hide");
            predicates.add(cb.equal(hidePath.as(Integer.class), hide));
        }

        //加载查询条件
        criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()]));
        criteriaQueryCount.where(predicates.toArray(new Predicate[predicates.size()]));

        //加载排序条件
        Path<Integer> sortPath = root.get("sort");
        Path<Integer> classIdPath = root.get("classId");
        criteriaQuery.orderBy(cb.desc(sortPath.as(Integer.class)),cb.asc(classIdPath.as(Integer.class)));

        //获取查询工具类实体
        TypedQuery query = em.createQuery(criteriaQuery);
//        int totalRows = query.getResultList().size();  //不建议使用该方式,效率差,使用统计查询
        //加入分页信息
        query.setFirstResult((pageNum - 1) * pageSize);
        query.setMaxResults(pageSize);
        List<Tuple> list = query.getResultList();//获取查询结果

        //查询结果解析
        List<Map<String, Object>> dataList = new ArrayList<>(); //解析后的查询结果
        if (list != null && !list.isEmpty()) {

            for (Tuple tu : list) {
                Map<String, Object> itemmap = new HashMap<>();
                for (TupleElement element : tu.getElements()) {
                    itemmap.put(element.getAlias(), tu.get(element.getAlias()));

                }
                dataList.add(itemmap);
            }
        }

        //将查询结果填入结果集中
        resultMap.put("data", dataList);
        resultMap.put("pageNum", pageNum + 1);
        resultMap.put("pageSize", pageSize);
        resultMap.put("totalPage", dataList.size());

        //将统计结果加入结果map中
        TypedQuery queryCount = em.createQuery(criteriaQueryCount);
        List<Tuple> listcount = queryCount.getResultList();
        if (listcount != null && !listcount.isEmpty()) {
            Tuple tu = listcount.get(0);
            for (TupleElement element : tu.getElements()) {
                //将统计查询结果填入结果集中
                resultMap.put(element.getAlias(), tu.get(element.getAlias()));
            }
        }

        return resultMap;
    }

个人对比意见:

  1.方法一代码量较少,但是需要自己拼接jpql,易出错,如果对于自己jpql语法很有信心,推荐使用(毕竟我是个懒人);

  2.方法二支持查询指定项,而方法一将对象的全部信息都查了出来,后期自己做了处理后返回给前端。

参考文章: 《JPA Criteria Query 的 变态例子》光影路西法,网址:    https://www.jianshu.com/p/69fa02602904

ps:本人第一次发布博文,十分粗糙,望大家多多包涵,取之精华,弃之糟粕。特别鸣谢好友鹏飞关于JPA的指点。

猜你喜欢

转载自www.cnblogs.com/aloneMoonlit/p/10953814.html
今日推荐