全局异常处理
title: 全局异常处理
cover: 'https://i.loli.net/2021/10/14/921G8ZSv4nHAXti.png'
secret: false
categories:
- code
tags: - 异常
- AOP
- '@ControllerAdvice'
abbrlink: 33238
date: 2021-10-14 01:15:03
password:
message:
前言
在Java web 项目中,我们经常需要自己去实现一些异常处理的代码。随着Spring框架的不断升级,也给我们带来了更多的选择。下面说一下可行性比较好的两个方式吧:
- 采用 Spring AOP 方式实现
- 采用 Spring3.2之后提供的 @ControllerAdvice 注解 和 @ExceptionHandler 实现
关于 Controller 层异常的处理
如果你是想处理关于Controller层的异常(不仅限于是controller层自身主动抛出/catch的异常,只要是最终由controller层抛出的异常都可以使用 @ControllerAdvice 方式),那么以上两种方式均可由你选择。
@ControllerAdvice + @ExceptionHandler 方式#
见名知意,@ControllerAdvice 是对于 使用@Controller的建议,那么凡是使用了@RequestMapping的地方的异常均可该种方式处理。
下面我以一个demo来说明一下,如何使用吧。
controller
层
@RestController
public class UserController {
@RequestMapping(value = "/update", method = RequestMethod.POST)
public R update(@RequestBody User user){
userService.update(user);
return R.success(null);
}
}
注意:在调用的service中,我手动模拟抛出了一个异常,如下所示:
@Service
public class UserServiceImpl implements UserService {
@Override
public void update(User user) {
userMapper.update(user);
throw new RuntimeException("运行时易出错");
}
}
关于类似这种controller层的异常我们就可以构造一个全局controller异常的处理工具,如下:
// 使用 @ControllerAdvice 方式来实现对 @RequestMapping 的异常拦截 // 缺点很明显,是对于 controller 的建议,只能对controller起作用
@ControllerAdvice
public class ControllerException {
private static final Logger log = LoggerFactory.getLogger(ControllerException.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String, String> getMsg(HttpServletRequest request, HttpServletResponse response, Exception e){
log.error("该服务可能出错了");
return Collections.singletonMap("msg", "服务出错");
}
}
这样当调用 /update
接口时,service层会报错,从而传递到controller层,从而被 ControllerException 异常处理类拦截,就可以在这里解决了,可以down下代码,自行测试一下,这里不做演示了。
这种方式的缺点很明显:只能处理 controller 层抛出的异常,对例如 Interceptor(拦截器)层的异常、定时任务中的异常、异步方法中的异常,不会进行处理。
Spring AOP 动态代理方式#
上面的controller层和service代码不用作任何修改。只需要再新增一个异常处理类即可。
package com.example.study_source.transaction.exception;
// 使用 aop 来全局拦截异常,可以作用于你自定义的任何包路径下 // 相比 @ControllerAdvice 有优势
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
public class AOPGlobalException {
@Pointcut("execution(* com.example.study_source.transaction..*.*(..))")
public void point1(){
}
@AfterReturning(pointcut = "point1()")
public void afterReturn(JoinPoint joinPoint){
log.error("全局捕获到异常了..............");
//纪录错误信息
// todo 想要执行的操作
}
}
如上方式不仅可以实现controller层的异常处理,只要符合切点包的定义的方法,都可以拦截。
本文参考于segmentfault,特此表示感谢!
作者:Lorem Moon
出处:https://www.cnblogs.com/hello-cnblogs/p/16398851.html
版权:本作品采用「 CC BY-NC-SA 4.0 」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix