本文目录导读:

我来介绍Java Boot中异常处理的封装最佳实践,包含完整的案例实现。
统一响应结果封装
全局响应对象
// 统一响应结果类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiResult<T> {
private Integer code;
private String message;
private T data;
private Long timestamp;
// 成功响应
public static <T> ApiResult<T> success() {
return ApiResult.<T>builder()
.code(200)
.message("操作成功")
.timestamp(System.currentTimeMillis())
.build();
}
public static <T> ApiResult<T> success(T data) {
return ApiResult.<T>builder()
.code(200)
.message("操作成功")
.data(data)
.timestamp(System.currentTimeMillis())
.build();
}
public static <T> ApiResult<T> success(String message, T data) {
return ApiResult.<T>builder()
.code(200)
.message(message)
.data(data)
.timestamp(System.currentTimeMillis())
.build();
}
// 失败响应
public static <T> ApiResult<T> error(Integer code, String message) {
return ApiResult.<T>builder()
.code(code)
.message(message)
.timestamp(System.currentTimeMillis())
.build();
}
public static <T> ApiResult<T> error(ErrorCode errorCode) {
return ApiResult.<T>builder()
.code(errorCode.getCode())
.message(errorCode.getMessage())
.timestamp(System.currentTimeMillis())
.build();
}
public static <T> ApiResult<T> error(ErrorCode errorCode, Object... args) {
return ApiResult.<T>builder()
.code(errorCode.getCode())
.message(String.format(errorCode.getMessage(), args))
.timestamp(System.currentTimeMillis())
.build();
}
}
错误码枚举
// 错误码枚举
public enum ErrorCode {
// 通用错误码
SUCCESS(200, "操作成功"),
BAD_REQUEST(400, "请求参数错误"),
UNAUTHORIZED(401, "未授权"),
FORBIDDEN(403, "权限不足"),
NOT_FOUND(404, "资源不存在"),
METHOD_NOT_ALLOWED(405, "请求方法不支持"),
INTERNAL_ERROR(500, "服务器内部错误"),
SERVICE_UNAVAILABLE(503, "服务不可用"),
// 业务错误码
PARAM_VALIDATION_ERROR(1001, "参数校验失败"),
USER_NOT_EXIST(1002, "用户不存在"),
USER_ALREADY_EXIST(1003, "用户已存在"),
PASSWORD_ERROR(1004, "密码错误"),
ACCOUNT_LOCKED(1005, "账号已被锁定"),
TOKEN_EXPIRED(1006, "Token已过期"),
TOKEN_INVALID(1007, "Token无效"),
// 数据错误码
DATA_NOT_FOUND(2001, "数据不存在"),
DATA_ALREADY_EXIST(2002, "数据已存在"),
DATA_CREATE_FAILED(2003, "数据创建失败"),
DATA_UPDATE_FAILED(2004, "数据更新失败"),
DATA_DELETE_FAILED(2005, "数据删除失败"),
// 系统错误码
SYSTEM_ERROR(5000, "系统繁忙,请稍后重试"),
DATABASE_ERROR(5001, "数据库操作异常"),
CACHE_ERROR(5002, "缓存操作异常"),
NETWORK_ERROR(5003, "网络通信异常");
private final Integer code;
private final String message;
ErrorCode(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
自定义异常类
业务异常
// 业务异常类
@Data
@EqualsAndHashCode(callSuper = true)
public class BusinessException extends RuntimeException {
private Integer code;
private String message;
private Object[] args;
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
}
public BusinessException(ErrorCode errorCode, Object... args) {
super(String.format(errorCode.getMessage(), args));
this.code = errorCode.getCode();
this.message = String.format(errorCode.getMessage(), args);
this.args = args;
}
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
}
参数校验异常
// 参数校验异常
@Data
@EqualsAndHashCode(callSuper = true)
public class ParamValidationException extends RuntimeException {
private final String field;
private final String message;
public ParamValidationException(String field, String message) {
super(message);
this.field = field;
this.message = message;
}
}
全局异常处理器
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public ApiResult<Void> handleBusinessException(BusinessException e) {
log.warn("业务异常: code={}, message={}", e.getCode(), e.getMessage());
return ApiResult.error(e.getCode(), e.getMessage());
}
// 处理参数校验异常
@ExceptionHandler(ParamValidationException.class)
public ApiResult<Void> handleParamValidationException(ParamValidationException e) {
log.warn("参数校验异常: field={}, message={}", e.getField(), e.getMessage());
return ApiResult.error(ErrorCode.PARAM_VALIDATION_ERROR.getCode(), e.getMessage());
}
// 处理方法参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ApiResult<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
String message = fieldErrors.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining(", "));
log.warn("参数校验失败: {}", message);
return ApiResult.error(ErrorCode.PARAM_VALIDATION_ERROR.getCode(), message);
}
// 处理约束违反异常
@ExceptionHandler(ConstraintViolationException.class)
public ApiResult<Void> handleConstraintViolationException(ConstraintViolationException e) {
String message = e.getConstraintViolations().stream()
.map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
.collect(Collectors.joining(", "));
log.warn("约束违反: {}", message);
return ApiResult.error(ErrorCode.PARAM_VALIDATION_ERROR.getCode(), message);
}
// 处理HTTP消息不可读异常
@ExceptionHandler(HttpMessageNotReadableException.class)
public ApiResult<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
log.warn("请求体格式错误: {}", e.getMessage());
return ApiResult.error(ErrorCode.BAD_REQUEST.getCode(), "请求体格式错误");
}
// 处理类型不匹配异常
@ExceptionHandler(TypeMismatchException.class)
public ApiResult<Void> handleTypeMismatchException(TypeMismatchException e) {
log.warn("参数类型不匹配: {}", e.getMessage());
return ApiResult.error(ErrorCode.BAD_REQUEST.getCode(), "参数类型不匹配");
}
// 处理缺失请求参数异常
@ExceptionHandler(MissingServletRequestParameterException.class)
public ApiResult<Void> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
log.warn("缺少参数: {}", e.getParameterName());
return ApiResult.error(ErrorCode.BAD_REQUEST.getCode(), "缺少参数: " + e.getParameterName());
}
// 处理认证异常
@ExceptionHandler(AuthenticationException.class)
public ApiResult<Void> handleAuthenticationException(AuthenticationException e) {
log.warn("认证失败: {}", e.getMessage());
return ApiResult.error(ErrorCode.UNAUTHORIZED.getCode(), "认证失败: " + e.getMessage());
}
// 处理权限异常
@ExceptionHandler(AccessDeniedException.class)
public ApiResult<Void> handleAccessDeniedException(AccessDeniedException e) {
log.warn("权限不足: {}", e.getMessage());
return ApiResult.error(ErrorCode.FORBIDDEN.getCode(), "权限不足,无法访问");
}
// 处理HTTP请求方法不支持异常
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ApiResult<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
log.warn("请求方法不支持: {}", e.getMessage());
return ApiResult.error(ErrorCode.METHOD_NOT_ALLOWED.getCode(), "请求方法不支持");
}
// 处理空指针异常
@ExceptionHandler(NullPointerException.class)
public ApiResult<Void> handleNullPointerException(NullPointerException e) {
log.error("空指针异常", e);
return ApiResult.error(ErrorCode.INTERNAL_ERROR.getCode(), "系统异常,请联系管理员");
}
// 处理数据访问异常
@ExceptionHandler(DataAccessException.class)
public ApiResult<Void> handleDataAccessException(DataAccessException e) {
log.error("数据库访问异常", e);
return ApiResult.error(ErrorCode.DATABASE_ERROR.getCode(), "数据库操作异常");
}
// 处理通用异常
@ExceptionHandler(Exception.class)
public ApiResult<Void> handleException(Exception e) {
log.error("系统异常", e);
return ApiResult.error(ErrorCode.SYSTEM_ERROR.getCode(), ErrorCode.SYSTEM_ERROR.getMessage());
}
}
使用示例
Service层使用
@Service
@Slf4j
public class UserService {
@Autowired
private UserRepository userRepository;
public User getUserById(Long id) {
// 参数校验
if (id == null || id <= 0) {
throw new ParamValidationException("id", "用户ID不能为空且必须大于0");
}
// 业务逻辑
User user = userRepository.findById(id)
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_EXIST));
// 检查用户状态
if (user.getStatus() == Status.LOCKED) {
throw new BusinessException(ErrorCode.ACCOUNT_LOCKED);
}
return user;
}
@Transactional
public User createUser(UserCreateDTO createDTO) {
// 检查用户是否已存在
if (userRepository.existsByUsername(createDTO.getUsername())) {
throw new BusinessException(ErrorCode.USER_ALREADY_EXIST);
}
try {
User user = new User();
BeanUtils.copyProperties(createDTO, user);
user.setStatus(Status.ACTIVE);
user.setCreateTime(LocalDateTime.now());
return userRepository.save(user);
} catch (DataIntegrityViolationException e) {
log.error("创建用户失败: {}", e.getMessage());
throw new BusinessException(ErrorCode.DATA_CREATE_FAILED);
}
}
public Page<User> listUsers(UserQueryDTO queryDTO) {
try {
Pageable pageable = PageRequest.of(
queryDTO.getPage(),
queryDTO.getSize(),
Sort.by(Sort.Direction.DESC, "createTime")
);
Specification<User> specification = Specification.where(null);
if (StringUtils.hasText(queryDTO.getUsername())) {
specification = specification.and(
(root, query, cb) -> cb.like(root.get("username"),
"%" + queryDTO.getUsername() + "%")
);
}
return userRepository.findAll(specification, pageable);
} catch (Exception e) {
log.error("查询用户列表失败", e);
throw new BusinessException(ErrorCode.DATA_NOT_FOUND);
}
}
}
Controller层使用
@RestController
@RequestMapping("/api/users")
@Validated
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ApiResult<User> getUser(@PathVariable Long id) {
return ApiResult.success(userService.getUserById(id));
}
@PostMapping
public ApiResult<User> createUser(@Valid @RequestBody UserCreateDTO createDTO) {
User user = userService.createUser(createDTO);
return ApiResult.success("用户创建成功", user);
}
@GetMapping
public ApiResult<Page<User>> listUsers(@Valid UserQueryDTO queryDTO) {
return ApiResult.success(userService.listUsers(queryDTO));
}
@PutMapping("/{id}")
public ApiResult<Void> updateUser(@PathVariable Long id,
@Valid @RequestBody UserUpdateDTO updateDTO) {
userService.updateUser(id, updateDTO);
return ApiResult.success("用户更新成功");
}
@DeleteMapping("/{id}")
public ApiResult<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ApiResult.success("用户删除成功");
}
}
DTO验证示例
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserCreateDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 50, message = "用户名长度在3-50个字符之间")
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线")
private String username;
@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码长度在6-20个字符之间")
private String password;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
@NotNull(message = "年龄不能为空")
@Min(value = 0, message = "年龄不能小于0")
@Max(value = 150, message = "年龄不能大于150")
private Integer age;
}
配置全局异常处理
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
// 配置404异常处理
@Bean
public DispatcherServlet dispatcherServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
// 配置资源处理器
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
}
日志记录增强
@Aspect
@Component
@Slf4j
public class ExceptionLogAspect {
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))",
throwing = "ex")
public void logException(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
Object[] args = joinPoint.getArgs();
// 记录详细异常信息
log.error("异常发生 - 类: {}, 方法: {}, 参数: {}",
className, methodName, args, ex);
// 发送告警通知(可选)
if (ex instanceof BusinessException) {
BusinessException be = (BusinessException) ex;
if (be.getCode() >= 5000) {
sendAlert(className, methodName, be);
}
}
}
private void sendAlert(String className, String methodName, BusinessException ex) {
// 实现告警通知逻辑,如邮件、短信、钉钉等
log.warn("系统告警: {} - {} - {}", className, methodName, ex.getMessage());
}
}
配置文件
# application.yml
server:
error:
include-stacktrace: never
include-binding-errors: always
include-message: always
include-exception: false
spring:
jackson:
default-property-inclusion: non_null
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
这个完整的异常处理封装方案提供了统一的异常处理机制,包括:
- 统一响应格式:标准的API响应结构
- 自定义异常:业务异常和参数校验异常
- 异常分类处理:针对不同类型的异常提供不同的处理逻辑
- 日志记录:完整的异常日志记录
- 参数校验:结合Spring Validation实现参数校验
- 错误码管理:统一的错误码体系
这样的设计可以让后端错误处理更加规范和易于维护。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播