From ed838e62602c0a63a64ff4bd144a0d16cc9a7cf8 Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期五, 10 四月 2026 09:39:25 +0800
Subject: [PATCH] 和客户同步1.0版本

---
 xp-robotaxi-common/xp-common-security/src/main/java/com/xiaopeng/common/security/handler/GlobalExceptionHandler.java |  369 +++++++++++++++++++++++++++++-----------------------
 1 files changed, 208 insertions(+), 161 deletions(-)

diff --git a/xp-robotaxi-common/xp-common-security/src/main/java/com/xiaopeng/common/security/handler/GlobalExceptionHandler.java b/xp-robotaxi-common/xp-common-security/src/main/java/com/xiaopeng/common/security/handler/GlobalExceptionHandler.java
index ef00afd..d5b7ec4 100644
--- a/xp-robotaxi-common/xp-common-security/src/main/java/com/xiaopeng/common/security/handler/GlobalExceptionHandler.java
+++ b/xp-robotaxi-common/xp-common-security/src/main/java/com/xiaopeng/common/security/handler/GlobalExceptionHandler.java
@@ -1,5 +1,7 @@
 package com.xiaopeng.common.security.handler;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.xiaopeng.common.core.constant.HttpStatus;
 import com.xiaopeng.common.core.exception.DemoModeException;
 import com.xiaopeng.common.core.exception.InnerAuthException;
@@ -10,6 +12,7 @@
 import com.xiaopeng.common.core.exception.user.UserAppletException;
 import com.xiaopeng.common.core.utils.StringUtils;
 import com.xiaopeng.common.core.web.domain.AjaxResult;
+import feign.FeignException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -32,170 +35,214 @@
  */
 @RestControllerAdvice
 public class GlobalExceptionHandler {
-	private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
-	
-	@Value("${spring.servlet.multipart.max-file-size:50MB}")
-	private String maxFileSize;
-	@Value("${spring.servlet.multipart.max-request-size:100MB}")
-	private String maxRequestSize;
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
-	@Autowired
-	private MessageSource messageSource;
-	/**
-	 * 权限码异常
-	 */
-	@ExceptionHandler(NotPermissionException.class)
-	public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
-		String requestURI = request.getRequestURI();
-		log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage());
-		return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权");
-	}
-	
-	/**
-	 * 角色权限异常
-	 */
-	@ExceptionHandler(NotRoleException.class)
-	public AjaxResult handleNotRoleException(NotRoleException e, HttpServletRequest request) {
-		String requestURI = request.getRequestURI();
-		log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage());
-		return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权");
-	}
-	
-	/**
-	 * 没有登录异常
-	 * @param e
-	 * @param request
-	 * @return
-	 */
-	@ExceptionHandler(NotLoginException.class)
-	public AjaxResult notLoginException(NotLoginException e, HttpServletRequest request) {
-		String requestURI = request.getRequestURI();
-		log.error("请求地址'{}',登录校验失败'{}'", requestURI, e.getMessage());
-		return AjaxResult.error(HttpStatus.UNAUTHORIZED, e.getMessage());
-	}
-	
-	/**
-	 * 请求方式不支持
-	 */
-	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
-	public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
-	                                                      HttpServletRequest request) {
-		String requestURI = request.getRequestURI();
-		log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
-		return AjaxResult.error(e.getMessage());
-	}
-	
-	/**
-	 * 业务异常
-	 */
-	@ExceptionHandler(ServiceException.class)
-	public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) {
-		log.error(e.getMessage(), e);
-		Integer code = e.getCode();
-		String msg = e.getMessage();
-		if (StringUtils.hasText(e.getMessageKey())) {
-			msg = messageSource.getMessage(e.getMessageKey(), e.getArgs(), LocaleContextHolder.getLocale());
-		}
-		return StringUtils.isNotNull(code) ? AjaxResult.error(code, msg) : AjaxResult.error(msg);
-	}
-	
-	/**
-	 * 拦截未知的运行时异常
-	 */
-	@ExceptionHandler(RuntimeException.class)
-	public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) {
-		String requestURI = request.getRequestURI();
-		log.error("请求地址'{}',发生未知异常.", requestURI, e);
-		return AjaxResult.error("系统繁忙,请稍后重试");
-	}
-	
-	/**
-	 * 系统异常
-	 */
-	@ExceptionHandler(Exception.class)
-	public AjaxResult handleException(Exception e, HttpServletRequest request) {
-		String requestURI = request.getRequestURI();
-		log.error("请求地址'{}',发生系统异常.", requestURI, e);
-		return AjaxResult.error("系统繁忙,请稍后重试");
-	}
-	
-	/**
-	 * 自定义验证异常
-	 */
-	@ExceptionHandler(BindException.class)
-	public AjaxResult handleBindException(BindException e) {
-		log.error(e.getMessage(), e);
-		String message = e.getAllErrors().get(0).getDefaultMessage();
+    @Value("${spring.servlet.multipart.max-file-size:50MB}")
+    private String maxFileSize;
+    @Value("${spring.servlet.multipart.max-request-size:100MB}")
+    private String maxRequestSize;
 
-		// 支持国际化消息键(格式:{message.key})
-		if (StringUtils.hasText(message) && message.startsWith("{") && message.endsWith("}")) {
-			// 提取消息键
-			String messageKey = message.substring(1, message.length() - 1);
-			try {
-				// 使用 MessageSource 获取国际化消息
-				message = messageSource.getMessage(messageKey, null, LocaleContextHolder.getLocale());
-			} catch (Exception ex) {
-				log.warn("国际化消息键不存在: {}", messageKey);
-				// 返回消息键本身作为降级方案
-				message = messageKey;
-			}
-		}
+    @Autowired
+    private MessageSource messageSource;
 
-		return AjaxResult.error(message);
-	}
-	
-	/**
-	 * 自定义验证异常
-	 */
-	@ExceptionHandler(MethodArgumentNotValidException.class)
-	public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
-		log.error(e.getMessage(), e);
-		String message = e.getBindingResult().getFieldError().getDefaultMessage();
+    /**
+     * 权限码异常
+     */
+    @ExceptionHandler(NotPermissionException.class)
+    public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage());
+        return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权");
+    }
 
-		// 支持国际化消息键(格式:{message.key})
-		if (StringUtils.hasText(message) && message.startsWith("{") && message.endsWith("}")) {
-			// 提取消息键
-			String messageKey = message.substring(1, message.length() - 1);
-			try {
-				// 使用 MessageUtils 获取国际化消息
-				message = messageSource.getMessage(messageKey, null, LocaleContextHolder.getLocale());
-			} catch (Exception ex) {
-				log.warn("国际化消息键不存在: {}", messageKey);
-				// 返回消息键本身作为降级方案
-				message = messageKey;
-			}
-		}
+    /**
+     * 角色权限异常
+     */
+    @ExceptionHandler(NotRoleException.class)
+    public AjaxResult handleNotRoleException(NotRoleException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage());
+        return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权");
+    }
 
-		return AjaxResult.error(message);
-	}
-	
-	/**
-	 * 内部认证异常
-	 */
-	@ExceptionHandler(InnerAuthException.class)
-	public AjaxResult handleInnerAuthException(InnerAuthException e) {
-		return AjaxResult.error(e.getMessage());
-	}
-	
-	/**
-	 * 演示模式异常
-	 */
-	@ExceptionHandler(DemoModeException.class)
-	public AjaxResult handleDemoModeException(DemoModeException e) {
-		return AjaxResult.error("演示模式,不允许操作");
-	}
-	
-	@ExceptionHandler(MaxUploadSizeExceededException.class)
-	public AjaxResult fileUpLoad(MaxUploadSizeExceededException e) {
-		log.error("上传文件异常 => : {}", e.getMessage());
-		return AjaxResult.error("文件识别大小超出限制,允许的大小在" + maxFileSize);
-	}
-	
-	/**
-	 * 学生端单点登录-异常信息
-	 */
-	@ExceptionHandler(UserAppletException.class)
-	public AjaxResult<String> studyLoginExceptionHandler(UserAppletException e) {
-		return AjaxResult.error(e.getCode(), e.getMessage());
-	}
+    /**
+     * 没有登录异常
+     *
+     * @param e
+     * @param request
+     * @return
+     */
+    @ExceptionHandler(NotLoginException.class)
+    public AjaxResult notLoginException(NotLoginException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',登录校验失败'{}'", requestURI, e.getMessage());
+        return AjaxResult.error(HttpStatus.UNAUTHORIZED, e.getMessage());
+    }
+
+    /**
+     * 请求方式不支持
+     */
+    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
+                                                          HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 业务异常
+     */
+    @ExceptionHandler(ServiceException.class)
+    public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) {
+        log.error(e.getMessage(), e);
+        Integer code = e.getCode();
+        String msg = e.getMessage();
+        if (StringUtils.hasText(e.getMessageKey())) {
+            msg = messageSource.getMessage(e.getMessageKey(), e.getArgs(), LocaleContextHolder.getLocale());
+        }
+        return StringUtils.isNotNull(code) ? AjaxResult.error(code, msg) : AjaxResult.error(msg);
+    }
+
+    /**
+     * 拦截未知的运行时异常
+     */
+    @ExceptionHandler(RuntimeException.class)
+    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生未知异常.", requestURI, e);
+        return AjaxResult.error("系统繁忙,请稍后重试");
+    }
+
+    /**
+     * 系统异常
+     */
+    @ExceptionHandler(Exception.class)
+    public AjaxResult handleException(Exception e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生系统异常.", requestURI, e);
+        return AjaxResult.error("系统繁忙,请稍后重试");
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(BindException.class)
+    public AjaxResult handleBindException(BindException e) {
+        log.error(e.getMessage(), e);
+        String message = e.getAllErrors().get(0).getDefaultMessage();
+
+        // 支持国际化消息键(格式:{message.key})
+        if (StringUtils.hasText(message) && message.startsWith("{") && message.endsWith("}")) {
+            // 提取消息键
+            String messageKey = message.substring(1, message.length() - 1);
+            try {
+                // 使用 MessageSource 获取国际化消息
+                message = messageSource.getMessage(messageKey, null, LocaleContextHolder.getLocale());
+            } catch (Exception ex) {
+                log.warn("国际化消息键不存在: {}", messageKey);
+                // 返回消息键本身作为降级方案
+                message = messageKey;
+            }
+        }
+
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+        log.error(e.getMessage(), e);
+        // 收集所有字段校验错误,格式:fieldName: message
+        StringBuilder sb = new StringBuilder();
+        e.getBindingResult().getFieldErrors().forEach(fieldError -> {
+            String message = fieldError.getDefaultMessage();
+            if (StringUtils.hasText(message) && message.startsWith("{") && message.endsWith("}")) {
+                String messageKey = message.substring(1, message.length() - 1);
+                try {
+                    message = messageSource.getMessage(messageKey, null, LocaleContextHolder.getLocale());
+                } catch (Exception ex) {
+                    log.warn("国际化消息键不存在: {}", messageKey);
+                    message = messageKey;
+                }
+            }
+            if (sb.length() > 0) {
+                sb.append("; ");
+            }
+            sb.append(fieldError.getField()).append(": ").append(message);
+        });
+        return AjaxResult.error(sb.toString());
+    }
+
+    /**
+     * 内部认证异常
+     */
+    @ExceptionHandler(InnerAuthException.class)
+    public AjaxResult handleInnerAuthException(InnerAuthException e) {
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 演示模式异常
+     */
+    @ExceptionHandler(DemoModeException.class)
+    public AjaxResult handleDemoModeException(DemoModeException e) {
+        return AjaxResult.error("演示模式,不允许操作");
+    }
+
+    /**
+     * Feign调用异常 - 专门处理403 Forbidden异常
+     * 解析并返回原始响应中的code、msg、data
+     */
+    @ExceptionHandler(FeignException.class)
+    public AjaxResult handleFeignException(FeignException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}', Feign调用403异常: {}", requestURI, e.getMessage());
+
+        // 获取原始响应内容
+        String responseBody = e.contentUTF8();
+        if (StringUtils.hasText(responseBody)) {
+            try {
+                // 使用 Jackson 解析 JSON 响应
+                ObjectMapper objectMapper = new ObjectMapper();
+                JsonNode jsonNode = objectMapper.readTree(responseBody);
+
+                // 提取 code、msg、data 字段
+                Integer code = jsonNode.has("code") ? jsonNode.get("code").asInt() : null;
+                String msg = jsonNode.has("msg") ? jsonNode.get("msg").asText() : null;
+                Object data = jsonNode.has("data") && !jsonNode.get("data").isNull() ?
+                        objectMapper.treeToValue(jsonNode.get("data"), Object.class) : null;
+
+                // 直接使用 AjaxResult 构造方法返回原始的code、msg、data
+                if (code != null) {
+                    return new AjaxResult(code, msg, data);
+                } else {
+                    return AjaxResult.error(msg != null ? msg : "服务调用失败");
+                }
+            } catch (Exception ex) {
+                log.warn("解析Feign异常响应内容失败,返回默认错误: {}", ex.getMessage());
+                // 解析失败时返回默认的403错误
+                return AjaxResult.error(HttpStatus.FORBIDDEN, "服务调用失败");
+            }
+        }
+
+        // 如果没有响应体,返回默认的403错误
+        return AjaxResult.error(HttpStatus.FORBIDDEN, "服务调用失败");
+    }
+
+    @ExceptionHandler(MaxUploadSizeExceededException.class)
+    public AjaxResult fileUpLoad(MaxUploadSizeExceededException e) {
+        log.error("上传文件异常 => : {}", e.getMessage());
+        return AjaxResult.error("文件识别大小超出限制,允许的大小在" + maxFileSize);
+    }
+
+    /**
+     * 学生端单点登录-异常信息
+     */
+    @ExceptionHandler(UserAppletException.class)
+    public AjaxResult<String> studyLoginExceptionHandler(UserAppletException e) {
+        return AjaxResult.error(e.getCode(), e.getMessage());
+    }
 }

--
Gitblit v1.7.1