---
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() + ")");
}
}
}
```