完善 Dubbo Provider 异常过滤器,接入新的异常体系
This commit is contained in:
parent
32c1cfb3a7
commit
c0407267b9
@ -16,10 +16,13 @@ public class MallUtils {
|
|||||||
* @return 链路追踪编号
|
* @return 链路追踪编号
|
||||||
*/
|
*/
|
||||||
public static String getTraceId() {
|
public static String getTraceId() {
|
||||||
String traceId = TraceContext.traceId();
|
// 通过 SkyWalking 获取链路编号
|
||||||
if (StringUtils.hasText(traceId)) {
|
try {
|
||||||
return traceId;
|
String traceId = TraceContext.traceId();
|
||||||
}
|
if (StringUtils.hasText(traceId)) {
|
||||||
|
return traceId;
|
||||||
|
}
|
||||||
|
} catch (Throwable ignore) {}
|
||||||
// TODO 芋艿 多次调用会问题
|
// TODO 芋艿 多次调用会问题
|
||||||
return UUID.randomUUID().toString();
|
return UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
@ -141,4 +141,14 @@ public final class CommonResult<T> implements Serializable {
|
|||||||
throw new ServiceException(code, message).setDetailMessage(detailMessage);
|
throw new ServiceException(code, message).setDetailMessage(detailMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> CommonResult<T> error(ServiceException serviceException) {
|
||||||
|
return error(serviceException.getCode(), serviceException.getMessage(),
|
||||||
|
serviceException.getDetailMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommonResult<T> error(GlobalException globalException) {
|
||||||
|
return error(globalException.getCode(), globalException.getMessage(),
|
||||||
|
globalException.getDetailMessage());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,8 @@
|
|||||||
|
|
||||||
<!-- RPC 相关 -->
|
<!-- RPC 相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
<artifactId>dubbo</artifactId>
|
<artifactId>spring-cloud-starter-dubbo</artifactId>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 日志相关 -->
|
<!-- 日志相关 -->
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package cn.iocoder.mall.dubbo.core.filter;
|
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.exception.ServiceException;
|
||||||
import cn.iocoder.common.framework.util.ExceptionUtil;
|
import cn.iocoder.common.framework.util.ExceptionUtil;
|
||||||
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
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.*;
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
import org.apache.dubbo.rpc.service.GenericService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -14,6 +15,9 @@ import javax.validation.ConstraintViolation;
|
|||||||
import javax.validation.ConstraintViolationException;
|
import javax.validation.ConstraintViolationException;
|
||||||
import java.lang.reflect.Type;
|
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 {
|
public class DubboProviderExceptionFilter implements Filter, Filter.Listener {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(DubboProviderExceptionFilter.class);
|
private Logger logger = LoggerFactory.getLogger(DubboProviderExceptionFilter.class);
|
||||||
@ -32,26 +36,27 @@ public class DubboProviderExceptionFilter implements Filter, Filter.Listener {
|
|||||||
// 1. 参数校验异常
|
// 1. 参数校验异常
|
||||||
if (exception instanceof ConstraintViolationException) {
|
if (exception instanceof ConstraintViolationException) {
|
||||||
exception = this.constraintViolationExceptionHandler((ConstraintViolationException) exception);
|
exception = this.constraintViolationExceptionHandler((ConstraintViolationException) exception);
|
||||||
// 2. 非 ServiceException 业务异常,转换成 ServiceException 业务异常,避免可能存在的反序列化问题
|
// 2. ServiceException 业务异常,因为不会有序列化问题,所以无需处理
|
||||||
} if (!(exception instanceof ServiceException)) {
|
} else if (exception instanceof ServiceException) {
|
||||||
|
// 3. 其它异常,转换成 ServiceException 业务异常,避免可能存在的反序列化问题
|
||||||
|
} else {
|
||||||
exception = this.defaultExceptionHandler(exception, invocation);
|
exception = this.defaultExceptionHandler(exception, invocation);
|
||||||
|
assert exception != null;
|
||||||
}
|
}
|
||||||
assert exception != null;
|
|
||||||
ServiceException serviceException = (ServiceException) exception;
|
|
||||||
// 根据不同的方法 schema 返回结果
|
// 根据不同的方法 schema 返回结果
|
||||||
// 第一种情况,返回参数类型是 CommonResult 的情况,则将 ServiceException 转换成 CommonResult
|
// 第一种情况,返回参数类型是 CommonResult 的情况,则将 ServiceException 转换成 CommonResult
|
||||||
if (isReturnCommonResult(invocation)) {
|
if (isReturnCommonResult(invocation)) {
|
||||||
// 清空异常
|
// 清空异常
|
||||||
appResponse.setException(null);
|
appResponse.setException(null);
|
||||||
// 设置结果
|
// 设置结果
|
||||||
CommonResult exceptionResult = new CommonResult();
|
if (exception instanceof ServiceException) {
|
||||||
exceptionResult.setCode(serviceException.getCode());
|
appResponse.setValue(CommonResult.error((ServiceException) exception));
|
||||||
exceptionResult.setMessage(serviceException.getMessage());
|
} else {
|
||||||
exceptionResult.setDetailMessage(serviceException.getDetailMessage());
|
appResponse.setValue(CommonResult.error((GlobalException) exception));
|
||||||
appResponse.setValue(exceptionResult);
|
}
|
||||||
// 第二种情况,未包装成 CommonResult 的情况,则直接抛出 ServiceException 异常
|
// 第二种情况,未包装成 CommonResult 的情况,则直接抛出 ServiceException 异常
|
||||||
} else {
|
} else {
|
||||||
appResponse.setException(serviceException);
|
appResponse.setException(exception);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} 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);
|
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 校验不通过产生的异常
|
* 处理 Validator 校验不通过产生的异常
|
||||||
*/
|
*/
|
||||||
private ServiceException constraintViolationExceptionHandler(ConstraintViolationException ex) {
|
private GlobalException constraintViolationExceptionHandler(ConstraintViolationException ex) {
|
||||||
logger.warn("[constraintViolationExceptionHandler]", ex);
|
logger.warn("[constraintViolationExceptionHandler]", ex);
|
||||||
ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next();
|
ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next();
|
||||||
return ServiceExceptionUtil.exception0(GlobalErrorCodeEnum.BAD_REQUEST.getCode(),
|
return new GlobalException(BAD_REQUEST.getCode(),
|
||||||
String.format("请求参数不正确:%s", constraintViolation.getMessage()));
|
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({}) 执行异常]",
|
logger.error("[defaultExceptionHandler][service({}) method({}) params({}) 执行异常]",
|
||||||
invocation.getServiceName(), invocation.getServiceName(), invocation.getArguments(), exception);
|
invocation.getServiceName(), invocation.getServiceName(), invocation.getArguments(), exception);
|
||||||
return ServiceExceptionUtil.exception0(GlobalErrorCodeEnum.INTERNAL_SERVER_ERROR.getCode(),
|
return new GlobalException(INTERNAL_SERVER_ERROR)
|
||||||
GlobalErrorCodeEnum.INTERNAL_SERVER_ERROR.getMessage())
|
|
||||||
.setDetailMessage(this.buildDetailMessage(exception, invocation));
|
.setDetailMessage(this.buildDetailMessage(exception, invocation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
dubboExceptionFilter=cn.iocoder.common.framework.dubbo.DubboExceptionFilter
|
dubboExceptionFilter=cn.iocoder.mall.dubbo.core.filter.DubboProviderExceptionFilter
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.mall.web.core.handler;
|
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.ServiceException;
|
||||||
import cn.iocoder.common.framework.exception.enums.GlobalErrorCodeConstants;
|
import cn.iocoder.common.framework.exception.enums.GlobalErrorCodeConstants;
|
||||||
import cn.iocoder.common.framework.util.ExceptionUtil;
|
import cn.iocoder.common.framework.util.ExceptionUtil;
|
||||||
@ -148,16 +149,37 @@ public class GlobalExceptionHandler {
|
|||||||
*/
|
*/
|
||||||
@ExceptionHandler(value = ServiceException.class)
|
@ExceptionHandler(value = ServiceException.class)
|
||||||
public CommonResult serviceExceptionHandler(ServiceException ex) {
|
public CommonResult serviceExceptionHandler(ServiceException ex) {
|
||||||
logger.debug("[serviceExceptionHandler]", ex);
|
logger.info("[serviceExceptionHandler]", ex);
|
||||||
return CommonResult.error(ex.getCode(), ex.getMessage());
|
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)
|
@ExceptionHandler(value = Exception.class)
|
||||||
public CommonResult defaultExceptionHandler(HttpServletRequest req, Throwable e) {
|
public CommonResult defaultExceptionHandler(HttpServletRequest req, Throwable ex) {
|
||||||
logger.error("[defaultExceptionHandler]", e);
|
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();
|
SystemExceptionLogCreateDTO exceptionLog = new SystemExceptionLogCreateDTO();
|
||||||
try {
|
try {
|
||||||
@ -166,12 +188,20 @@ public class GlobalExceptionHandler {
|
|||||||
// 初始化 exceptionLog
|
// 初始化 exceptionLog
|
||||||
initExceptionLog(exceptionLog, req, e);
|
initExceptionLog(exceptionLog, req, e);
|
||||||
// 执行插入 exceptionLog
|
// 执行插入 exceptionLog
|
||||||
addExceptionLog(exceptionLog);
|
createExceptionLog(exceptionLog);
|
||||||
} catch (Throwable th) {
|
} 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) {
|
private void initExceptionLog(SystemExceptionLogCreateDTO exceptionLog, HttpServletRequest request, Throwable e) {
|
||||||
@ -201,14 +231,4 @@ public class GlobalExceptionHandler {
|
|||||||
.setExceptionTime(new Date());
|
.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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
<yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
|
<yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
|
||||||
<aliyun-java-sdk-core.version>4.1.0</aliyun-java-sdk-core.version>
|
<aliyun-java-sdk-core.version>4.1.0</aliyun-java-sdk-core.version>
|
||||||
<!-- 监控相关 -->
|
<!-- 监控相关 -->
|
||||||
<skywalking.version>7.0.0</skywalking.version>
|
<skywalking.version>8.0.1</skywalking.version>
|
||||||
<spring-boot-admin-starter-client.version>2.2.2</spring-boot-admin-starter-client.version>
|
<spring-boot-admin-starter-client.version>2.2.2</spring-boot-admin-starter-client.version>
|
||||||
<!-- 工具类相关 -->
|
<!-- 工具类相关 -->
|
||||||
<fastjson.version>1.2.56</fastjson.version>
|
<fastjson.version>1.2.56</fastjson.version>
|
||||||
@ -213,6 +213,12 @@
|
|||||||
<version>${dubbo.version}</version>
|
<version>${dubbo.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
|
<artifactId>mall-spring-boot-starter-dubbo</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Job 相关 -->
|
<!-- Job 相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.xuxueli</groupId>
|
<groupId>com.xuxueli</groupId>
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- RPC 相关 -->
|
<!-- RPC 相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.cloud</groupId>
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
<artifactId>spring-cloud-starter-dubbo</artifactId>
|
<artifactId>mall-spring-boot-starter-dubbo</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package cn.iocoder.mall.systemservice.manager.permission;
|
package cn.iocoder.mall.systemservice.manager.permission;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
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.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.PermissionAssignAdminRoleDTO;
|
||||||
import cn.iocoder.mall.systemservice.rpc.permission.dto.PermissionAssignRoleResourceDTO;
|
import cn.iocoder.mall.systemservice.rpc.permission.dto.PermissionAssignRoleResourceDTO;
|
||||||
import cn.iocoder.mall.systemservice.rpc.permission.dto.PermissionCheckDTO;
|
import cn.iocoder.mall.systemservice.rpc.permission.dto.PermissionCheckDTO;
|
||||||
@ -98,7 +98,7 @@ public class PermissionManager {
|
|||||||
// 查询管理员拥有的角色关联数据
|
// 查询管理员拥有的角色关联数据
|
||||||
Set<Integer> roleIds = permissionService.listAdminRoleIds(checkDTO.getAdminId());
|
Set<Integer> roleIds = permissionService.listAdminRoleIds(checkDTO.getAdminId());
|
||||||
if (CollectionUtil.isEmpty(roleIds)) { // 如果没有角色,默认无法访问
|
if (CollectionUtil.isEmpty(roleIds)) { // 如果没有角色,默认无法访问
|
||||||
throw ServiceExceptionUtil.exception(FORBIDDEN);
|
throw new GlobalException(FORBIDDEN);
|
||||||
}
|
}
|
||||||
// 判断是否为超管。若是超管,默认有所有权限
|
// 判断是否为超管。若是超管,默认有所有权限
|
||||||
if (roleService.hasSuperAdmin(roleIds)) {
|
if (roleService.hasSuperAdmin(roleIds)) {
|
||||||
|
@ -158,7 +158,7 @@ public class PermissionService {
|
|||||||
RoleResourceDO::getResourceId, RoleResourceDO::getRoleId);
|
RoleResourceDO::getResourceId, RoleResourceDO::getRoleId);
|
||||||
for (Map.Entry<Integer, List<Integer>> entry : resourceRoleMap.entrySet()) {
|
for (Map.Entry<Integer, List<Integer>> entry : resourceRoleMap.entrySet()) {
|
||||||
if (!CollectionUtil.containsAny(roleIds, entry.getValue())) { // 所以有任一不满足,就验证失败,抛出异常
|
if (!CollectionUtil.containsAny(roleIds, entry.getValue())) { // 所以有任一不满足,就验证失败,抛出异常
|
||||||
throw ServiceExceptionUtil.exception(FORBIDDEN);
|
throw new GlobalException(FORBIDDEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user