实体对象转QueryWrapper 便捷实现条件查询

4,816 阅读1分钟

1.背景

mybatis plus中提供了QueryWrapper做条件查询,

方法定义是public Children eq(boolean condition,R column,java.lang.Object val)

参数: condition - 执行条件;column - 字段;val - 值

我们通常是这样写的

public IhTimeSchedule  getTimeSchedule(String serviceCode,String appointDate, String noonType,
                                           String appointTimeInterval, String deptCode, String doctorCode,
                                           String clinicTypeCode,String serviceType) {
        QueryWrapper<IhTimeSchedule> wrapper=new QueryWrapper<IhTimeSchedule>()
                .eq("DEPT_CODE",deptCode)
                .eq("SERVICE_CODE",serviceCode)
                .eq(StringUtils.isNotBlank(doctorCode),"DOCTOR_CODE",doctorCode)
                .eq("CLINIC_DATE",appointDate+" 00:00:00")
                .eq(StringUtils.isNotBlank(noonType),"NOON_TYPE",noonType).
                eq(StringUtils.isNotBlank(appointTimeInterval),"TIME_DIVISION",appointTimeInterval).
                eq("CLINIC_TYPE_CODE",clinicTypeCode);
        IhTimeSchedule schedule = scheduleMapper.selectOne(wrapper);
        return  schedule;
    }

java8后,也可以这样写

public List<HpSystemConfig> queryConfig(HpSystemConfig config) {
        if(config==null){
            throw new RRException(ResultCode.PARAM_IS_BLANK);
        }
        LambdaQueryWrapper<HpSystemConfig> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(config.getConfigName()),HpSystemConfig::getConfigName,config.getConfigName()).
                eq(StringUtils.isNotBlank(config.getConfigValue()),HpSystemConfig::getConfigValue,config.getConfigValue())
                .eq(StringUtils.isNotBlank(config.getDeptCode()),HpSystemConfig::getDeptCode,config.getDeptCode())
                .eq(StringUtils.isNotBlank(config.getUnitsCode()),HpSystemConfig::getUnitsCode,config.getUnitsCode())
                .eq(config.getId()!=null,HpSystemConfig::getId,config.getId());
        return this.baseMapper.selectList(wrapper);
    }

2.问题

不难看出,当实体类中很多属性都需要作为查询条件的时候,QueryWrapper就需要定义的很长,也比较麻烦。

@Data
@TableName("HP_SCHEDULING_RECORD")
@ApiModel
public class HpSchedulingRecord implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "ID", type = IdType.ID_WORKER)
    private Long id;

    @ApiModelProperty(value = "医院编号")
    @TableField("HSR_HOSPOTALCODE")
    private String hsrHospotalcode;

    @ApiModelProperty(value = "医生编号")
    @TableField("HSR_DOCTOR")
    private Integer hsrDoctor;

    @ApiModelProperty(value = "房间编号")
    @TableField("HSR_ROOM")
    private Integer hsrRoom;

    @ApiModelProperty(value = "科室编号")
    @TableField("HSR_DEPT")
    private Integer hsrDept;

    @ApiModelProperty(value = "排班日期 形如yyyy-MM-dd")
    @TableField("HS_SHIFT_DATE")
    private String hsShiftDate;


}

3.改进

可以看到上面我们的实体类,每个属性都用mybatis注解标明了数据库表的列名,所以我就想,不如利用反射,写一个工具类,根据实体类自动生成QueryWrapper。

思路:

1.传入实体类对象作为参数,获取这个对象的Class对象。

2.遍历实体类声明的每个属性

3.获取属性上的mybatis注解TableField或者TableId,注解的value值即是数据库表的列名

4.构造QueryWrapper的eq条件(get方法返回值类型不同,则执行条件的判断有不同)

具体实现如下

public static QueryWrapper entity2Wrapper(Object obj) {
        Class<?> aClass = obj.getClass();
        Field[] fields = obj.getClass().getDeclaredFields();
        QueryWrapper wrapper = new QueryWrapper();
        //遍历属性
        for (Field field : fields) {
            Method method = null;
            try {
                String fieldName = field.getName();
                //跳过serialVersionUID
                if (fieldName.equals("serialVersionUID")) {
                    continue;
                }
                //获取属性上的注解
                TableField fieldAnnotation = field.getAnnotation(TableField.class);
                TableId idAnnotation = field.getAnnotation(TableId.class);
                //拿到列名
                String value = fieldAnnotation == null ? idAnnotation.value() : fieldAnnotation.value();
                //get方法
                method = aClass.getDeclaredMethod("get" + captureName(fieldName), null);
                Object returnValue = method.invoke(obj);
                if (returnValue instanceof String) {
                    String str = (String) returnValue;
                    wrapper.eq(StringUtils.isNotBlank(str), value, returnValue);
                } else {
                    wrapper.eq(returnValue != null, value, returnValue);
                }

            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        return wrapper;
    }

/**
     * 将字符串的首字母转大写
     *
     * @param str 需要转换的字符串
     * @return
     */
    private static String captureName(String str) {
        // 进行字母的ascii编码前移,效率要高于截取字符串进行转换的操作
        char[] cs = str.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

使用方式如下

public List<HpSchedulingRecord> queryRecord(HpSchedulingRecord record) {
        if(record==null){
            throw new RRException(ResultCode.PARAM_IS_BLANK);
        }
        QueryWrapper queryWrapper = WrapperUtil.entity2Wrapper(record);
        return this.baseMapper.selectList(queryWrapper);
    }

是不是简单了很多,通过工具类得到了QueryWrapper对象后,还可以链式附加别的需要的条件,比如select,orderBy.

4.测试

swagger2测试,如下图,符合预期。

image.png image.png