spring boot+自定義 AOP 實現(xiàn)全局校驗的實例代碼
最近公司重構(gòu)項目,重構(gòu)為最熱的微服務(wù)框架 spring boot, 重構(gòu)的時候遇到幾個可以統(tǒng)一處理的問題,也是項目中經(jīng)常遇到,列如:統(tǒng)一校驗參數(shù),統(tǒng)一捕獲異常。。。
僅憑代碼 去控制參數(shù)的校驗,有時候是冗余的,但通過框架支持的 去控制參數(shù)的校驗,是對于開發(fā)者很友好,先看下面的例子
@NotEmpty(message="手機號不能為空") @Size(min=11,max=11,message="手機號碼長度不正確") @Pattern(regexp=StringUtils.REGEXP_MOBILE,message="手機號格式不正確") private String mobile;
這是spring boot支持的 校驗注解,然后我們在 contoller層 加上@Valid 注解 就可以達到校驗的目的。這是一種框架自帶的
本章 就展示一種 自定義的 AOP 校驗,首先 寫一個注解,注解里面可以寫上 我們需要校驗的規(guī)則, 比如長度,正則。。。
@Documented
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateParam {
int min() default 0;
int max() default Integer.MAX_VALUE;
String message() default "params is not null";
String regexp();
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
boolean isNotNull() default true;
}
然后定義一個AOP類
package com.onecard.primecard.common.aop;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Pattern;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import com.jfcf.core.dto.ResultData;
import com.onecard.core.support.util.StringUtils;
import com.onecard.primecard.common.annotation.ValidateParam;
import com.onecard.primecard.common.utils.ResultDataUtil;
/**
* 全局 切面類(校驗參數(shù))
*
* @author Administrator
*
*/
@Aspect
@Component
public class GobalHandlerAspect {
private static Logger logger = LoggerFactory.getLogger(GobalHandlerAspect.class);
@Pointcut("execution(* 包名.controller..*.*(..)) && execution(* 包名.controller..*.*(..))")
public void checkAspect(){};
@Before("checkAspect()")
public void befor(JoinPoint joinPoint) throws Exception{
//前置統(tǒng)一輸出參數(shù)
Object[] args = joinPoint.getArgs();
if(args != null && args.length>0){
Object obj = args[0];
ParameterizedType pt = (ParameterizedType)obj.getClass().getGenericSuperclass();
Class<?> classzz = (Class<?>) pt.getActualTypeArguments()[0];
logger.info("【小X卡】-【請求實體入?yún)ⅰ浚?+classzz.newInstance().toString());
}
}
@Around("checkAspect()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
//校驗參數(shù)
Object[] args = joinPoint.getArgs();
Object obj = null;
if(args != null && args.length > 0){
obj = args[0];
Class classzz = obj.getClass();
//沒有順序和秩序的數(shù)組
Field[] fieldArray = classzz.getDeclaredFields();
ArrayList<Field> fieldList = new ArrayList<Field>(Arrays.asList(fieldArray));
String res = checkParam(fieldList,obj);
if(StringUtils.isNotNull(res)){
return ResultDataUtil.result(ResultData.STATUS_PARAM_ERROR, res);
}
}
return joinPoint.proceed();
}
private String checkParam(ArrayList<Field> fieldList, Object obj) throws Exception {
for(Field field : fieldList){
ValidateParam validateParam = field.getAnnotation(ValidateParam.class);
logger.info("【小X卡】獲取注解值:"+validateParam.isNotNull()+"min="+validateParam.min()+"max="+validateParam.max());
Method method = obj.getClass().getMethod("get"+getMethodName(field.getName()));
logger.info("【小X卡】入?yún)嶓w方法名稱:"+method.getName());
if(method != null){
Object val = method.invoke(obj);
logger.info("【小x卡】回調(diào)方法:"+val);
if(validateParam != null && validateParam.isNotNull() == true){
if(null == val || "".equals(val) ){
return field.getName()+"必填參數(shù)為空";
}
}
if(validateParam.min()==11 && validateParam.max() == 11){
if(val.toString().length() != 11){
return field.getName()+"請輸入?yún)?shù)正確的長度";
}
}
if(validateParam.regexp().equals(StringUtils.REGEXP_MOBILE)){
if(!Pattern.matches(StringUtils.REGEXP_MOBILE, val.toString())){
return field.getName()+"參數(shù)格式錯誤";
}
}
}
}
return null;
}
/**
* 方法首字母大寫
* @param fieldName
* @return
*/
private String getMethodName(String fieldName) {
StringBuffer buffer = new StringBuffer();
String firstLetter = fieldName.substring(0, 1).toUpperCase();
return buffer.append(firstLetter).append(fieldName.substring(1, fieldName.length())).toString();
}
}
定義一個切點 @Pointcut, 用execution 表達式,去獲取要校驗的 某個類 和某個方法, 也就是連接點,然后 用定義一個通知,上面代碼中有2個通知,一個前置通知@Before,一個環(huán)繞通知@Around,我們使用功能最強大的環(huán)繞通知。
通過上面的代碼可以看出 首先獲取參數(shù),然后通過反射機制 獲取 入?yún)ο笾械娜孔侄危?再去獲取 我們在字段中加 我們自定義注解的字段,通過反射方法的回調(diào),獲取字段值,對值做判斷, 返回校驗結(jié)果。
總結(jié)
以上所述是小編給大家介紹的spring boot+自定義 AOP 實現(xiàn)全局校驗的實例代碼,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復(fù)大家的!
- springBoot整合CXF并實現(xiàn)用戶名密碼校驗的方法
- Spring Boot實現(xiàn)通用的接口參數(shù)校驗
- Spring boot進行參數(shù)校驗的方法實例詳解
- SpringBoot實現(xiàn)前端驗證碼圖片生成和校驗
- springboot使用校驗框架validation校驗的示例
- springboot使用hibernate validator校驗方式
- Springboot 使用 JSR 303 對 Controller 控制層校驗及 Service 服務(wù)層 AOP 校驗 使用消息資源文件對消息國際化
- SpringBoot實現(xiàn)短信驗證碼校驗方法思路詳解
- 詳解如何在Spring Boot項目使用參數(shù)校驗
相關(guān)文章
@RequestParam 接收參數(shù)的值為null的處理方式
這篇文章主要介紹了@RequestParam 接收參數(shù)的值為null的處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
使用Feign調(diào)用注解組件(實現(xiàn)字段賦值功能)
這篇文章主要介紹了使用Feign調(diào)用注解組件(實現(xiàn)字段賦值功能),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
IntelliJ IDEA 2019.1.1 for MAC 下載和注
這篇文章主要介紹了IntelliJ IDEA 2019.1.1 for MAC 下載和注冊碼激活,教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04
Spring Boot使用Servlet及Filter過程詳解
這篇文章主要介紹了Spring Boot使用Servlet及Filter過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07

