aop

  1. 1. spring aop
    1. 1.1. 配置

spring aop

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

配置

  • mvc 配置文件 添加
    1
    <aop:aspectj-autoproxy proxy-target-class="true"/>

开启自动切面代理

  • 添加自定义注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    /**
    * @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
    }
  • 添加处理逻辑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    @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() + ")");
    }
    }

    }
支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者