--- title: aop date: 2018-12-03 15:38:33 tags: [Spring Boot,AOP] categories: [Java,Spring] --- ### spring aop 通过自定义注解和aop实现参数校验. #### 配置 - mvc 配置文件 添加 ``` ``` 开启自动切面代理 - 添加自定义注解 ```java /** * @author : wangzhiyong * @date : 2018/11/12 17:41 * description : 参数校验自定义注解 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) @Documented @Inherited public @interface ParamCheck { /** * 是否必填 * * @return */ public boolean require() default true; /** * 参数类型 * {@link com.ys.tools.paramcheck.ParamType} * * @return */ public ParamType type() default ParamType.STRING; /** * 长度 * * @return */ public int size() default Integer.MAX_VALUE; /** * 最小值 * * @return */ public double min() default Integer.MIN_VALUE; /** * 最大值 * * @return */ public double max() default Integer.MAX_VALUE; /** * 格式化 * * @return */ public String pattern() default "yyyy-MM-dd HH:mm:ss"; /** * 是否是加密字段 * * @return */ public boolean cipher() default false; } ``` - 添加指定类型 ```java public enum ParamType { /** * 基本参数类型 */ BYTE,SHORT,INT,LONG,FLOAT,DOUBLE,BOOLEAN,CHAR, /** * 拓展参数类型 */ STRING,DATE } ``` - 添加处理逻辑 ```java @Aspect @Component public class ParamCheckAspect { private static final Logger logger = Logger.getLogger(ParamCheckAspect.class); @Pointcut("@args(com.dragon.chaofeng.annotation.ParamCheck, ..) && execution(* com.dragon.chaofeng.web..*.*(..))") // @Pointcut("execution(* com.dragon.chaofeng.web..*.*(..))") // @Pointcut("@args(org.springframework.web.bind.annotation.RequestBody, ..)") // @Pointcut("@within(com.dragon.chaofeng.annotation.ParamCheck)") // @Pointcut("execution (* com.dragon.chaofeng.service..*.*(..))") // @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") public void paramPointcut() { } @Before("paramPointcut()") public void before(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0) { return; } // 方法的参数 Class[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes(); for (int i = 0; i < parameterTypes.length; i++) { Class parameterType = parameterTypes[i]; // 若参数未注解ParamCheck, 忽略验证 if (parameterType.getAnnotation(ParamCheck.class) == null) { continue; } // 传入的参数 Object arg = args[i]; if (arg == null) { throw new AtdsException("parameter should not be null or empty"); } //获取所有变量 List fieldList = new ArrayList<>(); Class argClass = arg.getClass(); // 去重临时变量 Set temp = new HashSet<>(); //当父类为null的时候说明到达了最上层的父类(Object类). while (argClass != null && !argClass.getName().toLowerCase().equals("java.lang.object")) { for (Field field : argClass.getDeclaredFields()) { if (!temp.contains(field.getName())) { fieldList.add(field); temp.add(field.getName()); } } //得到父类,然后赋给自己 argClass = argClass.getSuperclass(); } // 获取注解 for (Field field : fieldList) { // 获取注解 ParamCheck annotationsByType = field.getAnnotation(ParamCheck.class); // 只检查@ParamCheck注解字段 if (annotationsByType == null) { continue; } // 设置字段可访问并取值 field.setAccessible(true); Object argValue = null; try { argValue = field.get(arg); } catch (IllegalAccessException e) { e.printStackTrace(); logger.error("ParamCheckAspect: " + e.getMessage()); } // 字段类型 Class type = field.getType(); // 字段为null或空string if (argValue == null || (String.class.equals(type) && "".equals(argValue))) { // 若注解声明非空, 抛出异常, 否则忽略本字段 if (annotationsByType.require()) { throw new AtdsException("parameter " + field.getName() + " should not be null or empty"); } else { continue; } } // 字段类型非数字 且非String, 忽略本字段, 不深入检查 if (!isNumberType(type) && !String.class.equals(type)) { continue; } try { // 字段类型为 String 或 数字, 走各自验证 if (String.class.equals(type)) { checkString(String.valueOf(argValue), annotationsByType); } else { checkNumber(argValue, annotationsByType); } } catch (AtdsException e) { throw new AtdsException(String.format(e.getMessage(), field.getName())); } } } } /** * 是否数字类型 * * @param type * @return */ private boolean isNumberType(Class type) { return isNumberType(type.getSimpleName()); } /** * 是否数字类型 * * @param typeName * @return */ private boolean isNumberType(String typeName) { if ("integer".equalsIgnoreCase(typeName) || ParamType.INT.name().equalsIgnoreCase(typeName)) { return true; } else if ("long".equalsIgnoreCase(typeName) || ParamType.LONG.name().equalsIgnoreCase(typeName)) { return true; } else if ("double".equalsIgnoreCase(typeName) || ParamType.DOUBLE.name().equalsIgnoreCase(typeName)) { return true; } else if ("float".equalsIgnoreCase(typeName) || ParamType.FLOAT.name().equalsIgnoreCase(typeName)) { return true; } else if ("byte".equalsIgnoreCase(typeName) || ParamType.BYTE.name().equalsIgnoreCase(typeName)) { return true; } else if ("short".equalsIgnoreCase(typeName) || ParamType.SHORT.name().equalsIgnoreCase(typeName)) { return true; } else if ("character".equalsIgnoreCase(typeName) || ParamType.CHAR.name().equalsIgnoreCase(typeName)) { return true; } return false; } /** * 检查String类型的参数 * 包括 size/根据 type 检查 min/max/pattern * * @param value * @param paramCheck */ private void checkString(String value, ParamCheck paramCheck) throws AtdsException { // 检查长度 if (paramCheck.size() < value.length()) { throw new AtdsException("parameter %s is too long. (" + value.length() + " of " + paramCheck.size() + ")"); } // 日期时 if (ParamType.DATE.equals(paramCheck.type())) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(paramCheck.pattern()); try { formatter.parse(value); } catch (Exception e) { throw new AtdsException("parameter %s needs correct pattern. (" + paramCheck.pattern() + ")"); } } else if (ParamType.BOOLEAN.equals(paramCheck.type())) { if (!"true".equals(value) && !"false".equals(value)) { throw new AtdsException("parameter %s is not a " + paramCheck.type()); } } else if (isNumberType(paramCheck.type().name())) { checkNumber(value, paramCheck); } } /** * 检查数字类型(BYTE/SHORT/INT/LONG/FLOAT/DOUBLE)以及字符类型的参数 * 包括 min/max * * @param value * @param paramCheck */ private void checkNumber(Object value, ParamCheck paramCheck) { BigDecimal numberValue; try { String stringValue = value.toString(); if (ParamType.CHAR.equals(paramCheck.type())) { if (stringValue.length() != 1) { throw new NumberFormatException(); } numberValue = new BigDecimal(stringValue.toCharArray()[0]); } else { numberValue = new BigDecimal(stringValue); } } catch (NumberFormatException e) { throw new AtdsException("parameter %s is not a " + paramCheck.type()); } // 检查最大值 BigDecimal min = new BigDecimal(paramCheck.min()); if (numberValue.compareTo(min) < 0) { throw new AtdsException("parameter %s is out of range. (min: " + paramCheck.min() + ")"); } // 检查最小值 BigDecimal max = new BigDecimal(paramCheck.max()); if (numberValue.compareTo(max) > 0) { throw new AtdsException("parameter %s is out of range. (max: " + paramCheck.max() + ")"); } } } ```