AOP Aspect無限遞歸驗證controller請求參數

場景是對controller提交的參數進行驗證,滿足單個基本/包裝類型屬性參數和實體類內部參數,沒有去找其他插件框架,直接自己寫了一個

廢話不多說,代碼:

  ValidationAspect

package com.shinedata.aop;

import com.shinedata.Exception.ValidationException;
import com.shinedata.annotation.Validation;
import com.shinedata.annotation.ValidationModel;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Pattern;

/**
 * @ClassName ValidationAspect
 * @Author yupanpan
 * @Date 2019/9/29 15:27
 */
@Order(0)
@Aspect
@Component
public class ValidationAspect {

    @Pointcut("execution(* com.shinedata.controller..*(..))")
    public void validation() { }

    @Before("validation()")
    public void validateParam(JoinPoint point) throws NoSuchMethodException, InvocationTargetException,
            IllegalAccessException {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        //所有參數名稱的字符串數組
        String[] parameterNames = methodSignature.getParameterNames();
        //參數值
        Object[] args = point.getArgs();
        //獲取參數註解 //參數註解,1維是參數,2維是註解
        Annotation[][] parameterAnnotations = methodSignature.getMethod().getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            Annotation[] paramAnn = parameterAnnotations[i];
            String parameterName = parameterNames[i];
            //參數沒有註解,直接下一個參數
            if(paramAnn.length == 0){
                continue;
            }
            for (Annotation annotation : paramAnn) {
                Object param = args[i];
                //這裏判斷當前註解是否爲Validation.class
                if(annotation.annotationType().equals(Validation.class)){
                    validateParamValue(param,annotation,parameterName);
                }else if(annotation.annotationType().equals(ValidationModel.class)){
                    validateParamModelValue(param);
                }
            }
        }
    }

    private void validateParamModelValue(Object param) throws InvocationTargetException, IllegalAccessException,
            NoSuchMethodException {
        //遍歷屬性字段,獲取屬性上的註解值
        Field[] fields = param.getClass().getDeclaredFields();
        if(fields!=null&&fields.length>0){
            for (Field field : fields) {
                Annotation[] annotations = field.getAnnotations();
                if(annotations!=null&&annotations.length>0){
                    for (Annotation classFieldAnn : annotations) {
                            //獲取屬性值
                            String fieldName=field.getName();
                            Method method=param.getClass().getMethod("get"+ fieldName.substring(0,1).toUpperCase()+fieldName.substring(1));
                            Object classFiledValue = method.invoke(param);
                        if(classFieldAnn.annotationType().equals(Validation.class)) {
                            validateParamValue(classFiledValue, classFieldAnn, fieldName);
                        }else if(classFieldAnn.annotationType().equals(ValidationModel.class)){
                            validateParamModelValue(classFiledValue);
                        }
                    }
                }
            }
        }
    }

    private void validateParamValue(Object param,Annotation annotation,String parameterName){
        Validation validation=(Validation)annotation;
        if(validation.notNull()&&param==null){
            throw new ValidationException(StringUtils.isBlank(validation.message())?parameterName+"不能爲空":validation.message());
        }
        String p = param.toString();
        if(StringUtils.isNotBlank(validation.min())){
            if(Long.valueOf(validation.min())>(Long.valueOf(p))){
                throw new ValidationException(parameterName+"參數值錯誤,最小值"+validation.min());
            }
        }
        if(StringUtils.isNotBlank(validation.max())){
            if(Long.valueOf(validation.max())<(Long.valueOf(p))){
                throw new ValidationException(parameterName+"參數值錯誤,最大值"+validation.max());
            }
        }
        if(StringUtils.isNotBlank(validation.pattern())){
            boolean isMatch = Pattern.matches(validation.pattern(), p);
            if(!isMatch){
                throw new ValidationException(parameterName+"參數格式錯誤");
            }
        }
    }

}

核心在上面的切面。

自定義異常ValidationException

package com.shinedata.Exception;

/**
 * @ClassName ValidationException
 * @Author yupanpan
 * @Date 2019/9/29 16:08
 */
public class ValidationException extends Exception {

    private static final long serialVersionUID = -7328486927134375179L;

    public ValidationException(String message) {
        super(message);
    }

    public ValidationException(String message,Exception e) {
        super(message,e);
    }
}
@ControllerAdvice 增強Controller捕獲異常給前端返回錯誤信息

全局異常處理GlobalExceptionHandler

package com.shinedata.Exception;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONException;
import com.shinedata.util.Result;

/**
 * 全局異常處理
 * @ClassName ValidationAspect
 * @Author yupanpan
 * @Date 2019/9/29 15:27
 */
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
	
	
	private static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
	
	
	@ExceptionHandler(ValidationException.class)
	public Result exceptionHandler(ValidationException e){
		Map<String, Object> map = new HashMap<>();
		map.put("flag", 600);
		Result result = Result.getResult(600, e.getMessage(), map);
		return result;
	}
	
	
}

 

自定義的兩個簡單的註解

ValidationModel  註解用於請求參數爲實體類

package com.shinedata.annotation;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @ClassName ValidateParams
 * @Author yupanpan
 * @Date 2019/9/29 14:44
 */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE,ElementType.PARAMETER,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidationModel {

    /**
     * A list of {@link Validation}s available to the param operation.
     */
    //Validation[] value();
}

Validation  註解用於請求參數非實體類

package com.shinedata.annotation;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @ClassName ValidateParams
 * @Author yupanpan
 * @Date 2019/9/29 14:44
 */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE,ElementType.PARAMETER,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Validation {

    /**
     * 驗證失敗返回描述
     * @return
     */
    String message() default "";

    /**
     *最大值 數字字符串
     * @return
     */
    String max() default "";
    /**
     *最小值
     * @return
     */
    String min() default "";
    /**
     *正則驗證
     * @return
     */
    String pattern() default "";
    /**
     *是否必填,默認是
     * @return
     */
    boolean notNull() default true;


}

 

使用方式,舉個例子

@ValidationModel

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章