开发过程中我们经常会用到@Validated这个来校验参数信息,同理也能实现一些其他的一些校验信息,所以这里就利用切面的方式来实现类似@Validated的功能,@Validated有自己的实现方式,具体的我也没有深究过。
实现原理
其实原理很简单,就是通过两个注解或者多个注解和springboot的AOP功能,两个注解分别作用为:一个注解作为切点来确认需要判断的方法,另外一个则是标记需要验证的参数信息;当方法进入的切面中,利用反射来处理切面中的参数和对象信息。
代码
所列代码仅供参考,大概看看就好,里面用到的一些方法可能也不是最优的,我没有深入的去看api介绍。
添加AOPmaven配置
1 2 3 4 5
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
|
EnableVerify 注解
该注解可作用于方法上或类上,用于切面的切点使用,也只有加了此注解,该功能才能生效
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EnableVerify {
}
|
Verify注解
该注解可以在方法的参数上使用,或者是方法参数对象中的字段上使用
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
|
@Target({ElementType.PARAMETER, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Verify {
VerifyEnum value() default VerifyEnum.NOTBANK;
String message() default "参数有误"; }
|
VerifyEnum 枚举
此枚举作用是列举需要判断的类别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public enum VerifyEnum {
NOTBANK,
THENZERO }
|
VerifyAspect切面类
基本的业务逻辑都在该切面类中实现
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
|
@Aspect @Component public class VerifyAspect { private Logger log = LoggerFactory.getLogger(VerifyAspect.class);
@Pointcut("@annotation(com.lengff.demo.annotation.EnableVerify)||@within(com.lengff.demo.annotation.EnableVerify)") public void pointcut() { }
@Before("pointcut()") public void Before(JoinPoint point) { MethodSignature method = (MethodSignature) point.getSignature(); Parameter[] parameters = method.getMethod().getParameters(); if (parameters.length < 1) { return; } Object[] args = point.getArgs(); for (Parameter parameter : parameters) { Integer index = Integer.valueOf(parameter.getName().replace("arg", "")); Object arg = args[index]; log.info("参数值为:", arg); if (parameter.isAnnotationPresent(Verify.class)) { Verify annotation = parameter.getAnnotation(Verify.class); if (!verify(annotation, arg)) { return; } } else { Field[] declaredFields = arg.getClass().getDeclaredFields(); if (declaredFields.length < 1) { continue; } for (Field field : declaredFields) { if (field.isAnnotationPresent(Verify.class)) { Verify annotation = field.getAnnotation(Verify.class); Object argValue = getArgValue(arg, field.getName()); if (!verify(annotation, argValue)) { return; } } } } } }
private Object getArgValue(Object arg, String fieldName) { String names = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); String setMethodname = String.format("set%s", names); String getMethodname = String.format("get%s", names); try { Method method = arg.getClass().getMethod(getMethodname, null); return method.invoke(arg, null); } catch (NoSuchMethodException e) { log.warn("实体对象无get/set方法"); } catch (IllegalAccessException | InvocationTargetException e) { log.warn("执行实体对象get/set方法出现异常"); } return null; }
private boolean verify(Verify annotation, Object arg) { switch (annotation.value()) { case NOTBANK: if (arg instanceof String) { String arg1 = (String) arg; if (arg1 == null || "".equals(arg)) { returnMessage("参数" + arg + annotation.message()); return false; } } break; case THENZERO: if (arg instanceof Integer || arg instanceof Long) { if (Long.valueOf(arg.toString()) <= 0) { returnMessage("参数" + arg + annotation.message()); return false; } } break; } return true; }
private void returnMessage(String message) { ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletResponse response = requestAttributes.getResponse(); try { response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8"); PrintWriter writer = response.getWriter(); writer.print(message); writer.flush(); writer.close(); } catch (IOException e) { log.info(e.getMessage()); } } }
|
测试代码
controller类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
@EnableVerify @RestController @RequestMapping("verify") public class VerifyController {
@GetMapping("param") public String verifyParam(@Verify(message = "参数信息不能为空", value = VerifyEnum.NOTBANK) String param) { return param; }
@GetMapping("field") public String verifyField(VerifyParam param) { return param.toString(); } }
|
参数类
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
|
public class VerifyParam implements Serializable {
@Verify(value = VerifyEnum.THENZERO, message = "年龄不能为空") private Integer age;
@Verify(message = "姓名不能为空") private String name;
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override public String toString() { return "VerifyParam{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
|
示例代码
示例代码下载