aop.md 9.6 KB


title: aop date: 2018-12-03 15:38:33 tags: [Spring Boot,AOP]

categories: [Java,Spring]

spring aop

通过自定义注解和aop实现参数校验

配置

  • mvc 配置文件 添加

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    

    开启自动切面代理

  • 添加自定义注解 ```java /**

    /**

    • 是否必填 *
    • @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<Field> fieldList = new ArrayList<>();
        Class<?> argClass = arg.getClass();
        // 去重临时变量
        Set<String> 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() + ")"); } }

} ```