From c0407267b92e0be43650a726092c58f39b845f34 Mon Sep 17 00:00:00 2001 From: YunaiV <> Date: Sun, 19 Jul 2020 01:34:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=20Dubbo=20Provider=20?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E8=BF=87=E6=BB=A4=E5=99=A8=EF=BC=8C=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=E6=96=B0=E7=9A=84=E5=BC=82=E5=B8=B8=E4=BD=93=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/framework/util/MallUtils.java | 11 ++-- .../common/framework/vo/CommonResult.java | 10 ++++ common/mall-spring-boot-starter-dubbo/pom.xml | 8 +-- .../filter/DubboProviderExceptionFilter.java | 38 +++++++------ .../dubbo/com.alibaba.dubbo.rpc.Filter | 2 +- .../core/handler/GlobalExceptionHandler.java | 54 +++++++++++++------ mall-dependencies/pom.xml | 8 ++- .../system-service-app/pom.xml | 4 +- .../manager/permission/PermissionManager.java | 4 +- .../service/permission/PermissionService.java | 2 +- 10 files changed, 90 insertions(+), 51 deletions(-) diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/MallUtils.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/MallUtils.java index 1205c5aec..54c897e0b 100644 --- a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/MallUtils.java +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/MallUtils.java @@ -16,10 +16,13 @@ public class MallUtils { * @return 链路追踪编号 */ public static String getTraceId() { - String traceId = TraceContext.traceId(); - if (StringUtils.hasText(traceId)) { - return traceId; - } + // 通过 SkyWalking 获取链路编号 + try { + String traceId = TraceContext.traceId(); + if (StringUtils.hasText(traceId)) { + return traceId; + } + } catch (Throwable ignore) {} // TODO 芋艿 多次调用会问题 return UUID.randomUUID().toString(); } diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/CommonResult.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/CommonResult.java index 7b77f42db..dfaec09f9 100644 --- a/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/CommonResult.java +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/vo/CommonResult.java @@ -141,4 +141,14 @@ public final class CommonResult implements Serializable { throw new ServiceException(code, message).setDetailMessage(detailMessage); } + public static CommonResult error(ServiceException serviceException) { + return error(serviceException.getCode(), serviceException.getMessage(), + serviceException.getDetailMessage()); + } + + public static CommonResult error(GlobalException globalException) { + return error(globalException.getCode(), globalException.getMessage(), + globalException.getDetailMessage()); + } + } diff --git a/common/mall-spring-boot-starter-dubbo/pom.xml b/common/mall-spring-boot-starter-dubbo/pom.xml index 35e5202c4..ca4cfca0d 100644 --- a/common/mall-spring-boot-starter-dubbo/pom.xml +++ b/common/mall-spring-boot-starter-dubbo/pom.xml @@ -20,12 +20,8 @@ - org.apache.dubbo - dubbo - - - org.apache.dubbo - dubbo-spring-boot-starter + com.alibaba.cloud + spring-cloud-starter-dubbo diff --git a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboProviderExceptionFilter.java b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboProviderExceptionFilter.java index d2fd83373..43cab7eb7 100644 --- a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboProviderExceptionFilter.java +++ b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboProviderExceptionFilter.java @@ -1,10 +1,11 @@ package cn.iocoder.mall.dubbo.core.filter; -import cn.iocoder.common.framework.exception.enums.GlobalErrorCodeEnum; +import cn.iocoder.common.framework.exception.GlobalException; import cn.iocoder.common.framework.exception.ServiceException; import cn.iocoder.common.framework.util.ExceptionUtil; -import cn.iocoder.common.framework.util.ServiceExceptionUtil; import cn.iocoder.common.framework.vo.CommonResult; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.rpc.*; import org.apache.dubbo.rpc.service.GenericService; import org.slf4j.Logger; @@ -14,6 +15,9 @@ import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import java.lang.reflect.Type; +import static cn.iocoder.common.framework.exception.enums.GlobalErrorCodeConstants.*; + +@Activate(group = CommonConstants.PROVIDER) public class DubboProviderExceptionFilter implements Filter, Filter.Listener { private Logger logger = LoggerFactory.getLogger(DubboProviderExceptionFilter.class); @@ -32,26 +36,27 @@ public class DubboProviderExceptionFilter implements Filter, Filter.Listener { // 1. 参数校验异常 if (exception instanceof ConstraintViolationException) { exception = this.constraintViolationExceptionHandler((ConstraintViolationException) exception); - // 2. 非 ServiceException 业务异常,转换成 ServiceException 业务异常,避免可能存在的反序列化问题 - } if (!(exception instanceof ServiceException)) { + // 2. ServiceException 业务异常,因为不会有序列化问题,所以无需处理 + } else if (exception instanceof ServiceException) { + // 3. 其它异常,转换成 ServiceException 业务异常,避免可能存在的反序列化问题 + } else { exception = this.defaultExceptionHandler(exception, invocation); + assert exception != null; } - assert exception != null; - ServiceException serviceException = (ServiceException) exception; // 根据不同的方法 schema 返回结果 // 第一种情况,返回参数类型是 CommonResult 的情况,则将 ServiceException 转换成 CommonResult if (isReturnCommonResult(invocation)) { // 清空异常 appResponse.setException(null); // 设置结果 - CommonResult exceptionResult = new CommonResult(); - exceptionResult.setCode(serviceException.getCode()); - exceptionResult.setMessage(serviceException.getMessage()); - exceptionResult.setDetailMessage(serviceException.getDetailMessage()); - appResponse.setValue(exceptionResult); + if (exception instanceof ServiceException) { + appResponse.setValue(CommonResult.error((ServiceException) exception)); + } else { + appResponse.setValue(CommonResult.error((GlobalException) exception)); + } // 第二种情况,未包装成 CommonResult 的情况,则直接抛出 ServiceException 异常 } else { - appResponse.setException(serviceException); + appResponse.setException(exception); } } catch (Throwable e) { logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e); @@ -84,21 +89,20 @@ public class DubboProviderExceptionFilter implements Filter, Filter.Listener { /** * 处理 Validator 校验不通过产生的异常 */ - private ServiceException constraintViolationExceptionHandler(ConstraintViolationException ex) { + private GlobalException constraintViolationExceptionHandler(ConstraintViolationException ex) { logger.warn("[constraintViolationExceptionHandler]", ex); ConstraintViolation constraintViolation = ex.getConstraintViolations().iterator().next(); - return ServiceExceptionUtil.exception0(GlobalErrorCodeEnum.BAD_REQUEST.getCode(), + return new GlobalException(BAD_REQUEST.getCode(), String.format("请求参数不正确:%s", constraintViolation.getMessage())); } /** * 处理系统异常,兜底处理所有的一切 */ - private ServiceException defaultExceptionHandler(Throwable exception, Invocation invocation) { + private GlobalException defaultExceptionHandler(Throwable exception, Invocation invocation) { logger.error("[defaultExceptionHandler][service({}) method({}) params({}) 执行异常]", invocation.getServiceName(), invocation.getServiceName(), invocation.getArguments(), exception); - return ServiceExceptionUtil.exception0(GlobalErrorCodeEnum.INTERNAL_SERVER_ERROR.getCode(), - GlobalErrorCodeEnum.INTERNAL_SERVER_ERROR.getMessage()) + return new GlobalException(INTERNAL_SERVER_ERROR) .setDetailMessage(this.buildDetailMessage(exception, invocation)); } diff --git a/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter b/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter index 7bae86c9d..d7eb81217 100644 --- a/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter +++ b/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter @@ -1 +1 @@ -dubboExceptionFilter=cn.iocoder.common.framework.dubbo.DubboExceptionFilter +dubboExceptionFilter=cn.iocoder.mall.dubbo.core.filter.DubboProviderExceptionFilter diff --git a/common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/core/handler/GlobalExceptionHandler.java b/common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/core/handler/GlobalExceptionHandler.java index 1a8498f4c..b4c672f1b 100644 --- a/common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/core/handler/GlobalExceptionHandler.java +++ b/common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/core/handler/GlobalExceptionHandler.java @@ -1,5 +1,6 @@ package cn.iocoder.mall.web.core.handler; +import cn.iocoder.common.framework.exception.GlobalException; import cn.iocoder.common.framework.exception.ServiceException; import cn.iocoder.common.framework.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.common.framework.util.ExceptionUtil; @@ -148,16 +149,37 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(value = ServiceException.class) public CommonResult serviceExceptionHandler(ServiceException ex) { - logger.debug("[serviceExceptionHandler]", ex); + logger.info("[serviceExceptionHandler]", ex); return CommonResult.error(ex.getCode(), ex.getMessage()); } + /** + * 处理全局异常 ServiceException + * + * 例如说,Dubbo 请求超时,调用的 Dubbo 服务系统异常 + */ + @ExceptionHandler(value = GlobalException.class) + public CommonResult globalExceptionHandler(HttpServletRequest req, GlobalException ex) { + logger.error("[globalExceptionHandler]", ex); + // 插入异常日志 + this.createExceptionLog(req, ex); + // 返回 ERROR CommonResult + return CommonResult.error(ex); + } + /** * 处理系统异常,兜底处理所有的一切 */ @ExceptionHandler(value = Exception.class) - public CommonResult defaultExceptionHandler(HttpServletRequest req, Throwable e) { - logger.error("[defaultExceptionHandler]", e); + public CommonResult defaultExceptionHandler(HttpServletRequest req, Throwable ex) { + logger.error("[defaultExceptionHandler]", ex); + // 插入异常日志 + this.createExceptionLog(req, ex); + // 返回 ERROR CommonResult + return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMessage()); + } + + public void createExceptionLog(HttpServletRequest req, Throwable e) { // 插入异常日志 SystemExceptionLogCreateDTO exceptionLog = new SystemExceptionLogCreateDTO(); try { @@ -166,12 +188,20 @@ public class GlobalExceptionHandler { // 初始化 exceptionLog initExceptionLog(exceptionLog, req, e); // 执行插入 exceptionLog - addExceptionLog(exceptionLog); + createExceptionLog(exceptionLog); } catch (Throwable th) { - logger.error("[defaultExceptionHandler][插入访问日志({}) 发生异常({})", JSON.toJSONString(exceptionLog), ExceptionUtils.getRootCauseMessage(th)); + logger.error("[createExceptionLog][插入访问日志({}) 发生异常({})", JSON.toJSONString(exceptionLog), ExceptionUtils.getRootCauseMessage(th)); + } + } + + // TODO 优化点:后续可以增加事件 + @Async + public void createExceptionLog(SystemExceptionLogCreateDTO exceptionLog) { + try { + systemExceptionLogRpc.createSystemExceptionLog(exceptionLog); + } catch (Throwable th) { + logger.error("[addAccessLog][插入异常日志({}) 发生异常({})", JSON.toJSONString(exceptionLog), ExceptionUtils.getRootCauseMessage(th)); } - // 返回 ERROR CommonResult - return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getMessage()); } private void initExceptionLog(SystemExceptionLogCreateDTO exceptionLog, HttpServletRequest request, Throwable e) { @@ -201,14 +231,4 @@ public class GlobalExceptionHandler { .setExceptionTime(new Date()); } - // TODO 优化点:后续可以增加事件 - @Async - public void addExceptionLog(SystemExceptionLogCreateDTO exceptionLog) { - try { - systemExceptionLogRpc.createSystemExceptionLog(exceptionLog); - } catch (Throwable th) { - logger.error("[addAccessLog][插入异常日志({}) 发生异常({})", JSON.toJSONString(exceptionLog), ExceptionUtils.getRootCauseMessage(th)); - } - } - } diff --git a/mall-dependencies/pom.xml b/mall-dependencies/pom.xml index 288eb7f11..6250d7a93 100644 --- a/mall-dependencies/pom.xml +++ b/mall-dependencies/pom.xml @@ -51,7 +51,7 @@ 1.2.7 4.1.0 - 7.0.0 + 8.0.1 2.2.2 1.2.56 @@ -213,6 +213,12 @@ ${dubbo.version} + + cn.iocoder.mall + mall-spring-boot-starter-dubbo + 1.0-SNAPSHOT + + com.xuxueli diff --git a/system-service-project/system-service-app/pom.xml b/system-service-project/system-service-app/pom.xml index 923ef2670..e5f4b97a8 100644 --- a/system-service-project/system-service-app/pom.xml +++ b/system-service-project/system-service-app/pom.xml @@ -13,8 +13,8 @@ - com.alibaba.cloud - spring-cloud-starter-dubbo + cn.iocoder.mall + mall-spring-boot-starter-dubbo diff --git a/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/manager/permission/PermissionManager.java b/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/manager/permission/PermissionManager.java index 642ebf2e5..ad40fac28 100644 --- a/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/manager/permission/PermissionManager.java +++ b/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/manager/permission/PermissionManager.java @@ -1,8 +1,8 @@ package cn.iocoder.mall.systemservice.manager.permission; import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.common.framework.exception.GlobalException; import cn.iocoder.common.framework.util.CollectionUtils; -import cn.iocoder.common.framework.util.ServiceExceptionUtil; import cn.iocoder.mall.systemservice.rpc.permission.dto.PermissionAssignAdminRoleDTO; import cn.iocoder.mall.systemservice.rpc.permission.dto.PermissionAssignRoleResourceDTO; import cn.iocoder.mall.systemservice.rpc.permission.dto.PermissionCheckDTO; @@ -98,7 +98,7 @@ public class PermissionManager { // 查询管理员拥有的角色关联数据 Set roleIds = permissionService.listAdminRoleIds(checkDTO.getAdminId()); if (CollectionUtil.isEmpty(roleIds)) { // 如果没有角色,默认无法访问 - throw ServiceExceptionUtil.exception(FORBIDDEN); + throw new GlobalException(FORBIDDEN); } // 判断是否为超管。若是超管,默认有所有权限 if (roleService.hasSuperAdmin(roleIds)) { diff --git a/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/service/permission/PermissionService.java b/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/service/permission/PermissionService.java index 72f9cc158..57bd0c9d5 100644 --- a/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/service/permission/PermissionService.java +++ b/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/service/permission/PermissionService.java @@ -158,7 +158,7 @@ public class PermissionService { RoleResourceDO::getResourceId, RoleResourceDO::getRoleId); for (Map.Entry> entry : resourceRoleMap.entrySet()) { if (!CollectionUtil.containsAny(roleIds, entry.getValue())) { // 所以有任一不满足,就验证失败,抛出异常 - throw ServiceExceptionUtil.exception(FORBIDDEN); + throw new GlobalException(FORBIDDEN); } } }