Java异常处理与全局异常处理全面指南
Java异常处理与全局异常处理全面指南
一、Java异常处理基础
1. 异常分类
Java中的异常分为两大类:
- Checked Exception(检查型异常):必须被捕获或声明抛出,如IOException、SQLException
- Unchecked Exception(非检查型异常):RuntimeException及其子类,如NullPointerException、ArrayIndexOutOfBoundsException
2. 基本异常处理语法
try {
// 可能抛出异常的代码
} catch (SpecificException e) {
// 处理特定异常
} catch (GeneralException e) {
// 处理更一般的异常
} finally {
// 无论是否发生异常都会执行的代码
}
3. 异常处理最佳实践
- 不要忽略异常:空的catch块是"罪恶"的
- 优先处理最具体的异常
- 合理使用finally释放资源
- 考虑使用try-with-resources(Java 7+)
- 避免在finally块中使用return
二、Spring全局异常处理机制
1. @ControllerAdvice + @ExceptionHandler
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
ErrorResponse error = new ErrorResponse(
"SERVER_ERROR",
"An unexpected error occurred",
HttpStatus.INTERNAL_SERVER_ERROR.value()
);
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(
ResourceNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
"NOT_FOUND",
ex.getMessage(),
HttpStatus.NOT_FOUND.value()
);
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
}
2. 自定义异常类
public class BusinessException extends RuntimeException {
private String errorCode;
private HttpStatus httpStatus;
public BusinessException(String message, String errorCode, HttpStatus httpStatus) {
super(message);
this.errorCode = errorCode;
this.httpStatus = httpStatus;
}
// getters
}
3. 统一响应格式
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {
private String errorCode;
private String message;
private int status;
private long timestamp;
private String path;
private List<ValidationError> validationErrors;
public ErrorResponse(String errorCode, String message, int status) {
this.errorCode = errorCode;
this.message = message;
this.status = status;
this.timestamp = System.currentTimeMillis();
}
}
@Data
@AllArgsConstructor
public class ValidationError {
private String field;
private String message;
}
三、高级异常处理技巧
1. 处理验证异常(Validation)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(
MethodArgumentNotValidException ex) {
List<ValidationError> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> new ValidationError(
error.getField(),
error.getDefaultMessage()))
.collect(Collectors.toList());
ErrorResponse error = new ErrorResponse(
"VALIDATION_FAILED",
"Validation failed for one or more fields",
HttpStatus.BAD_REQUEST.value(),
errors
);
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
2. 国际化异常消息
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(
BusinessException ex,
WebRequest request,
Locale locale) {
String message = messageSource.getMessage(
ex.getMessageKey(),
ex.getArgs(),
locale);
ErrorResponse error = new ErrorResponse(
ex.getErrorCode(),
message,
ex.getHttpStatus().value()
);
return new ResponseEntity<>(error, ex.getHttpStatus());
}
3. 日志记录策略
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex, WebRequest request) {
logger.error("Unexpected error occurred: {}", ex.getMessage(), ex);
ErrorResponse error = new ErrorResponse(
"SERVER_ERROR",
"An unexpected error occurred",
HttpStatus.INTERNAL_SERVER_ERROR.value(),
request.getDescription(false)
);
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
四、实战建议
-
分层异常处理:
- 控制器层:处理HTTP相关异常
- 服务层:处理业务逻辑异常
- 数据访问层:处理数据相关异常
-
异常转换:将底层异常转换为上层业务异常
-
异常信息设计:
- 包含足够的信息用于调试
- 不暴露敏感信息
- 提供明确的错误代码
-
监控与报警:对关键异常设置监控报警
-
文档化:为API消费者提供清晰的错误代码和含义文档
五、常见问题解决方案
- 处理404错误:
@ControllerAdvice
public class CustomErrorController implements ErrorController {
@RequestMapping("/error")
public ResponseEntity<ErrorResponse> handleError(HttpServletRequest request) {
Integer status = (Integer) request.getAttribute("javax.servlet.error.status_code");
Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
ErrorResponse error = new ErrorResponse(
"NOT_FOUND",
"Requested resource not found",
status
);
return new ResponseEntity<>(error, HttpStatus.valueOf(status));
}
}
- 处理跨域异常:
@ExceptionHandler
public ResponseEntity<ErrorResponse> handleCorsException(CorsException ex) {
ErrorResponse error = new ErrorResponse(
"CORS_ERROR",
ex.getMessage(),
HttpStatus.FORBIDDEN.value()
);
return new ResponseEntity<>(error, HttpStatus.FORBIDDEN);
}
- 处理文件上传大小限制异常:
@ExceptionHandler(MaxUploadSizeExceededException.class)
public ResponseEntity<ErrorResponse> handleMaxSizeException(
MaxUploadSizeExceededException exc) {
ErrorResponse error = new ErrorResponse(
"FILE_TOO_LARGE",
"File size exceeds the allowed limit",
HttpStatus.BAD_REQUEST.value()
);
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
六、总结
良好的异常处理是构建健壮Java应用程序的关键。通过合理使用Java原生异常机制和Spring的全局异常处理功能,可以:
- 提高代码的健壮性和可维护性
- 提供一致的用户体验
- 便于问题排查和调试
- 实现更好的系统监控
记住:异常处理的目标不是消灭所有异常,而是以可控的方式处理异常,并提供有意义的反馈。