Skip to content

业务异常与全局异常处理

Forge 通过自定义异常和全局异常处理器统一管理错误响应。你需要在 Service 层抛出业务异常,由全局处理器转换为 RespInfo

自定义业务异常

java
public class BusinessException extends RuntimeException {

    private int code;
    private String message;

    public BusinessException(String message) {
        super(message);
        this.code = 500;
        this.message = message;
    }

    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }
}

使用方式

在 Service 层抛出业务异常:

java
@Service
public class OrderServiceImpl implements OrderService {

    @Override
    public OrderVO create(OrderDTO dto) {
        // 校验订单号唯一
        if (orderMapper.selectByOrderNo(dto.getOrderNo()) != null) {
            throw new BusinessException("订单号已存在");
        }

        // 校验金额
        if (dto.getAmount() <= 0) {
            throw new BusinessException(400, "金额必须大于0");
        }

        OrderEntity entity = new OrderEntity();
        BeanUtils.copyProperties(dto, entity);
        orderMapper.insert(entity);
        return toVO(entity);
    }
}

全局异常处理

GlobalExceptionHandler 使用 @RestControllerAdvice 捕获异常:

java
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 业务异常
    @ExceptionHandler(BusinessException.class)
    public RespInfo handleBusiness(BusinessException e) {
        log.warn("业务异常: {}", e.getMessage());
        return RespInfo.error(e.getCode(), e.getMessage());
    }

    // 参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RespInfo handleValidation(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
            .map(f -> f.getField() + ": " + f.getDefaultMessage())
            .collect(Collectors.joining("; "));
        return RespInfo.error(400, message);
    }

    // 权限异常
    @ExceptionHandler(NotPermissionException.class)
    public RespInfo handlePermission(NotPermissionException e) {
        return RespInfo.error(403, "无权限访问");
    }

    // 认证异常
    @ExceptionHandler(NotLoginException.class)
    public RespInfo handleLogin(NotLoginException e) {
        return RespInfo.error(401, "未登录或登录已过期");
    }

    // 兜底异常
    @ExceptionHandler(Exception.class)
    public RespInfo handleException(Exception e) {
        log.error("系统异常", e);
        return RespInfo.error(500, "系统异常,请联系管理员");
    }
}

错误码定义

建议在常量类中统一定义错误码:

java
public class ErrorCode {
    public static final int SUCCESS = 200;
    public static final int BAD_REQUEST = 400;
    public static final int UNAUTHORIZED = 401;
    public static final int FORBIDDEN = 403;
    public static final int SERVER_ERROR = 500;

    // 业务错误码 1xxx
    public static final int ORDER_NOT_FOUND = 1001;
    public static final int ORDER_STATUS_ERROR = 1002;
    public static final int ORDER_ALREADY_PAID = 1003;
}

使用:

java
throw new BusinessException(ErrorCode.ORDER_NOT_FOUND, "订单不存在");

异常处理流程

Service 抛出 BusinessException

GlobalExceptionHandler 捕获

转换为 RespInfo.error(code, msg)

返回前端 JSON

注意事项

  • 不要在 Controller 层 try-catch 吞异常,让全局处理器统一处理
  • 业务异常用 BusinessException,不要用 RuntimeException
  • 日志级别:业务异常用 warn,系统异常用 error
  • 异常消息:面向用户,不要暴露技术细节(如堆栈信息)

Forge Admin — 基于 Vue3 + Spring Boot 的企业级后台管理框架