package com.vincent.rsf.server.common.exception; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.common.constant.Constants; import com.vincent.rsf.server.common.utils.CommonUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DuplicateKeyException; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.request.async.AsyncRequestNotUsableException; import jakarta.servlet.http.HttpServletResponse; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 全局异常处理器 * * @author vincent * @since 2018-02-22 11:29:30 */ @ControllerAdvice public class GlobalExceptionHandler { private final Logger logger = LoggerFactory.getLogger(getClass()); @ResponseBody @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public R methodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e, HttpServletResponse response) { e.printStackTrace(); CommonUtil.addCrossHeaders(response); return R.error("The request method is incorrect"); } @ResponseBody @ExceptionHandler(AccessDeniedException.class) public R accessDeniedExceptionHandler(AccessDeniedException e, HttpServletResponse response) { CommonUtil.addCrossHeaders(response); return R.parse(Constants.UNAUTHORIZED_CODE + "-" + Constants.UNAUTHORIZED_MSG); } @ResponseBody @ExceptionHandler(BusinessException.class) public R businessExceptionHandler(BusinessException e, HttpServletResponse response) { CommonUtil.addCrossHeaders(response); return R.parse(e.getMessage()); } @ResponseBody @ExceptionHandler(CoolException.class) public R coolExceptionHandler(CoolException e, HttpServletResponse response) { CommonUtil.addCrossHeaders(response); return R.error(e.getMessage()); } @ResponseBody @ExceptionHandler(DuplicateKeyException.class) public R duplicateKeyExceptionHandler(DuplicateKeyException e, HttpServletResponse response) { CommonUtil.addCrossHeaders(response); String msg = e.getMessage(); String out = "唯一索引冲突"; try { Pattern p = Pattern.compile("Duplicate entry '(.+?)' for key '(.+?)'"); Matcher m = p.matcher(msg); if (m.find()) { String value = m.group(1); String key = m.group(2); if ("idx_code".equalsIgnoreCase(key)) { out = "编码已存在:" + value; } else { out = "唯一索引[" + key + "]值已存在:" + value; } } } catch (Exception ignore) {} return R.error(out); } @ExceptionHandler(AsyncRequestNotUsableException.class) public void asyncRequestNotUsableExceptionHandler(AsyncRequestNotUsableException e) { logger.warn("Client connection aborted: {}", resolveAbortMessage(e)); } @ResponseBody @ExceptionHandler(RuntimeException.class) public R runtimeExceptionHandler(RuntimeException e, HttpServletResponse response) { if (isClientAbortException(e)) { logger.warn("Client connection aborted: {}", resolveAbortMessage(e)); return null; } CommonUtil.addCrossHeaders(response); Throwable cause = e.getCause(); if (cause instanceof CoolException) { return R.error(cause.getMessage()); } logger.error(e.getMessage(), e); return R.error(Constants.RESULT_ERROR_MSG); } @ResponseBody @ExceptionHandler(Throwable.class) public R exceptionHandler(Throwable e, HttpServletResponse response) { if (isClientAbortException(e)) { logger.warn("Client connection aborted: {}", resolveAbortMessage(e)); return null; } logger.error(e.getMessage(), e); CommonUtil.addCrossHeaders(response); return R.error(Constants.RESULT_ERROR_MSG); } private boolean isClientAbortException(Throwable throwable) { Throwable current = throwable; while (current != null) { String message = current.getMessage(); if (message != null) { String normalized = message.toLowerCase(); if (normalized.contains("broken pipe") || normalized.contains("connection reset") || normalized.contains("forcibly closed") || normalized.contains("abort")) { return true; } } current = current.getCause(); } return false; } private String resolveAbortMessage(Throwable throwable) { Throwable current = throwable; while (current != null) { String message = current.getMessage(); if (message != null && !message.isBlank()) { return message; } current = current.getCause(); } return "client aborted connection"; } }