場景是對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()&¶m==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