本文目录导读:

我来为您提供一个完整的Spring Boot全局异常处理案例,包含常见的异常处理场景。
项目依赖配置
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
统一响应结果封装
// Result.java
import lombok.Data;
import java.io.Serializable;
@Data
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
private Integer code;
private String message;
private T data;
private long timestamp = System.currentTimeMillis();
public Result() {}
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
public static <T> Result<T> success(String message, T data) {
return new Result<>(200, message, data);
}
public static <T> Result<T> error(Integer code, String message) {
return new Result<>(code, message, null);
}
public static <T> Result<T> error(Integer code, String message, T data) {
return new Result<>(code, message, data);
}
}
// ResultCode.java 状态码枚举
public enum ResultCode {
SUCCESS(200, "操作成功"),
BAD_REQUEST(400, "请求参数错误"),
UNAUTHORIZED(401, "未认证"),
FORBIDDEN(403, "无权限"),
NOT_FOUND(404, "资源不存在"),
INTERNAL_SERVER_ERROR(500, "系统内部错误"),
SERVICE_UNAVAILABLE(503, "服务不可用");
private final Integer code;
private final String message;
ResultCode(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
自定义业务异常
// BusinessException.java
import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
private final Integer code;
private final String message;
public BusinessException(String message) {
super(message);
this.code = ResultCode.INTERNAL_SERVER_ERROR.getCode();
this.message = message;
}
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
public BusinessException(ResultCode resultCode) {
super(resultCode.getMessage());
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
}
public BusinessException(ResultCode resultCode, String message) {
super(message);
this.code = resultCode.getCode();
this.message = message;
}
}
全局异常处理器(核心类)
// GlobalExceptionHandler.java
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.resource.NoResourceFoundException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.stream.Collectors;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理业务异常
*/
@ExceptionHandler(BusinessException.class)
public ResponseEntity<Result<Object>> handleBusinessException(BusinessException e, WebRequest request) {
log.error("业务异常: {}", e.getMessage());
log.error("请求路径: {}", request.getDescription(false));
return ResponseEntity
.status(HttpStatus.OK)
.body(Result.error(e.getCode(), e.getMessage()));
}
/**
* 处理参数校验异常(@RequestBody)
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Result<Object>> handleMethodArgumentNotValid(MethodArgumentNotValidException e) {
String message = e.getBindingResult()
.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining("; "));
log.warn("参数校验失败: {}", message);
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(Result.error(ResultCode.BAD_REQUEST.getCode(), message));
}
/**
* 处理参数绑定异常(表单提交)
*/
@ExceptionHandler(BindException.class)
public ResponseEntity<Result<Object>> handleBindException(BindException e) {
String message = e.getBindingResult()
.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining("; "));
log.warn("参数绑定失败: {}", message);
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(Result.error(ResultCode.BAD_REQUEST.getCode(), message));
}
/**
* 处理单个参数校验异常
*/
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Result<Object>> handleConstraintViolation(ConstraintViolationException e) {
String message = e.getConstraintViolations()
.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining("; "));
log.warn("参数校验失败: {}", message);
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(Result.error(ResultCode.BAD_REQUEST.getCode(), message));
}
/**
* 处理参数类型不匹配异常
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<Result<Object>> handleTypeMismatch(MethodArgumentTypeMismatchException e) {
String message = "参数类型不匹配";
log.warn("参数类型不匹配: {}", e.getMessage());
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(Result.error(ResultCode.BAD_REQUEST.getCode(), message));
}
/**
* 处理404异常
*/
@ExceptionHandler({NoHandlerFoundException.class, NoResourceFoundException.class})
public ResponseEntity<Result<Object>> handleNotFoundException(Exception e, WebRequest request) {
log.warn("请求资源不存在: {}", request.getDescription(false));
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(Result.error(ResultCode.NOT_FOUND.getCode(), "请求的资源不存在"));
}
/**
* 处理运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<Result<Object>> handleRuntimeException(RuntimeException e, WebRequest request) {
log.error("系统运行时异常: {}", e.getMessage(), e);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Result.error(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "系统内部错误,请稍后重试"));
}
/**
* 处理所有未捕获的异常
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<Result<Object>> handleException(Exception e, WebRequest request) {
log.error("系统异常: {}", e.getMessage(), e);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Result.error(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "系统内部错误,请联系管理员"));
}
}
应用配置
# application.yml
spring:
mvc:
throw-exception-if-no-handler-found: true
web:
resources:
add-mappings: false
server:
error:
include-message: always
测试示例
// TestController.java
import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/test")
@Validated
public class TestController {
@PostMapping("/error")
public Result<Object> testBusinessException() {
throw new BusinessException(ResultCode.BAD_REQUEST, "业务处理失败");
}
@PostMapping("/valid")
public Result<UserDTO> testValid(@Valid @RequestBody UserDTO userDTO) {
return Result.success(userDTO);
}
@GetMapping("/param")
public Result<Object> testParamValidation(
@NotBlank(message = "用户名不能为空") @RequestParam String username,
@Email(message = "邮箱格式不正确") @RequestParam String email) {
return Result.success(Map.of("username", username, "email", email));
}
@GetMapping("/type")
public Result<Object> testTypeMismatch(@RequestParam Integer age) {
return Result.success(Map.of("age", age));
}
@GetMapping("/npe")
public Result<Object> testNPE() {
String str = null;
str.length(); // 触发空指针异常
return Result.success(null);
}
// 测试DTO
static class UserDTO {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@Email(message = "邮箱格式不正确")
private String email;
@NotEmpty(message = "兴趣爱好不能为空")
private List<String> hobbies;
// getters and setters...
}
}
自定义异常处理器增强版
// EnhancedGlobalExceptionHandler.java
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class EnhancedGlobalExceptionHandler {
/**
* 完整的错误响应体,包含错误详情
*/
private Map<String, Object> buildErrorBody(Integer code, String message, HttpServletRequest request) {
Map<String, Object> errorBody = new HashMap<>();
errorBody.put("code", code);
errorBody.put("message", message);
errorBody.put("path", request.getRequestURI());
errorBody.put("timestamp", LocalDateTime.now().toString());
errorBody.put("method", request.getMethod());
return errorBody;
}
@ExceptionHandler(BusinessException.class)
public ResponseEntity<Map<String, Object>> handleBusiness(BusinessException e) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return ResponseEntity
.status(HttpStatus.OK)
.body(buildErrorBody(e.getCode(), e.getMessage(), request));
}
}
前端统一处理示例
// 前端统一错误处理
async function request(url, options = {}) {
const response = await fetch(url, {
headers: { 'Content-Type': 'application/json' },
...options
});
const result = await response.json();
if (result.code !== 200) {
// 统一错误提示
ElMessage.error(result.message);
// 401跳转登录
if (result.code === 401) {
window.location.href = '/login';
}
throw new Error(result.message);
}
return result.data;
}
使用说明
- 统一响应格式:所有成功和失败都返回
Result对象 - 业务异常:自定义
BusinessException用于业务逻辑错误 - 参数校验:使用
@Validated和@Valid结合异常处理 - 日志记录:异常都记录了日志,方便排查
- 错误信息:对外部返回友好提示,内部记录详细信息
这个全局异常处理方案能够覆盖项目中的绝大部分异常场景,具有很好的扩展性和维护性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播