开发java项目时, 如果需要实现范围查询, 或是多个范围查询等更复杂的查询, 往往需要设计复杂的接口入参, 为了简化开发, 本文通过设计一个基于MyBatis-Plus的Wrapper类(条件构造器)的公共方法类, 以一种规范化的FROM接收入参, 实现复杂查询
同时, 此方法可以给所有查询统一添加默认查询条件, 如:是否删除、租户等
需要掌握的知识:
1.MyBatis-Plus 官网
2.条件构造器Wrapper 条件构造器
3.了解Wrapper和LambdaWrapper的区别
4.方法引用
1.类
1.1 查询条件DTO
@Data
public class SearchRangeDTO {
@ApiModelProperty(value = "范围搜索-起始值")
private String startRange = "";
@ApiModelProperty(value = "范围搜索-结束值")
private String endRange = "";
public SearchRangeDTO() {
}
public SearchRangeDTO(String startRange) {
this.startRange = startRange != null ? startRange : "";
}
public SearchRangeDTO(String startRange, String endRange) {
this.startRange = startRange != null ? startRange : "";
this.endRange = endRange != null ? endRange : "";
}
}
1.2 查询接口入参FORM
@Data
public class GetListFORM{
/**
* 编码
*/
@ApiModelProperty(value = "编码")
private List<SearchRangeDTO> code;
}
1.3 interface
便于开发者寻找自己需要的方法
public interface IConditionDTOWrapper<T> {
/**
* 静态方法
* 直接返回一个基础的wrapper
* 默认拼接条件
* @param <T>
* @return
*/
static<T> LambdaQueryWrapper<T> createWrapper() { return null; }
/**
* 静态方法
* 先拼接前置查询条件
* 再返回一个基础的wrapper
* 默认拼接条件
* @param <T>
* @param preconditions
* @return
*/
static <T> LambdaQueryWrapper<T> createWrapper(String... preconditions) { return null; }
/**
* 组装范围查询条件
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,使用方法引用的方式传入
* @param conditionsList 查询条件列表
* @return
*/
ConditionDTOWrapper<T> assemblyConditions(SFunction<T, ?> func, List<SearchRangeDTO> conditionsList);
/**
* 组装是否包含包含查询条件
* 原字段是多个数据用逗号分隔拼接而成的,匹配包含某一个或者某几个数据的结果
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,传入字符串
* @param conditionsList 查询条件列表
* @return
*/
ConditionDTOWrapper<T> containConditions(String func, List<SearchRangeDTO> conditionsList);
/**
* 组装模糊查询条件
* 模糊条件只能有一个
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,使用方法引用的方式传入
* @param conditionsList 查询条件列表
* @return
*/
ConditionDTOWrapper<T> fuzzyConditions(SFunction<T, ?> func, List<SearchRangeDTO> conditionsList);
/**
* 组装查询条件, 单个普通条件
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,使用方法引用的方式传入
* @param condition 查询条件
* @return
*/
ConditionDTOWrapper<T> assemblyConditions(SFunction<T, ?> func, String condition);
/**
* 组装模糊查询条件, 单个普通条件
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,使用方法引用的方式传入
* @param condition 查询条件
* @return
*/
ConditionDTOWrapper<T> fuzzyConditions(SFunction<T, ?> func, String condition);
}
1.4 工具类
@Data
@Slf4j
public class ConditionDTOWrapper<T> implements IConditionDTOWrapper<T>{
private LambdaQueryWrapper<T> wrapper;
/**
* 无参构造方法,创建一个基础的wrapper
* 默认拼接条件
*/
public ConditionDTOWrapper(){
this.wrapper = Wrappers.<T>query()
.nested(i -> i.eq("字段名", "要匹配的值"))
.lambda();
}
/**
* 构造方法,创建一个基础的wrapper
* 需要提供默认条件对应的字段
* @param func1 字段1
* @param func2 字段2
*/
public ConditionDTOWrapper(SFunction<T, ?> func1, SFunction<T, ?> func2){
this.wrapper = Wrappers.<T>query().lambda()
.nested(i -> i.eq(func1, "")
.eq(func2, ""));
}
/**
* 静态方法
* 直接返回一个基础的wrapper
* 默认拼接条件
* @param <T>
* @return
*/
public static<T> LambdaQueryWrapper<T> createWrapper(){
return new ConditionDTOWrapper<T>().getWrapper();
}
public static<T> LambdaQueryWrapper<T> createWrapper(Class<T> t){
return new ConditionDTOWrapper<T>().getWrapper();
}
/**
* 静态方法
* 先拼接前置查询条件
* 再返回一个基础的wrapper
* 默认拼接条件
* @param <T>
* @return
*/
public static<T> LambdaQueryWrapper<T> createWrapper(String...preconditions){
return Wrappers.<T>query()
.select(preconditions)
.nested(i -> i.eq("字段名", "要匹配的值"))
.lambda();
}
/**
* 组装范围查询条件
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,使用方法引用的方式传入
* @param conditionsList 查询条件列表
*/
@Override
public ConditionDTOWrapper<T> assemblyConditions(SFunction<T, ?> func, List<SearchRangeDTO> conditionsList){
if(func != null && CollectionUtils.isNotEmpty(conditionsList)){
this.wrapper.and(
conditionsList.stream().anyMatch(conditions -> null != conditions
&& (StringUtils.isNotBlank(conditions.getStartRange()) || StringUtils.isNotBlank(conditions.getEndRange()))),
i -> ConditionDTOWrapper.assemblyConditions(i, func, conditionsList)
);
}
return this;
}
/**
* 静态方法,组装范围查询条件
* 需要传入初始wrapper
* 拼接条件后直接返回组装好的wrapper
* @param func 查询条件对应的实体类字段,使用方法引用的方式传入
* @param conditionsList 查询条件列表
*/
public static<T> void assemblyConditions(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> func, List<SearchRangeDTO> conditionsList){
if(wrapper != null && func != null && CollectionUtils.isNotEmpty(conditionsList)){
conditionsList.forEach(searchRangeDTO -> {
if (0 == conditionsList.indexOf(searchRangeDTO)) {
//字段的第一个条件
firstRangeJudge(wrapper, func, searchRangeDTO);
} else {
//字段的其他条件
laterRangeJudge(wrapper, func, searchRangeDTO);
}
});
}
}
/**
* 首次范围条件判断
* 不同字段的条件之间是且的关系,用and拼接
* @param wrapper
* @param func
* @param conditions
*/
public static<T> void firstRangeJudge(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> func, SearchRangeDTO conditions){
if(wrapper != null && func != null && conditions != null){
//起始范围和结束范围
String startRange = conditions.getStartRange();
String endRanger = conditions.getEndRange();
if(StringUtils.isNotBlank(startRange) && StringUtils.isNotBlank(endRanger)){
if(startRange.compareTo(endRanger) > 0){
//起始范围大于结束范围,抛出异常
log.error("范围条件: startRange: "+startRange+", "+"endRanger: "+endRanger);
throw new ServiceException(ResultCode.REQUEST_PARAMETER_ERROR);
} else {
//查询大于等于起始范围,小于等于结束范围的条件
wrapper.between(func, startRange, endRanger);
}
} else if(StringUtils.isNotBlank(startRange)){
//查询等于起始范围条件
wrapper.eq(func, startRange);
} else if(StringUtils.isNotBlank(endRanger)){
//查询小于等于结束范围条件
wrapper.le(func, endRanger);
}
}
}
/**
* 其余范围条件判断
* 同一个字段的多个条件是或的关系,用or拼接
* @param wrapper
* @param func
* @param conditions
*/
public static<T> void laterRangeJudge(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> func, SearchRangeDTO conditions){
if(wrapper != null && func != null && conditions != null){
//起始范围和结束范围
String startRange = conditions.getStartRange();
String endRanger = conditions.getEndRange();
if(StringUtils.isNotBlank(startRange) && StringUtils.isNotBlank(endRanger)){
if(startRange.compareTo(endRanger) > 0){
//起始范围大于结束范围,抛出异常
log.error("范围条件: startRange: "+startRange+", "+"endRanger: "+endRanger);
throw new ServiceException(ResultCode.REQUEST_PARAMETER_ERROR);
} else {
//查询大于等于起始范围,小于等于结束范围的条件
wrapper.or().between(func, startRange, endRanger);
}
} else if(StringUtils.isNotBlank(startRange)){
//查询等于起始范围条件
wrapper.or().eq(func, startRange);
} else if(StringUtils.isNotBlank(endRanger)){
//查询小于等于结束范围条件
wrapper.or().le(func, endRanger);
}
}
}
/**
* 组装是否包含包含查询条件
* 原字段是多个数据用逗号分隔拼接而成的,匹配包含某一个或者某几个数据的结果
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,传入字符串
* @param conditionsList 查询条件列表
*/
@Override
public ConditionDTOWrapper<T> containConditions(String func, List<SearchRangeDTO> conditionsList){
LambdaQueryWrapper<T> wrapper = this.wrapper;
if(wrapper != null && func != null && CollectionUtils.isNotEmpty(conditionsList)){
conditionsList.forEach(searchRangeDTO -> {
if (0 == conditionsList.indexOf(searchRangeDTO)) {
//字段的第一个条件
firstContainJudge(wrapper, func, searchRangeDTO);
} else {
//字段的其他条件
laterContainJudge(wrapper, func, searchRangeDTO);
}
});
}
this.setWrapper(wrapper);
return this;
}
/**
* 首次包含条件判断
* 不同字段的条件之间是且的关系,用and拼接
* @param wrapper
* @param func
* @param conditions
*/
public void firstContainJudge(LambdaQueryWrapper<T> wrapper, String func, SearchRangeDTO conditions){
if(wrapper != null && func != null && conditions != null){
//起始范围和结束范围
String startRange = conditions.getStartRange();
String endRanger = conditions.getEndRange();
if(StringUtils.isNotBlank(startRange)){
//查询包含条件
wrapper.apply("FIND_IN_SET ( "+"\""+startRange+"\", " + func + " ) ");
} else if(StringUtils.isNotBlank(endRanger)){
//包含条件不能同时是范围条件
log.error("包含条件: startRange: "+startRange+", "+"endRanger: "+endRanger);
throw new ServiceException(ResultCode.REQUEST_PARAMETER_ERROR);
}
}
}
/**
* 其余包含条件判断
* 同一个字段的多个条件是或的关系,用or拼接
* @param wrapper
* @param func
* @param conditions
*/
public void laterContainJudge(LambdaQueryWrapper<T> wrapper, String func, SearchRangeDTO conditions){
if(wrapper != null && func != null && conditions != null){
//起始范围和结束范围
String startRange = conditions.getStartRange();
String endRanger = conditions.getEndRange();
if(StringUtils.isNotBlank(startRange)){
//查询包含条件
wrapper.or().apply("FIND_IN_SET ( "+"\""+startRange+"\", " + func + " ) ");
} else if(StringUtils.isNotBlank(endRanger)){
//包含条件不能同时是范围条件
log.error("包含条件: startRange: "+startRange+", "+"endRanger: "+endRanger);
throw new ServiceException(ResultCode.REQUEST_PARAMETER_ERROR);
}
}
}
/**
* 组装模糊查询条件
* 模糊条件只能有一个
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,使用方法引用的方式传入
* @param conditionsList 查询条件列表
*/
@Override
public ConditionDTOWrapper<T> fuzzyConditions(SFunction<T, ?> func, List<SearchRangeDTO> conditionsList){
LambdaQueryWrapper<T> wrapper = this.wrapper;
if(wrapper != null && func != null && CollectionUtils.isNotEmpty(conditionsList)){
conditionsList.forEach(searchRangeDTO -> {
if (0 == conditionsList.indexOf(searchRangeDTO)) {
//字段的第一个条件
firstFuzzyJudge(wrapper, func, searchRangeDTO);
} else {
//字段的其他条件
//一个字段只能有一个模糊条件
log.error("模糊条件数量: "+conditionsList.size());
throw new ServiceException(ResultCode.REQUEST_PARAMETER_ERROR);
}
});
}
this.setWrapper(wrapper);
return this;
}
/**
* 首次模糊条件判断
* 不同字段的条件之间是且的关系,用and拼接
* @param wrapper
* @param func
* @param conditions
*/
public void firstFuzzyJudge(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> func, SearchRangeDTO conditions){
if(wrapper != null && func != null && conditions != null){
//起始范围和结束范围
String startRange = conditions.getStartRange();
String endRanger = conditions.getEndRange();
if(StringUtils.isNotBlank(startRange)){
//模糊条件
wrapper.like(func,startRange);
} else if(StringUtils.isNotBlank(endRanger)){
//模糊条件不能同时是范围条件
log.error("模糊条件: startRange: "+startRange+", "+"endRanger: "+endRanger);
throw new ServiceException(ResultCode.REQUEST_PARAMETER_ERROR);
}
}
}
/**
* 组装查询条件, 单个普通条件
* 返回ConditionDTOWrapper对象
* @param func 查询条件对应的实体类字段,使用方法引用的方式传入
* @param condition 查询条件
* @return
*/
@Override
public ConditionDTOWrapper<T> assemblyConditions(SFunction<T, ?> func, String condition) {
if(StringUtil.isNotBlank(condition)){
this.wrapper.eq(func, condition);
}
return this;
}
@Override
public ConditionDTOWrapper<T> fuzzyConditions(SFunction<T, ?> func, String condition) {
if(StringUtil.isNotBlank(condition)){
this.wrapper.like(func, condition);
}
return this;
}
}
2.使用方法
实体类
@Data
@TableName("table_user")
public class User extends Client {
/**
* ID
*/
@TableField("id")
private String id;
/**
* 名称
*/
@TableField("name")
private String name;
}
Mapper
public interface UserMapper extends BaseMapper<User> {
}
Service
ConditionDTOWrapper<User> condition = new ConditionDTOWrapper<>();
condition.assemblyConditions(User::getId,"");
LambdaQueryWrapper<User> wrapper = condition.getWrapper();
List<User> userList = userMapper.selectList(wrapper);
或者
List<User> userList = userMapper.selectList(ConditionDTOWrapper.createWrapper(User.class).assemblyConditions(User::getId,"").getWrapper());
该方法的本质是使用工具类统一处理入参, 构造查询条件(即wrapper), 在调用查询方法前, 仍可对继续向查询条件(即wrapper)中添加其他条件.