背景

开发中我们可能会遇到会页面对应的数据表量级较大、页面查询条件过多的情况,那么有时候我们可能会限制做查询操作是必须选择至少一个查询条件。

页面效果:

页面多查询条件必选的统一处理思路-LMLPHP

直接查询会提示:

页面多查询条件必选的统一处理思路-LMLPHP

正文

思路:

我们考虑使用注解+切面的形式来实现,用来确定哪些方法、哪些参数是需要做筛选和判断的。

注解类:用来标识某个参数和某个类的切入点

/**
 * 用来标识某个参数和某个类的切入点
 * @author zhouli
 * @Classname ConditionLimitAspect
 * @Date 2022/4/6 19:39
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
public @interface ConditionLimit {
    /**
     * 限制条件最少个数
     *
     * @return
     */
    int conditionNumberLimit() default 1;
}

/**
 * 用来标识哪些字段用来统计查询列
 * @author zhouli
 * @Classname ConditionLimitAspect
 * @Date 2022/4/6 19:39
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ConditionField {
}

切面类:

@Slf4j
@Aspect
@Component
public class ConditionLimitAspect {
    @Around("execution(* com.p4.tp.system.modules.*.rest.*.*(..,@com.p4.tp.system.config.aop.ConditionLimit (*),..))")
    public Object doCheckCondition(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            //多个参数时循环
            ConditionLimit annotation = parameters[i].getAnnotation(ConditionLimit.class);
            if (annotation == null) {
                continue;
            }
            //设定的最小查询列数量
            int numberLimit = annotation.conditionNumberLimit();
            Object[] args = point.getArgs();
            Class<?> aClass =args[i].getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            //查询条件计数
            int realNum = 0;
            for (Field field : declaredFields) {
                //获取带ConditionField注解的字段
                ConditionField conditionField = field.getAnnotation(ConditionField.class);
                if (conditionField == null) {
                    continue;
                }
                field.setAccessible(true);
                //获取列值
                Object value = field.get(args[i]);
                if (value == null) {
                    continue;
                }
                try {
                    //列举三种情况
                    if (value instanceof String && StringUtils.isNotBlank((String) value)) {
                        realNum++;
                    } else if (value instanceof Collection && !CollectionUtils.isEmpty((Collection<?>) value)) {
                            realNum++;
                    } else if (value instanceof Date) {
                            realNum++;
                    }
                } catch (Exception e) {
                    log.error("条件限定异常,", e);
                }
            }
            if (realNum < numberLimit) {
                log.info("查询条件不足,请至少选择或输入" + numberLimit + "个查询条件");
                throw new BusinessException("查询条件不足,请至少选择或输入" + numberLimit + "个查询条件");
            }
        }
        return point.proceed();
    }
}

使用

创建实体

@Data
public class FlowCardInfoParam {

    @ConditionField
    private String iccId;

    @ConditionField
    private String termSn;

    @ConditionField
    private String imei;
}

方法使用

	@PostMapping("/getPage")
    public ResponseEntity<Object> getPage(@RequestBody @ConditionLimit FlowCardInfoParam param) {
        return new ResponseEntity<>(null, HttpStatus.OK);
    }

现在我们使用接口请求

第一次不填写参数值:{} ,查看日志结果:

页面多查询条件必选的统一处理思路-LMLPHP

第二次填写 iccId 值重新请求: {"iccid":"898604B11921D0192003"},我们就能看到直接放过进行正常的业务调用了。

尾言

以上便是实现多查询条件中必选至少一种字段值的一种思路,正常情况下我们没有必要也没有办法枚举出所有页面中出现的所有必要的查询条件,那么就可以考虑做找一个前置的统一处理方法。利用切面在进入方法前就进行判断,该次请求是否符合接口最低的要求。

11-09 15:07