Java , 写了一个生成模糊查询和时间区间查询 wrapper 的函数,有什么优化建议或是隐藏的坑吗?

查看 39|回复 2
作者:Mrzhs   
模糊查询大致思路是先遍历实体类,然后实体类如果有值,则获取它的 TableField 注解,获取字段名,然后拼接 wrapper 。
时间查询的大体思路和上面差不多,前端传来 xxxStart 和 xxxxEnd, 首先保存到实体类中,然后再做字符拼接。
想起写这个的原因是因为基本每个前端 Table 都需要类似的查询,本来是写在 XML 文件里,但是每改一次字段都会联动着更改 XML ,太过繁琐,增加出错几率。 所以写了这么一个工具类来通过实体类动态拼接模糊查询。
//拼接函数
/**
     * 通过实体类生成模糊搜索和日期区间查询的 wrapper
     * @param cls   类名
     * @param entity    实体类
     * @param orderByField  排序字段
     * @param orderByAsc    是否升序
     * @return  QueryWrapper
     * @param    实体类
     */
    public  QueryWrapper generateFuzzySearchAndBetweenDateWrapper(Class cls, T entity, String orderByField, Boolean orderByAsc) {
        QueryWrapper wrapper = new QueryWrapper();
        //先检查是否排序
        if (!DataUtil.isEmpty(orderByField)) {
            wrapper.orderBy(true, orderByAsc, StringFormat.camelToUnderscore(orderByField));
        }
        //再检查实体类是否为空
        if (DataUtil.isEmpty(entity)) {
            return wrapper;
        }
        try {
            //遍历实体类的所有字段. getAllFields 方法获取不止当前类的字段, 还包括父类的字段
            for (Field field: DataUtil.getAllFields(cls)) {
                //如果是 final, static, transient 修饰的字段, 则跳过. 一般用来排除 private static final long serialVersionUID = 1L; 序列化 id
                if (Modifier.isFinal(field.getModifiers())
                        || Modifier.isStatic(field.getModifiers())
                        || Modifier.isTransient(field.getModifiers())) {
                    continue;
                }
                //获取字段的 get 方法
                Method getFunc = cls.getMethod("get" + StringFormat.capitalize(field.getName()));
                Object value = getFunc.invoke(entity);
                //如果字段有 TableField 注解, 并且值不为空
                if (field.isAnnotationPresent(TableField.class) && !DataUtil.isEmpty(value)) {
                    //如果 TableField 注解的 exist 属性为 true, 则使用注解的 value 作为字段名
                    if (field.getAnnotation(TableField.class).exist()) {
                        String column = field.getAnnotation(TableField.class).value();
                        wrapper.like(column, value);
                    } else {
                        //如果 TableField 注解的 exist 属性为 false, 证明可能是一个时间区域查询
                        String name = field.getName();
                        if (name.endsWith("Start")) {
                            String column = name.substring(0, name.length() - 5);
                            wrapper.ge(StringFormat.camelToUnderscore(column), value);
                        } else if (name.endsWith("End")) {
                            String column = name.substring(0, name.length() - 3);
                            wrapper.le(StringFormat.camelToUnderscore(column), value);
                        }
                    }
                }
            }
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        return wrapper;
    }
//controller
@GetMapping("select/page")
    public IPage selectPage(@RequestBody(required = false) Company company,
                                    @RequestParam(defaultValue = "1") Integer current,
                                    @RequestParam(defaultValue = "10") Integer size,
                                    @RequestParam(required = false)String orderByField,
                                    @RequestParam(defaultValue = "true")Boolean orderByAsc) {
        QueryWrapper companyQueryWrapper = generateFuzzySearchAndBetweenDateWrapper(Company.class, company, orderByField,orderByAsc);
        Page companyPage = new Page();
        companyPage.setCurrent(current);
        companyPage.setSize(size);
        IPage companyIPage = companyService.page(companyPage, companyQueryWrapper);
        return companyIPage;
    }
已知的问题:
1.Get 请求携带请求体,功能是可以实现,但似乎有些不合规矩,隐隐约约记得当时学 J2EE 的时候有讲过不要在 Get 请求携带请求体
2.每个时间字段都需要增加两个虚拟属性,用于接受前端发来的时间范围数据
                @TableField("expire_date")
        @ApiModelProperty(value = "到期时间")
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date expireDate;
        @TableField(exist = false)
        private String expireDateStart;
        @TableField(exist = false)
        private String expireDateEnd;
3.想实现数据字典的功能,但是感觉有点复杂, 首先需要调用其他 Service 来查询数据表,然后实体类还需要多加一个虚拟字段,用于存储数据字典对应的值。例如:
               
        @TableField("industry_type")
        @ApiModelProperty(value = "企业类型")
        private Integer industryType;
                @TableField(exist = false)
                private String industryTypeValue;
running17   
俺的思路是做成一个新的注解,注解携带对应筛选的字段名和筛选的类型,直接解析这个注释来做这个逻辑;直接用 name 判断万一有业务是用 Start 和 End 的字段那就尴尬了;然后反射的操作记得用 map 之类的缓存起来,没有必要每次都去反射然后判断
Mrzhs
OP
  
@running17 虽然但是,如果通过注解来实现这两个字段的功能, 首先问题是, 如何将前端请求的 XXXStart 映射到注解里呢? Controller 貌似没有提供相关的功能
您需要登录后才可以回帖 登录 | 立即注册

返回顶部