springboot全局异常处理器处理顺序问题
在使用异常处理器时,代码
package com.ecode.handler;
import com.ecode.constant.MessageConstant;
import com.ecode.exception.BaseException;
import com.ecode.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.sql.SQLException;
/**
* 全局异常处理器,处理项目中抛出的业务异常
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 捕获业务异常
* @param ex
* @return
*/
@ExceptionHandler
public Result exceptionHandler(BaseException ex){
log.error("业务异常:{}", ex.getMessage());
return Result.error(ex.getMessage());
}
/**
* @param ex 数据库异常
* @return 后端统一返回结果
*/
@ExceptionHandler
public Result exceptionHandler(SQLException ex){
String message = ex.getMessage();
log.error("数据库异常:{}",message);
if (message.contains("Duplicate entry")){
String username = message.split(" ")[2];
return Result.error(username + MessageConstant.ALREADY_EXISTS);
}else {
return Result.error(MessageConstant.SQL_UNKNOWN_ERROR);
}
}
@ExceptionHandler
public Result exceptionHandler(Exception ex){
log.error("服务器异常:{}",ex.getMessage());
return Result.error("服务器异常");
}
}
当出现数据库异常时,返回
2024-10-05 22:56:13.798 ERROR 26216 --- [nio-8080-exec-4] c.ecode.handler.GlobalExceptionHandler : 服务器异常:
### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'xu*****@foxmail.com' for key 'user.邮箱'
### The error may exist in com/ecode/mapper/UserMapper.java (best guess)
### The error may involve com.ecode.mapper.UserMapper.insert-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO user ( username, password, email, status, name, profile_picture, score, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )
### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'xu****@foxmail.com' for key 'user.邮箱'
; Duplicate entry 'xu*****@foxmail.com' for key 'user.邮箱'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'xu*******@foxmail.com' for key 'user.邮箱'
按理说越精确优先级越高,SQLIntegrityConstraintViolationException继承SQLException,为什么返回的却是被Exception异常捕获?求解答
我尝试注释Exception异常捕获,此时异常能被SQLException捕获
你的代码就是错误的,SQLException
及其子类SQLIntegrityConstraintViolationException
是个检查时异常,你在运行时捕获,是捕获不到的,这个函数永远不会执行的
/**
* @param ex 数据库异常
* @return 后端统一返回结果
*/
@ExceptionHandler
public Result exceptionHandler(SQLException ex){
String message = ex.getMessage();
log.error("数据库异常:{}",message);
if (message.contains("Duplicate entry")){
String username = message.split(" ")[2];
return Result.error(username + MessageConstant.ALREADY_EXISTS);
}else {
return Result.error(MessageConstant.SQL_UNKNOWN_ERROR);
}
}
你在日志中看到SQLIntegrityConstraintViolationException
错误,是MyBatis
输出时,从MyBatisSystemException.getCause()
得到的,实际的异常在返回到控制层时,已经经过了spring-jdbc
和MyBatis
的包装处理,你可以改成这样看看具体的异常类型
@ExceptionHandler
public Result exceptionHandler(Exception ex){
log.error("服务器{}异常:{}",ex.getClass(),ex.getMessage());
return Result.error("服务器异常");
}
在Spring Boot中,全局异常处理器的处理顺序主要基于几个因素,但最关键的是方法上的@ExceptionHandler
注解指定的异常类型以及这些异常类型之间的继承关系。当你定义了多个@ExceptionHandler
方法用于捕获不同类型的异常时,Spring会根据异常的具体类型以及你定义的捕获顺序(实际上是方法的定义顺序,但更准确地说是类型匹配度)来决定调用哪个处理器。
在你的例子中,虽然SQLIntegrityConstraintViolationException
继承自SQLException
,但Spring在决定调用哪个@ExceptionHandler
方法时,并不是简单地按照继承关系从基类到子类进行匹配,而是首先查找与异常类型最精确匹配的方法。然而,由于Java的类型擦除和Spring的异常解析机制,有时候可能会出现一些不太直观的行为。
然而,在大多数情况下,如果SQLIntegrityConstraintViolationException
被抛出,并且你有一个专门捕获SQLException
的方法,Spring会优先调用这个更具体的方法(即捕获SQLException
的方法),因为它更精确地匹配了异常的类型。但在你的情况下,如果SQLIntegrityConstraintViolationException
被捕获为Exception
而不是SQLException
,这通常意味着有其他因素在起作用。
这里有几个可能的原因:
SQLIntegrityConstraintViolationException
可能被另一个异常包装(比如RuntimeException
或Exception
),这取决于你的应用程序和Spring Boot的配置。如果它被包装了,那么它可能不再直接匹配SQLException
处理器。@ExceptionHandler
方法时遇到某种签名冲突(尽管这在这个案例中不太可能),它可能无法正确选择方法。@ExceptionHandler
干扰:虽然你的示例中没有显示,但如果你的应用中有其他@ExceptionHandler
定义在其他类或同一个类中,它们也可能影响异常处理的顺序。@ExceptionHandler
方法的异常类型。在你的情况下,当你注释掉捕获Exception
的方法时,SQLException
的方法能够正确捕获SQLIntegrityConstraintViolationException
,这表明SQLIntegrityConstraintViolationException
本身没有被包装成另一个类型的异常,并且没有其他@ExceptionHandler
干扰。这进一步支持了Spring通常会根据异常类型的精确匹配来选择处理器的观点。
因此,如果你的应用程序在没有注释掉捕获Exception
的方法时不能按预期工作,建议检查以下几点:
@ExceptionHandler
方法干扰。SQLIntegrityConstraintViolationException
是否确实没有被包装成另一个类型的异常。@ExceptionHandler
方法的异常对象的确切类型。本文向大家介绍springboot全局异常处理详解,包括了springboot全局异常处理详解的使用技巧和注意事项,需要的朋友参考一下 一、单个controller范围的异常处理 说明: 在controller中加入被@ExceptionHandler修饰的类即可(在该注解中指定该方法需要处理的那些异常类) 该异常处理方法只在当前的controller中起作用 二、全部controller范围内起
问题内容: 有没有一种方法可以在Java中创建全局异常处理程序。我想这样使用: 处理程序可能无法捕获在主体中引发的异常。 马丁 问题答案: 使用Thread.setDefaultUncaughtExceptionHandler。有关示例,请参见Rod Hilton的“ Global Exception Handling ”博客文章。
统一错误处理 文档:https://eggjs.org/zh-cn/tutorials/restful.html 自定义一个异常基类 // app / exceptions / http_exceptions.js class HttpExceptions extends Error { constructor(msg='服务器异常', code=1, httpCode=400) {
本文向大家介绍springboot全局异常处理代码实例,包括了springboot全局异常处理代码实例的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了springboot全局异常处理代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言: 开发中异常的处理必不可少,常用的就是 throw 和 try catch,这样一个项目到最
Middleware: 全局异常处理 我们在岩浆的实例其实已经注意到了,compose 的连接方式,让我们有能力精确控制异常。 Koa中间件最终行为强依赖注册顺序,比如我们这里要引入的异常处理,必须在业务逻辑中间件前注册,才能捕获后续中间件中未捕获异常,回想一下我们的调度器实现的异常传递流程。 <?php class ExceptionHandler implements Middleware
一.问题前置信息 1.1项目配置了token拦截器只重写了preHandle()方法 1.2全局异常处理器只处理了两个token相关的自定义异常 1.3登录接口配置了白名单,请求不会经过拦截器 二.问题描述:页面调用登录接口,内部异常流转到了拦截器的preHandle()方法内? 三.问题详细描述 接口内部调用了org.mybatis.spring包下的SqlSessionTemplate类的se