mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-08 16:57:09 +08:00
feat(web): 新增链路跟踪自动配置
基于 TLog(轻量级的分布式日志标记追踪神器),并适配 Spring Boot 3.x
This commit is contained in:
@@ -52,6 +52,16 @@ public class PropertiesConstants {
|
||||
*/
|
||||
public static final String SPRINGDOC_SWAGGER_UI = SPRINGDOC + ".swagger-ui";
|
||||
|
||||
/**
|
||||
* 安全配置
|
||||
*/
|
||||
public static final String SECURITY = CONTINEW_STARTER + ".security";
|
||||
|
||||
/**
|
||||
* 密码编解码配置
|
||||
*/
|
||||
public static final String PASSWORD = SECURITY + ".password";
|
||||
|
||||
/**
|
||||
* Web 配置
|
||||
*/
|
||||
@@ -62,6 +72,11 @@ public class PropertiesConstants {
|
||||
*/
|
||||
public static final String CORS = WEB + ".cors";
|
||||
|
||||
/**
|
||||
* 链路配置
|
||||
*/
|
||||
public static final String TRACE = WEB + ".trace";
|
||||
|
||||
/**
|
||||
* 日志配置
|
||||
*/
|
||||
@@ -91,9 +106,4 @@ public class PropertiesConstants {
|
||||
* 行为验证码配置
|
||||
*/
|
||||
public static final String CAPTCHA_BEHAVIOR = CAPTCHA + ".behavior";
|
||||
|
||||
/**
|
||||
* 密码编解码配置
|
||||
*/
|
||||
public static final String PASSWORD_ENCODER = CONTINEW_STARTER + ".password-encoder";
|
||||
}
|
||||
|
@@ -63,4 +63,9 @@ public class StringConstants implements StrPool {
|
||||
* 路径模式
|
||||
*/
|
||||
public static final String PATH_PATTERN = "/**";
|
||||
|
||||
/**
|
||||
* 路径模式(仅匹配当前目录)
|
||||
*/
|
||||
public static final String PATH_PATTERN_CURRENT_DIR = "/*";
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ import java.util.Map;
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@EnableConfigurationProperties(PasswordEncoderProperties.class)
|
||||
@ConditionalOnProperty(prefix = PropertiesConstants.PASSWORD_ENCODER, name = PropertiesConstants.ENABLED, havingValue = "true")
|
||||
@ConditionalOnProperty(prefix = PropertiesConstants.PASSWORD, name = PropertiesConstants.ENABLED, havingValue = "true")
|
||||
public class PasswordEncoderAutoConfiguration {
|
||||
private static final Logger log = LoggerFactory.getLogger(PasswordEncoderAutoConfiguration.class);
|
||||
|
||||
|
@@ -25,7 +25,7 @@ import top.charles7c.continew.starter.core.constant.PropertiesConstants;
|
||||
* @author Jasmine
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties(PropertiesConstants.PASSWORD_ENCODER)
|
||||
@ConfigurationProperties(PropertiesConstants.PASSWORD)
|
||||
public class PasswordEncoderProperties {
|
||||
|
||||
/**
|
||||
|
@@ -45,6 +45,12 @@
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- TLog(轻量级的分布式日志标记追踪神器) -->
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>tlog-web-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- API 文档模块 -->
|
||||
<dependency>
|
||||
<groupId>top.charles7c.continew</groupId>
|
||||
|
@@ -72,7 +72,7 @@ public class CorsAutoConfiguration {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration(StringConstants.PATH_PATTERN, config);
|
||||
CorsFilter corsFilter = new CorsFilter(source);
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'CorsFilter' completed initialization.");
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Web-CorsFilter' completed initialization.");
|
||||
return corsFilter;
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.core.exception;
|
||||
package top.charles7c.continew.starter.web.autoconfigure.exception;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.core.exception;
|
||||
package top.charles7c.continew.starter.web.autoconfigure.exception;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
@@ -30,8 +30,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;
|
||||
import top.charles7c.continew.starter.web.core.exception.GlobalErrorHandler;
|
||||
import top.charles7c.continew.starter.web.core.exception.GlobalExceptionHandler;
|
||||
|
||||
/**
|
||||
* 全局异常处理器自动配置
|
||||
@@ -67,6 +65,6 @@ public class GlobalExceptionHandlerAutoConfiguration {
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Extension-Global Exception Handler' completed initialization.");
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Web-Global Exception Handler' completed initialization.");
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.autoconfigure.trace;
|
||||
|
||||
/**
|
||||
* TLog 配置属性
|
||||
*
|
||||
* <p>
|
||||
* 重写 TLog 配置以适配 Spring Boot 3.x
|
||||
* </p>
|
||||
*
|
||||
* @see com.yomahub.tlog.springboot.property.TLogProperty
|
||||
* @author Bryan.Zhang
|
||||
* @author Jasmine
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class TLogProperties {
|
||||
|
||||
/**
|
||||
* 日志标签模板
|
||||
*/
|
||||
private String pattern;
|
||||
|
||||
/**
|
||||
* 自动打印调用参数和时间
|
||||
*/
|
||||
private Boolean enableInvokeTimePrint;
|
||||
|
||||
/**
|
||||
* 自定义 TraceId 生成器
|
||||
*/
|
||||
private String idGenerator;
|
||||
|
||||
/**
|
||||
* MDC 模式
|
||||
*/
|
||||
private Boolean mdcEnable;
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void setPattern(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public Boolean getEnableInvokeTimePrint() {
|
||||
return enableInvokeTimePrint;
|
||||
}
|
||||
|
||||
public void setEnableInvokeTimePrint(Boolean enableInvokeTimePrint) {
|
||||
this.enableInvokeTimePrint = enableInvokeTimePrint;
|
||||
}
|
||||
|
||||
public String getIdGenerator() {
|
||||
return idGenerator;
|
||||
}
|
||||
|
||||
public void setIdGenerator(String idGenerator) {
|
||||
this.idGenerator = idGenerator;
|
||||
}
|
||||
|
||||
public Boolean getMdcEnable() {
|
||||
return mdcEnable;
|
||||
}
|
||||
|
||||
public void setMdcEnable(Boolean mdcEnable) {
|
||||
this.mdcEnable = mdcEnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TLogProperties{" + "pattern='" + pattern + '\'' + ", enableInvokeTimePrint=" + enableInvokeTimePrint + ", idGenerator='" + idGenerator + '\'' + ", mdcEnable=" + mdcEnable + '}';
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.autoconfigure.trace;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.tlog.context.TLogContext;
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* TLog 过滤器
|
||||
*
|
||||
* <p>
|
||||
* 重写 TLog 配置以适配 Spring Boot 3.x
|
||||
* </p>
|
||||
*
|
||||
* @see com.yomahub.tlog.web.filter.TLogServletFilter
|
||||
* @author Bryan.Zhang
|
||||
* @author Jasmine
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class TLogServletFilter implements Filter {
|
||||
|
||||
private final TraceProperties traceProperties;
|
||||
|
||||
public TLogServletFilter(TraceProperties traceProperties) {
|
||||
this.traceProperties = traceProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request,
|
||||
ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
if (request instanceof HttpServletRequest httpServletRequest && response instanceof HttpServletResponse httpServletResponse) {
|
||||
try {
|
||||
TLogWebCommon.loadInstance().preHandle(httpServletRequest);
|
||||
// 把 traceId 放入 response 的 header,为了方便有些人有这样的需求,从前端拿整条链路的 traceId
|
||||
String headerName = traceProperties.getHeaderName();
|
||||
if (StrUtil.isNotBlank(headerName)) {
|
||||
httpServletResponse.addHeader(headerName, TLogContext.getTraceId());
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
} finally {
|
||||
TLogWebCommon.loadInstance().afterCompletion();
|
||||
}
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.autoconfigure.trace;
|
||||
|
||||
import com.yomahub.tlog.constant.TLogConstants;
|
||||
import com.yomahub.tlog.core.rpc.TLogLabelBean;
|
||||
import com.yomahub.tlog.core.rpc.TLogRPCHandler;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* TLog Web 通用拦截器
|
||||
*
|
||||
* <p>
|
||||
* 重写 TLog 配置以适配 Spring Boot 3.x
|
||||
* </p>
|
||||
*
|
||||
* @see com.yomahub.tlog.web.common.TLogWebCommon
|
||||
* @author Bryan.Zhang
|
||||
* @author Jasmine
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class TLogWebCommon extends TLogRPCHandler {
|
||||
|
||||
private static volatile TLogWebCommon tLogWebCommon;
|
||||
|
||||
public static TLogWebCommon loadInstance() {
|
||||
if (tLogWebCommon == null) {
|
||||
synchronized (TLogWebCommon.class) {
|
||||
if (tLogWebCommon == null) {
|
||||
tLogWebCommon = new TLogWebCommon();
|
||||
}
|
||||
}
|
||||
}
|
||||
return tLogWebCommon;
|
||||
}
|
||||
|
||||
public void preHandle(HttpServletRequest request) {
|
||||
String traceId = request.getHeader(TLogConstants.TLOG_TRACE_KEY);
|
||||
String spanId = request.getHeader(TLogConstants.TLOG_SPANID_KEY);
|
||||
String preIvkApp = request.getHeader(TLogConstants.PRE_IVK_APP_KEY);
|
||||
String preIvkHost = request.getHeader(TLogConstants.PRE_IVK_APP_HOST);
|
||||
String preIp = request.getHeader(TLogConstants.PRE_IP_KEY);
|
||||
TLogLabelBean labelBean = new TLogLabelBean(preIvkApp, preIvkHost, preIp, traceId, spanId);
|
||||
processProviderSide(labelBean);
|
||||
}
|
||||
|
||||
public void afterCompletion() {
|
||||
cleanThreadLocal();
|
||||
}
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.autoconfigure.trace;
|
||||
|
||||
import com.yomahub.tlog.id.TLogIdGenerator;
|
||||
import com.yomahub.tlog.id.TLogIdGeneratorLoader;
|
||||
import com.yomahub.tlog.spring.TLogPropertyInit;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import top.charles7c.continew.starter.core.constant.PropertiesConstants;
|
||||
import top.charles7c.continew.starter.core.constant.StringConstants;
|
||||
|
||||
/**
|
||||
* 链路跟踪自动配置
|
||||
*
|
||||
* @author Jasmine
|
||||
* @author Charles7c
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@EnableConfigurationProperties(TraceProperties.class)
|
||||
@ConditionalOnProperty(prefix = PropertiesConstants.TRACE, name = PropertiesConstants.ENABLED, havingValue = "true")
|
||||
public class TraceAutoConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TraceAutoConfiguration.class);
|
||||
|
||||
private final TraceProperties traceProperties;
|
||||
|
||||
public TraceAutoConfiguration(TraceProperties traceProperties) {
|
||||
this.traceProperties = traceProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public TLogPropertyInit tLogPropertyInit(TLogIdGenerator tLogIdGenerator) {
|
||||
TLogProperties tLogProperties = traceProperties.getTlog();
|
||||
TLogPropertyInit tLogPropertyInit = new TLogPropertyInit();
|
||||
tLogPropertyInit.setPattern(tLogProperties.getPattern());
|
||||
tLogPropertyInit.setEnableInvokeTimePrint(tLogProperties.getEnableInvokeTimePrint());
|
||||
tLogPropertyInit.setMdcEnable(tLogProperties.getMdcEnable());
|
||||
// 设置自定义 TraceId 生成器
|
||||
TLogIdGeneratorLoader.setIdGenerator(tLogIdGenerator);
|
||||
return tLogPropertyInit;
|
||||
}
|
||||
|
||||
/**
|
||||
* TLog 过滤器配置
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean<TLogServletFilter> filterRegistration() {
|
||||
FilterRegistrationBean<TLogServletFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new TLogServletFilter(traceProperties));
|
||||
registration.addUrlPatterns(StringConstants.PATH_PATTERN_CURRENT_DIR);
|
||||
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
|
||||
return registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 Trace ID 生成器配置
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TLogIdGenerator tLogIdGenerator() {
|
||||
return new TraceIdGenerator();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Web-Trace' completed initialization.");
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.autoconfigure.trace;
|
||||
|
||||
import com.yomahub.tlog.id.TLogIdGenerator;
|
||||
import com.yomahub.tlog.id.snowflake.UniqueIdGenerator;
|
||||
|
||||
/**
|
||||
* TLog ID 生成器
|
||||
*
|
||||
* @author Jasmine
|
||||
* @author Charles7c
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class TraceIdGenerator extends TLogIdGenerator {
|
||||
@Override
|
||||
public String generateTraceId() {
|
||||
return String.valueOf(UniqueIdGenerator.generateId());
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.autoconfigure.trace;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import top.charles7c.continew.starter.core.constant.PropertiesConstants;
|
||||
|
||||
/**
|
||||
* 链路跟踪配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties(PropertiesConstants.TRACE)
|
||||
public class TraceProperties {
|
||||
|
||||
/**
|
||||
* 是否启用链路跟踪配置
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* 响应头名称
|
||||
*/
|
||||
private String headerName = "traceId";
|
||||
|
||||
/**
|
||||
* TLog 配置
|
||||
*/
|
||||
@NestedConfigurationProperty
|
||||
private TLogProperties tlog;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getHeaderName() {
|
||||
return headerName;
|
||||
}
|
||||
|
||||
public void setHeaderName(String headerName) {
|
||||
this.headerName = headerName;
|
||||
}
|
||||
|
||||
public TLogProperties getTlog() {
|
||||
return tlog;
|
||||
}
|
||||
|
||||
public void setTlog(TLogProperties tlog) {
|
||||
this.tlog = tlog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TraceProperties{" + "enabled=" + enabled + ", headerName='" + headerName + '\'' + ", tlog=" + tlog + '}';
|
||||
}
|
||||
}
|
@@ -1 +1,2 @@
|
||||
top.charles7c.continew.starter.web.autoconfigure.cors.CorsAutoConfiguration
|
||||
top.charles7c.continew.starter.web.autoconfigure.cors.CorsAutoConfiguration
|
||||
top.charles7c.continew.starter.web.autoconfigure.trace.TraceAutoConfiguration
|
Reference in New Issue
Block a user