Merge remote-tracking branch 'origin/master' into feature/REQ-2300
This commit is contained in:
commit
f5b72655b4
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-autoconfigure</artifactId>
|
||||
@ -94,5 +94,11 @@
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
package cn.axzo.framework.autoconfigure.feign;
|
||||
|
||||
import cn.axzo.framework.core.RecordException;
|
||||
import feign.Feign;
|
||||
import feign.Response;
|
||||
import feign.Util;
|
||||
import feign.codec.ErrorDecoder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import java.io.IOException;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* 为兼容 X-Metadata-Tag 的异常解码器
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024/6/25 21:55
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnClass({Feign.class, Servlet.class, DispatcherServlet.class})
|
||||
public class FeignErrorDecoderAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ErrorDecoder feignErrorDecoder() {
|
||||
return (methodKey, response) -> {
|
||||
if (response.status() != 512) {
|
||||
return new ErrorDecoder.Default().decode(methodKey, response);
|
||||
}
|
||||
byte[] body = {};
|
||||
try {
|
||||
if (response.body() != null) {
|
||||
body = Util.toByteArray(response.body().asInputStream());
|
||||
}
|
||||
} catch (IOException ignored) { // NOPMD
|
||||
}
|
||||
return new RecordException(new String(body, UTF_8));
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,10 @@ import cn.axzo.framework.autoconfigure.web.exception.resolver.internal.RequestRe
|
||||
import cn.axzo.framework.autoconfigure.web.exception.support.GlobalErrorController;
|
||||
import cn.axzo.framework.autoconfigure.web.exception.support.GlobalExceptionHandler;
|
||||
import cn.axzo.framework.domain.web.result.Result;
|
||||
import cn.axzo.framework.web.feign.FeignRecordExceptionInterceptor;
|
||||
import cn.axzo.framework.web.filter.BasicRecordExceptionFilter;
|
||||
import feign.RequestInterceptor;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@ -22,6 +26,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
|
||||
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
@ -184,4 +189,19 @@ public class ExceptionHandlerAutoConfiguration implements WebMvcConfigurer {
|
||||
return new RequestRejectedExceptionHttpStatusResolver();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RequestInterceptor.class)
|
||||
public static class RecordExceptionConfiguration {
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor(){
|
||||
return new FeignRecordExceptionInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(MDC.class)
|
||||
public OncePerRequestFilter oncePerRequestFilter() {
|
||||
return new BasicRecordExceptionFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,14 +3,22 @@ package cn.axzo.framework.autoconfigure.web.exception.support;
|
||||
import cn.axzo.framework.autoconfigure.web.exception.handler.ExceptionResultHandler;
|
||||
import cn.axzo.framework.autoconfigure.web.exception.handler.internal.StandardExceptionResultHandler;
|
||||
import cn.axzo.framework.core.InternalException;
|
||||
import cn.axzo.framework.core.RecordException;
|
||||
import cn.axzo.framework.core.util.ClassUtil;
|
||||
import cn.axzo.framework.domain.web.code.BaseCode;
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.framework.domain.web.result.ApiReportResult;
|
||||
import cn.axzo.framework.domain.web.result.Result;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.web.ErrorProperties;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||
@ -19,6 +27,8 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
@ -34,12 +44,22 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.framework.domain.web.result.ApiReportResult.err;
|
||||
import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_FILTER_PACKAGE_VALUE;
|
||||
import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME;
|
||||
import static java.lang.String.format;
|
||||
import static jodd.util.StringUtil.isNotBlank;
|
||||
import static org.springframework.http.HttpHeaders.CACHE_CONTROL;
|
||||
|
||||
/**
|
||||
* @Description spring mvc全局异常捕获
|
||||
@ -48,6 +68,7 @@ import static jodd.util.StringUtil.isNotBlank;
|
||||
**/
|
||||
@RestControllerAdvice(annotations = {Controller.class, RestController.class})
|
||||
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||
|
||||
private final List<ExceptionResultHandler<? extends Throwable, ? extends Result>> handlers;
|
||||
|
||||
@ -55,6 +76,19 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
|
||||
private final ErrorAttributes errorAttributes;
|
||||
|
||||
public static final String CTX_LOG_ID = "ctxLogId";
|
||||
/**
|
||||
* 多设置一个key = TraceId, value为traceId的变量到MDC. 以兼容目前的logback-spring.xml的配置
|
||||
*/
|
||||
public static final String TRACE_ID_IN_MDC = "traceId";
|
||||
private static final String RECORD_FLAG = "debug";
|
||||
|
||||
|
||||
@Value("${axzo.framework.debug:X-Metadata-Tag}")
|
||||
private String recordExceptionHeaderName;
|
||||
@Value("${spring.application.name:}")
|
||||
private String applicationName;
|
||||
|
||||
public GlobalExceptionHandler(List<ExceptionResultHandler<? extends Throwable, ? extends Result>> handlers,
|
||||
ErrorAttributes errorAttributes,
|
||||
ServerProperties properties) {
|
||||
@ -85,7 +119,7 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
}
|
||||
|
||||
// 3.响应
|
||||
return ApiResult.err(Integer.parseInt(code), message);
|
||||
return err(Integer.parseInt(code), message);
|
||||
});
|
||||
|
||||
return super.handleExceptionInternal(ex, result, headers, status, request);
|
||||
@ -111,7 +145,7 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
}
|
||||
|
||||
// 3.响应
|
||||
return ApiResult.err(Integer.parseInt(code), message);
|
||||
return err(Integer.parseInt(code), message);
|
||||
});
|
||||
return super.handleExceptionInternal(ex, result, headers, status, request);
|
||||
}
|
||||
@ -136,7 +170,7 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
}
|
||||
|
||||
// 3.响应
|
||||
return ApiResult.err(Integer.parseInt(code), message);
|
||||
return err(Integer.parseInt(code), message);
|
||||
});
|
||||
return super.handleExceptionInternal(ex, result, headers, status, request);
|
||||
}
|
||||
@ -162,7 +196,7 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
}
|
||||
|
||||
// 3.响应
|
||||
return ApiResult.err(Integer.parseInt(code), message);
|
||||
return err(Integer.parseInt(code), message);
|
||||
});
|
||||
return super.handleExceptionInternal(ex, result, headers, status, request);
|
||||
}
|
||||
@ -185,7 +219,7 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
message = "Required parameter '" + field + "' is not present";
|
||||
|
||||
// 3.响应
|
||||
return ApiResult.err(Integer.parseInt(code), message);
|
||||
return err(Integer.parseInt(code), message);
|
||||
});
|
||||
return super.handleExceptionInternal(ex, result, headers, status, request);
|
||||
}
|
||||
@ -230,7 +264,7 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
}
|
||||
|
||||
// 3.响应
|
||||
return ApiResult.err(Integer.parseInt(code), message);
|
||||
return err(Integer.parseInt(code), message);
|
||||
});
|
||||
return super.handleExceptionInternal(ex, result, headers, status, request);
|
||||
}
|
||||
@ -240,8 +274,16 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
throw e;
|
||||
}
|
||||
|
||||
@ExceptionHandler(RecordException.class)
|
||||
public String recordException(HttpServletRequest request, HttpServletResponse response, Throwable e) {
|
||||
return e.getMessage();
|
||||
}
|
||||
|
||||
@ExceptionHandler(Throwable.class)
|
||||
public Result handleAllException(HttpServletRequest request, HttpServletResponse response, Throwable e) {
|
||||
if (shouldRecordException(request)) {
|
||||
return buildResult(request, response, e);
|
||||
}
|
||||
Map<String, Object> attributes = Requests.from(request).getErrorAttributes(errorAttributes, errorProperties);
|
||||
return _handleException(request, response, e, attributes)
|
||||
.orElseGet(() -> handlers.stream()
|
||||
@ -252,6 +294,16 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
);
|
||||
}
|
||||
|
||||
private Result buildResult(HttpServletRequest request, HttpServletResponse response, Throwable e) {
|
||||
response.setHeader(CACHE_CONTROL, "no-store");
|
||||
response.setStatus(512);
|
||||
ApiReportResult<Object> err = err(512, "discovery server internal error");
|
||||
Map<String, ExceptionWrapper> recordExceptionMap = new HashMap<>();
|
||||
recordExceptionMap.put(StringUtils.hasText(applicationName) ? applicationName : "not applicationName found", rebuildThrowable(e, request));
|
||||
err.setAnalysis(recordExceptionMap);
|
||||
return err;
|
||||
}
|
||||
|
||||
private Optional<Result> _handleException(WebRequest webRequest, Throwable e) {
|
||||
Map<String, Object> attributes = Requests.from(webRequest).getErrorAttributes(errorAttributes, errorProperties);
|
||||
if (webRequest instanceof ServletWebRequest) {
|
||||
@ -279,10 +331,84 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldRecordException(HttpServletRequest request) {
|
||||
String headerValue = request.getHeader(recordExceptionHeaderName);
|
||||
if (!StringUtils.hasText(headerValue)) {
|
||||
headerValue = MDC.get(recordExceptionHeaderName);
|
||||
}
|
||||
log.info("recordException HeaderName: {}", headerValue);
|
||||
if(!StringUtils.hasText(headerValue)) {
|
||||
return false;
|
||||
}
|
||||
return headerValue.contains(RECORD_FLAG);
|
||||
}
|
||||
|
||||
private boolean shouldFilter(ExceptionResultHandler<? extends Throwable, ? extends Result> handler, Throwable e) {
|
||||
if (handler.isRecursive()) {
|
||||
return handler.getExceptionClass().isAssignableFrom(e.getClass());
|
||||
}
|
||||
return handler.getExceptionClass() == e.getClass();
|
||||
}
|
||||
|
||||
private ExceptionWrapper rebuildThrowable(Throwable throwable, HttpServletRequest request) {
|
||||
return new ExceptionWrapper(throwable, request);
|
||||
}
|
||||
|
||||
@Getter
|
||||
static class ExceptionWrapper implements Serializable {
|
||||
private final String traceId = getOutsideTraceId();
|
||||
private final String causeMessage;
|
||||
private final List<String> stackTrace = new ArrayList<>();
|
||||
|
||||
public ExceptionWrapper(Throwable throwable, HttpServletRequest request) {
|
||||
this.causeMessage = throwable.getMessage();
|
||||
init(throwable, request);
|
||||
}
|
||||
|
||||
private void init(Throwable throwable, HttpServletRequest request) {
|
||||
List<StackTraceElement> elements = Arrays.stream(throwable.getStackTrace()).collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(elements)) {
|
||||
return;
|
||||
}
|
||||
String[] parameterValues = request.getParameterValues(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME);
|
||||
List<String> filterPackageNames = Lists.newArrayList(MICRO_SERVER_RECORD_ERROR_FILTER_PACKAGE_VALUE);
|
||||
if (Objects.nonNull(parameterValues) && parameterValues.length > 0) {
|
||||
filterPackageNames = Arrays.asList(parameterValues);
|
||||
} else if (StringUtils.hasText(MDC.get(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME))) {
|
||||
filterPackageNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray(MDC.get(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME)));
|
||||
}
|
||||
for (StackTraceElement e : elements) {
|
||||
if (StringUtils.hasText(e.getClassName())) {
|
||||
filterPackageNames.stream().filter(i -> e.getClassName().contains(i)).findAny().ifPresent(t -> {
|
||||
StackTraceWrapper wrapper = new StackTraceWrapper();
|
||||
wrapper.setClassName(e.getClassName());
|
||||
wrapper.setMethodName(e.getMethodName());
|
||||
wrapper.setLineNumber(e.getLineNumber());
|
||||
stackTrace.add(wrapper.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
static class StackTraceWrapper implements Serializable {
|
||||
private String className;
|
||||
private String methodName;
|
||||
private Integer lineNumber;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return className + "#" + methodName + ":" + lineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static String getOutsideTraceId() {
|
||||
String res = MDC.get(TRACE_ID_IN_MDC);
|
||||
if (Objects.isNull(res)) {
|
||||
res = MDC.get(CTX_LOG_ID);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,5 +16,6 @@ cn.axzo.framework.autoconfigure.web.rest.EnumResource,\
|
||||
cn.axzo.framework.autoconfigure.validation.SpringValidatorAutoConfiguration,\
|
||||
cn.axzo.framework.autoconfigure.web.advice.BodyAdviceAutoConfiguration,\
|
||||
cn.axzo.framework.autoconfigure.web.FilterAutoConfiguration,\
|
||||
cn.axzo.framework.autoconfigure.web.context.WebMvcAwareAutoConfiguration
|
||||
cn.axzo.framework.autoconfigure.web.context.WebMvcAwareAutoConfiguration,\
|
||||
cn.axzo.framework.autoconfigure.feign.FeignErrorDecoderAutoConfiguration
|
||||
# cn.axzo.framework.autoconfigure.web.swagger.SwaggerAutoConfiguration,\
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-boot</artifactId>
|
||||
@ -82,4 +82,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<name>Axzo Common Cache</name>
|
||||
<artifactId>axzo-common-cache</artifactId>
|
||||
@ -21,4 +21,4 @@
|
||||
<artifactId>jetcache-starter-redis</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-clients</artifactId>
|
||||
<groupId>cn.axzo.framework.client</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>feign-starter</artifactId>
|
||||
@ -62,4 +62,4 @@
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<groupId>cn.axzo.framework.client</groupId>
|
||||
@ -19,4 +19,4 @@
|
||||
<module>retrofit-starter</module>
|
||||
<module>feign-starter</module>
|
||||
</modules>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.axzo.framework.client</groupId>
|
||||
<artifactId>axzo-common-clients</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>retrofit-starter</artifactId>
|
||||
@ -35,4 +35,4 @@
|
||||
<artifactId>adapter-rxjava2</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-core</artifactId>
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package cn.axzo.framework.core;
|
||||
|
||||
/**
|
||||
* 记录异常
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024/6/25 21:06
|
||||
*/
|
||||
public class RecordException extends RuntimeException {
|
||||
public RecordException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RecordException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public RecordException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-datas</artifactId>
|
||||
<groupId>cn.axzo.framework.data</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-data-mybatis-plus</artifactId>
|
||||
@ -50,4 +50,4 @@
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<groupId>cn.axzo.framework.data</groupId>
|
||||
@ -18,4 +18,4 @@
|
||||
<modules>
|
||||
<module>axzo-data-mybatis-plus</module>
|
||||
</modules>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-domain</artifactId>
|
||||
@ -103,4 +103,4 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
package cn.axzo.framework.domain.web.result;
|
||||
|
||||
import cn.axzo.framework.domain.web.ApiException;
|
||||
import cn.axzo.framework.domain.web.code.IRespCode;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static cn.axzo.framework.domain.web.code.BaseCode.SERVER_ERROR;
|
||||
import static cn.axzo.framework.domain.web.code.BaseCode.SUCCESS;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author liyong.tian
|
||||
* @Date 2020/9/7 20:33
|
||||
**/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ApiReportResult<E> extends ApiCoreResult<E> {
|
||||
|
||||
@ApiModelProperty(value = "异常记录信息", position = 101)
|
||||
protected Map<String, ?> analysis = new HashMap<>();
|
||||
|
||||
public static <E> ApiReportResult<E> ok() {
|
||||
return ok(null);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> ok(E data) {
|
||||
return build(SUCCESS, data);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> err(IRespCode code) {
|
||||
return err(code, code.getMessage());
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> err(IRespCode code, String message) {
|
||||
return err(Integer.parseInt(code.getRespCode()), message);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> err(IRespCode code, E data) {
|
||||
return build(Integer.parseInt(code.getRespCode()), code.getMessage(), data);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> err(String message) {
|
||||
return err(Integer.parseInt(SERVER_ERROR.getRespCode()), message);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> err(Integer code, String message) {
|
||||
if (code == null) {
|
||||
return err(message);
|
||||
}
|
||||
return build(code, message, null);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> build(IRespCode code) {
|
||||
return build(code, null);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> build(IRespCode code, E data) {
|
||||
return build(Integer.parseInt(code.getRespCode()), code.getMessage(), data);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> build(Integer code, String message, E data) {
|
||||
return new ApiReportResult<>(code, message, data);
|
||||
}
|
||||
|
||||
public static <E> ApiReportResult<E> with(Throwable e) {
|
||||
if (e != null && e instanceof ApiException) {
|
||||
return err(((ApiException) e).getCode(), e.getMessage());
|
||||
}
|
||||
if (e != null) {
|
||||
return err(SERVER_ERROR, e.getMessage());
|
||||
}
|
||||
return err(SERVER_ERROR);
|
||||
}
|
||||
|
||||
public ApiReportResult(Integer code, String msg, E data) {
|
||||
super(code, msg, data);
|
||||
}
|
||||
|
||||
public Map<String, ?> getAnalysis() {
|
||||
return analysis;
|
||||
}
|
||||
|
||||
public void setAnalysis(Map<String, ?> analysis) {
|
||||
this.analysis = analysis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> map = super.toMap();
|
||||
map.put("analysis", getAnalysis());
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-framework</artifactId>
|
||||
<groupId>cn.axzo.framework.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-context</artifactId>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<groupId>cn.axzo.framework.framework</groupId>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-jackson</artifactId>
|
||||
<groupId>cn.axzo.framework.jackson</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -39,4 +39,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-jackson</artifactId>
|
||||
<groupId>cn.axzo.framework.jackson</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -44,4 +44,4 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-jackson</artifactId>
|
||||
<groupId>cn.axzo.framework.jackson</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -40,4 +40,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-jackson</artifactId>
|
||||
<groupId>cn.axzo.framework.jackson</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -33,4 +33,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-jackson</artifactId>
|
||||
<groupId>cn.axzo.framework.jackson</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -86,4 +86,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-jackson</artifactId>
|
||||
<groupId>cn.axzo.framework.jackson</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -157,4 +157,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -94,4 +94,4 @@
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-loggings</artifactId>
|
||||
<groupId>cn.axzo.framework.logging</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>axzo-common-trace</artifactId>
|
||||
<name>Axzo Common trace</name>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-loggings</artifactId>
|
||||
<groupId>cn.axzo.framework.logging</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>log4j2-starter</artifactId>
|
||||
@ -35,4 +35,4 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-common-loggings</artifactId>
|
||||
<groupId>cn.axzo.framework.logging</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>logback-starter</artifactId>
|
||||
@ -19,4 +19,4 @@
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -20,4 +20,4 @@
|
||||
<module>logback-starter</module>
|
||||
<module>axzo-common-trace</module>
|
||||
</modules>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-math</artifactId>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<groupId>cn.axzo.framework.rocketmq</groupId>
|
||||
@ -33,4 +33,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -80,10 +80,12 @@ public interface EventConsumer {
|
||||
/**
|
||||
* 只elapse 超过多少毫秒才进行日志记录。默认 3ms
|
||||
*/
|
||||
@Setter
|
||||
private Long logElapsedThreshold;
|
||||
|
||||
private Map<String, byte[]> headers;
|
||||
private Map<String, Object> ext;
|
||||
@Setter
|
||||
private Long maxAllowElapsedMillis;
|
||||
private Boolean logEnabled;
|
||||
private transient Predicate<Event> logFilter;
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-validator</artifactId>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>axzo-common-web</artifactId>
|
||||
@ -43,5 +43,18 @@
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-core</artifactId>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>4.0.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
package cn.axzo.framework.web.feign;
|
||||
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME;
|
||||
import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_HEADER_NAME;
|
||||
|
||||
|
||||
/**
|
||||
* 用于 Feign 调用时,传递外部 HTTP 请求中携带的特殊 Header
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024/6/24 19:29
|
||||
*/
|
||||
public class FeignRecordExceptionInterceptor implements RequestInterceptor {
|
||||
private static final Logger log = LoggerFactory.getLogger(FeignRecordExceptionInterceptor.class);
|
||||
|
||||
@Override
|
||||
public void apply(RequestTemplate template) {
|
||||
HttpServletRequest originalRequest = getOriginalRequest();
|
||||
|
||||
setRequestParams(template, originalRequest);
|
||||
|
||||
setXMetaDataTag(template, originalRequest);
|
||||
}
|
||||
|
||||
private void setRequestParams(RequestTemplate template, HttpServletRequest originalRequest) {
|
||||
String[] packageNames = null;
|
||||
if(Objects.nonNull(originalRequest)) {
|
||||
packageNames = originalRequest.getParameterValues(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME);
|
||||
}
|
||||
if (Objects.isNull(packageNames) || packageNames.length == 0) {
|
||||
packageNames = StringUtils.commaDelimitedListToStringArray(MDC.get(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME));
|
||||
}
|
||||
template.query(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME, packageNames);
|
||||
}
|
||||
|
||||
private static void setXMetaDataTag(RequestTemplate template, HttpServletRequest originalRequest) {
|
||||
String headerValue = null;
|
||||
if(Objects.nonNull(originalRequest)) {
|
||||
// 需要传递外部传入的标识
|
||||
headerValue = originalRequest.getHeader(MICRO_SERVER_RECORD_ERROR_HEADER_NAME);
|
||||
}
|
||||
if (!StringUtils.hasText(headerValue)) {
|
||||
headerValue = MDC.get(MICRO_SERVER_RECORD_ERROR_HEADER_NAME);
|
||||
}
|
||||
template.header(MICRO_SERVER_RECORD_ERROR_HEADER_NAME, headerValue);
|
||||
}
|
||||
|
||||
public static HttpServletRequest getOriginalRequest() {
|
||||
try {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
return attributes.getRequest();
|
||||
} catch (Exception e) {
|
||||
log.debug("not HttpServletRequest instance bean found");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package cn.axzo.framework.web.filter;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* 用于入口请求收集记录异常开关信息
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024/6/25 09:40
|
||||
*/
|
||||
public class BasicRecordExceptionFilter extends OncePerRequestFilter implements PriorityOrdered {
|
||||
public static final String MICRO_SERVER_RECORD_ERROR_HEADER_NAME = "X-Metadata-Tag";
|
||||
public static final String MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME = "pkg";
|
||||
public static final String MICRO_SERVER_RECORD_ERROR_FILTER_PACKAGE_VALUE = "cn.axzo";
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
String[] packageNames = request.getParameterValues(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME);
|
||||
MDC.put(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME, StringUtils.arrayToCommaDelimitedString(packageNames));
|
||||
|
||||
// 需要传递外部传入的标识
|
||||
MDC.put(MICRO_SERVER_RECORD_ERROR_HEADER_NAME, request.getHeader(MICRO_SERVER_RECORD_ERROR_HEADER_NAME));
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -73,4 +73,4 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
5
pom.xml
5
pom.xml
@ -13,7 +13,7 @@
|
||||
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-framework-commons</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Axzo Framework Commons</name>
|
||||
@ -41,7 +41,8 @@
|
||||
|
||||
<properties>
|
||||
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
|
||||
<axzo-commons.version>1.0.0-SNAPSHOT</axzo-commons.version>
|
||||
<revision>1.0.0-SNAPSHOT</revision>
|
||||
<axzo-commons.version>${revision}</axzo-commons.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user