背景引入:最近实现了一个限流切面类,但是在限流方法中throw异常,会直接打印到控制台,报错500,对前端很不友好。因为是注解,又没办法捕获再处理。那么怎么才能将错误码返回给前端呢?原来是全局异常处理……
切面方法:
@Before(value = "AccessLimitPointcut()")
public void handleAccessLimit(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
RateLimiter annotation = AnnotationUtils.findAnnotation(method, RateLimiter.class);
int accessMaxTimes = annotation.count();
long timeOut = annotation.time();
TimeUnit timeUnit = annotation.timeUnit();
String key = annotation.key();
// 如果redis不存在或已经过期
Long expire = redisTemplate.opsForValue().getOperations().getExpire(key);
if (!redisTemplate.hasKey(key) || Objects.requireNonNull(expire).intValue() < 0) {
redisTemplate.opsForValue().set(key, 1, timeOut, timeUnit);
} else {
long increment = redisTemplate.opsForValue().increment(key).intValue();
if (increment > accessMaxTimes) {
throw new AIDocException("PA-COM-000001", "访问已经超过最大值: " + accessMaxTimes);
}
}
}
如果没有引入全局异常处理,那么异常会直接展示在控制台
如何实现:用@RestControllerAdvice和@ExceptionHandler注解在SpringBoot中实现全局异常处理
1、@RestControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。
2、@RestControllerAdvice 是组件注解,他使得其实现类能够被classpath扫描自动发现,如果应用是通过MVC命令空间或MVC Java编程方式配置,那么该特性默认是自动开启的。
@RestControllerAdvice
public class AIDocExceptionHandler {
private Logger logger = LoggerFactory.getLogger(AIDocExceptionHandler.class);
/**
* 处理自定义异常
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Map<String, Object> handleRRException(Exception e) {
Map<String, Object> map = new HashMap<>();
if (e instanceof AIDocException) {
map.put("code",((AIDocException) e).getCode());
map.put("msg", ((AIDocException) e).getMsg());
}else {
logger.error("【系统异常】{}", e);
map.put("code", ErrorConstants.INVOKE_FAIL);
map.put("msg","未知异常!");
}
return map;
}
}
其中AIDocException是自定义异常类,你可以根据你的需求编写自己的自定义异常类。
以上就实现了全局统一异常管理,是不是很简单?