1. 错误码枚举类
package com.example.order.common.enums;
import lombok.Getter;
@Getter
public enum ResultCode {
SUCCESS(200, "操作成功"),
PARAM_ERROR(400, "参数错误"),
UNAUTHORIZED(401, "未授权"),
FORBIDDEN(403, "禁止访问"),
NOT_FOUND(404, "资源不存在"),
USER_NOT_FOUND(1000, "用户不存在"),
PASSWORD_ERROR(1001, "密码错误"),
ACCOUNT_LOCKED(1002, "账号已被锁定"),
LOGIN_EXPIRED(1003, "登录已过期"),
INVALID_TOKEN(1004, "无效的token"),
USERNAME_EXISTED(1100, "用户名已存在"),
EMAIL_EXISTED(1101, "邮箱已被使用"),
PHONE_EXISTED(1102, "手机号已被使用"),
NO_PERMISSION(1200, "没有操作权限"),
ROLE_NOT_FOUND(1201, "角色不存在"),
OPERATION_FAILED(2000, "操作失败"),
DATA_NOT_FOUND(2001, "数据不存在"),
DATA_EXISTED(2002, "数据已存在"),
FILE_UPLOAD_ERROR(3000, "文件上传失败"),
FILE_TYPE_ERROR(3001, "文件类型错误"),
FILE_SIZE_ERROR(3002, "文件大小超限"),
SYSTEM_ERROR(500, "系统内部错误"),
SERVICE_UNAVAILABLE(503, "服务不可用"),
GATEWAY_ERROR(504, "网关错误");
private final int code;
private final String message;
ResultCode(int code, String message) {
this.code = code;
this.message = message;
}
}
2. 统一响应对象
package com.example.order.common.result;
import com.example.order.common.enums.ResultCode;
import lombok.Data;
@Data
public class Result<T> {
private int code;
private String message;
private T data;
private long timestamp;
private Result() {
this.timestamp = System.currentTimeMillis();
}
public static <T> Result<T> success() {
return success(null);
}
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(ResultCode.SUCCESS.getCode());
result.setMessage(ResultCode.SUCCESS.getMessage());
result.setData(data);
return result;
}
public static <T> Result<T> error(ResultCode resultCode) {
Result<T> result = new Result<>();
result.setCode(resultCode.getCode());
result.setMessage(resultCode.getMessage());
return result;
}
public static <T> Result<T> error(ResultCode resultCode, String message) {
Result<T> result = new Result<>();
result.setCode(resultCode.getCode());
result.setMessage(message);
return result;
}
}
3. 自定义业务异常
package com.example.order.common.exception;
import com.example.order.common.enums.ResultCode;
import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
private final ResultCode resultCode;
public BusinessException(ResultCode resultCode) {
super(resultCode.getMessage());
this.resultCode = resultCode;
}
public BusinessException(ResultCode resultCode, String message) {
super(message);
this.resultCode = resultCode;
}
}
4. 全局异常处理器
package com.example.order.common.handler;
import com.example.order.common.exception.BusinessException;
import com.example.order.common.result.Result;
import com.example.order.common.enums.ResultCode;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.validation.BindException;
import cn.dev33.satoken.exception.NotLoginException;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusinessException(BusinessException e) {
return Result.error(e.getResultCode(), e.getMessage());
}
@ExceptionHandler(NotLoginException.class)
public Result<?> handleNotLoginException(NotLoginException e) {
return Result.error(ResultCode.UNAUTHORIZED, "请先登录");
}
@ExceptionHandler(BindException.class)
public Result<?> handleBindException(BindException e) {
return Result.error(ResultCode.PARAM_ERROR, e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
}
@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e) {
return Result.error(ResultCode.SYSTEM_ERROR, "系统异常,请联系管理员");
}
}
5. 使用示例
在登录服务中使用
@Override
public String login(String username, String password) {
UPerson user = this.findByLoginIdentifier(username);
if (user == null) {
throw new BusinessException(ResultCode.USER_NOT_FOUND);
}
if (!BCrypt.checkpw(password, user.getEncodedPassword())) {
throw new BusinessException(ResultCode.PASSWORD_ERROR);
}
if (user.getStatus() != null && user.getStatus() == 0) {
throw new BusinessException(ResultCode.ACCOUNT_LOCKED);
}
StpUtil.login(user.getId());
return StpUtil.getTokenValue();
}
Controller中使用
@PostMapping("/login")
public Result<String> login(@RequestBody LoginRequest request) {
String token = personService.login(request.getUsername(), request.getPassword());
return Result.success(token);
}
响应示例
成功响应
{
"code": 200,
"message": "操作成功",
"data": "your-token-here",
"timestamp": 1646534400000
}
错误响应
{
"code": 1001,
"message": "密码错误",
"data": null,
"timestamp": 1646534400000
}
设计优点
- 错误码统一管理,便于维护
- 支持自定义错误信息
- 统一的响应格式
- 分类清晰的错误码区间
- 全局异常处理
- 支持国际化(可以扩展)