GlobalExceptionHandler.java 2.35 KB
package com.xly.erp.common.exception;

import com.xly.erp.common.response.Result;
import com.xly.erp.common.response.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理(docs/04 § 1.5 SSoT)。
 *
 * <p>REQ-USR-001 T2:把 BusinessException / 参数校验失败 / 唯一键冲突 / 未捕获异常
 * 统一转为 {@link Result},失败响应不抛栈到前端。</p>
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 业务异常 → 对应错误码。
     */
    @ExceptionHandler(BusinessException.class)
    public <T> Result<T> handleBusinessException(BusinessException ex) {
        return Result.fail(ex.getResultCode(), ex.getMessage());
    }

    /**
     * Bean Validation(@Valid)失败 → 40001,message 取首个字段错误提示。
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public <T> Result<T> handleValidationException(MethodArgumentNotValidException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        String message = fieldError != null
                ? fieldError.getField() + ": " + fieldError.getDefaultMessage()
                : ResultCode.PARAM_INVALID.getMessage();
        return Result.fail(ResultCode.PARAM_INVALID, message);
    }

    /**
     * 唯一键冲突(并发兜底)→ 40901 用户名已存在。
     */
    @ExceptionHandler(DuplicateKeyException.class)
    public <T> Result<T> handleDuplicateKeyException(DuplicateKeyException ex) {
        return Result.fail(ResultCode.USERNAME_EXISTS, ResultCode.USERNAME_EXISTS.getMessage());
    }

    /**
     * 兜底:未捕获异常记录 ERROR 日志(含栈),对外只返回通用错误码,不泄露内部细节。
     */
    @ExceptionHandler(Exception.class)
    public <T> Result<T> handleException(Exception ex) {
        LOG.error("系统异常", ex);
        return Result.fail(ResultCode.SYSTEM_ERROR, ResultCode.SYSTEM_ERROR.getMessage());
    }
}