springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版)
一.引入相应的maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二.自定义参数校验注解
/**
* @Author: guandezhi
* @Date: 2019/3/11 13:07
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ParamValidate {
String value() default "";
}
三.自定义异常切面
package com.gdz.paramvalidate.aspect; import com.gdz.paramvalidate.annotation.ParamValidate;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError; import java.lang.reflect.Method;
import java.util.List; /**
* 异常处理切面
* @Author: guandezhi
* @Date: 2019/3/11 13:03
*/
@Slf4j
@Aspect
@Component
public class ExceptionAspect { @Before("@annotation(com.gdz.paramvalidate.annotation.ParamValidate)")
public void before(JoinPoint jp) throws Exception {
doBefore(jp);
} private void doBefore(JoinPoint jp) throws Exception {
if (getParamValidate(jp) == null) {return;}
Object[] args = jp.getArgs();
if (args == null) {return;}
//将异常格式化成通用格式
formateException(args);
} private ParamValidate getParamValidate(JoinPoint jp) {
MethodSignature methodSignature = (MethodSignature) jp.getSignature();
Method method = methodSignature.getMethod();
return method.getAnnotation(ParamValidate.class);
} private void formateException(Object[] args) throws Exception {
for (Object arg : args) {
if (arg instanceof BindingResult) {
BindingResult result = (BindingResult) arg;
if (result != null && result.getErrorCount() > 0) {
List<ObjectError> errors = result.getAllErrors();
String errorMsg = "";
for (ObjectError error : errors) {
if (error instanceof FieldError) {
FieldError fe = (FieldError) error;
errorMsg = String.format("%s:%s", fe.getField(), error.getDefaultMessage());
} else {
errorMsg = String.format("%s:%s ", error.getCode(), error.getDefaultMessage());
}
log.error(errorMsg);
throw new Exception(errorMsg);
}
}
}
}
} }
四.自定义全局异常处理器
package com.gdz.paramvalidate.exception; import com.gdz.paramvalidate.bean.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; /**
* 全局异常处理
*
* @Author: guandezhi
* @Date: 2019/3/11 14:43
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler { @ResponseBody
@ExceptionHandler(value = Exception.class)
public ResultVo<Object> handleException(Exception e) {
String errorMsg = "";
if (e instanceof NullPointerException) {
errorMsg = "参数空指针异常";
} else if (e instanceof HttpMessageNotReadableException) {
errorMsg = "请求参数匹配错误," + e.getLocalizedMessage();
} else {
errorMsg = e.getMessage();
}
log.error(String.format("请求异常[%s]", e)); ResultVo<Object> resultVo = new ResultVo<>();
resultVo.setResultCode("501");
resultVo.setResultMsg(errorMsg);
return resultVo;
}
}
其中的resultVo如下: /**
* @Author: guandezhi
* @Date: 2019/3/11 12:14
*/
@Data
public class ResultVo<T> { private String resultCode; private String resultMsg; private T data; }
五.在需要校验入参的controller方法上加上自定义注(@ParamValidate)
/**
* @Author: guandezhi
* @Date: 2019/3/11 12:15
*/
@Slf4j
@RequestMapping("/user")
@RestController
public class UserController { @ParamValidate
@RequestMapping("/addUser")
public String addUser(@RequestBody @Valid User user, BindingResult result) throws Exception {
int i = 1 / 0;
return "success";
}
}
这里必须加上@ParamValidate @Valid这两个注解才能生效
其中User类如下:
/**
* @Author: guandezhi
* @Date: 2019/3/11 12:19
*/
@Data
public class User { @NotNull(message = "用户名不能为空")
private String name; @NotNull(message = "手机号不能为空")
private String mobile;
}
六.测试一下
1.当入参为空值时

1.当程序有异常时

代码地址:https://github.com/dezhiguan/GlobalExceptionHandler
---------------------
作者: guandezhi
来源:CSDN
原文:https://blog.csdn.net/qq_35859844/article/details/88394376
版权声明:本文为博主原创文章,转载请附上博文链接!
springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版)的更多相关文章
- 全局异常处理及参数校验-SpringBoot 2.7 实战基础 (建议收藏)
优雅哥 SpringBoot 2.7 实战基础 - 08 - 全局异常处理及参数校验 前后端分离开发非常普遍,后端处理业务,为前端提供接口.服务中总会出现很多运行时异常和业务异常,本文主要讲解在 Sp ...
- springboot aop 自定义注解方式实现完善日志记录(完整源码)
版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 一:功能简介 本文主要记录如何使用aop切面的方式来实现日志记录功能. 主要记录的信息有: 操作人,方法名,参数,运行时间,操作类型 ...
- springboot aop 自定义注解方式实现一套完善的日志记录(完整源码)
https://www.cnblogs.com/wenjunwei/p/9639909.html https://blog.csdn.net/tyrant_800/article/details/78 ...
- springboot aop 自定义注解
枚举类: /** * Created by tzq on 2018/5/21. */ public enum MyAnnoEnum { SELECT("select"," ...
- 使用AOP+自定义注解完成spring boot的接口权限校验
记使用AOP+自定义注解完成接口的权限校验,代码如下: pom文件添加所需依赖: 1 <dependency> 2 <groupId>org.aspectj</group ...
- SpringBoot系列(十三)统一日志处理,logback+slf4j AOP+自定义注解,走起!
往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)we ...
- redis分布式锁-spring boot aop+自定义注解实现分布式锁
接这这一篇redis分布式锁-java实现末尾,实现aop+自定义注解 实现分布式锁 1.为什么需要 声明式的分布式锁 编程式分布式锁每次实现都要单独实现,但业务量大功能复杂时,使用编程式分布式锁无疑 ...
- 利用Spring AOP自定义注解解决日志和签名校验
转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...
- ssm+redis整合(通过aop自定义注解方式)
此方案借助aop自定义注解来创建redis缓存机制. 1.创建自定义注解类 package com.tp.soft.common.util; import java.lang.annotation.E ...
随机推荐
- 099、如何访问Service (Swarm06)
参考https://www.cnblogs.com/CloudMan6/p/7909136.html 前面已经学习了如何部署Service吗,也验证了swarm的failover特性,下面我们要学 ...
- chrome 浏览器安装 postman
chrome 浏览器安装 postman(插件下载见文章末尾) 1.安装方法 将下载的crx插件拖拽到chrome浏览器即可安装成功. 2.特殊情况 问题: chrome73版本后拖拽安装chrome ...
- 谷歌浏览器(Chrome)离线包的下载方法!
谷歌浏览器(Chrome)其实可以下载离线包,用离线包安装的好处,就是一次获得全部安装文件,不需要漫长的在线下载过程了! 下载地址:https://www.google.com/chrome/eula ...
- Go语法的基本使用(三)
// 长度 vs 容量. // 长度是目前里面有几个值 // 容量是最多能放多少个值 func main(){ var a =make(chan int,4) a<-1 a<-2 a< ...
- 深入理解并使用python的模块与包
模块 编写好的一个python文件可以有两种用途:1)脚本,一个文件就是整个程序,用来被执行2)模块,文件中存放着一堆功能,用来被导入使用 模块的分类 1)开发者编写的 .py文件2 ) 由C或C++ ...
- 两种Tensorflow模型保存的方法
在Tensorflow中,有两种保存模型的方法:一种是Checkpoint,另一种是Protobuf,也就是PB格式: 一. Checkpoint方法: 1.保存时使用方法: tf.train.Sav ...
- vmware虚拟机安装centos7.3
vmware准备 CentOS准备,这里下载的是CentOS 7.3CentOS-7-x86_64-Everything-1611.iso 创建新的虚拟机 选择自定义安装 硬件兼容性默认最新的,不用动 ...
- PowerDesigner连接 MySQL 生成 ER图
powerdesigner 16.5 http://www.pcsoft.com.cn/soft/27495.html jdk 1.8 32位 https://mirrors.huaweicloud. ...
- 【转载】Stanford CoreNLP Typed Dependencies
总结自Stanford typed dependencies manual 原文链接:http://www.jianshu.com/p/5c461cf096c4 依存关系描述句子中词与词之间的各种语法 ...
- Detecting Unstable Periodic Orbits in Chaotic Experimental Data (解析)
原文链接:https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.76.4705 发表在:PRL 1996 ---------------- ...