spring boot+自定義 AOP 實(shí)現(xiàn)全局校驗(yàn)的實(shí)例代碼
最近公司重構(gòu)項(xiàng)目,重構(gòu)為最熱的微服務(wù)框架 spring boot, 重構(gòu)的時(shí)候遇到幾個(gè)可以統(tǒng)一處理的問題,也是項(xiàng)目中經(jīng)常遇到,列如:統(tǒng)一校驗(yàn)參數(shù),統(tǒng)一捕獲異常。。。
僅憑代碼 去控制參數(shù)的校驗(yàn),有時(shí)候是冗余的,但通過框架支持的 去控制參數(shù)的校驗(yàn),是對于開發(fā)者很友好,先看下面的例子
@NotEmpty(message="手機(jī)號不能為空") @Size(min=11,max=11,message="手機(jī)號碼長度不正確") @Pattern(regexp=StringUtils.REGEXP_MOBILE,message="手機(jī)號格式不正確") private String mobile;
這是spring boot支持的 校驗(yàn)注解,然后我們在 contoller層 加上@Valid 注解 就可以達(dá)到校驗(yàn)的目的。這是一種框架自帶的
本章 就展示一種 自定義的 AOP 校驗(yàn),首先 寫一個(gè)注解,注解里面可以寫上 我們需要校驗(yàn)的規(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;
}
然后定義一個(gè)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;
/**
* 全局 切面類(校驗(yàn)參數(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卡】-【請求實(shí)體入?yún)ⅰ浚?+classzz.newInstance().toString());
}
}
@Around("checkAspect()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
//校驗(yàn)參數(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)?shí)體方法名稱:"+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ù)格式錯(cuò)誤";
}
}
}
}
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();
}
}
定義一個(gè)切點(diǎn) @Pointcut, 用execution 表達(dá)式,去獲取要校驗(yàn)的 某個(gè)類 和某個(gè)方法, 也就是連接點(diǎn),然后 用定義一個(gè)通知,上面代碼中有2個(gè)通知,一個(gè)前置通知@Before,一個(gè)環(huán)繞通知@Around,我們使用功能最強(qiáng)大的環(huán)繞通知。
通過上面的代碼可以看出 首先獲取參數(shù),然后通過反射機(jī)制 獲取 入?yún)ο笾械娜孔侄危?再去獲取 我們在字段中加 我們自定義注解的字段,通過反射方法的回調(diào),獲取字段值,對值做判斷, 返回校驗(yàn)結(jié)果。
總結(jié)
以上所述是小編給大家介紹的spring boot+自定義 AOP 實(shí)現(xiàn)全局校驗(yàn)的實(shí)例代碼,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時(shí)回復(fù)大家的!
- springBoot整合CXF并實(shí)現(xiàn)用戶名密碼校驗(yàn)的方法
- Spring Boot實(shí)現(xiàn)通用的接口參數(shù)校驗(yàn)
- Spring boot進(jìn)行參數(shù)校驗(yàn)的方法實(shí)例詳解
- SpringBoot實(shí)現(xiàn)前端驗(yàn)證碼圖片生成和校驗(yàn)
- springboot使用校驗(yàn)框架validation校驗(yàn)的示例
- springboot使用hibernate validator校驗(yàn)方式
- Springboot 使用 JSR 303 對 Controller 控制層校驗(yàn)及 Service 服務(wù)層 AOP 校驗(yàn) 使用消息資源文件對消息國際化
- SpringBoot實(shí)現(xiàn)短信驗(yàn)證碼校驗(yàn)方法思路詳解
- 詳解如何在Spring Boot項(xiàng)目使用參數(shù)校驗(yàn)
相關(guān)文章
@RequestParam 接收參數(shù)的值為null的處理方式
這篇文章主要介紹了@RequestParam 接收參數(shù)的值為null的處理方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
使用Feign調(diào)用注解組件(實(shí)現(xiàn)字段賦值功能)
這篇文章主要介紹了使用Feign調(diào)用注解組件(實(shí)現(xiàn)字段賦值功能),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
IntelliJ IDEA 2019.1.1 for MAC 下載和注
這篇文章主要介紹了IntelliJ IDEA 2019.1.1 for MAC 下載和注冊碼激活,教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
Spring Boot使用Servlet及Filter過程詳解
這篇文章主要介紹了Spring Boot使用Servlet及Filter過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07

