頁面多查詢條件必選的統一處理思路

2022-11-09 18:01:18

背景

開發中我們可能會遇到會頁面對應的資料表量級較大、頁面查詢條件過多的情況,那麼有時候我們可能會限制做查詢操作是必須選擇至少一個查詢條件。

頁面效果:

直接查詢會提示:

正文

思路:

我們考慮使用註解+切面的形式來實現,用來確定哪些方法、哪些引數是需要做篩選和判斷的。

註解類:用來標識某個引數和某個類的切入點

/**
 * 用來標識某個引數和某個類的切入點
 * @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);
    }

現在我們使用介面請求

第一次不填寫引數值:{} ,檢視紀錄檔結果:

第二次填寫 iccId 值重新請求: {"iccid":"898604B11921D0192003"},我們就能看到直接放過進行正常的業務呼叫了。

尾言

以上便是實現多查詢條件中必選至少一種欄位值的一種思路,正常情況下我們沒有必要也沒有辦法列舉出所有頁面中出現的所有必要的查詢條件,那麼就可以考慮做找一個前置的統一處理方法。利用切面在進入方法前就進行判斷,該次請求是否符合介面最低的要求。