bom 文件调整

This commit is contained in:
YunaiV
2020-07-17 19:59:43 +08:00
parent 26ea8dd907
commit e3f2e15c43
87 changed files with 383 additions and 1898 deletions

View File

@@ -21,39 +21,47 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!-- RPC 相关 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<optional>true</optional>
</dependency>
<!-- 监控相关 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<optional>true</optional>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试相关 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<!-- 工具相关 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
@@ -62,21 +70,11 @@
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<optional>true</optional>
</dependency>
<!-- hutool 工具集减少重复开发各种Util-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>

View File

@@ -1,106 +0,0 @@
package cn.iocoder.common.framework.dubbo;
import cn.iocoder.common.framework.exception.ServiceException;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.filter.ExceptionFilter;
import org.apache.dubbo.rpc.service.GenericService;
import java.lang.reflect.Method;
/**
* 基于 {@link org.apache.dubbo.rpc.filter.ExceptionFilter} 实现
*
* 主要目的是一些全局性的异常能够返回。因为Dubbo Consumer 能够保证,一定会引入全局性的异常。
*/
@Activate(group = CommonConstants.PROVIDER)
public class DubboExceptionFilter implements Filter {
private final Logger logger;
public DubboExceptionFilter() {
this(LoggerFactory.getLogger(ExceptionFilter.class));
}
public DubboExceptionFilter(Logger logger) {
this.logger = logger;
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
try {
return invoker.invoke(invocation);
} catch (RuntimeException e) {
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()
+ ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
+ ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
throw e;
}
}
@Override
public Result onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
if (result.hasException() && GenericService.class != invoker.getInterface()) {
try {
Throwable exception = result.getException();
// directly throw if it's checked exception
if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
return result;
} else if (exception instanceof ServiceException) { // add by 芋艿。如果是业务异常,继续抛出
return result;
}
// directly throw if the exception appears in the signature
try {
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
Class<?>[] exceptionClassses = method.getExceptionTypes();
for (Class<?> exceptionClass : exceptionClassses) {
if (exception.getClass().equals(exceptionClass)) {
return result;
}
}
} catch (NoSuchMethodException e) {
return result;
}
// for the exception not found in method's signature, print ERROR message in server's log.
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()
+ ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
+ ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);
// directly throw if exception class and interface class are in the same jar file.
String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {
return result;
}
// directly throw if it's JDK exception
String className = exception.getClass().getName();
if (className.startsWith("java.") || className.startsWith("javax.")) {
return result;
}
// directly throw if it's dubbo exception
if (exception instanceof RpcException) {
return result;
}
// otherwise, wrap with RuntimeException and throw back to the client
result.setException(new RuntimeException(StringUtils.toString(exception)));
return result;
} 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);
return result;
}
}
return result;
}
}

View File

@@ -43,4 +43,6 @@ public final class ServiceException extends RuntimeException {
return code;
}
}

View File

@@ -1,52 +1,9 @@
package cn.iocoder.common.framework.util;
import cn.iocoder.common.framework.exception.ServiceException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import javax.validation.ConstraintViolationException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
public class ExceptionUtil {
public static ServiceException getServiceException(Exception e) {
if (e instanceof UndeclaredThrowableException) {
return getServiceException((UndeclaredThrowableException) e);
}
return null;
}
// 处理 Spring 动态代理调用时,发生 UndeclaredThrowableException 的情况。
// 不了解的胖友,可以先看看 https://segmentfault.com/a/1190000012262244 文章
// 原因是:
// 1. Dubbo 动态代理 Wrapper 会将抛出的异常,包装成 InvocationTargetException 异常
// 2. Spring AOP 发现是 InvocationTargetException 异常是非方法定义的异常,则会包装成 UndeclaredThrowableException 异常。
@Deprecated // https://github.com/apache/incubator-dubbo/issues/3386 Dubbo 2.6.5 会触发该问题,在 2.7.1 版本已经解决。
public static ServiceException getServiceException(UndeclaredThrowableException e) {
Throwable undeclaredThrowable = e.getUndeclaredThrowable();
if (undeclaredThrowable instanceof InvocationTargetException) {
InvocationTargetException invocationTargetException = (InvocationTargetException) undeclaredThrowable;
Throwable targetException = invocationTargetException.getTargetException();
if (targetException != null & targetException instanceof ServiceException) {
return (ServiceException) targetException;
}
}
return null;
}
@Deprecated // https://github.com/apache/incubator-dubbo/issues/3386 Dubbo 2.6.5 会触发该问题,在 2.7.1 版本已经解决。
public static ConstraintViolationException getConstraintViolationException(UndeclaredThrowableException e) {
Throwable undeclaredThrowable = e.getUndeclaredThrowable();
if (undeclaredThrowable instanceof InvocationTargetException) {
InvocationTargetException invocationTargetException = (InvocationTargetException) undeclaredThrowable;
Throwable targetException = invocationTargetException.getTargetException();
if (targetException instanceof ConstraintViolationException) {
return (ConstraintViolationException) targetException;
}
}
return null;
}
public static String getMessage(Throwable th) {
return ExceptionUtils.getMessage(th);
}

View File

@@ -2,7 +2,7 @@ package cn.iocoder.common.framework.vo;
import cn.iocoder.common.framework.enums.GlobalErrorCodeEnum;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.alibaba.fastjson.annotation.JSONField;
import org.springframework.util.Assert;
import java.io.Serializable;
@@ -95,12 +95,12 @@ public final class CommonResult<T> implements Serializable {
return this;
}
@JsonIgnore
@JSONField(serialize = false) // 避免序列化
public boolean isSuccess() {
return CODE_SUCCESS.equals(code);
}
@JsonIgnore
@JSONField(serialize = false) // 避免序列化
public boolean isError() {
return !isSuccess();
}

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mall-spring-boot-starter-dubbo</artifactId>
<dependencies>
<!-- 通用相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>common-framework</artifactId>
</dependency>
<!-- RPC 相关 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- 工具相关 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,116 @@
package cn.iocoder.mall.dubbo.core.filter;
import cn.iocoder.common.framework.enums.GlobalErrorCodeEnum;
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.rpc.*;
import org.apache.dubbo.rpc.service.GenericService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.lang.reflect.Type;
public class DubboProviderExceptionFilter implements Filter, Filter.Listener {
private Logger logger = LoggerFactory.getLogger(DubboProviderExceptionFilter.class);
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
return invoker.invoke(invocation);
}
@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
try {
// 转换异常
Throwable exception = appResponse.getException();
if (exception instanceof ConstraintViolationException) {
exception = this.constraintViolationExceptionHandler((ConstraintViolationException) exception);
}
// 根据不同的方法 schema 返回结果
// 第一种情况,则根据返回参数类型是否是 CommonResult 的情况,则将 ServiceException 转换成 CommonResult
if (isReturnCommonResult(invocation)) {
// 清空异常
appResponse.setException(null);
// 设置结果
CommonResult exceptionResult = new CommonResult();
appResponse.setValue(exceptionResult);
// 处理非 ServiceException 业务异常,转换成 ServiceException 业务异常
if (!(exception instanceof ServiceException)) {
logger.error("[onResponse][service({}) method({}) params({}) 执行异常]",
invocation.getServiceName(), invocation.getServiceName(), invocation.getArguments(), exception);
//
}
}
// 1. 处理 ServiceException 异常的情况
if (exception instanceof ServiceException) {
ServiceException serviceException = (ServiceException) exception;
// 则根据返回参数类型是否是 CommonResult 的情况,则将 ServiceException 转换成 CommonResult
if (isReturnCommonResult(invocation)) {
// 通用返回
CommonResult exceptionResult = new CommonResult();
exceptionResult.setCode(serviceException.getCode());
exceptionResult.setMessage(serviceException.getMessage());
appResponse.setValue(exceptionResult);
// 清空异常
appResponse.setException(null);
// 如果不是 CommonResult 的情况,则将 ServiceException 转换成 DubboInvokeException 避免可能存在的反序列化问题
} else {
RpcContext context = RpcContext.getContext();
appResponse.setException(new DubboInvokeException(exception.getMessage(), context.getLocalHost(), context.getLocalHostName()));
}
// 2. 处理非 ServiceException 异常的情况
} else {
RpcContext context = RpcContext.getContext();
appResponse.setException(new DubboInvokeException(exception.getMessage(), context.getLocalHost(), context.getLocalHostName()));
}
} 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);
}
}
}
@Override
public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
}
private boolean isReturnCommonResult(Invocation invocation) {
if (!(invocation instanceof RpcInvocation)) {
return false;
}
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
Type[] returnTypes = rpcInvocation.getReturnTypes();
if (returnTypes.length == 0) {
return false;
}
Type returnType = returnTypes[0];
if (!(returnType instanceof Class)) {
return false;
}
Class returnClass = (Class) returnType;
return returnClass == CommonResult.class;
}
/**
* 处理 Validator 校验不通过产生的异常
*/
private ServiceException constraintViolationExceptionHandler(ConstraintViolationException ex) {
logger.warn("[constraintViolationExceptionHandler]", ex);
ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next();
return ServiceExceptionUtil.exception0(GlobalErrorCodeEnum.BAD_REQUEST.getCode(),
String.format("请求参数不正确:%s", constraintViolation.getMessage()));
}
private ServiceException defaultExceptionHandler() {
}
}

View File

@@ -0,0 +1,4 @@
/**
* 占坑
*/
package cn.iocoder.mall.dubbo.core;

View File

@@ -6,7 +6,9 @@ import cn.iocoder.mall.web.config.CommonWebAutoConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -15,10 +17,17 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@AutoConfigureAfter(CommonWebAutoConfiguration.class) // 在 CommonWebAutoConfiguration 之后自动配置,保证过滤器的顺序
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableConfigurationProperties(AdminSecurityProperties.class)
public class AdminSecurityAutoConfiguration implements WebMvcConfigurer {
private Logger logger = LoggerFactory.getLogger(getClass());
@Bean
@ConditionalOnMissingBean
public AdminSecurityProperties adminSecurityProperties() {
return new AdminSecurityProperties();
}
// ========== 拦截器相关 ==========
@Bean
@@ -33,11 +42,16 @@ public class AdminSecurityAutoConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
AdminSecurityProperties properties = this.adminSecurityProperties();
// AdminSecurityInterceptor 拦截器
registry.addInterceptor(this.adminSecurityInterceptor());
registry.addInterceptor(this.adminSecurityInterceptor())
.excludePathPatterns(properties.getIgnorePaths())
.excludePathPatterns(properties.getDefaultIgnorePaths());
logger.info("[addInterceptors][加载 AdminSecurityInterceptor 拦截器完成]");
// AdminDemoInterceptor 拦截器
registry.addInterceptor(this.adminDemoInterceptor());
registry.addInterceptor(this.adminDemoInterceptor())
.excludePathPatterns(properties.getIgnorePaths())
.excludePathPatterns(properties.getDefaultIgnorePaths());
logger.info("[addInterceptors][加载 AdminDemoInterceptor 拦截器完成]");
}

View File

@@ -0,0 +1,41 @@
package cn.iocoder.mall.security.admin.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("mall.security.admin")
public class AdminSecurityProperties {
private static final String[] DEFAULT_IGNORE_PATHS = new String[]{
// Swagger 相关
"/doc.html", "/swagger-resources", "/swagger-resources/**",
// Actuator 相关
};
/**
* 自定义忽略 Path
*/
private String[] ignorePaths = new String[0];
/**
* 默认忽略 Path
*/
private String[] defaultIgnorePaths = DEFAULT_IGNORE_PATHS;
public String[] getIgnorePaths() {
return ignorePaths;
}
public AdminSecurityProperties setIgnorePaths(String[] ignorePaths) {
this.ignorePaths = ignorePaths;
return this;
}
public String[] getDefaultIgnorePaths() {
return defaultIgnorePaths;
}
public AdminSecurityProperties setDefaultIgnorePaths(String[] defaultIgnorePaths) {
this.defaultIgnorePaths = defaultIgnorePaths;
return this;
}
}

View File

@@ -154,7 +154,7 @@ public class GlobalExceptionHandler {
* 处理系统异常,兜底处理所有的一切
*/
@ExceptionHandler(value = Exception.class)
public CommonResult exceptionHandler(HttpServletRequest req, Throwable e) {
public CommonResult defaultExceptionHandler(HttpServletRequest req, Throwable e) {
logger.error("[exceptionHandler]", e);
// 插入异常日志
SystemExceptionLogCreateDTO exceptionLog = new SystemExceptionLogCreateDTO();

View File

@@ -20,17 +20,8 @@
<module>mall-spring-boot-starter-security-admin</module>
<module>mall-spring-boot-starter-security-user</module>
<module>mall-spring-boot-starter-mybatis</module>
<module>mall-spring-boot-starter-dubbo</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>