The custom filter throws an exception and does not use the global custom exception.

Problem description

Tips: Describe the problems encountered in the project here:

Exceptions thrown by custom filters do not use custom global exceptions

Cause analysis:

The exception thrown when customizing the filter cannot go to the controller, so it will not go to the custom global exception.

{<!-- -->
    "timestamp": "2023-09-06 16:29:30",
    "status": 500,
    "error": "Internal Server Error",
    "path": "/openapi/openApi/test"
}

Solution:

1. Customize a filter to capture filter exceptions

public class ExceptionFilter implements Filter {<!-- -->
    public static final String ERROR_CONTROLLER_PATH = "/error/throw";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {<!-- -->
        try {<!-- -->
            filterChain.doFilter(request, response);
        } catch (BizException e) {<!-- -->
            e.printStackTrace();
            // Pass exception information
            request.setAttribute("filterError", e);
            //Specify the processor to handle the request
            request.getRequestDispatcher(ERROR_CONTROLLER_PATH).forward(request, response);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {<!-- -->

    }


    @Override
    public void destroy() {<!-- -->

    }
}

Register filter:

@Configuration
public class OpenApiFilterConfig {<!-- -->
    // Filter code class
    @Bean
    public ExceptionFilter ExceptionFilter() {<!-- -->
        return new ExceptionFilter();
    }
    @Bean
    public FilterRegistrationBean exceptionFilter(ExceptionFilter exceptionFilter) {<!-- -->
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(exceptionFilter);
        registrationBean.setName("exceptionFilter");
        registrationBean.setOrder(-1);
        return registrationBean;
    }
}

Define exception handling controller:

@RestController
public class ExceptionController {<!-- -->
    public static final String ERROR_CONTROLLER_PATH = "/error/throw";

    @RequestMapping(ERROR_CONTROLLER_PATH)
    public void handleException(HttpServletRequest request) {<!-- -->
        throw (BizException) request.getAttribute("filterError");
    }
}

Custom global exception

@ControllerAdvice
public class GlobalExceptionHandler {<!-- -->
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * Handle customized business exceptions
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e) {<!-- -->
        logger.error("A business exception occurred! The reason is: {}", e.getErrorMsg());
        return ResultBody.error(e.getErrorCode(), e.getErrorMsg(),e.getMessage());
    }

    /**
     * Handle null pointer exceptions
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {<!-- -->
        logger.error("A null pointer exception occurred! The reason is:", e);
        return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
    }


    /**
     * Handle other exceptions
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResultBody exceptionHandler(HttpServletRequest req, Exception e) {<!-- -->
        logger.error("Unknown exception! The reason is:", e);
        return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
    }

Related encapsulation classes and interfaces

public class BizException extends RuntimeException {<!-- -->
    private static final long serialVersionUID = 1L;

    /**
     * error code
     */
    protected String errorCode;
    /**
     * error message
     */
    protected String errorMsg;
    /**
     * Error message code
     */
    protected String message;

    public BizException() {<!-- -->
        super();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface) {<!-- -->
        super(errorInfoInterface.getResultCode());
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
        this.message = errorInfoInterface.getMessage();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {<!-- -->
        super(errorInfoInterface.getResultCode(), cause);
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
        this.message = errorInfoInterface.getMessage();
    }

    public BizException(String errorMsg) {<!-- -->
        super(errorMsg);
        this.message = errorMsg;
    }

    public BizException(String errorCode, String errorMsg) {<!-- -->
        super(errorCode);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg, String message) {<!-- -->
        super(errorCode);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
        this.message = message;
    }

    public BizException(String errorCode, String errorMsg, Throwable cause) {<!-- -->
        super(errorCode, cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg, String message, Throwable cause) {<!-- -->
        super(errorCode, cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
        this.message = message;

    }


    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 message;
    }

    public void setMessage(String message) {<!-- -->
        this.message = message;
    }

    @Override
    public Throwable fillInStackTrace() {<!-- -->
        return this;
    }

}

public interface BaseErrorInfoInterface {<!-- -->
    /**
     * error code
     */
    String getResultCode();

    /**
     * wrong description
     */
    String getResultMsg();

    /**
     * Error message code
     */
    String getMessage();
}

public enum CommonEnum implements BaseErrorInfoInterface {<!-- -->
    //Data operation error definition
    SUCCESS("200", "Success!", "SUCCESS"),
    BODY_NOT_MATCH("400", "The requested data format does not match!", "BODY_NOT_MATCH"),
    INTERNAL_SERVER_ERROR("500", "Server internal error!", "INTERNAL_SERVER_ERROR"),
    INVALID_ACCOUNTID("406", "Invalid Happy Office ID", "INVALID_ACCOUNTID"),
    NOT_FOUND_ACCOUNTID("407", "The Happy Office ID must be sent but was not sent", "NOT_FOUND_ACCOUNTID"),
    NOT_FOUND_PROCINSID_FORMID_FORMTITLE("402", "Process definition id form id work order title priority process type must be passed but not passed", "NOT_FOUND_PROCINSID_FORMID_FORMTITLE"),
    NOT_FOUND_PROCINSID_DEPLOYID("408", "Process id deployment id must be passed but was not passed", "NOT_FOUND_PROCINSID_DEPLOYID"),
    BODY_NOT_TIMESTAMP("400", "The request header does not carry a timestamp", "BODY_NOT_TIMESTAMP"),
    BODY_NOT_SIGN("400", "The request header sign is empty", "BODY_NOT_SIGN"),
    BODY_NOT_APPID("400", "The request header appId is empty and the signature verification failed", "BODY_NOT_APPID"),
    TIMEOUT("406", "Signature verification failed, more than three minutes", "TIMEOUT"),
    NOT_APPINFO("406", "No corresponding information found, signature verification failed.", "NOT_APPINFO"),
    NOT_APP_SECRET("406", "app_secret, the query is empty, the signature verification failed", "NOT_APP_SECRET"),
    DIFFERENT_SIGN("406", "sign encryption is different, signature verification failed", "DIFFERENT_SIGN"),
    SERVER_BUSY("503", "The server is busy, please try again later!", "SERVER_BUSY");

    /**
     * error code
     */
    private String resultCode;

    /**
     * wrong description
     */
    private String resultMsg;
    /**
     * Error message code
     */
    private String message;

    CommonEnum(String resultCode, String resultMsg, String message) {<!-- -->
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;
        this.message = message;
    }

    @Override
    public String getResultCode() {<!-- -->
        return resultCode;
    }

    @Override
    public String getResultMsg() {<!-- -->
        return resultMsg;
    }

    @Override
    public String getMessage() {<!-- -->
        return message;
    }

}

public class ResultBody {<!-- -->
    /**
     * response code
     */
    private String code;

    /**
     * response message
     */
    private String message;
    /**
     *Response message code
     */
    private String msg;

    /**
     *Response results
     */
    private Object result;

    public ResultBody() {<!-- -->
    }

    public ResultBody(BaseErrorInfoInterface errorInfo) {<!-- -->
        this.code = errorInfo.getResultCode();
        this.message = errorInfo.getResultMsg();
        this.msg = errorInfo.getMessage();
    }

    public String getCode() {<!-- -->
        return code;
    }

    public void setCode(String code) {<!-- -->
        this.code = code;
    }

    public String getMessage() {<!-- -->
        return message;
    }

    public void setMessage(String message) {<!-- -->
        this.message = message;
    }

    public Object getResult() {<!-- -->
        return result;
    }

    public void setResult(Object result) {<!-- -->
        this.result = result;
    }

    public String getMsg() {<!-- -->
        return msg;
    }

    public void setMsg(String msg) {<!-- -->
        this.msg = msg;
    }

    /**
     * success
     *
     * @return
     */
    public static ResultBody success() {<!-- -->
        return success(null);
    }

    /**
     * success
     *
     * @param data
     * @return
     */
    public static ResultBody success(Object data) {<!-- -->
        ResultBody rb = new ResultBody();
        rb.setCode(CommonEnum.SUCCESS.getResultCode());
        rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
        rb.setMsg(CommonEnum.SUCCESS.getMessage());
        rb.setResult(data);
        return rb;
    }

    /**
     * fail
     */
    public static ResultBody error(BaseErrorInfoInterface errorInfo) {<!-- -->
        ResultBody rb = new ResultBody();
        rb.setCode(errorInfo.getResultCode());
        rb.setMessage(errorInfo.getResultMsg());
        rb.setMsg(errorInfo.getMessage());
        rb.setResult(null);
        return rb;
    }

    /**
     * fail
     */
    public static ResultBody error(String code, String message, String msg) {<!-- -->
        ResultBody rb = new ResultBody();
        rb.setCode(code);
        rb.setMessage(message);
        rb.setMsg(msg);
        rb.setResult(null);
        return rb;
    }

    /**
     * fail
     */
    public static ResultBody error(String message) {<!-- -->
        ResultBody rb = new ResultBody();
        rb.setCode("-1");
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    @Override
    public String toString() {<!-- -->
        return JSONObject.toJSONString(this);
    }

}

perfect solution

{<!-- -->
"code": "400",
"message": "The request header does not carry a timestamp",
"msg": "BODY_NOT_TIMESTAMP",
"result": null
}