☰
异常处理通关篇
2026/10/13 3:05:13 网站建设 项目流程

异常是什么

  • 异常是一个对象,封装了出了什么错,错在哪一行
// 一个异常对象至少包含这些信息:ArithmeticExceptione=newArithmeticException("/ by zero");e.getMessage();// "/ by zero" —— 错误描述e.getStackTrace();// 堆栈信息 —— 记录了异常在哪些类的哪些方法里传播过// 比如:at com.lucky.service.LotteryDrawService.doDraw(LotteryDrawService.java:62)// at com.lucky.service.impl.LotteryServiceImpl.draw(LotteryServiceImpl.java:45)// at com.lucky.controller.LotteryController.draw(LotteryController.java:29

异常产生的类型

JVM自动抛出

// 例子1:空指针Stringname=null;name.length();// JVM 自动抛 NullPointerException// 例子2:数组越界int[]arr=newint[3];arr[5]=1;// JVM 自动抛 ArrayIndexOutOfBoundsException// 例子3:类型转换错误Objectobj="hello";Integernum=(Integer)obj;// JVM 自动抛 ClassCastException

自己手动throw

if(round.getStatus()!=null&&round.getStatus()==1){thrownewBusinessException("该轮次已完成抽奖");// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 手动创建 BusinessException 对象,用 throw 抛出// 这行之后的代码不会执行,方法立即"中断"}System.out.println("这行永远不会执行(如果上面抛了异常)");
  • 立即终止当前方法,后面方法不跑了
  • 给异常这个对象抛给方法上层

异常的传播

  • 一直往上面传播,直到有人接住他,就是try——catch

异常的捕获和处理

try——catch处理

try{// 可能出异常的代码intresult=10/0;}catch(ArithmeticExceptione){// 捕获到异常,在这里处理System.out.println("除数不能为0: "+e.getMessage());}// 异常被 catch 住了,不会继续向上抛,程序继续往下执行

全局异常处理

  • 不在每个方法里写 try-catch,而是用 @RestControllerAdvice 声明一个全局处理器,Spring 会自动把所有 Controller 抛出的异常交给它处理
  • @RestControllerAdvice 的本质是 Spring AOP 环绕通知——它在所有 Controller 方法外面包了一层"虚拟的 try-catch":
// 你可以理解为 Spring 自动帮你做了这件事(伪代码):try{// 执行 Controller 方法Objectresult=lotteryController.draw(roundId);returnresult;}catch(BusinessExceptione){// 匹配到 @ExceptionHandler(BusinessException.class)returnglobalExceptionHandler.handleBusinessException(e);}catch(MethodArgumentNotValidExceptione){returnglobalExceptionHandler.handleValidationException(e);}catch(RuntimeExceptione){returnglobalExceptionHandler.handleRuntimeException(e);}catch(Exceptione){returnglobalExceptionHandler.handleException(e);}

处理完成后返回给前端

@ExceptionHandler(BusinessException.class)publicResult<Void>handleBusinessException(BusinessExceptione){// 第1步:打日志(warn 级别,因为是预期内的业务异常,不是系统崩溃)log.warn("业务异常: {}",e.getMessage());// 控制台输出:业务异常: 该轮次已完成抽奖// 第2步:构造统一返回体returnResult.error(e.getCode(),e.getMessage());// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// e.getCode() = 500(BusinessException 默认 code)// e.getMessage() = "该轮次已完成抽奖"// 返回 Result{code:500, message:"该轮次已完成抽奖", data:null}}// 第3步:Spring 把 Result 对象序列化成 JSON// 第4步:通过 HTTP 响应返回给前端// 前端收到的 HTTP 响应:// HTTP/1.1 200 OK// Content-Type: application/json// Body: {"code":500,"message":"该轮次已完成抽奖","data":null}
  • 注意一个细节:虽然业务失败了,但 HTTP 状态码仍然是 200(因为 @ExceptionHandler(BusinessException.class) 没有加 @ResponseStatus )。失败信息通过 JSON body 里的 code 字段传递。这是前后端分离项目的常见做法——HTTP 状态码只表示"请求有没有到达服务器",业务成败由 body 里的 code 决定
  • 对比参数校验异常,它加了 @ResponseStatus(HttpStatus.BAD_REQUEST) ,所以 HTTP 状态码是 400
@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)// ← HTTP 状态码 400publicResult<Void>handleValidationException(...){...}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询