Spring Boot maneja las excepciones globales de manera uniforme

Introducción a @ControllerAdvice

La anotación @ControllerAdvice es una nueva anotación en Spring 3.2 El nombre científico es Controller Enhancer, que se usa para agregar operaciones unificadas o procesamiento al controlador Controller.

Aquí ControllerAdvice también puede entenderse de esta manera. Su nivel de abstracción debe usarse para rodear al Controller, y el método de tejido de negocios específico se realiza combinando otras anotaciones.

uso

1. Combinado con la anotación del método @ExceptionHandler, se usa para capturar el tipo específico de excepción lanzada en el controlador, para lograr el propósito de distinguir diferentes tipos de excepciones.

2. Combinado con la anotación del método @InitBinder, se usa para registrar el método de análisis de parámetros personalizados en la solicitud, para lograr el propósito de personalizar los parámetros de formato especificados.

3. Combinado con la anotación del método @ModelAttribute, significa que el método anotado se ejecutará antes de que se ejecute el método del controlador de destino.

Como se puede ver en la explicación anterior, el uso de @ControllerAdvice es básicamente declararlo en un bean y luego usar otras anotaciones en el método bean para especificar una lógica de tejido diferente. Sin embargo, @ControllerAdvice no usa AOP para tejer la lógica empresarial, pero Spring tiene soporte integrado para tejer sus diversas lógicas.

@Component @ExceptionHandler para las clases que declaran los métodos @ExceptionHandler, @InitBinder o @ModelAttribute, @InitBinder se comparte entre varias clases de @Controller.

Las clases anotadas con @ControllerAdvice pueden declararse explícitamente como Spring beans o detectarse automáticamente mediante el escaneo de classpath. Todos estos beans están ordenados de acuerdo con la semántica ordenada o las declaraciones @Order/@Priority. La semántica ordenada tiene prioridad sobre las declaraciones @Order/@Priority. Los beans @ControllerAdvice luego se aplican en ese orden en tiempo de ejecución. Tenga en cuenta, sin embargo, que un bean que implementa PriorityOrdered @ControllerAdvice no tiene mayor PriorityOrdered que un bean que implementa Ordered @ControllerAdvice. Además, Ordered no se aplica a un @ControllerAdvice con ámbito, por ejemplo, si dicho bean se ha configurado como un bean con ámbito de solicitud o de sesión. Para el manejo de excepciones, se seleccionará @ExceptionHandler en la primera notificación con un método de manejo de excepciones coincidente. Para la inicialización del enlace de datos y atributos del modelo, los métodos @ModelAttribute y @InitBinder seguirán el orden @ControllerAdvice.

Nota: Para los métodos @ExceptionHandler, en el método del controlador de un bean de aviso en particular, la coincidencia de la excepción raíz tendrá prioridad sobre la coincidencia de la causa de la excepción actual. Sin embargo, aún se prefiere una coincidencia de causa en una sugerencia de prioridad más alta que cualquier coincidencia en un bean de sugerencia de prioridad más baja, ya sea a nivel raíz o de causa. Por lo tanto, declare su mapeo de excepción raíz principal en el bean de asesoramiento de prioridad en el orden apropiado.

De forma predeterminada, los métodos @ControllerAdvice en ControllerAdvice se aplican globalmente a todos los controladores. Use selectores como anotaciones, basePackageClasses y basePackages (o su valor de alias) para definir un subconjunto más limitado de controladores de destino. Si se declaran varios selectores, se aplica la lógica OR booleana, lo que significa que el controlador seleccionado debe coincidir con al menos un selector. Tenga en cuenta que la verificación del selector se realiza en tiempo de ejecución, por lo que agregar muchos selectores puede afectar negativamente el rendimiento y aumentar la complejidad.

@ExceptionHandler intercepta excepciones y las maneja de manera uniforme

En combinación con la anotación @ExceptionHandler, cuando la excepción se lanza a la capa del controlador, la excepción se puede manejar de manera uniforme, especificando el formato json devuelto o saltando a la página de error especificada, etc.

La función de @ExceptionHandler es principalmente declarar uno o más tipos de excepciones. Cuando el Controlador calificado lanza estas excepciones, estas excepciones serán capturadas y luego procesadas de acuerdo con la lógica de los métodos marcados por ellos, cambiando así la información de vista devuelta. .

Anotación para manejar excepciones en una clase de controlador y/o método de controlador específicos.

Los métodos de controlador anotados con esta anotación permiten tener firmas muy flexibles. Pueden tener parámetros de los siguientes tipos, en cualquier orden:

Parámetro de excepción: declarado como una excepción general o una excepción más específica. Esto también se puede usar como una sugerencia de mapeo si la anotación en sí no limita el tipo de excepción por su valor ()

Código

/**
 * 自定义一个异常类,用于处理我们发生的业务异常

 */
public class BizException extends RuntimeException {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 错误码
     */
    protected String errorCode;
    /**
     * 错误信息
     */
    protected String errorMsg;
 
    public BizException() {
        super();
    }
 
    public BizException(FrontResult errorInfoInterface) {
        super(errorInfoInterface.getCode());
        this.errorCode = errorInfoInterface.getMessage();
        this.errorMsg = errorInfoInterface.getMessage();
    }
 
    public BizException(FrontResult errorInfoInterface, Throwable cause) {
        super(errorInfoInterface.getCode(), cause);
        this.errorCode = errorInfoInterface.getCode();
        this.errorMsg = errorInfoInterface.getMessage();
    }
 
    public BizException(String errorMsg) {
        super(errorMsg);
        this.errorMsg = errorMsg;
    }
 
    public BizException(String errorCode, String errorMsg) {
        super(errorCode);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }
 
    public BizException(String errorCode, String errorMsg, Throwable cause) {
        super(errorCode, cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }
 
 
    public String getErrorCode() {
        return errorCode;
    }
 
    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }
 
    public String getErrorMsg() {
        return errorMsg;
    }
 
    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }
 
    public String getMessage() {
        return errorMsg;
    }
 
    @Override
    public Throwable fillInStackTrace() {
        return this;
    }
 
}

Manejo unificado de excepciones

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
 
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.SQLException;
 
/**
 * 统一异常处理

 */
@ControllerAdvice//使用该注解表示开启了全局异常的捕获
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
    /**
     * 处理自定义的业务异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public  FrontResult bizExceptionHandler(HttpServletRequest req, BizException e){
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生业务异常!原因是:{}",e.getErrorMsg());
        return FrontResult.getExceptionResult(e.getErrorCode(),e.getErrorMsg());
    }
 
    /**
     * 处理空指针的异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, NullPointerException e)  {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生空指针异常!原因是:",e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());
    }
 
    /**
     * 处理索引越界异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =IndexOutOfBoundsException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, IndexOutOfBoundsException e){
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("索引越界异常!原因是:",e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());
    }
 
    /**
     * 处理类未找到异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =ClassNotFoundException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, ClassNotFoundException e)  {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生类未找到异常!原因是:",e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());
    }
 
 
    /**
     * 处理SQL异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = SQLException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, SQLException e)  {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生SQL异常!原因是:",e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());
    }
 
    /**
     * 处理IO异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = IOException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, IOException e)  {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生IO异常!原因是:",e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());
    }
 
 
    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, Exception e){
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("未知异常!原因是:",e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());
    }
 
 
 
}

Clase de valor de retorno de front-end

 
 

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FrontResult {
    /**
     * 结果状态码
     */
    private String code;
    /**
     * 响应结果描述
     */
    private String message;
    /**
     * 返回数据
     */
    private Object data;
 
    /**
     * 静态方法,返回前端实体结果
     *
     * @param code    状态码
     * @param message 消息
     * @param data    数据
     * @return 前端实体结果
     */
    public static FrontResult build(String code, String message, Object data) {
        return new FrontResult(code, message, data);
    }
 
    /**
     * 返回成功的结果实体
     *
     * @param message 消息
     * @param data    数据
     * @return 实体
     */
    public static FrontResult getSuccessResult(String message, Object data) {
        FrontResult result = new FrontResult();
        result.code = ResultCodeEnum.SUCCESS.getCode();
        result.message = message;
        result.data = data;
        return result;
    }
 
    /**
     * 返回无需data的成功结果实体
     *
     * @param message 消息内容
     * @return 返回结果
     */
    public static FrontResult getSuccessResultOnlyMessage(String message) {
        FrontResult result = new FrontResult();
        result.code = ResultCodeEnum.SUCCESS.getCode();
        result.message = message;
        result.data = null;
        return result;
    }
 
    /**
     * 获取一个异常结果
     *
     * @param code 错误码
     * @param message 自定义异常信息
     * @return FrontResult
     */
    public static FrontResult getExceptionResult(String code, String message) {
        FrontResult result = new FrontResult();
        result.code = code.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getCode() : code;
        result.message = message.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getMsg() : message;
        return result;
    }
}
import lombok.AllArgsConstructor;
 
@AllArgsConstructor
public enum ResultCodeEnum {
    // 请求成功
    SUCCESS("0000"),
    // 请求失败
    FAIL("1111"),
    // EXCEL 导入失败
    EXCEL_FAIL("1000"),
    // userID 为空
    ID_NULL("1001"),
    // 前端传的实体为空
    MODEL_NULL("1002"),
    // 更新失败
    UPDATE_FAIL("1011"),
    // 参数为空
    PARAM_ERROR("400"),
    // 代码内部异常
    CODE_EXCEPTION("500", "代码内部异常");
 
    /**
     * 状态码
     */
    private String code;
 
    public String getCode() {
        return code;
    }
 
    ResultCodeEnum(String code) {
        this.code = code;
    }
 
    private String msg;
 
    public String getMsg() {
        return msg;
    }
 
}
 
 
public enum ResutlMsgEnum {
 
    //查询成功
    FIND_SUCCESS("查询成功!"),
    //查询失败
    FIND_FAIL("查询失败!"),
 
    //更新成功
    UPDATE_SUCCESS("更新成功"),
    //更新失败
    UPDATE_FAIL("更新成功"),
   
    SEND_SUCCESS("发送成功"),
 
    SEND_FAIL("发送失败");
 
 
    private String msg;
 
    ResutlMsgEnum(String msg) {
        this.msg = msg;
    }
 
    public String getMsg() {
        return msg;
    }
}
/**
 * 测试用例

 */
@Api(tags = {"测试controller"})
@RequestMapping(value = "/testController")
@RestController
public class TestController {
 
   
    @ApiOperation(value = "测试null")
    @GetMapping(value = "getNull")
    public FrontResult getNull() {
        int length = 0;
 
            String name=null;
            length = name.length();
 
 
        return FrontResult.build(ResultCodeEnum.SUCCESS.getCode(),
                ResutlMsgEnum.EXECUTE_SUCCESS.getMsg(), length);
    }
}

Supongo que te gusta

Origin blog.csdn.net/liuerchong/article/details/123712804
Recomendado
Clasificación