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 ...
随机推荐
- leetcode 1266. Minimum Time Visiting All Points
On a plane there are n points with integer coordinates points[i] = [xi, yi]. Your task is to find th ...
- nginx配置详解和原理
1.nginx的配置文件 nginx 配置文件的整体结构 user nobody nobody; # 指定Nginx Worker进程运行用户以及用户组,默认由nobody账号运行,nobody 是系 ...
- hadoop离线数据存储和挖掘架构
前序: 当你把你知道的东西,写下来,让人看明白是一种境界:当你能把自己写下来的东西给人讲明白,又是另一种境界.在这个过程中,我们都需要历练. 基于hadoop集群下海量离线数据存储和挖掘分析架构: 架 ...
- bootstrap之响应式布局
1.手动配置viewport 在HTML中: <meta name="viewport" content="width=device-width,initial-s ...
- 第八篇 CSS定位
CSS定位 CSS除了内外边距控制元素,还有定位,看到“定位”两个字,同学们应该就能清楚,它能够做什么. 在刚学习的时候,我也经常使用定位,来控制元素的位置,但是初学的同学可能会注意不到定位的一些 ...
- spring-boot 启动图标修改-启动彩蛋
spring boot启动总会显示这样的图标,但是我想不一样 到网上找了一圈,恩,找到一个不错的,做个记录 首先我们在resource目录下面放入一个banner.txt文件,Spring Boot启 ...
- Ubuntu18.10中pip install mysqlclient 出现EnvironmentError: mysql_config not found错误
Complete output from command python setup.py egg_info: sh: 1: mysql_config: not found Traceback (mos ...
- ubuntu终端安装最新ss
有时候因为加密方式比较新,比如aes-256-gcm,导致旧版本的不能用 一句命令安装ss最新版本 aes-256-gcm加密方式可以用,没毛病
- lftp连接异常情况分析过程
[问题现象]:通过rpm安装好lftp后,执行lftp huangmr:huangmr@192.168.107.132无法连接(lftp huangmr@192.168.107.132:~> l ...
- MobileNet系列
最近一段时间,重新研读了谷歌的mobilenet系列,对该系列有新的认识. 1.MobileNet V1 这篇论文是谷歌在2017年提出了,专注于移动端或者嵌入式设备中的轻量级CNN网络.该论文最大的 ...