spring boot+自定义 AOP 实现全局校验的实例代码

最近公司重构项目,重构为最热的微服务框架 spring boot, 重构的时候遇到几个可以统一处理的问题,也是项目中经常遇到,列如:统一校验参数,统一捕获异常。。。

仅凭代码 去控制参数的校验,有时候是冗余的,但通过框架支持的 去控制参数的校验,是对于开发者很友好,先看下面的例子

 @NotEmpty(message="手机号不能为空")
   @Size(min=11,max=11,message="手机号码长度不正确")
   @Pattern(regexp=StringUtils.REGEXP_MOBILE,message="手机号格式不正确")
  private String mobile;

这是spring boot支持的 校验注解,然后我们在 contoller层 加上@Valid 注解 就可以达到校验的目的。这是一种框架自带的

本章 就展示一种 自定义的 AOP 校验,首先 写一个注解,注解里面可以写上 我们需要校验的规则, 比如长度,正则。。。

@Documented
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateParam {
  int min() default 0;
  int max() default Integer.MAX_VALUE;
  String message() default "params is not null";
  String regexp();
  Class<?>[] groups() default { };
   Class<? extends Payload>[] payload() default { };
   boolean isNotNull() default true;
}

然后定义一个AOP类

package com.onecard.primecard.common.aop;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Pattern;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import com.jfcf.core.dto.ResultData;
import com.onecard.core.support.util.StringUtils;
import com.onecard.primecard.common.annotation.ValidateParam;
import com.onecard.primecard.common.utils.ResultDataUtil;
/**
 * 全局 切面类(校验参数)
 *
 * @author Administrator
 *
 */
@Aspect
@Component
public class GobalHandlerAspect {
  private static Logger logger = LoggerFactory.getLogger(GobalHandlerAspect.class);
  @Pointcut("execution(* 包名.controller..*.*(..)) && execution(* 包名.controller..*.*(..))")
  public void checkAspect(){};
  @Before("checkAspect()")
  public void befor(JoinPoint joinPoint) throws Exception{
    //前置统一输出参数
    Object[] args = joinPoint.getArgs();
    if(args != null && args.length>0){
      Object obj = args[0];
      ParameterizedType pt = (ParameterizedType)obj.getClass().getGenericSuperclass();
      Class<?> classzz = (Class<?>) pt.getActualTypeArguments()[0];
      logger.info("【小X卡】-【请求实体入参】:"+classzz.newInstance().toString());
    }
  }
  @Around("checkAspect()")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
    //校验参数
    Object[] args = joinPoint.getArgs();
    Object obj = null;
    if(args != null && args.length > 0){
      obj = args[0];
      Class classzz = obj.getClass();
      //没有顺序和秩序的数组
      Field[] fieldArray = classzz.getDeclaredFields();
      ArrayList<Field> fieldList = new ArrayList<Field>(Arrays.asList(fieldArray));
      String res = checkParam(fieldList,obj);
      if(StringUtils.isNotNull(res)){
        return ResultDataUtil.result(ResultData.STATUS_PARAM_ERROR, res);
      }
    }
    return joinPoint.proceed();
  }
  private String checkParam(ArrayList<Field> fieldList, Object obj) throws Exception {
    for(Field field : fieldList){
      ValidateParam validateParam = field.getAnnotation(ValidateParam.class);
      logger.info("【小X卡】获取注解值:"+validateParam.isNotNull()+"min="+validateParam.min()+"max="+validateParam.max());
      Method method = obj.getClass().getMethod("get"+getMethodName(field.getName()));
      logger.info("【小X卡】入参实体方法名称:"+method.getName());
      if(method != null){
        Object val = method.invoke(obj);
        logger.info("【小x卡】回调方法:"+val);
        if(validateParam != null && validateParam.isNotNull() == true){
          if(null == val || "".equals(val) ){
            return field.getName()+"必填参数为空";
          }
        }
        if(validateParam.min()==11 && validateParam.max() == 11){
          if(val.toString().length() != 11){
            return field.getName()+"请输入参数正确的长度";
          }
        }
        if(validateParam.regexp().equals(StringUtils.REGEXP_MOBILE)){
          if(!Pattern.matches(StringUtils.REGEXP_MOBILE, val.toString())){
            return field.getName()+"参数格式错误";
          }
        }
      }
    }
    return null;
  }
   /**
   * 方法首字母大写
   * @param fieldName
   * @return
   */
  private String getMethodName(String fieldName) {
    StringBuffer buffer = new StringBuffer();
    String firstLetter = fieldName.substring(0, 1).toUpperCase();
    return buffer.append(firstLetter).append(fieldName.substring(1, fieldName.length())).toString();
  }
 }

定义一个切点 @Pointcut, 用execution 表达式,去获取要校验的 某个类 和某个方法, 也就是连接点,然后 用定义一个通知,上面代码中有2个通知,一个前置通知@Before,一个环绕通知@Around,我们使用功能最强大的环绕通知。

通过上面的代码可以看出  首先获取参数,然后通过反射机制 获取 入参对象中的全部字段, 再去获取 我们在字段中加 我们自定义注解的字段,通过反射方法的回调,获取字段值,对值做判断, 返回校验结果。

总结

以上所述是小编给大家介绍的spring boot+自定义 AOP 实现全局校验的实例代码,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

(0)

相关推荐

  • Springboot 使用 JSR 303 对 Controller 控制层校验及 Service 服务层 AOP 校验 使用消息资源文件对消息国际化

    导包和配置 导入 JSR 303 的包.hibernate valid 的包 <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.5.Final</version> </dependency> <dependency> <

  • SpringBoot实现前端验证码图片生成和校验

    SpringBoot下实现前端验证码图片的生成和校验,供大家参考,具体内容如下 1.效果 点击验证码可以获取新的验证码 2.原理 后台生成验证码图片,将图片传到前台. 后台在session中保存验证码内容. 前台输入验证码后传到后台在后台取出session中保存的验证码进行校验. 注意,验证码的明文是不能传送到前端的.前端内容都是透明的,不安全.验证码是用来防机器人并不是单单防人.如果把验证码明文传到前端很容易就会被破解. 3.图片生成 验证码生成工具类RandomValidateCodeUti

  • springBoot整合CXF并实现用户名密码校验的方法

    准备工作: 创建springBoot项目webservice_server 创建springBoot项目webservice_client 分别添加CXF的依赖: <!-- CXF webservice --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version

  • springboot使用校验框架validation校验的示例

    b/s系统中对http请求数据的校验多数在客户端进行,这也是出于简单及用户体验性上考虑,但是在一些安全性要求高的系统中服务端校验是不可缺少的. Spring3支持JSR-303验证框架,JSR-303 是Java EE 6 中的一项子规范,叫做BeanValidation,官方参考实现是hibernate Validator(与Hibernate ORM 没有关系),JSR 303 用于对Java Bean 中的字段的值进行验证. Validator主要是校验用户提交的数据的合理性的,比如是否为

  • springboot使用hibernate validator校验方式

    一.参数校验 在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码个人感觉有两个麻烦: 验证代码繁琐,重复劳动 方法内代码显得冗长 每次要看哪些参数验证是否完整,需要去翻阅验证逻辑代码 hibernate validator(官方文档)提供了一套比较完善.便捷的验证实现方式. spring-boot-starter-web包里面有hibernate-validator包,不需要引用hibernate validator依赖. 二.hi

  • SpringBoot实现短信验证码校验方法思路详解

    有关阿里云通信短信服务验证码的发送,请参考我的另一篇文章   Springboot实现阿里云通信短信服务有关短信验证码的发送功能 思路 用户输入手机号后,点击按钮获取验证码.并设置冷却时间,防止用户频繁点击. 后台生成验证码并发送到用户手机上,根据验证码.时间及一串自定义秘钥生成MD5值,并将时间也传回到前端. 用户输入验证码后,将验证码和时间传到后台.后台先用当前时间减去前台传过来的时间验证是否超时.如果没有超时,就用用户输入的验证码 + 时间 + 自定义秘钥生成MD5值与之前的MD5值比较,

  • Spring Boot实现通用的接口参数校验

    本文介绍基于 Spring Boot 和 JDK8 编写一个 AOP ,结合自定义注解实现通用的接口参数校验. 缘由 目前参数校验常用的方法是在实体类上添加注解,但对于不同的方法,所应用的校验规则也是不一样的,例如有一个 AccountVO 实体: public class AccountVO { private String name; // 姓名 private Integer age; // 年龄 } 假设存在这样一个业务:用户注册时需要填写姓名和年龄,用户登陆时只需要填写姓名就可以了.那

  • 详解如何在Spring Boot项目使用参数校验

    开发web项目有时候我们需要对controller层传过来的参数进行一些基本的校验,比如非空,非null,整数值的范围,字符串的个数,日期,邮箱等等.最常见的就是我们直接写代码校验,这样以后比较繁琐,而且不够灵活. Bean Validation 1.0(JSR-303)是一个校验规范,在spring Boot项目由于自带了hibernate validator 5(http://hibernate.org/validator/)实现,所以我们可以非常方便的使用这个特性 . 核心的pom依赖:

  • Spring boot进行参数校验的方法实例详解

    Spring boot开发web项目有时候我们需要对controller层传过来的参数进行一些基本的校验,比如非空.整数值的范围.字符串的长度.日期.邮箱等等.Spring支持JSR-303 Bean Validation API,可以方便的进行校验. 使用注解进行校验 先定义一个form的封装对象 class RequestForm { @Size(min = 1, max = 5) private String name; public String getName() { return n

  • spring boot+自定义 AOP 实现全局校验的实例代码

    最近公司重构项目,重构为最热的微服务框架 spring boot, 重构的时候遇到几个可以统一处理的问题,也是项目中经常遇到,列如:统一校验参数,统一捕获异常... 仅凭代码 去控制参数的校验,有时候是冗余的,但通过框架支持的 去控制参数的校验,是对于开发者很友好,先看下面的例子 @NotEmpty(message="手机号不能为空") @Size(min=11,max=11,message="手机号码长度不正确") @Pattern(regexp=StringUt

  • spring boot springjpa 支持多个数据源的实例代码

    1.SpringBoot的程序启动类 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.web

  • spring boot整合spring-kafka实现发送接收消息实例代码

    前言 由于我们的新项目使用的是spring-boot,而又要同步新项目中建的数据到老的系统当中.原来已经有一部分的同步代码,使用的是kafka. 其实只是做数据的同步,我觉得选MQ没必要使用kafka.首先数据量不大,其实搞kafka又要搞集群,ZK.只是用做一些简单数据同步的话,有点大材小用. 没办法,咱只是个打工的,领导让搞就搞吧.刚开始的时候发现有一个spring-integration-kafka,描述中说是基于spring-kafka做了一次重写.但是我看了官方文档.实在是搞的有点头大

  • 详解使用Spring Boot的AOP处理自定义注解

    上一篇文章Java 注解介绍讲解了下Java注解的基本使用方式,并且通过自定义注解实现了一个简单的测试工具:本篇文章将介绍如何使用Spring Boot的AOP来简化处理自定义注解,并将通过实现一个简单的方法执行时间统计工具为样例来讲解这些内容. AOP概念 面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计.观点导向编程.剖面导向程序设计)是计算机科学中的一个术语,指一种程序设计范型.该范型以一种称为侧面(aspect,又译作方面)的语

  • Spring Boot 通过AOP和自定义注解实现权限控制的方法

    本文介绍了Spring Boot 通过AOP和自定义注解实现权限控制,分享给大家,具体如下: 源码:https://github.com/yulc-coding/java-note/tree/master/aop 思路 自定义权限注解 在需要验证的接口上加上注解,并设置具体权限值 数据库权限表中加入对应接口需要的权限 用户登录时,获取当前用户的所有权限列表放入Redis缓存中 定义AOP,将切入点设置为自定义的权限 AOP中获取接口注解的权限值,和Redis中的数据校验用户是否存在该权限,如果R

  • spring boot自定义log4j2日志文件的实例讲解

    背景:因为从 spring boot 1.4开始的版本就要用log4j2 了,支持的格式有json和xml两种格式,此次实践主要使用的是xml的格式定义日志说明. spring boot 1.5.8.RELEASE 引入log4j2的开发步骤如下: 1.首先把spring-boot-starter-web以及spring-boot-starter包下面的spring-boot-starter-logging排除,然后引入spring-boot-starter-log4j2包. <dependen

  • Spring boot通过AOP防止API重复请求代码实例

    这篇文章主要介绍了Spring boot通过AOP防止API重复请求代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 实现思路 基于Spring Boot 2.x 自定义注解,用来标记是哪些API是需要监控是否重复请求 通过Spring AOP来切入到Controller层,进行监控 检验重复请求的Key:Token + ServletPath + SHA1RequestParas Token:用户登录时,生成的Token Servlet

  • spring boot 自定义starter的实现教程

    spring boot 使用 starter 解决了很多配置问题, 但是, 他是怎么来解决这些问题的呢? 这里通过一个简单的例子, 来看一下, starter是怎么来设置默认配置的. 一. 建 starter 项目 自定义的starter, 项目命名规范是: 自定义名-spring-boot-starter 先来看一下, 我最后的目录结构 1. 修改pom.xml文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns

  • Spring Boot 自定义 Shiro 过滤器无法使用 @Autowired问题及解决方法

    在 Spring Boot 中集成 Shiro,并使用 JWT 进行接口认证. 为了统一对 Token 进行过滤,所以自定义了一个 JwtTokenFilter 过滤器. 期间遇到了以下几个问题,这里逐一进行记录,以备日后查阅. 问题一:JwtTokenFilter 无法使用 @Autowired 因为自定义了一个 JWT Token 工具类,用来解析和创建 Token,JwtTokenFilter 中需要用到此工具类,这里本来可以直接手动进行 new 一个新的实例,但由于在 Spring 配置

  • Spring Boot自定义配置实现IDE自动提示功能

    一.背景 官方提供的spring boot starter的配置项,我们用IDE配置的时候一般都有自动提示的,如下图所示 而我们自己自定义的配置却没有,对开发非常不友好容易打错配置, 那这个是怎样实现的呢? 二.提示原理 IDE是通过读取配置信息的元数据而实现自动提示的,而元数据在目录 META-INF 中的 spring-configuration-metadata.json 或者 additional-spring-configuration-metadata.json 三.实现自动提示 以

随机推荐