推荐使用自定义LoginFailureException异常类配合业务分层与全局异常处理器统一处理登录失败:Service层按原因抛出带错误码的异常,@ControllerAdvice捕获并返回标准JSON响应,可选枚举管理错误码提升可维护性。

在 Java 中,封装用户登录失败的错误,推荐通过自定义异常类 + 业务逻辑分层(如 Controller → Service)协同处理,让错误语义清晰、可捕获、可统一响应。
定义登录专用异常类
创建一个继承 RuntimeException 的自定义异常(运行时异常,无需强制 try-catch),明确表达“登录失败”语义:
public class LoginFailureException extends RuntimeException {
private final String errorCode; // 如 "USER_NOT_FOUND", "PASSWORD_WRONG", "ACCOUNT_LOCKED"
public LoginFailureException(String message) {
this(message, null, "UNKNOWN_ERROR");
}
public LoginFailureException(String message, String errorCode) {
this(message, null, errorCode);
}
public LoginFailureException(String message, Throwable cause, String errorCode) {
super(message, cause);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
这样设计支持携带结构化错误码,便于前端区分处理(比如跳转不同提示页或触发重置流程)。
在 Service 层抛出具体登录异常
登录逻辑中,根据失败原因抛出带语义的异常,而不是返回 null 或通用错误码:
立即学习“Java免费学习笔记(深入)”;
- 用户名不存在 →
throw new LoginFailureException("用户不存在", "USER_NOT_FOUND"); - 密码错误 →
throw new LoginFailureException("密码错误", "PASSWORD_WRONG"); - 账号被锁定 →
throw new LoginFailureException("账号已被锁定,请联系管理员", "ACCOUNT_LOCKED");
Service 方法保持专注:只做校验和业务判断,不处理 HTTP 响应,也不打印日志(交由全局异常处理器统一处理)。
全局异常处理器统一响应格式
使用 @ControllerAdvice 捕获 LoginFailureException,返回标准 JSON 错误结构:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(LoginFailureException.class)
public ResponseEntity<ApiResponse> handleLoginFailure(LoginFailureException e) {
ApiResponse response = ApiResponse.fail(e.getMessage())
.withCode(e.getErrorCode())
.withTimestamp(System.currentTimeMillis());
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
}
}
其中 ApiResponse 是你项目约定的统一响应体(含 code、message、data、timestamp 等字段),确保前端始终收到可解析的错误结构。
可选:配合枚举增强可维护性
把错误码和默认消息抽成枚举,避免硬编码字符串:
public enum LoginError {
USER_NOT_FOUND("USER_NOT_FOUND", "用户不存在"),
PASSWORD_WRONG("PASSWORD_WRONG", "密码错误"),
ACCOUNT_LOCKED("ACCOUNT_LOCKED", "账号已被锁定");
private final String code;
private final String defaultMessage;
LoginError(String code, String defaultMessage) {
this.code = code;
this.defaultMessage = defaultMessage;
}
public String getCode() { return code; }
public String getDefaultMessage() { return defaultMessage; }
}
Service 中即可写:throw new LoginFailureException(err.getDefaultMessage(), err.getCode());,后续增删类型更安全。


















