| | |
| | | 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 javax.servlet.http.HttpServletResponse; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * 全局异常处理器 |
| | |
| | | @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"; |
| | | } |
| | | |
| | | } |
| | | |