登录失败应使用多个细分自定义异常类,如accountnotfoundexception、passwordmismatchexception等,继承非受检基类loginexception,携带错误码和提示信息,服务层按校验逻辑主动抛出,配合@controlleradvice统一响应。

登录失败场景适合用多个细分的自定义异常类来区分错误类型,而不是统一抛一个 RuntimeException 或泛化异常。核心是让调用方能精准识别失败原因(比如账号不存在、密码错误、账户被锁定、验证码过期等),便于前端做差异化提示或后端做针对性处理(如触发风控、记录审计日志)。
定义分层的自定义异常基类
先建一个受检或非受检的基类(推荐非受检,避免强制 try-catch 干扰业务流程),统一携带错误码和提示信息:
public class LoginException extends RuntimeException {
private final String errorCode;
public LoginException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
为每种失败原因创建具体子类
每个子类对应一种明确的业务语义,便于识别和扩展:
- AccountNotFoundException:用户名/手机号未注册
- PasswordMismatchException:密码不匹配(注意:不暴露是否账号存在,生产环境建议与上一条合并提示“账号或密码错误”,但内部仍可区分)
- AccountLockedException:因多次失败被临时锁定
- VerificationCodeExpiredException:短信/图形验证码已过期
- InvalidCredentialsException:通用凭证无效(如 token 格式错、JWT 解析失败)
示例:
public class AccountLockedException extends LoginException {
public AccountLockedException() {
super("LOGIN_ACCOUNT_LOCKED", "账号已被锁定,请稍后再试");
}
}
在服务层按规则主动抛出
不要等 DAO 返回 null 再统一包装——要在逻辑判断点就抛出语义明确的异常:
- 查不到用户 → 抛
AccountNotFoundException - 查到用户但密码校验失败 → 抛
PasswordMismatchException - 查到用户且状态为 LOCKED → 抛
AccountLockedException - 验证码校验不通过且原因是超时 → 抛
VerificationCodeExpiredException
这样 Controller 层能直接捕获不同异常,返回对应 HTTP 状态码和 JSON 错误结构(如 401、403、422),前端也能根据 errorCode 做定制化提示。
配合全局异常处理器统一响应格式
用 @ControllerAdvice 拦截所有 LoginException 及其子类,封装成标准错误响应:
@ExceptionHandler(LoginException.class)
public ResponseEntity<errorresponse> handleLoginException(LoginException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(new ErrorResponse(e.getErrorCode(), e.getMessage()));
}</errorresponse>
确保所有登录异常都走同一出口,避免分散处理导致响应不一致。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











