美文网首页
利用java反射动态拼接JPA查询条件

利用java反射动态拼接JPA查询条件

作者: ivms8200 | 来源:发表于2020-05-09 18:44 被阅读0次

起因

假设有个需求是需要按照条件查询数据库的数据。一般来说我们可以根据指定的参数去创建JPA查询条件。就像这样:

if (StringUtils.isNotBlank(pageCgRecordInfoValidator.getCgmc())) {
  list.add(cb.like(root.get("cgmc"), "%" + pageCgRecordInfoValidator.getCgmc() + "%"));
}

如果有多个参数,那么就要写很多行这样的代码。这样实在是太麻烦了。能不能写一个方法,让他去动态拼接查询参数?这时候就可以用到反射了。

实现

首先我们约定,把参数放到一个对象里面,这个对象可以是DTO BO DO等。然后我们通过反射去解析这个对象,如果该对象的某个属性有值,我们就在List<Predicate> list中添加一条查询条件。
代码如下

package com.*****.utils;
import org.apache.commons.lang3.StringUtils;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class JpaUtils {

    /**
     * 获取List<Predicate>,暂时只支持String,Integer,Long,Double,Short,Date
     * 只适用于全包装类属性的对象
     * 该方法暂时不适用于数字或者日期之间查询,如需查询要单独将条件加入predicateList
     *
     * @param o
     * @param root
     * @param cb
     * @return
     */
    public static List<Predicate> getPredicateList(Object o, Root root, CriteriaBuilder cb) {
        //集合 用于封装查询条件
        List<Predicate> list = new ArrayList<>();
        // 得到类对象
        Class objClass = (Class) o.getClass();
        /* 得到类中的所有属性集合 */
        Field[] fs = objClass.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            Field f = fs[i];
            f.setAccessible(true); // 设置些属性是可以访问的
            Object value;
            try {
                value = f.get(o);
                // 得到此属性的键
                String key = f.getName();
                //得到此属性的类型
                String type = f.getType().toString();
                String substring = type.substring(type.lastIndexOf(".") + 1);
                switch (substring) {
                    case "String":
                        String trValue = (String) value;
                        if (StringUtils.isNotBlank(trValue)) {
                            list.add(cb.like(root.get(key), "%" + trValue + "%"));
                        }
                        break;
                    case "Date":
                    case "Integer":
                    case "Long":
                    case "Double":
                    case "Short":
                        if (value != null) {
                            list.add(cb.equal(root.get(key), value));
                        }
                        break;
                    default:
                        System.out.println("不适用");
                }

            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return list;
    }
}

因为项目中还没遇到其他的类型,所以暂时只写了对以上几种类型的处理。
使用方法如下,是不是方便很多了?

    /**
     * 根据参数查询一条数据
     */
    @Override
    public List<CgRecordInfo> findByParam(CgRecordInfoDTO cgRecordInfoDTO) {
        //构造自定义查询条件
        // Root 用于获取属性字段,CriteriaQuery可以用于简单条件查询,CriteriaBuilder 用于构造复杂条件查询
        Specification<CgRecordInfo> specification = (root, query, cb) -> {
            List<Predicate> predicateList = JpaUtils.getPredicateList(cgRecordInfoDTO, root, cb);
            return cb.and(predicateList.toArray(new Predicate[0]));
        };
        return cgRecordInfoRepository.findAll(specification);
    }

测试

经测试,该方式几乎不会有性能损失。

注意

实体最好使用包装类,这样便于判断是否有传入值作为查询条件。
该方法暂时不适用于数字或者日期之间查询。
如果有特殊需求,可以在获取List<Predicate> predicateList后手动添加查询条件。比如我要查询某个时间范围内的数据

if(pageCgRecordInfoValidator.getUpdateTimeStart() != null && pageCgRecordInfoValidator.getUpdateTimeEnd() != null){
  predicateList.add(cb.between(root.get("updateTime"), pageCgRecordInfoValidator.getUpdateTimeStart(), pageCgRecordInfoValidator.getUpdateTimeEnd()));
}

相关文章

  • 利用java反射动态拼接JPA查询条件

    起因 假设有个需求是需要按照条件查询数据库的数据。一般来说我们可以根据指定的参数去创建JPA查询条件。就像这样: ...

  • Spring Data Jpa的使用(二)

    使用Jpa进行多表关联查询,利用java反射将查询结果封装到对象中 在使用Jpa进行数据库查询的时候,经常会遇到这...

  • Spring Data JPA

    Spring Data JPA,一种动态条件查询的写法 我们在使用SpringData JPA框架时,进行条件查询...

  • 日常坑我

    条件查询 jpa应该继承JpaSpecificationExecutor 5/31 java基础疯狂java...

  • 7 Spring-data-jpa查询方法

    springdata-jpa 八种查询方法 Spring Data JPA 简单查询--接口方法 jpa动态查询-...

  • Select/Multiselect在JPA的Specifica

    在项目中想实现动态返回指定列,还有聚合查询如sum()等,还需支持动态查询条件,看到JPA中dao继承JpaSpe...

  • JPA多表分页动态多条件查询

    参考文章: 解决 JPA 多表动态查询 JPA EntityManager createNativeQuery 多...

  • Spring Data JPA 动态条件查询+指定查询列

    JPA在使用(Specification的动态条件查询)时将不能指定查询列,这非常的操蛋,底层代码中封死了,必须返...

  • JPA-复杂查询

    时间相关查询 Spring data jpa 条件查询-按时间段查询Jpa查询排序,时间范围查询,当天时间范围查询...

  • 2018-03-16

    聊聊JPA Criteria查询中的坑 JPA Criteria查询被称作动态安全类型查询,比JPQL这种方式更加...

网友评论

      本文标题:利用java反射动态拼接JPA查询条件

      本文链接:https://www.haomeiwen.com/subject/caklnhtx.html