ControllerAdvice 有条件地处理异常

Posted

技术标签:

【中文标题】ControllerAdvice 有条件地处理异常【英文标题】:ControllerAdvice conditionally handle exception 【发布时间】:2020-12-02 05:46:56 【问题描述】:

我有一个控制器建议来处理我的 REST 控制器中的异常行为,我遇到了一种情况,我必须有条件地处理具有特定消息(重复键的消息)的 SQLIntegrityConstraintViolationException,返回 409 ,让其他的由默认处理程序处理(返回500 错误代码)。

我正在考虑两种可能的方法来实现这一目标:

    根据我的情况在 else 分支上抛出一个新的裸机 Exception,因此处理由 Spring 完成。 显式调用通用异常处理程序(例如从我的 else 分支内部调用 return handleGeneralException(exception))。

我有一种“正确”的方式可以将我的ControllerAdvice 中的一小部分异常传递给另一个处理程序,而不是“原始”处理程序?

编辑 1: 我想在我的 ControllerAdvice 中做这样的事情:

if (exception.getMessage.contains("something")) 
    // handle exception
 else 
    // pass to other handler

【问题讨论】:

【参考方案1】:

有一个自定义异常类,然后当您抛出 SQLIntegrityConstraintViolationException 时,将其包装在您的自定义异常类中,其中包含您希望在控制器建议中访问的任何附加字段。处理控制器建议类中的自定义异常。

@ControllerAdvice
public class CustomExceptionHandler 

    @ExceptionHandler(YourCustomException.class)
    public final ResponseEntity<ExceptionResponse> handleNotFoundException(YourCustomExceptionex,
            WebRequest request) 
        ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(),
                request.getDescription(false), HttpStatus.NOT_ACCEPTABLE.getReasonPhrase());
        return new ResponseEntity<>(exceptionResponse, HttpStatus.CONFLICT);
    


虽然在代码中使用 try catch 块来处理此异常,但如果您使用 Spring Data JPA,请确保处理 DataIntegrityViolationException 而不是 SQLIntegrityConstraintViolationException。因此,如果您使用的是 Spring Data Jpa,那么:

try 
    anyRepository.save(new YourModel(..));
 catch (DataIntegrityViolationException e) 
    System.out.println("history already exist");in res
    throw New YourCustomException("additional msg if you need it ", e);

【讨论】:

问题是这是一个运行时异常——我可以在哪里处理和包装它?有在控制器的建议?我的意思是,我从来没有在我的代码中处理它 为您的代码创建一个 try catch 块,并在 catch 块句柄 SQLIntegrityConstraintViolationException 中重新抛出它作为您的自定义异常类。 我的问题是我应该在哪里有那个 try-catch 块。请看我的编辑 @AvramPop 尝试捕获将在运行时抛出此异常的代码块。【参考方案2】:

以下代码将在ControllerAdbvice中捕获异常SQLIntegrityConstraintViolationException的错误信息,无需在代码中处理

@ControllerAdvice
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler 
@ExceptionHandler(value = DataIntegrityViolationException.class)
public ResponseEntity<ExceptionResponse> dataIntegrityViolationExceptionHandler(Exception ex) 
ExceptionResponse response = new ExceptionResponse();
    Throwable throwable = ex.getCause();
    while (throwable != null) 
        if (throwable instanceof SQLIntegrityConstraintViolationException) 
            String errorMessage = throwable.getMessage();
            response.setErrors(new ArrayList<>(Arrays.asList(errorMessage)));
        
        throwable = throwable.getCause();
           
    return new ResponseEntity<Object>(response, HttpStatus.CONFLICT);


【讨论】:

你可能没有理解这个问题...我想做一些类似 if(throwable.getCause().equals("somecause")) return new ResponseEntity; else (见我的编辑)

以上是关于ControllerAdvice 有条件地处理异常的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot @ControllerAdvice 异常处理程序未触发

@ControllerAdvice自定义异常统一处理

@ControllerAdvice

如何让一个由 ControllerAdvice 注释的类来处理不同类型的异常?

@ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常

@ControllerAdvice(处理全局异常)