在 Spring Boot 中，错误处理可以通过多种方式实现，从全局异常处理到自定义错误响应，以下是完整的错误处理方案：

---

**1. 全局异常处理（推荐）**
使用 `@ControllerAdvice` + `@ExceptionHandler` 统一捕获异常，返回结构化错误信息。

**(1) 定义全局异常处理器**
```java
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    // 处理自定义业务异常
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
        ErrorResponse error = new ErrorResponse(
            ex.getErrorCode(),
            ex.getMessage(),
            System.currentTimeMillis()
        );
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }

    // 处理所有未捕获的异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) {
        ErrorResponse error = new ErrorResponse(
            "SERVER_ERROR",
            "Internal server error",
            System.currentTimeMillis()
        );
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

// 自定义错误响应体
class ErrorResponse {
    private String code;
    private String message;
    private long timestamp;
    // 构造方法/getters/setters
}
```

**(2) 抛出自定义异常**
```java
// 自定义业务异常
public class BusinessException extends RuntimeException {
    private String errorCode;

    public BusinessException(String errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }
    // getter
}

// 在Controller中使用
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
    if (id == 0) {
        throw new BusinessException("INVALID_ID", "ID cannot be zero");
    }
    return userService.findById(id);
}
```

---

**2. HTTP 状态码控制**
通过 `ResponseEntity` 或注解直接指定状态码：

**(1) 使用 `ResponseEntity`**
```java
@GetMapping("/resource/{id}")
public ResponseEntity<?> getResource(@PathVariable Long id) {
    return resourceRepository.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
}
```

**(2) 使用 `@ResponseStatus`**
```java
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}
```

---

**3. 自定义错误页面（适用于传统Web应用）**
**(1) 静态错误页面**
在 `src/main/resources/static/error/` 下添加：
• `404.html`（Not Found）

• `500.html`（Server Error）


**(2) 动态模板错误页（Thymeleaf/FreeMarker）**
```java
@Controller
public class CustomErrorController implements ErrorController {

    @RequestMapping("/error")
    public String handleError(HttpServletRequest request) {
        Integer status = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (status == 404) {
            return "error-404";
        }
        return "error-default";
    }
}
```

---

**4. 验证错误处理（@Valid）**
自动处理 `@Valid` 参数校验失败的情况：
```java
@PostMapping("/users")
public ResponseEntity<?> createUser(@Valid @RequestBody User user) {
    // 正常逻辑
}

// 在GlobalExceptionHandler中添加
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
    List<String> errors = ex.getBindingResult()
            .getFieldErrors()
            .stream()
            .map(FieldError::getDefaultMessage)
            .collect(Collectors.toList());

    ErrorResponse error = new ErrorResponse(
        "VALIDATION_FAILED",
        String.join("; ", errors),
        System.currentTimeMillis()
    );
    return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
```

---

**5. 异常日志记录**
结合 `@Slf4j` 记录异常：
```java
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) {
        log.error("Unhandled exception: ", ex); // 记录完整堆栈
        ErrorResponse error = new ErrorResponse(/* ... */);
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
```

---

**6. 特定Controller的异常处理**
```java
@RestController
public class UserController {

    @ExceptionHandler(UserNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse handleUserNotFound(UserNotFoundException ex) {
        return new ErrorResponse(/* ... */);
    }
}
```

---

**7. 禁用默认的Whitelabel错误页**
在 `application.properties` 中：
```properties
server.error.whitelabel.enabled=false
```

---

**最佳实践总结**
1. 分层处理：
   • 业务异常：自定义 `BusinessException`

   • 系统异常：全局捕获 `Exception`

   • 校验异常：自动处理 `MethodArgumentNotValidException`


2. 统一响应格式：
   ```json
   {
     "code": "INVALID_ID",
     "message": "ID cannot be zero",
     "timestamp": 1630000000000,
     "path": "/api/users/0"
   }
   ```

3. 生产环境安全：
   • 避免暴露堆栈信息（可通过 `server.error.include-stacktrace=never` 关闭）

   • 敏感错误信息过滤


通过以上方式，Spring Boot 的错误处理可以做到与 Laravel 的 `Handler.php` 类似的集中管理效果。