Browse Source

添加 aop 文章

王智勇 5 years ago
parent
commit
bf327aed0b
2 changed files with 281 additions and 0 deletions
  1. 4 0
      readme.md
  2. 277 0
      source/_posts/aop.md

+ 4 - 0
readme.md

@@ -0,0 +1,4 @@
+#### hexo常用命令
+```
+hexo new [layout] <title>
+```

+ 277 - 0
source/_posts/aop.md

@@ -0,0 +1,277 @@
+---
+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
+/**
+ * @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);
+
+    //todo 暂时使用 方法扫描 以 O 结尾的方法 标识对外的接口 后期改为 @args
+    //    @Pointcut("@args(com.ys.atds.annotation.ParamCheck)")
+    // 定义切点 返回类型 或包名等
+    @Pointcut("execution(* com.ys.*.api.impl..*.*O(..))")
+    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");
+            }
+            // 获取注解
+            for (Field field : arg.getClass().getDeclaredFields()) {
+                // 获取注解
+                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() + ")");
+        }
+    }
+
+}
+```