197 lines
8.0 KiB
Markdown
197 lines
8.0 KiB
Markdown
## 任务名称: Restful接口回应数据的统一封装
|
||
### 目标
|
||
- 掌握Spring Boot框架的异常处理
|
||
|
||
### 预备知识
|
||
- java的异常机制
|
||
|
||
### 操作步骤
|
||
#### 1. 自定义异常的基类
|
||
|
||
实现一个项目的异常基类,设计为抽象类避免直接使用此类。基类继承自RuntimeException,并添加一个code属性,为每个异常类型分配一个唯一的code值。
|
||
|
||
自定义异常时定义一个基类可以带来多个好处,以下是一些主要优势:
|
||
|
||
> **代码复用**:基类可以包含所有自定义异常的通用属性和方法,减少了代码重复。
|
||
>
|
||
> **统一管理**:通过基类可以统一管理异常处理,比如定义一个通用的异常处理机制,简化异常的捕获和处理。
|
||
>
|
||
> **清晰的层次结构**:基类提供了一个清晰的异常层次结构,使得异常更加有组织,易于理解和使用。
|
||
>
|
||
> **维护方便**:当需要对异常进行修改或添加新特性时,只需在基类中进行一次修改,所有派生异常都会自动获得这些更改。
|
||
>
|
||
> **异常编码**:如你所提到的,基类可以包含一个错误码(code属性),为每个异常类型分配一个唯一值,这有助于快速识别和处理特定类型的异常。
|
||
>
|
||
> **信息丰富**:基类可以定义一些通用的构造函数,允许派生异常类在创建时提供额外的信息,如错误消息、原始异常等。
|
||
>
|
||
> **控制异常的传播**:基类可以决定异常是否应该被检查(checked)或不被检查(unchecked)。通过继承 `RuntimeException`,可以创建非检查型异常,这通常用于程序运行时错误,调用者不需要强制捕获。
|
||
|
||
|
||
```java
|
||
package com.lk.paopao.exception;
|
||
|
||
/**
|
||
* 定义一个基础异常类,用于封装业务异常信息。
|
||
* 这个类是 RuntimeException 的子类,意味着它是一个非检查(Unchecked)异常。
|
||
* 它添加了一个错误码(code)来详细描述异常的类型。
|
||
*/
|
||
public abstract class BaseException extends RuntimeException{
|
||
// 异常的错误码
|
||
private final int code;
|
||
|
||
/**
|
||
* 构造函数,用于创建一个带有错误码和消息的基础异常实例。
|
||
*
|
||
* @param code 异常的错误码,用于标识异常的类型。
|
||
* @param message 异常的详细信息,帮助理解异常的原因。
|
||
*/
|
||
public BaseException(int code, String message){
|
||
// 调用父类构造函数,将消息传递给父类,以初始化异常的详细信息。
|
||
super(message);
|
||
this.code = code;
|
||
}
|
||
|
||
/**
|
||
* 构造函数,用于创建一个带有错误码、消息和导致异常的原因的基础异常实例。
|
||
*
|
||
* @param code 异常的错误码,用于标识异常的类型。
|
||
* @param message 异常的详细信息,帮助理解异常的原因。
|
||
* @param cause 导致异常的原因,便于问题追踪和处理。
|
||
*/
|
||
public BaseException(int code, String message, Throwable cause) {
|
||
// 调用父类构造函数,将消息和原因传递给父类,以初始化异常的详细信息和原因。
|
||
super(message, cause);
|
||
this.code = code;
|
||
}
|
||
|
||
public int getCode() {
|
||
return code;
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
#### 2. 实现三个具体的自定义异常类
|
||
|
||
ResourceNotFoundException: 找不到资源,用于统一处理找不到资源的情况。
|
||
|
||
```java
|
||
package com.lk.paopao.exception;
|
||
|
||
public class ResourceNotFoundException extends BaseException{
|
||
|
||
public ResourceNotFoundException(String resourceName, String condition){
|
||
super(404, "根据条件:【"+condition+"】无法找到"+resourceName+"资源");
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
ResourceExistedException: 资源已存在,用于统一处理资源已存在的情况。
|
||
```java
|
||
package com.lk.paopao.exception;
|
||
|
||
public class ResourceExistedException extends BaseException{
|
||
public ResourceExistedException(String resourceName, String condition){
|
||
super(409, "根据条件:【"+condition+"】可找到"+resourceName+"资源");
|
||
}
|
||
}
|
||
```
|
||
|
||
AuthFailedException: 认证失败,用于统一处理认证失败的情况。
|
||
```java
|
||
package com.lk.paopao.exception;
|
||
|
||
public class AuthFailedException extends BaseException{
|
||
public AuthFailedException(String message) {
|
||
super(401, message);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3. 实现异常的统一处理
|
||
|
||
在Spring框架中,`@ControllerAdvice` 是一个核心的类级别的注解,用于定义一个全局异常处理器。当一个Spring Boot应用中的控制器(即一个带有`@RestController`或`@Controller`注解的类)抛出异常时,Spring会检查所有的`@ControllerAdvice`注解的类,寻找匹配的异常处理器。
|
||
|
||
以下是`@ControllerAdvice`注解的一些关键点:
|
||
|
||
1. **全局异常处理**:`@ControllerAdvice` 注解的类可以包含一个或多个 `@ExceptionHandler` 方法,这些方法可以捕获并处理控制器层抛出的异常。
|
||
|
||
2. **注解方法**:在`@ControllerAdvice`类中,通过使用`@ExceptionHandler`注解的方法可以指定处理特定类型的异常。方法的参数可以是异常类型或者是`Throwable`类型。
|
||
|
||
3. **响应体**:`@ControllerAdvice`类中的方法通常使用`@ResponseBody`注解,这表明方法的返回值将直接作为HTTP响应的正文返回给客户端。
|
||
|
||
4. **日志记录**:在异常处理方法中,通常会记录异常信息,这有助于开发人员调试和监控应用。
|
||
|
||
5. **统一响应格式**:`@ControllerAdvice` 允许你定义一个统一的响应格式,无论哪种异常发生,客户端都会收到相同结构的响应,这有助于客户端统一处理不同异常情况。
|
||
|
||
6. **顺序**:如果有多个`@ControllerAdvice`注解的类,它们可以通过`@Order`注解或`Ordered`接口来指定处理顺序。
|
||
|
||
7. **作用域**:`@ControllerAdvice`注解的类可以是单例的(singleton),也可以是请求作用域的(request),具体取决于异常处理器的需要。
|
||
|
||
```java
|
||
package com.lk.paopao.exception;
|
||
|
||
import com.lk.paopao.dto.rest.response.Result;
|
||
import com.lk.paopao.dto.rest.response.ResultUtil;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||
import org.springframework.web.bind.annotation.ResponseBody;
|
||
|
||
/**
|
||
* 全局异常处理器,负责处理Controller层抛出的异常,提供统一的异常响应格式。
|
||
*/
|
||
|
||
@ControllerAdvice
|
||
public class GlobalExceptionHandler {
|
||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||
|
||
/**
|
||
* 处理自定义异常BaseException,返回相应的错误结果。
|
||
*
|
||
* @param ex 自定义异常BaseException实例
|
||
* @return 返回封装了错误信息的Result对象
|
||
*/
|
||
@ExceptionHandler(BaseException.class)
|
||
@ResponseBody
|
||
public Result handleBaseException(BaseException ex) {
|
||
// 记录未预期异常信息
|
||
log.info(ex.getMessage(),ex);
|
||
return ResultUtil.fail(ex.getCode(),ex.getMessage());
|
||
}
|
||
|
||
/**
|
||
* 处理未预期的异常,返回通用错误结果。
|
||
*
|
||
* @param ex 异常实例
|
||
* @return 返回封装了错误信息的Result对象
|
||
*/
|
||
@ExceptionHandler(Exception.class)
|
||
@ResponseBody
|
||
public Result handleUnexpectedException(Exception ex) {
|
||
// 记录未预期异常信息
|
||
log.warn(ex.getMessage(),ex);
|
||
// 返回通用错误结果, 500表示服务器内部错误
|
||
return ResultUtil.fail(500,ex.getMessage());
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
### 技术/工具需求:
|
||
- [列出完成任务所需的技术栈、工具、软件版本等。]
|
||
|
||
### 成功标准:
|
||
- [明确完成任务的评判标准,如代码功能实现、性能指标、测试通过条件等。]
|
||
|
||
### 扩展学习(可选):
|
||
- [提供一些额外学习资源或挑战性任务,鼓励学有余力的学生进一步探索。]
|
||
|
||
### 评估与反馈:
|
||
- [说明如何提交作业、代码审查的标准、或任何反馈收集机制。]
|
||
|
||
### 时间估算:
|
||
- [给出预计完成该任务所需的时间,帮助学生合理安排学习计划。] |