模糊查询大致思路是先遍历实体类,然后实体类如果有值,则获取它的 TableField 注解,获取字段名,然后拼接 wrapper 。
时间查询的大体思路和上面差不多,前端传来 xxxStart 和 xxxxEnd, 首先保存到实体类中,然后再做字符拼接。
想起写这个的原因是因为基本每个前端 Table 都需要类似的查询,本来是写在 XML 文件里,但是每改一次字段都会联动着更改 XML ,太过繁琐,增加出错几率。 所以写了这么一个工具类来通过实体类动态拼接模糊查询。
//拼接函数
/**
* 通过实体类生成模糊搜索和日期区间查询的 wrapper
* @param cls 类名
* @param entity 实体类
* @param orderByField 排序字段
* @param orderByAsc 是否升序
* @return QueryWrapper
* @param <T> 实体类
*/
public <T> QueryWrapper<T> generateFuzzySearchAndBetweenDateWrapper(Class<T> cls, T entity, String orderByField, Boolean orderByAsc) {
QueryWrapper<T> 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<Company> 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<Company> companyQueryWrapper = generateFuzzySearchAndBetweenDateWrapper(Company.class, company, orderByField,orderByAsc);
Page<Company> companyPage = new Page<>();
companyPage.setCurrent(current);
companyPage.setSize(size);
IPage<Company> 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;
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.