目录
在用户体验一个产品的时,如果产品出现问题进行报错例如:400,404,403,500这种错误,给用户报这个这种异常这就很过分了用户是不认识它的,无疑会对用户造成很不好的用户体验,但是难免会出现异常,这里进行统一的异常抓取和处理给用户友好提示
举个例子:在老师服务中,我们添加讲师时时间不按照格式【yyyy-MM-dd HH:mm:ss】进行添加,
演示程序报错:
在上面已经演示出来了程序的报错然后我们进行try catch方式解决
这个问题是在老师服务中的添加老师controller中出现,我对controller中添加老师这个方法进行异常try ...catch
- @ApiOperation("添加老师")
- @PostMapping
- public BaseResult addteacher(@RequestBody EduTeacher eduTeacher){
- boolean flag = false;
- try {
- flag = eduTeacherService.save(eduTeacher);
- throw new RuntimeException("报错了");
- } catch (Exception e) {
- return BaseResult.error("系统错误");
- }
-
- }
这里异常就成功抓取了
但是如果每个方法的异常都用try一下成本太大还很麻烦。我们可以通过第二种方式进行全局处理
spring mvc 提供 @RestControllerAdvice注解
@ControllerAdvice
是对Controller进行增强的注解,主要作用有三个:
全局异常处理(*)
全局数据绑定
全局数据预处理
在通用模块中:zx_common_practise模块中配置异常处理类
注意:要想这个配置类成功加载,必须让spring启动类扫描到
这样TeacherApplication就可以成功扫描到所写的exception包中
- @RestControllerAdvice // 对Controller进行增强也就是说进行处理,
- public class GlobalExceptionHandler {
- @ExceptionHandler(Exception.class)//拦截什么异常
- public BaseResult error(Exception e){
- e.printStackTrace();
- return BaseResult.error("系统错误");
- }
看一下效果:
模拟一个除0异常,在查询所有老师的方法中模拟一个除0异常
- @GetMapping
- @ApiOperation("查询所有老师")
- public BaseResult findAll(){
-
- List
list = eduTeacherService.list(); - //添加一个除0异常
- int exception = 1/0;
- return BaseResult.ok("查询成功",list);
- }
swagger测试一下:这里成功抓取到系统错误
注意:@RestControllerAdvice 和@controllerAdvice与@ResponseBody含义一致
这就相当于在controller类中的每个方法上面都加入了一个try...catch
以后开发中异常被处理之后就看不到了。两种方式获取异常信息
方案一:开发节点简单处理,将异常打印到控制台中
方案二:生成环境。使用【日志log】记录异常
特殊异常处理配置是什么意思呢?简单来说就是更精准处理异常
下图中在controller方法中try...catch一下异常,和统一配置异常中的Exception是同一个异常也是最大的异常,下左图中我们都知道异常可以catch多个异常,精准的更仔细,像Exception是最大异常我们可以将异常抓取的更精准一些!
在异常配置类中进行精准异常的抓取和处理,下面还是演示除0异常
可以看到除0异常是:ArithmeticException异常,专程在异常处理类中进行抓取这个异常进行精准处理
像上面全局统一异常处理和特殊异常处理已经可以处理大部分常见问题
为什么会有自定义异常?并且自定义异常在以后开发中还是占大部分
举个例子吧:
假如写一个添加用户的功能,方法实现在Serive中,添加成功或者失败可能会返回一个布尔值true、false,这都是正常的逻辑。
现在有个复杂的添加用户,老板添加前想让你先判断用户名是否存在或者说密码性别什么的,进行一波校验,那校验完成那就不一定是true/false,可能返回字符串,可能返回对象,那这样的话异常就起到了作用,因为异常可以携带信息,在Service层中可以校验完之后可以直接抛出一个异常,咱们到controller层中抓取异常获取到信息,这样也完成了校验判断的处理!
到Controller层中try的话每个方法都try一下也显然很多余,这样就全局异常处理
在Service里面抛出自定义异常到异常处理里面我应该怎么去选型
自定义异常:Exception编译时异常,RuntimeException运行时异常
在大部分情况下还是使用运行时异常,因为编译时异常会在方法上面声明,每一个调用者都需要进行处理。麻烦了!
运行时异常,try的时候你不知道抓取的时候系统自己产生的异常还是自己自定义的异常,因为运行时异常很多包括的范围也很广,根本就不好区分开来到底是自己的定义的Runtime还是系统产的Runtime,那怎么办?
解决我们可以进行继承Runtime异常用它的子类,用子类来抛出自己的自定义异常,就很好的解决
代码实例
在zx_common_practise中创建自定义EduException的异常类
测试:在业务中需要的位置抛出EduException,举例子在查询列表中出错:
- @GetMapping
- @ApiOperation("查询所有老师")
- public BaseResult findAll(){
- if (true){
- // throw new RuntimeException("我就是运行时异常");
- // 如果按照这种进行抛出压根不知道是自定义的异常抛出还是系统的运行时异常抛出
- throw new EduException("我是自定义异常");
- }
- List
list = eduTeacherService.list(); - return BaseResult.ok("查询成功",list);
- }
在 GlobalExceptionHandler类中添加自定义处理方法
- @ExceptionHandler(EduException.class)
- public BaseResult error(EduException e){
- e.printStackTrace();
- return BaseResult.error(e.getMessage());
- }
这个工具类是干嘛的呢?
在上文中抛出自定义异常都需要new 一个新的异常:如上图
我们把这new异常的过程提取到一个工具类中,这样就不需要每次再重新进行创建
直接调用工具类中的方法
工具类:源码
- public class ExceptionUtils {
- /**
- * 抛出异常
- * @param message
- */
- public static void cast(String message) {
- throw new EduException(message);
- }
- }