123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- package com.backendsys.exception;
- import cn.hutool.core.convert.Convert;
- import cn.hutool.core.date.DateUtil;
- import com.backendsys.modules.dingtalk.utils.DingTalkUtil;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.backendsys.utils.response.Result;
- import com.backendsys.utils.response.ResultEnum;
- import com.google.common.collect.Lists;
- import jakarta.servlet.http.HttpServletRequest;
- import jakarta.validation.ConstraintViolation;
- import jakarta.validation.ConstraintViolationException;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.ibatis.exceptions.PersistenceException;
- import org.apache.ibatis.exceptions.TooManyResultsException;
- import org.mybatis.spring.MyBatisSystemException;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.core.MethodParameter;
- import org.springframework.dao.DuplicateKeyException;
- import org.springframework.data.redis.RedisConnectionFailureException;
- import org.springframework.http.MediaType;
- import org.springframework.http.converter.HttpMessageConverter;
- import org.springframework.http.converter.HttpMessageNotReadableException;
- import org.springframework.http.server.ServerHttpRequest;
- import org.springframework.http.server.ServerHttpResponse;
- import org.springframework.security.access.AccessDeniedException;
- import org.springframework.validation.BindingResult;
- import org.springframework.web.HttpRequestMethodNotSupportedException;
- import org.springframework.web.bind.MethodArgumentNotValidException;
- import org.springframework.web.bind.MissingServletRequestParameterException;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.RestControllerAdvice;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
- import org.springframework.web.servlet.NoHandlerFoundException;
- import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
- import javax.security.auth.login.LoginException;
- import java.util.*;
- import java.util.concurrent.CompletableFuture;
- /**
- * https://juejin.cn/post/6844903902811275278
- * https://juejin.cn/post/7132747726965440520
- * 待看
- */
- @Slf4j
- @RestControllerAdvice
- public class GlobalExceptionHandler implements ResponseBodyAdvice<Object> {
- @Autowired
- private ObjectMapper objectMapper;
- /**
- * 是否开启功能 true:开启
- */
- @Override
- public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
- return true;
- }
- /**
- * 返回结果拦截器 (可以修改响应体的逻辑,或添加其他自定义逻辑)
- */
- @Override
- public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
- // System.out.println("beforeBodyWrite:");
- // System.out.println(o);
- // if(o instanceof String){
- // return o;
- // try {
- // return objectMapper.writeValueAsString(Result.success(o));
- // } catch (JsonProcessingException e) {
- // e.printStackTrace();
- // }
- // }
- // //返回类型是否已经封装
- // if(o instanceof Result){
- // return Result.success(o);
- // }
- return o;
- }
- // -- 记录当前 访问URL、访问人IP --------------------------------------------------
- private static void printRequestInfo() {
- // 获取请求的URL
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- if (attributes != null) {
- HttpServletRequest request = attributes.getRequest();
- if (request != null) {
- String method = request.getMethod();
- String url = request.getRequestURL().toString();
- String ip = request.getRemoteAddr();
- // 记录URL和IP地址
- log.warn("[" + method + "] " + url + ", (" + ip + ")");
- }
- }
- }
- // -- 自定义异常输出结构 (警告) ----------------------------------------------------
- private static void printWarnException(Exception e) {
- printRequestInfo();
- log.warn(e.getClass().getName() + ": " + e.getMessage());
- }
- // -- 自定义异常输出结构 (错误) ----------------------------------------------------
- private static void printErrorException(Exception e, Boolean isPrintStack) {
- log.error("========================================================================");
- // printRequestInfo();
- // 获取请求的URL
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- if (attributes != null) {
- HttpServletRequest request = attributes.getRequest();
- if (request != null) {
- String url = request.getRequestURL().toString();
- String ip = request.getRemoteAddr();
- String method = request.getMethod();
- String createTime = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
- String serverName = request.getServerName();
- // 访问根目录报404也会触发此错误提示
- // // --- 向钉钉发送消息 -----------------------------------
- // // (本地环境不触发)
- // if (!"localhost".equals(serverName)) {
- // // 创建一个 CompletableFuture 来执行异步任务
- // CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
- // try {
- // String message = "【系统异常】:" + e.getMessage() + "\n" +
- // "【异常接口】:" + url + "\n" +
- // "【异常堆栈】:" + Convert.toStr(e.getStackTrace()).substring(0, 400) + "\n" +
- // "【异常时间】:" + createTime + "\n" +
- // "【异常来源】:" + ip;
- // DingTalkUtil.sendTextMsg(message, Lists.newArrayList(), Lists.newLinkedList(), false);
- // } catch (Exception ex) {
- // System.out.println("钉钉群消息发送异常,异常原因:" + ex.getMessage());
- // log.error(ex.getMessage());
- // }
- // });
- // }
- // // ---------------------------------------------------
- // 记录URL和IP地址
- log.error("[" + method + "] " + url + ", (" + ip + ")");
- }
- }
- // 记录 当前异常类的class名称、异常消息
- log.error(e.getMessage() + " (" + e.getClass().getName() + ")");
- // 记录异常的详细信息
- if (isPrintStack) {
- log.error(Convert.toStr(e.getStackTrace()));
- e.printStackTrace();
- }
- log.error("========================================================================");
- }
- private static void printErrorException(Exception e) {
- printErrorException(e, false);
- }
- // -----------------------------------------------------------------------
- /**
- * 异常 参数错误
- */
- @ExceptionHandler(ConstraintViolationException.class)
- public Result handleConstraintViolationException(ConstraintViolationException e) {
- System.out.println("****** ConstraintViolationException.class: ******");
- printErrorException(e);
- Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
- Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
- List<String> msgList = new ArrayList<>();
- while (iterator.hasNext()) {
- ConstraintViolation<?> cvl = iterator.next();
- msgList.add(cvl.getMessageTemplate());
- }
- System.out.println(msgList.get(0));
- log.error(msgList.get(0));
- return Result.error(ResultEnum.PARAMETER_EXCEPTION.getCode(), msgList.get(0));
- }
- /**
- * 参数校验异常 (Validate)
- */
- // 未测试
- @ExceptionHandler(MethodArgumentNotValidException.class)
- public Result handlerMethodArgumentException(MethodArgumentNotValidException e){
- System.out.println("****** MethodArgumentNotValidException.class: ******");
- printWarnException(e);
- return Result.error(
- ResultEnum.PARAMETER_EXCEPTION.getCode(),
- e.getBindingResult().getAllErrors().get(0).getDefaultMessage(),
- "Field: " + e.getBindingResult().getFieldError().getField()
- );
- }
- @ExceptionHandler(MissingServletRequestParameterException.class)
- public Result handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
- System.out.println("****** MissingServletRequestParameterException.class: ******");
- printErrorException(e, true);
- return Result.error(
- ResultEnum.PARAMETER_EXCEPTION.getCode(),
- "缺少参数 " + e.getParameterName() + " 或类型不匹配 (" + e.getParameterType() + ")",
- e.getMessage()
- );
- }
- /**
- * 参数类型异常
- */
- @ExceptionHandler(NumberFormatException.class)
- public Result handleNumberFormatException(NumberFormatException e) {
- System.out.println("****** NumberFormatException.class: ******");
- printErrorException(e, true);
- return Result.error(ResultEnum.PARAMETER_EXCEPTION.getCode(), e.getMessage());
- }
- /**
- * 自定义异常类
- * throw new CustException("错误提示")
- */
- @ExceptionHandler(CustException.class)
- public Result handleCustException(CustException e) {
- System.out.println("****** CustException.class: ******");
- printWarnException(e);
- // printErrorException(e);
- return Result.error(e.getErrorCode() != null ? e.getErrorCode() : ResultEnum.PARAMETER_EXCEPTION.getCode(), e.getMessage(), e.getErrorObject());
- }
- /**
- * 自定义异常类 (仅返回文本)
- */
- @ExceptionHandler(CustExceptionSimple.class)
- public String handleCustExceptionSimple(CustExceptionSimple e) {
- System.out.println("****** CustExceptionSimple.class: ******");
- printErrorException(e);
- return e.getMessage();
- }
- /**
- * MyBatis异常
- */
- @ExceptionHandler(TooManyResultsException.class)
- public Result handleTooManyResultsException(TooManyResultsException e) {
- System.out.println("****** TooManyResultsException.class: ******");
- printErrorException(e, true);
- return Result.error(ResultEnum.SERVICE_EXCEPTION.getCode(), e.getMessage());
- }
- /**
- * 登录异常
- */
- @ExceptionHandler(LoginException.class)
- public Result handleLoginException(LoginException e) {
- System.out.println("****** LoginException.class: ******");
- printErrorException(e, true);
- return Result.error(ResultEnum.AUTH_ERROR.getCode(), e.getMessage());
- }
- /**
- * 权限异常
- */
- @ExceptionHandler(AccessDeniedException.class)
- public Result handleAccessDeniedException(AccessDeniedException e) {
- System.out.println("****** AccessDeniedException.class: ******");
- printWarnException(e);
- return Result.error(ResultEnum.AUTH_ROLE_ERROR.getCode(), ResultEnum.AUTH_ROLE_ERROR.getMessage());
- }
- /**
- * 接口不存在 异常
- */
- @ExceptionHandler(NoHandlerFoundException.class)
- public Result handleNoHandlerFoundException(NoHandlerFoundException e) {
- System.out.println("****** NoHandlerFoundException.class: ******");
- printErrorException(e, true);
- return Result.error(ResultEnum.INTERNAL_ERROR.getCode(), e.getMessage());
- }
- /**
- * Mybatis 异常抛出
- */
- @ExceptionHandler(MyBatisSystemException.class)
- public Result handleMyBatisSystemException(MyBatisSystemException e, BindingResult bindingResult) { // , BindingResult bindingResult
- System.out.println("****** MyBatisSystemException.class: ******");
- printErrorException(e, true);
- Throwable cause = e.getCause();
- if (cause instanceof PersistenceException) {
- Throwable sqlException = cause.getCause();
- if (sqlException != null ) {
- if (sqlException.getMessage() == "argument type mismatch") {
- System.out.println(sqlException.getMessage() + ", 参数类型不匹配");
- log.error(sqlException.getMessage() + ", 参数类型不匹配");
- }
- return Result.error(ResultEnum.INTERNAL_ERROR.getCode(), ResultEnum.INTERNAL_ERROR.getMessage(), sqlException.getMessage());
- } else {
- // [抛出异常] 实体类缺少字段
- return Result.error(ResultEnum.INTERNAL_ERROR.getCode(), ResultEnum.INTERNAL_ERROR.getMessage(), cause.getMessage());
- }
- }
- return Result.error(ResultEnum.INTERNAL_ERROR.getCode(), e.getMessage());
- }
- /**
- * MySQL 数据库 唯一值异常
- */
- @ExceptionHandler(DuplicateKeyException.class)
- public Result handleDuplicateKeyException(DuplicateKeyException e) {
- System.out.println("****** DuplicateKeyException.class: ******");
- printErrorException(e, true);
- DuplicateKeyExceptionHandler handler = new DuplicateKeyExceptionHandler();
- return handler.handleDuplicateKeyException(e);
- }
- /**
- * Redis 连接异常
- */
- @ExceptionHandler(RedisConnectionFailureException.class)
- public Result handleRedisConnectionFailureException(Exception e) {
- System.out.println("****** RedisConnectionFailureException.class: ******");
- printErrorException(e, true);
- return Result.error(ResultEnum.REDIS_ERROR.getCode(), e.getMessage());
- }
- /**
- * 请求体参数不能为空 (body)
- */
- @ExceptionHandler(HttpMessageNotReadableException.class)
- public Result handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
- System.out.println("****** HttpMessageNotReadableException.class: ******");
- printWarnException(e);
- return Result.error(ResultEnum.HTTP_BODY_EMPTY.getCode(), e.getMessage() != null ? e.getMessage() : ResultEnum.HTTP_BODY_EMPTY.getMessage());
- }
- /**
- * 请求方法不支持 (Get/Post)
- */
- @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
- public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
- System.out.println("****** HttpRequestMethodNotSupportedException.class: ******");
- printWarnException(e);
- return Result.error(ResultEnum.HTTP_METHOD_ERROR.getCode(), ResultEnum.HTTP_METHOD_ERROR.getMessage());
- }
- /**
- * 其他异常:
- */
- @ExceptionHandler(Exception.class)
- public Result handleException(Exception e) { // , BindingResult bindingResult
- System.out.println("****** Exception.class: ******");
- printErrorException(e, true);
- return Result.error(ResultEnum.INTERNAL_ERROR.getCode(), e.getMessage());
- }
- // 非法参数
- @ExceptionHandler(IllegalArgumentException.class)
- public Result handleIllegalArgumentException(IllegalArgumentException e) {
- System.out.println("****** IllegalArgumentException.class: ******");
- printErrorException(e);
- return Result.error(ResultEnum.PARAMETER_EXCEPTION.getCode(), ResultEnum.PARAMETER_EXCEPTION.getMessage(), e.getMessage());
- }
- // 优先级太高,会覆盖其他异常
- // @ExceptionHandler(RuntimeException.class)
- // public Result handleRuntimeException(RuntimeException e) {
- // System.out.println("****** RuntimeException.class: ******");
- // System.out.println(e);
- //// System.out.println(e.getMessage());
- //// if (e.getClass().getTypeName() == "java.lang.NullPointerException") {
- //// return Result.error(ResultEnum.NULL_POINTER.getCode(), e.getMessage());
- //// }
- // return Result.error(ResultEnum.SERVICE_EXCEPTION.getCode(), e.getMessage());
- // }
- }
|