Thymeleaf场景下Controller无法捕获OTPException问题求助
问题场景
在Controller方法中通过try-catch尝试捕获OTPException,但当service抛出该异常时,catch块无法命中;即使捕获Exception后判断e instanceof OTPException也不成立,同时存在标注了@Order(Ordered.HIGHEST_PRECEDENCE)的全局异常处理器处理OTPException。
核心原因
你代码中调用了service.generate(...).get(),这里的get()属于Future接口的同步阻塞方法,它会将任务执行过程中抛出的原始异常**包装为ExecutionException**抛出。也就是说,Controller方法实际接收到的异常是ExecutionException,而非直接的OTPException——这就是catch(OTPException)无法触发、instanceof判断不成立的根本原因。
解决方案
方案1:捕获包装异常,提取原始异常
修改Controller的try-catch逻辑,先捕获ExecutionException,再从其内部取出原始异常进行判断:
@GetMapping public String popup() { try { service.generate(new ExistOTPValidQuery().requestNumber("test"), Boolean.class).get(); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof OTPException) { return "user"; } // 处理其他类型异常 throw new RuntimeException(cause); } catch (InterruptedException e) { // 恢复线程中断状态 Thread.currentThread().interrupt(); return "error"; } return "error"; }
注意:Future.get()还会抛出InterruptedException,需额外捕获并处理,避免线程中断状态丢失。
方案2:改用异步回调(推荐)
如果service是异步方法,建议用CompletableFuture替代普通Future,通过回调处理异常,避免同步阻塞和异常包装:
@GetMapping public String popup() { service.generate(new ExistOTPValidQuery().requestNumber("test"), Boolean.class) .whenComplete((result, ex) -> { if (ex != null) { if (ex.getCause() instanceof OTPException) { // 处理OTP异常逻辑 } else { // 处理其他异常 } } else { // 处理正常结果 } }); return "user"; // 根据业务调整返回值 }
方案3:扩展全局异常处理器(可选)
如果希望全局异常处理器能处理包装后的异常,可新增对ExecutionException的处理逻辑,提取内部的OTPException:
@ExceptionHandler(ExecutionException.class) public ResponseEntity<Object> executionException(ExecutionException ex) { Throwable cause = ex.getCause(); if (cause instanceof OTPException) { return otpException((OTPException) cause); } // 处理其他包装异常 return buildResponseEntity(new ApiError(CustomHttpStatus.ERROR, new Date(), ex.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR); }
内容的提问来源于stack exchange,提问作者Aymen Kanzari

