Skip to content

异常处理


异常枚举接口

java
/**
 * 枚举接口
 */
public interface IBasicEnum {

    /**
     * 编码
     */
    public int getCode();

    /**
     * 信息
     */
    public String getMsg();

}

异常枚举类

java
/**
 * 基础枚举
 *
 * @author itcast
 */
@Getter
@AllArgsConstructor
public enum BasicEnum implements IBasicEnum {

    SUCCEED(200, "操作成功"),
    SECURITY_ACCESSDENIED_FAIL(401, "权限不足!"),
    LOGIN_FAIL(401, "用户登录失败"),
    LOGIN_LOSE_EFFICACY(401, "登录状态失效,请重新登录"),
    SYSYTEM_FAIL(500, "系统运行异常"),


    //权限相关异常:1400-1499
    DEPT_DEPTH_UPPER_LIMIT(1400, "部门最多4级"),
    PARENT_DEPT_DISABLE(1401, "父级部门为禁用状态,不允许启用"),
    DEPT_NULL_EXCEPTION(1402, "部门不能为空"),
    POSITION_DISTRIBUTED(1403, "职位已分配,不允许禁用"),
    MENU_NAME_DUPLICATE_EXCEPTION(1404, "菜单路由重复"),
    MENU_PATH_DUPLICATE_EXCEPTION(1405, "菜单路由重复"),
    RESOURCE_DEPTH_UPPER_LIMIT(1406, "菜单最多3级"),
    USER_ROLE_AND_MENU_EMPTY(1407, "请为用户分配角色和菜单"),
    PARENT_MENU_DISABLE(1408, "父级菜单为禁用状态,不允许启用"),
    MENU_DISTRIBUTED(1409, "菜单已分配,不允许禁用"),
    BUTTON_DISTRIBUTED(1410, "按钮已分配,不允许禁用"),
    ROLE_DISTRIBUTED(1411, "该角色已分配用户,不能删除"),
    USER_LOCATED_BOTTOMED_DEPT(1412, "请选择最底层部门"),
    DEPT_BINDING_USER(1413, "部门已绑定用户,不允许禁用"),
    USER_EMPTY_EXCEPTION(1414, "用户不存在,不能启用或禁用"),
    ORIGINAL_PASSWORD_ERROR(1415, "原密码不正确,请重新输入"),
    ORIGINAL_CANNOT_EQUAL_NEW(1416, "新密码和旧密码不能一致"),
    GET_OPENID_ERROR(1417, "小程序登录,获取openId失败"),
    GET_PHONE_ERROR(1418, "小程序登录,获取手机号失败"),
    GET_TOKEN_ERROR(1419, "小程序登录,获取token失败"),

    ACCOUNT_DISABLED(1420, "账号被禁用,请联系管理员"),
    INCORRECT_PASSWORD(1421, "用户或密码错误"),

    //业务相关异常:1500-1599
    WEBSOCKET_PUSH_MSG_ERROR(1500, "websocket推送消息失败"),
    CLOSE_BALANCE_ERROR(1501, "关闭余额账户失败"),
    MONTH_BILL_DUPLICATE_EXCEPTION(1502, "该老人的月度账单已生成,不可重复生成"),
    MONTH_OUT_CHECKIN_TERM(1503, "该月不在费用期限内"),
    RETREAT_TERM_LACK_MONTH_BILL(1504, "退住日期内缺少月度账单,请前往财务管理模块手动生成"),
    ELDER_ALREADY_CHECKIN(1505, "该老人已入住,请重新输入"),
    CHECKIN_TERM_SHOULD_CONTAIN_COST_TERM(1506, "费用期限应该在入住期限内"),
    DEVICE_NAME_EXIST(1507, "设备名称已存在,请重新输入"),
    LOCATION_BINDING_PRODUCT(1508, "该老人/位置已绑定该产品,请重新选择"),
    IOT_REGISTER_DEVICE_ERROR(1509, "物联网接口 - 注册设备,调用失败"),
    IOT_QUERY_PRODUCT_ERROR(1510, "物联网接口 - 查询产品,调用失败"),
    IOT_QUERY_DEVICE_ERROR(1511, "物联网接口 - 查询产品,调用失败"),
    IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR(1512, "物联网接口 - 查询设备的物模型运行状态,调用失败"),
    IOT_QUERY_THING_MODEL_PUBLISHED_ERROR(1513, "物联网接口 - 查询物模型数据,调用失败"),
    DEVICE_NOT_EXIST(1514, "该设备不存在,无法修改"),
    IOT_BATCH_UPDATE_DEVICE_ERROR(1515, "物联网接口 - 批量修改设备名称,调用失败"),
    RE_SELECT_PRODUCT(1516, "该老人/位置已绑定该产品,请重新选择"),
    IOT_DELETE_DEVICE_ERROR(1517, "物联网接口 - 删除设备,调用失败"),
    IOT_LIST_PRODUCT_ERROR(1518, "物联网接口 - 查看所有产品列表,调用失败"),
    IOT_OPEN_DOOR_ERROR(1519, "开门失败"),
    IOT_QUERY_DEVICE_SERVICE_DATA_ERROR(1520, "物联网接口 - 调用查询指定设备的服务调用记录接口,调用失败"),
    ELDER_NOT_EXIST(1521, "老人不存在"),
    MEMBER_ALREADY_BINDING_ELDER(1522, "已绑定过此家人"),
    CANNOT_PLACE_ORDER_DUE_ELDER_ALREADY_RETREATED(1523, "已退住,不可下单"),
    ORDER_CLOSED(1524, "订单已关闭"),
    CANNOT_RESERVATION_DUE_ELDER_ALREADY_RETREATED(1525, "已退住,不可预约"),
    RESERVATION_CANCEL_COUNT_UPPER_LIMIT(1526, "今天取消次数已达上限,不可进行预约"),
    TIME_ALREADY_RESERVATED_BY_PHONE(1527, "此手机号已预约该时间"),
    RETREAT_SHOULD_IN_COST_TERM(1528, "请在费用期限内发起退住申请"),
    UPLOAD_FILE_EMPTY(1529, "上传图片不能为空"),
    DONE_ORDER_CANNOT_REFUND(1530, "已执行的订单不可退款"),
    BED_INSERT_FAIL(1531,"床位新增失败"),
    ENABLED_CANNOT_DELETED(1532,"启用状态不能删除");

    /**
     * 编码
     */
    public final int code;
    /**
     * 信息
     */
    public final String msg;

}

BaseException

java
/**
 * BaseException
 * @author itheima
 **/
@Getter
@Setter
public class BaseException extends RuntimeException {

    private BasicEnum basicEnum;

    public BaseException(BasicEnum basicEnum) {
        this.basicEnum = basicEnum;
    }
}

全局异常处理器

java
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理自定义异常BaseException。
     * 返回自定义异常中的错误代码和错误消息。
     *
     * @param exception 自定义异常
     * @return 响应数据,包含错误代码和错误消息
     */
    @ExceptionHandler(BaseException.class)
    public ResponseResult<Object> handleBaseException(BaseException exception) {
        exception.printStackTrace();
        if (ObjectUtil.isNotEmpty(exception.getBasicEnum())) {
            log.error("自定义异常处理:{}", exception.getBasicEnum().getMsg());
        }

        return ResponseResult.error(exception.getBasicEnum());

    }

    /**
     * 处理其他未知异常。
     * 返回HTTP响应状态码500,包含错误代码和异常堆栈信息。
     *
     * @param exception 未知异常
     * @return 响应数据,包含错误代码和异常堆栈信息
     */
    @ExceptionHandler(Exception.class)
    public ResponseResult<Object> handleUnknownException(Exception exception) {
        exception.printStackTrace();
        if (ObjectUtil.isNotEmpty(exception.getCause())) {
            log.error("其他未知异常:{}", exception.getMessage());
        }
        return ResponseResult.error(500,exception.getMessage());
    }

}

SQL 异常处理

应用场景:使用了物理外键,且某些数据被引用,删除失败抛出的异常

在使用 Spring 框架时,通常会捕获更高层的 DataIntegrityViolationException,它是对 SQLIntegrityConstraintViolationException 的抽象

DataIntegrityViolationException 更符合 Spring 的异常处理模式,并且可以通过它获取底层的 SQLIntegrityConstraintViolationException 来了解详细的错误信息

java
/**
 * 数据完整性异常
 */
@ExceptionHandler(DataIntegrityViolationException.class)
public AjaxResult handelDataIntegrityViolationException(DataIntegrityViolationException e) {

    if (e.getMessage().contains("delete")) {

        return AjaxResult.error("无法删除,有其他数据引用");
    }
    return AjaxResult.error("您的操作违反了数据库中的完整性约束");
}