为了避免对大量参数进行过多的非空校验,我们可以自定义一个非空验证的注解,因为spring自带的@RequestParam并不能对参数进行非空

准备工作

首先需要创建一个spring boot项目,并引入相关maven依赖,pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.ooliuyue</groupId><artifactId>aoptest</artifactId><version>0.0.1-SNAPSHOT</version><name>aoptest</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>复制代码

自定义注解

总体思路:自定义一个注解,对必填的参数加上该注解,然后定义一个切面,校验该参数是否为空,如果为空则抛出自定义的异常,该异常被自定义的异常处理器捕获,然后返回相应的错误信息。 创建一个名为'ParamCheck'的注解,代码如下:

package com.ooliuyue.springboot_aoptest.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Auther: ly* @Date: 2018/12/27 11:43*//*** “参数不为空”注解,作用于方法上*/
@Target(ElementType.PARAMETER) //表示该注解作用于方法参数上
/*** @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;* 而另一些却被编译在class文件中;* 编译在class文件中的Annotation可能会被虚拟机忽略,* 而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。* 使用这个meta-Annotation可以对 Annotation的“生命周期”限制。* &emsp;&emsp;作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)* &emsp;&emsp;取值(RetentionPoicy)有:* &emsp;&emsp;&emsp;&emsp;1.SOURCE:在源文件中有效(即源文件保留)* &emsp;&emsp;&emsp;&emsp;2.CLASS:在class文件中有效(即class保留)* &emsp;&emsp;&emsp;&emsp;3.RUNTIME:在运行时有效(即运行时保留)*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamCheck {/*** 是否非空,默认不能为空* @return*/boolean notNull() default true;
}复制代码

自定义异常类

这个异常类与自定义注解配合一起使用,当加上'@ParamCheck'的参数为空时,抛出该异常,代码如下:

package com.ooliuyue.springboot_aoptest.exception;/*** 自定义异常类* @Auther: ly* @Date: 2018/12/27 09:55*/public class ParamIsNullException extends RuntimeException {private final String parameterName;private final String parameterType;public String getParameterName() {return parameterName;}public String getParameterType() {return parameterType;}public ParamIsNullException(String parameterName, String parameterType) {super("");this.parameterName = parameterName;this.parameterType = parameterType;}public String getMessage(){return "请求参数 "  + this.parameterName + " 不能为空 !";}}复制代码

自定义AOP

代码如下:

package com.ooliuyue.springboot_aoptest.aop;import com.ooliuyue.springboot_aoptest.annotation.ParamCheck;
import com.ooliuyue.springboot_aoptest.exception.ParamIsNullException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import java.lang.annotation.Annotation;
import java.lang.reflect.Method;/*** @Auther: ly* @Date: 2018/12/27 10:10*/
@Component //把切面类加入到IOC容器中
@Aspect
public class ParamCheckAop {private Logger logger = LoggerFactory.getLogger(this.getClass());/*** 定义一个切入点,范围为controller包下的类*/@Pointcut("execution(public * com.ooliuyue.springboot_aoptest.controller..*.*(..))")public void checkParam(){}/*** 前置通知,在连接点之前执行的通知* @param joinPoint*/@Before("checkParam()")public void doBefore(JoinPoint joinPoint){logger.info("进行非空验证");}@Around("checkParam()")public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();//得到拦截的方法Method method = signature.getMethod();//获取方法参数注解,返回二维数组是因为某些参数可能存在多个注解Annotation[][] parameterAnnotations = method.getParameterAnnotations();if (parameterAnnotations == null || parameterAnnotations.length == 0) {return proceedingJoinPoint.proceed();}//获取方法参数名String[] paramNames = signature.getParameterNames();//获取参数值Object[] paranValues = proceedingJoinPoint.getArgs();//获取方法参数类型Class<?>[] parameterTypes = method.getParameterTypes();for (int i = 0; i < parameterAnnotations.length; i++ ) {for (int j = 0; j < parameterAnnotations[i].length; j++) {//如果该参数前面的注解是ParamCheck的实例,并且notNull()=true,则进行非空校验if (parameterAnnotations[i][j] != null&& parameterAnnotations[i][j] instanceof ParamCheck&& ((ParamCheck) parameterAnnotations[i][j]).notNull()) {paramIsNull(paramNames[i], paranValues[i], parameterTypes[i] == null? null: parameterTypes[i].getName());break;}}}return proceedingJoinPoint.proceed();}/*** 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)** @param joinPoint*/@AfterReturning("checkParam()")public void doAfterReturning(JoinPoint joinPoint) {}/*** 参数非空校验,如果参数为空,则抛出ParamIsNullException异常* @param paramName* @param value* @param parameterType*/private void paramIsNull(String paramName, Object value, String parameterType) {if (value == null || "".equals(value.toString().trim())) {throw new ParamIsNullException(paramName, parameterType);}}}复制代码

全局异常处理器

该异常处理器捕获在ParamCheckAop类中抛出的ParamIsNullException异常,并进行处理,代码如下:

package com.ooliuyue.springboot_aoptest.exception;import com.ooliuyue.springboot_aoptest.common.Result;
import com.ooliuyue.springboot_aoptest.enums.EnumResultCode;
import com.ooliuyue.springboot_aoptest.utils.ResponseMsgUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** @Auther: ly* @Date: 2018/12/27 13:50*/
@RestControllerAdvice
public class GlobalExceptionHandler {private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);@ExceptionHandler({MissingServletRequestParameterException.class, ParamIsNullException.class})public Result<String> getException(Exception ex){LOGGER.error("request Exception:", ex);return ResponseMsgUtil.builderResponse(EnumResultCode.FAIL.getCode(),ex.getMessage(),null);}}复制代码

Controller

新建一个名为HelloController的类,用于测试,代码如下:

package com.ooliuyue.springboot_aoptest.controller;import com.ooliuyue.springboot_aoptest.annotation.ParamCheck;
import com.ooliuyue.springboot_aoptest.common.Result;
import com.ooliuyue.springboot_aoptest.enums.EnumResultCode;
import com.ooliuyue.springboot_aoptest.utils.ResponseMsgUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @Auther: ly* @Date: 2018/12/27 11:43*/
@RestControllerpublic class HelloController {/*** 测试@RequestParam注解* @param name* @return*/@GetMapping("/hello1")public Result<String> hello1(@RequestParam String name){return ResponseMsgUtil.builderResponse(EnumResultCode.SUCCESS.getCode(),"请求成功","Hello," + name);}/*** 测试@ParamCheck注解* @param name* @return*/@GetMapping("/hello2")public Result<String> hello2(@ParamCheck String name){return ResponseMsgUtil.builderResponse(EnumResultCode.SUCCESS.getCode(),"请求成功","Hello," + name);}/*** 测试@ParamCheck 和 @RequestParam** @param name* @return*/@GetMapping("/hello3")public Result<String> hello3(@ParamCheck @RequestParam String name){return ResponseMsgUtil.builderResponse(EnumResultCode.SUCCESS.getCode(),"请求成功","Hello," + name);}}复制代码

测试结果

  • 参数值为空 在浏览器输入http://localhost:8080/hello1,结果如下:

    控制台输出错误信息

  • 参数值不为空 在浏览器输入http://localhost:8080/hello1?name=张三,结果如下:

  • 参数值为空 在浏览器输入http://localhost:8080/hello2?name=,结果如下:

    控制台输出错误信息

  • 参数值不为空 在浏览器输入http://localhost:8080/hello2?name=李四,结果如下:

    和测试@ParamCheck 的结果一样

测试总结

当参数名为空时,分别添加两个注解的接口都会提示参数不能为空 当参数名不为空,值为空时,@RequestParam注解不会报错,但@ParamCheck注解提示参数'name'的值为空

源码下载地址

github 码云

SpringBoot基于AOP实现自定义非空验证的注解相关推荐

  1. 【转】ASP.NET验证控件详解(非空验证,比较验证,范围验证,正则表达式,自定义验证)...

    [转]ASP.NET验证控件详解(非空验证,比较验证,范围验证,正则表达式,自定义验证) ASP.NET验证控件详解 现在ASP.NET,你不但可以轻松的实现对用户输入的验证,而且,还可以选择验证在服 ...

  2. antd vue表单验证_antd-for-vue 表单验证失效 自定义表单验证使表单非空验证失效(其他验证失效)...

    ## antd-for-vue 表单验证失效 自定义表单验证使表单非空验证失效(其他验证失效) ##### antd 的 表单校验方法包括 validateFields 和 validateField ...

  3. layui自带验证体系:手机号验证、邮箱验证、必填项非空验证、数字验证(含代码、案例)

    layui自带验证体系:手机号验证.邮箱验证.必填项非空验证.数字验证(含代码.案例) 案例 · 截图: 实例代码: <!DOCTYPE html> <html> <he ...

  4. android非空验证,Android 非空格式验证框架

    Validation的简介 这是一个简单的函数库,使用注释语法来验证用户输入的表单信息.你仅需编写几行代码就可以实现一些表单验证功能,且显示的所有视图都将反馈给用户.它还带有一个可扩展的在线验证选项, ...

  5. ASP.NET中 RequiredFieldValidator(非空验证)的使用

    ylbtech-ASP.NET-Control-Validator: RequiredFieldValidator(非空验证)的使用 ASP.NET中 RequiredFieldValidator(非 ...

  6. php中表单的非空验证,Javascript的表单与验证-非空验证_javascript技巧

    JavaScript 可用来在数据被送往服务器前对 HTML 表单中的这些输入数据进行验证. 表单提交前要检查数据的合法性 在要对表单里的数据进行验证的时候,可以利用getElementById()来 ...

  7. 记录一次生产发布事件——(简单的非空验证也能引发大问题)

    事件经过 下午四点,发布生产g环境(生产环境m为正式环境,g为内测环境).这时测试有人提出"服务器忙".听到这里我赶紧翻了翻内测日志,发现了最熟悉的老朋友--未将对象引用设置到对象 ...

  8. javascript 校验 非空_Javascript的表单与验证-非空验证

    JavaScript 可用来在数据被送往服务器前对 HTML 表单中的这些输入数据进行验证. 表单提交前要检查数据的合法性 在要对表单里的数据进行验证的时候,可以利用getElementById()来 ...

  9. 非空验证方法(多值)和BindingResult提示验证信息

    非空验证方法(多值) function save() {//保存记录checkBlank([['type_name','类型名称'],['type_code','类型标识']]);if(!isNumb ...

最新文章

  1. 技术12期:如何设计rowkey使hbase更快更好用【大数据-全解析】
  2. SAP IDoc E1EDP04 Z8 数据错误之对策
  3. boost::uuids::entropy_error相关的测试程序
  4. 无意中发现的,自己看吧
  5. HDOJ2072解题报告【字典树】
  6. sqlserver2005仅当使用了列的列表,并且 IDENTITY_INSERT 为 ON 时,才能在表 'SendMealAddress'中为标识列指定显式值。...
  7. bmp转YUV RGB转YUV HM学习
  8. 如何做一个“千里马”
  9. ArrayBlockingQueue源码分析
  10. 计算机的编译原理pdf,计算机编译原理DK.pdf
  11. 漏洞四处,苹果电脑也不再安全?(转)
  12. 真实评测酷睿 i5 12400f和i3 10100f选哪个
  13. 安焦删除贴 牛人纷纷出现(1)
  14. springboot项目扫描不到controller中的解决方法
  15. 蜂鸣器干扰通讯_蜂鸣器常见错误电路分析
  16. ADI官网资料检索技巧
  17. Bootstrap-导航条-栅格系统-Carousel(轮播效果)-标签页
  18. 2020国赛C思路分析:中小微企业的信贷决策
  19. 透过镜头放大镜行业现状调研及趋势分析报告
  20. 使用Apache CXF和Apache Axis2实现Web Services客户端

热门文章

  1. 免费报名 | WPS专家教你文本分类在企业中的应用实践
  2. 专访百度熊辉:有人转AI纯粹因为好找工作,这样的人不是我想要的
  3. 观点PK_倘若做不好AI,云服务商还能勇往直前吗?
  4. 苹果和Siri的七年之痒:Siri的落寞之路
  5. 别再乱打日志了,这样才是定位 bug 打日志的方式!
  6. 主流微服务全链路监控系统之战
  7. 用Java实现天天酷跑(附源码),这个真的有点强了!
  8. SpringBoot+Mybatis+Swagger2环境搭建
  9. spring cloud config将配置存储在数据库中
  10. 机器学习项目的备忘清单!