背景
開發(fā)中我們可能會(huì)遇到會(huì)頁面對(duì)應(yīng)的數(shù)據(jù)表量級(jí)較大澡罚、頁面查詢條件過多的情況顶瞒,那么有時(shí)候我們可能會(huì)限制做查詢操作是必須選擇至少一個(gè)查詢條件跷叉。
頁面效果:
直接查詢會(huì)提示:
正文
思路
我們考慮使用注解+切面的形式來實(shí)現(xiàn)左敌,用來確定哪些方法瘾蛋、哪些參數(shù)是需要做篩選和判斷的俐镐。
注解類:用來標(biāo)識(shí)某個(gè)參數(shù)和某個(gè)類的切入點(diǎn)
/**
* 用來標(biāo)識(shí)某個(gè)參數(shù)和某個(gè)類的切入點(diǎn)
* @author zhouli
* @Classname ConditionLimitAspect
* @Date 2022/4/6 19:39
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
public @interface ConditionLimit {
/**
* 限制條件最少個(gè)數(shù)
*
* @return
*/
int conditionNumberLimit() default 1;
}
/**
* 用來標(biāo)識(shí)哪些字段用來統(tǒng)計(jì)查詢列
* @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++) {
//多個(gè)參數(shù)時(shí)循環(huán)
ConditionLimit annotation = parameters[i].getAnnotation(ConditionLimit.class);
if (annotation == null) {
continue;
}
//設(shè)定的最小查詢列數(shù)量
int numberLimit = annotation.conditionNumberLimit();
Object[] args = point.getArgs();
Class<?> aClass =args[i].getClass();
Field[] declaredFields = aClass.getDeclaredFields();
//查詢條件計(jì)數(shù)
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("查詢條件不足,請(qǐng)至少選擇或輸入" + numberLimit + "個(gè)查詢條件");
throw new BusinessException("查詢條件不足佩抹,請(qǐng)至少選擇或輸入" + numberLimit + "個(gè)查詢條件");
}
}
return point.proceed();
}
}
使用
創(chuàng)建實(shí)體
@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);
}
現(xiàn)在我們使用接口請(qǐng)求
第一次不填寫參數(shù)值:{}
,查看日志結(jié)果:
第二次填寫 iccId
值重新請(qǐng)求: {"iccId":"898604B11921D0192003"}
叼风,我們就能看到直接放過進(jìn)行正常的業(yè)務(wù)調(diào)用了。
尾言
以上便是實(shí)現(xiàn)多查詢條件中必選至少一種字段值的一種思路棍苹,正常情況下我們沒有必要也沒有辦法枚舉出所有頁面中出現(xiàn)的所有必要的查詢條件无宿,那么就可以考慮做找一個(gè)前置的統(tǒng)一處理方法。利用切面在進(jìn)入方法前就進(jìn)行判斷枢里,該次請(qǐng)求是否符合接口最低的要求孽鸡。