diff --git a/snowy-admin-web/src/views/auth/findPwd/emailFindForm.vue b/snowy-admin-web/src/views/auth/findPwd/emailFindForm.vue index bae2a2f0..b6145329 100644 --- a/snowy-admin-web/src/views/auth/findPwd/emailFindForm.vue +++ b/snowy-admin-web/src/views/auth/findPwd/emailFindForm.vue @@ -43,7 +43,9 @@ - {{ $t('login.backLogin') }} + + {{ $t('login.backLogin') }}? + {{ diff --git a/snowy-admin-web/src/views/auth/findPwd/phoneFindForm.vue b/snowy-admin-web/src/views/auth/findPwd/phoneFindForm.vue index 1d8322f4..fd6fd9b0 100644 --- a/snowy-admin-web/src/views/auth/findPwd/phoneFindForm.vue +++ b/snowy-admin-web/src/views/auth/findPwd/phoneFindForm.vue @@ -43,7 +43,9 @@ - {{ $t('login.backLogin') }} + + {{ $t('login.backLogin') }}? + {{ diff --git a/snowy-admin-web/src/views/auth/login/login.vue b/snowy-admin-web/src/views/auth/login/login.vue index d8687c04..620567b4 100644 --- a/snowy-admin-web/src/views/auth/login/login.vue +++ b/snowy-admin-web/src/views/auth/login/login.vue @@ -90,7 +90,9 @@ - {{ $t('login.forgetPassword') }}? + + {{ $t('login.forgetPassword') }}? + bufferHolder = + ThreadLocal.withInitial(() -> new StringBuilder(64)); + + @Override + public String convert(ILoggingEvent event) { + StringBuilder buffer = bufferHolder.get(); + buffer.setLength(0); + String traceId = CommonTraceIdUtil.getTraceId(); + + buffer.append(LEFT_BRACKET); + if (traceId != null && !traceId.isEmpty()) { + buffer.append(traceId); + } else { + buffer.append(event.getThreadName()); + } + buffer.append(RIGHT_BRACKET); + return buffer.toString(); + } +} \ No newline at end of file diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/interceptor/CommonTraceInterceptor.java b/snowy-common/src/main/java/vip/xiaonuo/common/interceptor/CommonTraceInterceptor.java new file mode 100644 index 00000000..a2c8a86a --- /dev/null +++ b/snowy-common/src/main/java/vip/xiaonuo/common/interceptor/CommonTraceInterceptor.java @@ -0,0 +1,42 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.common.interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.servlet.HandlerInterceptor; +import vip.xiaonuo.common.util.CommonTraceIdUtil; + +/** + * 公共链路追踪拦截器 + * + * @author dongxiayu + * @date 2025/1/10 11:42 + */ +public class CommonTraceInterceptor implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + try { + CommonTraceIdUtil.getTraceId(request); + } catch (Exception e) { + return false; + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + CommonTraceIdUtil.clear(); + HandlerInterceptor.super.afterCompletion(request, response, handler, ex); + } +} diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/pojo/CommonResult.java b/snowy-common/src/main/java/vip/xiaonuo/common/pojo/CommonResult.java index 1061a6c3..acfcbc2e 100644 --- a/snowy-common/src/main/java/vip/xiaonuo/common/pojo/CommonResult.java +++ b/snowy-common/src/main/java/vip/xiaonuo/common/pojo/CommonResult.java @@ -14,6 +14,7 @@ package vip.xiaonuo.common.pojo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; +import vip.xiaonuo.common.util.CommonTraceIdUtil; import java.io.Serial; import java.io.Serializable; @@ -47,6 +48,9 @@ public class CommonResult implements Serializable{ @Schema(description = "返回数据") private T data; + @Schema(description = "跟踪ID") + private String traceId; + public CommonResult() { } @@ -54,6 +58,7 @@ public class CommonResult implements Serializable{ this.setCode(code); this.setMsg(msg); this.setData(data); + this.setTraceId(CommonTraceIdUtil.getTraceId()); } /** @@ -64,6 +69,14 @@ public class CommonResult implements Serializable{ return this.code; } + /** + * 获取traceId + * @return traceId + */ + public String getTraceId() { + return this.traceId; + } + /** * 给code赋值,连缀风格 * @param code code @@ -94,6 +107,16 @@ public class CommonResult implements Serializable{ return this; } + /** + * 给traceId赋值,连缀风格 + * @param traceId traceId + * @return 对象自身 + */ + public CommonResult setTraceId(String traceId) { + this.traceId = traceId; + return this; + } + // ============================ 构建 ================================== diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/util/CommonTraceIdUtil.java b/snowy-common/src/main/java/vip/xiaonuo/common/util/CommonTraceIdUtil.java new file mode 100644 index 00000000..e20f490a --- /dev/null +++ b/snowy-common/src/main/java/vip/xiaonuo/common/util/CommonTraceIdUtil.java @@ -0,0 +1,60 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.common.util; + +import cn.hutool.core.util.StrUtil; +import jakarta.servlet.http.HttpServletRequest; + +import java.util.UUID; + +/** + * TraceId工具类 + * + * @author dongxiayu + * @date 2025/1/9 17:07 + */ +public class CommonTraceIdUtil { + + public static final String TRACE_ID_STRING = "traceId"; + + private static final InheritableThreadLocal TRACE_ID = new InheritableThreadLocal<>(); + + public static String generateTraceId(HttpServletRequest request) { + String header = request.getHeader(TRACE_ID_STRING); + if (header != null) { + return header; + } + return UUID.randomUUID().toString().replace(StrUtil.DASHED, StrUtil.EMPTY); + } + + public static String getTraceId() { + return TRACE_ID.get(); + } + + public static String getTraceId(HttpServletRequest request) { + String traceId = getTraceId(); + if (traceId == null) { + traceId = generateTraceId(request); + setTraceId(traceId); + } + return traceId; + } + + public static void setTraceId(String traceId) { + TRACE_ID.set(traceId); + } + + public static void clear() { + TRACE_ID.remove(); + } +} diff --git a/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/util/AuthEmailFormatUtl.java b/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/util/AuthEmailFormatUtil.java similarity index 98% rename from snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/util/AuthEmailFormatUtl.java rename to snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/util/AuthEmailFormatUtil.java index ced77820..8ae99e73 100644 --- a/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/util/AuthEmailFormatUtl.java +++ b/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/util/AuthEmailFormatUtil.java @@ -24,7 +24,7 @@ import vip.xiaonuo.dev.api.DevConfigApi; * @author xuyuxiang * @date 2025/3/21 19:07 **/ -public class AuthEmailFormatUtl { +public class AuthEmailFormatUtil { /** 系统名称 */ private static final String SNOWY_SYS_NAME_KEY = "SNOWY_SYS_NAME"; diff --git a/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/service/impl/AuthServiceImpl.java b/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/service/impl/AuthServiceImpl.java index 7a33d078..e2bd2b07 100644 --- a/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/service/impl/AuthServiceImpl.java +++ b/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/service/impl/AuthServiceImpl.java @@ -31,7 +31,7 @@ import vip.xiaonuo.auth.api.SaBaseLoginUserApi; import vip.xiaonuo.auth.core.enums.SaClientTypeEnum; import vip.xiaonuo.auth.core.pojo.SaBaseClientLoginUser; import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser; -import vip.xiaonuo.auth.core.util.AuthEmailFormatUtl; +import vip.xiaonuo.auth.core.util.AuthEmailFormatUtil; import vip.xiaonuo.auth.core.util.StpClientLoginUserUtil; import vip.xiaonuo.auth.core.util.StpClientUtil; import vip.xiaonuo.auth.core.util.StpLoginUserUtil; @@ -279,9 +279,9 @@ public class AuthServiceImpl implements AuthService { // 定义变量参数 JSONObject paramMap = JSONUtil.createObj().set("userEmail", email).set("validCode", emailValidCode).set("validTime", validCodeExpiredDuration/60); // 获取格式化后的主题 - String subject = AuthEmailFormatUtl.format(contentJSONObject.getStr("subject"), paramMap);; + String subject = AuthEmailFormatUtil.format(contentJSONObject.getStr("subject"), paramMap);; // 获取格式化后的内容 - String content = AuthEmailFormatUtl.format(contentJSONObject.getStr("content"), paramMap);; + String content = AuthEmailFormatUtil.format(contentJSONObject.getStr("content"), paramMap);; // 发送邮件 devEmailApi.sendDynamicHtmlEmail(email, subject, content); // 将请求号作为key,验证码的值作为value放到redis,用于校验 diff --git a/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java b/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java index c7b8fada..a2ccecd0 100644 --- a/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java +++ b/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java @@ -66,6 +66,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.stereotype.Component; import org.springframework.util.ResourceUtils; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import vip.xiaonuo.auth.core.util.StpClientUtil; @@ -74,6 +75,7 @@ import vip.xiaonuo.common.annotation.CommonWrapper; import vip.xiaonuo.common.cache.CommonCacheOperator; import vip.xiaonuo.common.enums.CommonDeleteFlagEnum; import vip.xiaonuo.common.exception.CommonException; +import vip.xiaonuo.common.interceptor.CommonTraceInterceptor; import vip.xiaonuo.common.listener.CommonDataChangeEventCenter; import vip.xiaonuo.common.listener.CommonDataChangeListener; import vip.xiaonuo.common.pojo.CommonResult; @@ -702,4 +704,14 @@ public class GlobalConfigure implements WebMvcConfigurer { public void registerListenerList(List dataChangeListenerList) { CommonDataChangeEventCenter.registerListenerList(dataChangeListenerList); } + + /** + * 添加应用拦截器 + * @param registry + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关,只是说明哪些接口不需要被拦截器拦截,此处都拦截) + registry.addInterceptor(new CommonTraceInterceptor()).addPathPatterns("/**"); + } } diff --git a/snowy-web-app/src/main/resources/application.properties b/snowy-web-app/src/main/resources/application.properties index 35fa6054..dd8324f9 100644 --- a/snowy-web-app/src/main/resources/application.properties +++ b/snowy-web-app/src/main/resources/application.properties @@ -2,76 +2,65 @@ # server configuration ######################################### server.port=82 - +spring.application.name=snowy ######################################### # spring allow-circular-references ######################################### spring.main.allow-circular-references=true - ######################################### # spring profiles configuration ######################################### spring.profiles.active=local #spring.profiles.active=test #spring.profiles.active=prod - ######################################### # multipart configuration ######################################### spring.servlet.multipart.max-request-size=100MB spring.servlet.multipart.max-file-size=100MB - ######################################### # datasource configuration ######################################### - # mysql spring.datasource.dynamic.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.dynamic.datasource.master.url=jdbc:mysql://localhost:3306/snowy?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&useInformationSchema=true&rewriteBatchedStatements=true spring.datasource.dynamic.datasource.master.username=root spring.datasource.dynamic.datasource.master.password=12345678 spring.datasource.dynamic.strict=true - # postgres #spring.datasource.dynamic.datasource.master.driver-class-name=org.postgresql.Driver #spring.datasource.dynamic.datasource.master.url=jdbc:postgresql://localhost:5432/snowy #spring.datasource.dynamic.datasource.master.username=postgres #spring.datasource.dynamic.datasource.master.password=123456 #spring.datasource.dynamic.strict=true - # oracle #spring.datasource.dynamic.datasource.master.driver-class-name=oracle.jdbc.OracleDriver #spring.datasource.dynamic.datasource.master.url=jdbc:oracle:thin:@//127.0.0.1:1521/ORCL?remarksReporting=true #spring.datasource.dynamic.datasource.master.username=SNOWY #spring.datasource.dynamic.datasource.master.password=12345678 #spring.datasource.dynamic.strict=true - # mssql #spring.datasource.dynamic.datasource.master.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver #spring.datasource.dynamic.datasource.master.url=jdbc:sqlserver://localhost:1433;DatabaseName=SNOWY #spring.datasource.dynamic.datasource.master.username=sa #spring.datasource.dynamic.datasource.master.password=123456 #spring.datasource.dynamic.strict=true - # dm database #spring.datasource.dynamic.datasource.master.driver-class-name=dm.jdbc.driver.DmDriver #spring.datasource.dynamic.datasource.master.url=jdbc:dm://localhost:5236/SNOWY #spring.datasource.dynamic.datasource.master.username=SYSDBA #spring.datasource.dynamic.datasource.master.password=SYSDBA #spring.datasource.dynamic.strict=true - # kingbase database #spring.datasource.dynamic.datasource.master.driver-class-name=com.kingbase8.Driver #spring.datasource.dynamic.datasource.master.url=jdbc:kingbase8://localhost:54321/snowy #spring.datasource.dynamic.datasource.master.username=SYSTEM #spring.datasource.dynamic.datasource.master.password=123456 #spring.datasource.dynamic.strict=true - # druid monitor configuration spring.datasource.druid.stat-view-servlet.enabled=true spring.datasource.druid.stat-view-servlet.login-username=admin spring.datasource.druid.stat-view-servlet.login-password=123456 - # druid global configuration spring.datasource.dynamic.public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMWiTVtdXFVrgFHDDKELZM0SywkWY3KjugN90eY5Sogon1j8Y0ClPF7nx3FuE7pAeBKiv7ChIS0vvx/59WUpKmUCAwEAAQ== spring.datasource.dynamic.druid.initial-size=5 @@ -89,7 +78,6 @@ spring.datasource.dynamic.druid.time-between-eviction-runs-millis=6000 spring.datasource.dynamic.druid.min-evictable-idle-time-millis=300000 spring.datasource.dynamic.druid.filters=stat spring.datasource.dynamic.druid.break-after-acquire-failure=false - ######################################### # jackson configuration ######################################### @@ -105,12 +93,10 @@ spring.data.redis.host=127.0.0.1 spring.data.redis.port=6379 spring.data.redis.password= spring.data.redis.timeout=10s - spring.data.redis.lettuce.pool.max-active=200 spring.data.redis.lettuce.pool.max-wait=-1ms spring.data.redis.lettuce.pool.max-idle=10 spring.data.redis.lettuce.pool.min-idle=0 - ######################################### # mybatis-plus configuration ######################################### @@ -124,7 +110,6 @@ mybatis-plus.global-config.db-config.logic-delete-value=DELETED mybatis-plus.global-config.db-config.logic-not-delete-value=NOT_DELETE mybatis-plus.mapper-locations=classpath*:vip/xiaonuo/**/mapping/*.xml,com/bstek/**/mapping/*.xml mybatis-plus.type-handlers-package=vip.xiaonuo.common.handler - ######################################### # easy-trans configuration ######################################### @@ -132,7 +117,6 @@ easy-trans.is-enable-redis=true easy-trans.is-enable-global=true easy-trans.is-enable-tile=true easy-trans.is-enable-cloud=false - ######################################### # sa-token configuration ######################################### @@ -145,7 +129,6 @@ sa-token.max-login-count=-1 sa-token.token-style=random-32 sa-token.is-log=false sa-token.is-print=false - # sa-token alone-redis configuration sa-token.alone-redis.database=2 sa-token.alone-redis.host=${spring.data.redis.host} @@ -156,7 +139,6 @@ sa-token.alone-redis.lettuce.pool.max-active=${spring.data.redis.lettuce.pool.ma sa-token.alone-redis.lettuce.pool.max-wait=${spring.data.redis.lettuce.pool.max-wait} sa-token.alone-redis.lettuce.pool.max-idle=${spring.data.redis.lettuce.pool.max-idle} sa-token.alone-redis.lettuce.pool.min-idle=${spring.data.redis.lettuce.pool.min-idle} - ######################################### # knife4j configuration ######################################### @@ -171,7 +153,6 @@ knife4j.setting.enableFooter=false knife4j.setting.enableFooterCustom=true knife4j.setting.footerCustomContent=Apache License 2.0 | Copyright 2020-2024[SNOWY](https://www.xiaonuo.vip) springdoc.default-flat-param-object=true - # knife4j doc groups springdoc.group-configs[0].group=SNOWY-PLUGIN-AUTH springdoc.group-configs[0].display-name=${springdoc.group-configs[0].group} @@ -194,14 +175,11 @@ springdoc.group-configs[5].packages-to-scan=vip.xiaonuo.mobile springdoc.group-configs[6].group=SNOWY-PLUGIN-SYS springdoc.group-configs[6].display-name=${springdoc.group-configs[6].group} springdoc.group-configs[6].packages-to-scan=vip.xiaonuo.sys - ######################################### # snowy configuration ######################################### - # common configuration snowy.config.common.backend-url=http://localhost:82 - # plugin dev-sms configuration sms-oa.config-type=yaml sms-oa.core-pool-size=20 diff --git a/snowy-web-app/src/main/resources/logback-spring.xml b/snowy-web-app/src/main/resources/logback-spring.xml index 5d28c043..d7109578 100644 --- a/snowy-web-app/src/main/resources/logback-spring.xml +++ b/snowy-web-app/src/main/resources/logback-spring.xml @@ -4,6 +4,13 @@ + + + + + + @@ -13,7 +20,7 @@ - ${CONSOLE_LOG_PATTERN} + ${CUSTOM_LOG_PATTERN} utf-8 @@ -36,7 +43,7 @@ - ${CONSOLE_LOG_PATTERN} + ${CUSTOM_LOG_PATTERN} utf-8