初始化

This commit is contained in:
xuelijun
2025-09-20 18:41:07 +08:00
commit a2d1fcde12
1437 changed files with 95746 additions and 0 deletions

48
.cursor/rules/1.mdc Normal file
View File

@@ -0,0 +1,48 @@
---
description:
globs:
alwaysApply: false
---
---
description:
globs:
alwaysApply: false
---
# Your rule content
#角色
你是一名精通开发的高级工程师拥有10年以上的应用开发经验熟悉*等开发工具和技术栈。
你的任务是帮助用户设计和开发易用且易于推护的 *** 应用。始终遵循最佳实践,并坚持干净代码和健壮架构的原则。
#目标
你的目标是以用户容易理解的方式帮助他们完成“应用的设计和开发工作,确保应用功能完善、性能优异、用户体验良好。
#要求
在理解用户需求、设计UI、编写代码、解决问题和项目选代优化时你应该始终遵循以下原则:
##需求理解
-充分理解用户需求,站在用户角度思考,分析需求是否存在缺漏,并与用户讨论完善需求;
-选择最简单的解决方案来满足用户需求,避免过度设计。
##UI和样式设计
-使用现代UI框架进行样式设计(例如***这里可以根据不同开发项目仔纽展开比如使用哪些视觉规范或者UI框架没有的话也可以不用过多展开);
-在不同平台上实现一致的设计和响应式模式
##代码编写
技术选型:根据项目需求选择合适的技术栈(例如***,这里需要仔细展开,比如介招某个技术栈用在什么地方,以及要遵循什么最佳实践)
代码结构:强调代码的清晰性、模块化、可维护性,遵循最佳实践(如DRY原则、最小权限原则、响应式设计等)
-代码安全性:在编写代码时,始终考虑安全性,避免引入漏洞,确保用户输入的安全处理
-性能优化:优化代码的性能,减少资源占用,提升加载速度,确保项目的高效运行
-测试与文档:编写单元测试,确保代码的健壮性,并提供清晰的中文注释和文档。方便后续阅读和维护
##问题解决
-全面阅读相关代码,理解***应用的工作原理
-根据用户的反馈分析问题的原因,提出解决问题的思路
-确保每次代码变更不会破坏现有功能,且尽可能保持最小的改动
##迭代优化
与用户保持密切沟通,根据反读调整功能和设计,确保应用符合用户需求
在不确定需求时,主动询问用户以澄清需求或技术细节
##方法论
-系统2思维:以分析严谨的方式解决问题。将需求分解为更小、可管理的部分,并在实施前仔细考虑每一步
思维树:评估多种可能的解决方案及其后果。使用结构化的方法探索不同的路径。并选择最优的解决方案
-选代改进:在最终确定代码之前,考虑改进、边缘情况和优化。通过潜在增强的迭代,确保最终解决方案是健壮的

76
.gitignore vendored Normal file
View File

@@ -0,0 +1,76 @@
# 查看更多 .gitignore 配置 -> https://help.github.com/articles/ignoring-files/
target/
!.mvn/wrapper/maven-wrapper.jar
.flattened-pom.xml
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
*.class
target/*
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/
.idea
### admin-web ###
# dependencies
**/node_modules
# roadhog-api-doc ignore
/src/utils/request-temp.js
_roadhog-api-doc
# production
/dist
/.vscode
# misc
.DS_Store
npm-debug.log*
yarn-error.log
/coverage
.idea
yarn.lock
package-lock.json
*bak
.vscode
# visual studio code
.history
*.log
functions/mock
.temp/**
# umi
.umi
.umi-production
# screenshot
screenshot
.firebase
sessionStore

View File

@@ -0,0 +1,2 @@
**添加规则文件可帮助模型精准理解你的编码偏好,如框架、代码风格等**
**规则文件只对当前工程生效单文件限制10000字符。如果无需将该文件提交到远程 Git 仓库,请将其添加到 .gitignore**

116
LOG_FILE_IS_UNDEFINED Normal file
View File

@@ -0,0 +1,116 @@
2025-09-15 10:17:42.991 |  INFO 4200 | main [TID: N/A] c.t.c.gateway.GatewayServerApplication  | Starting GatewayServerApplication using Java 17.0.14 with PID 4200 (D:\work\houtai\new_work\new-tashow-platform\tashow-platform\tashow-gateway\target\classes started by Administrator in D:\work\houtai\new_work\new-tashow-platform\tashow-platform)
2025-09-15 10:17:42.992 |  INFO 4200 | main [TID: N/A] c.t.c.gateway.GatewayServerApplication  | The following 1 profile is active: "local"
2025-09-15 10:17:43.019 | ERROR 4200 | main [TID: N/A] c.a.c.n.c.NacosConfigDataLoader  | Error getting properties from nacos: NacosConfigDataResource{properties=NacosConfigProperties{serverAddr='43.139.42.137:8848', encode='null', group='DEFAULT_GROUP', prefix='null', fileExtension='properties', timeout=3000, maxRetry='null', configLongPollTimeout='null', configRetryTime='null', enableRemoteSyncConfig=false, endpoint='null', namespace='76667956-2ac2-4e05-906b-4bca4ebcc5f0', accessKey='null', secretKey='null', ramRoleName='null', contextPath='null', clusterName='null', name='null'', shares=null, extensions=null, refreshEnabled=true}, optional=true, profiles=[Profiles@77128dab active = '[local]', default = '[default]', accepted = '[local]'], config=NacosItemConfig{group='DEFAULT_GROUP', dataId='gateway-server-local.yaml', suffix='yaml', refreshEnabled=true, preference=null}}
com.alibaba.nacos.api.exception.NacosException: http error, code=403,msg=user not found!,dataId=gateway-server-local.yaml,group=DEFAULT_GROUP,tenant=76667956-2ac2-4e05-906b-4bca4ebcc5f0
at com.alibaba.nacos.client.config.impl.ClientWorker$ConfigRpcTransportClient.queryConfigInner(ClientWorker.java:1194) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.nacos.client.config.impl.ClientWorker$ConfigRpcTransportClient.queryConfig(ClientWorker.java:1153) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.nacos.client.config.impl.ClientWorker.getServerConfig(ClientWorker.java:474) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.nacos.client.config.NacosConfigService.getConfigInner(NacosConfigService.java:188) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.nacos.client.config.NacosConfigService.getConfig(NacosConfigService.java:99) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader.pullConfig(NacosConfigDataLoader.java:142) ~[spring-alibaba-nacos-config-2023.0.3.2.jar:2023.0.3.2]
at com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader.doLoad(NacosConfigDataLoader.java:80) ~[spring-alibaba-nacos-config-2023.0.3.2.jar:2023.0.3.2]
at com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader.load(NacosConfigDataLoader.java:67) ~[spring-alibaba-nacos-config-2023.0.3.2.jar:2023.0.3.2]
at com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader.load(NacosConfigDataLoader.java:56) ~[spring-alibaba-nacos-config-2023.0.3.2.jar:2023.0.3.2]
at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:96) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:132) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:87) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:121) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:316) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:237) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:96) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:132) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:115) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185) ~[spring-context-6.2.1.jar:6.2.1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178) ~[spring-context-6.2.1.jar:6.2.1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156) ~[spring-context-6.2.1.jar:6.2.1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138) ~[spring-context-6.2.1.jar:6.2.1]
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64) ~[spring-boot-3.4.1.jar:3.4.1]
at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:353) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350) ~[spring-boot-3.4.1.jar:3.4.1]
at com.tashow.cloud.gateway.GatewayServerApplication.main(GatewayServerApplication.java:10) ~[classes/:na]
2025-09-15 10:17:43.021 | ERROR 4200 | main [TID: N/A] c.a.c.n.c.NacosConfigDataLoader  | Error getting properties from nacos: NacosConfigDataResource{properties=NacosConfigProperties{serverAddr='43.139.42.137:8848', encode='null', group='DEFAULT_GROUP', prefix='null', fileExtension='properties', timeout=3000, maxRetry='null', configLongPollTimeout='null', configRetryTime='null', enableRemoteSyncConfig=false, endpoint='null', namespace='76667956-2ac2-4e05-906b-4bca4ebcc5f0', accessKey='null', secretKey='null', ramRoleName='null', contextPath='null', clusterName='null', name='null'', shares=null, extensions=null, refreshEnabled=true}, optional=true, profiles=[Profiles@77128dab active = '[local]', default = '[default]', accepted = '[local]'], config=NacosItemConfig{group='DEFAULT_GROUP', dataId='application.yaml', suffix='yaml', refreshEnabled=true, preference=null}}
com.alibaba.nacos.api.exception.NacosException: http error, code=403,msg=user not found!,dataId=application.yaml,group=DEFAULT_GROUP,tenant=76667956-2ac2-4e05-906b-4bca4ebcc5f0
at com.alibaba.nacos.client.config.impl.ClientWorker$ConfigRpcTransportClient.queryConfigInner(ClientWorker.java:1194) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.nacos.client.config.impl.ClientWorker$ConfigRpcTransportClient.queryConfig(ClientWorker.java:1153) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.nacos.client.config.impl.ClientWorker.getServerConfig(ClientWorker.java:474) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.nacos.client.config.NacosConfigService.getConfigInner(NacosConfigService.java:188) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.nacos.client.config.NacosConfigService.getConfig(NacosConfigService.java:99) ~[nacos-client-2.4.2.jar:na]
at com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader.pullConfig(NacosConfigDataLoader.java:142) ~[spring-alibaba-nacos-config-2023.0.3.2.jar:2023.0.3.2]
at com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader.doLoad(NacosConfigDataLoader.java:80) ~[spring-alibaba-nacos-config-2023.0.3.2.jar:2023.0.3.2]
at com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader.load(NacosConfigDataLoader.java:67) ~[spring-alibaba-nacos-config-2023.0.3.2.jar:2023.0.3.2]
at com.alibaba.cloud.nacos.configdata.NacosConfigDataLoader.load(NacosConfigDataLoader.java:56) ~[spring-alibaba-nacos-config-2023.0.3.2.jar:2023.0.3.2]
at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:96) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:132) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:87) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:121) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:316) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:237) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:96) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:132) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:115) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185) ~[spring-context-6.2.1.jar:6.2.1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178) ~[spring-context-6.2.1.jar:6.2.1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156) ~[spring-context-6.2.1.jar:6.2.1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138) ~[spring-context-6.2.1.jar:6.2.1]
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64) ~[spring-boot-3.4.1.jar:3.4.1]
at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:353) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361) ~[spring-boot-3.4.1.jar:3.4.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350) ~[spring-boot-3.4.1.jar:3.4.1]
at com.tashow.cloud.gateway.GatewayServerApplication.main(GatewayServerApplication.java:10) ~[classes/:na]
2025-09-15 10:17:43.819 |  INFO 4200 | main [TID: N/A] o.s.cloud.context.scope.GenericScope  | BeanFactory id=855d66cd-16da-30e9-a12a-5b2f1bd783f0
2025-09-15 10:17:44.369 |  INFO 4200 | main [TID: N/A] c.t.c.g.j.JacksonAutoConfiguration  | [init][初始化 JsonUtils 成功]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [After]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Before]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Between]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Cookie]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Header]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Host]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Method]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Path]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Query]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [ReadBody]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [RemoteAddr]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [XForwardedRemoteAddr]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [Weight]
2025-09-15 10:17:44.743 |  INFO 4200 | main [TID: N/A] o.s.c.g.r.RouteDefinitionRouteLocator  | Loaded RoutePredicateFactory [CloudFoundryRouteService]
2025-09-15 10:17:45.241 |  INFO 4200 | main [TID: N/A] o.s.b.a.e.web.EndpointLinksResolver  | Exposing 1 endpoint beneath base path '/actuator'
2025-09-15 10:17:46.618 |  WARN 4200 | main [TID: N/A] iguration$LoadBalancerCaffeineWarnLogger | Spring Cloud LoadBalancer is currently working with the default cache. While this cache implementation is useful for development and tests, it's recommended to use Caffeine cache in production.You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-09-15 10:17:46.993 |  INFO 4200 | main [TID: N/A] o.s.b.web.embedded.netty.NettyWebServer  | Netty started on port 48080 (http)
2025-09-15 10:17:47.072 |  INFO 4200 | main [TID: N/A] c.a.n.p.a.s.c.ClientAuthPluginManager  | [ClientAuthPluginManager] Load ClientAuthService com.alibaba.nacos.client.auth.impl.NacosClientAuthServiceImpl success.
2025-09-15 10:17:47.072 |  INFO 4200 | main [TID: N/A] c.a.n.p.a.s.c.ClientAuthPluginManager  | [ClientAuthPluginManager] Load ClientAuthService com.alibaba.nacos.client.auth.ram.RamClientAuthServiceImpl success.
2025-09-15 10:17:47.403 |  INFO 4200 | main [TID: N/A] c.a.c.n.registry.NacosServiceRegistry  | nacos registry, DEFAULT_GROUP gateway-server 192.168.1.114:48080 register finished
2025-09-15 10:17:47.433 |  INFO 4200 | main [TID: N/A] c.t.c.gateway.GatewayServerApplication  | Started GatewayServerApplication in 6.966 seconds (process running for 7.886)
2025-09-15 10:17:48.441 |  INFO 4200 | pool-8-thread-1 [TID: N/A] c.t.c.g.util.BannerApplicationRunner  |
----------------------------------------------------------
项目启动成功!
接口文档: https://cloud.iocoder.cn/api-doc/
----------------------------------------------------------
2025-09-15 10:22:50.103 |  WARN 4200 | Thread-1 [TID: N/A] c.a.n.common.executor.ThreadPoolManager  | [ThreadPoolManager] Start destroying ThreadPool
2025-09-15 10:22:50.104 |  WARN 4200 | Thread-6 [TID: N/A] c.a.n.common.http.HttpClientBeanHolder  | [HttpClientBeanHolder] Start destroying common HttpClient
2025-09-15 10:22:50.104 |  WARN 4200 | Thread-1 [TID: N/A] c.a.n.common.executor.ThreadPoolManager  | [ThreadPoolManager] Destruction of the end
2025-09-15 10:22:50.104 |  WARN 4200 | Thread-8 [TID: N/A] c.a.nacos.common.notify.NotifyCenter  | [NotifyCenter] Start destroying Publisher
2025-09-15 10:22:50.104 |  WARN 4200 | Thread-8 [TID: N/A] c.a.nacos.common.notify.NotifyCenter  | [NotifyCenter] Destruction of the end
2025-09-15 10:22:50.105 |  WARN 4200 | Thread-6 [TID: N/A] c.a.n.common.http.HttpClientBeanHolder  | [HttpClientBeanHolder] Destruction of the end
2025-09-15 10:22:50.108 |  INFO 4200 | SpringApplicationShutdownHook [TID: N/A] o.s.b.w.embedded.netty.GracefulShutdown  | Commencing graceful shutdown. Waiting for active requests to complete
2025-09-15 10:22:50.110 |  INFO 4200 | netty-shutdown [TID: N/A] o.s.b.w.embedded.netty.GracefulShutdown  | Graceful shutdown complete

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

4
lombok.config Normal file
View File

@@ -0,0 +1,4 @@
config.stopBubbling = true
lombok.tostring.callsuper=CALL
lombok.equalsandhashcode.callsuper=CALL
lombok.accessors.chain=true

155
pom.xml Normal file
View File

@@ -0,0 +1,155 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-platform</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<modules>
<module>tashow-dependencies</module>
<module>tashow-framework</module>
<module>tashow-module</module>
<module>tashow-gateway</module>
<module>tashow-feign</module>
<module>tashow-sdk</module>
</modules>
<name>${project.artifactId}</name>
<description>bydj项目基础脚手架</description>
<properties>
<revision>1.0.0</revision>
<!-- Maven 相关 -->
<java.version>17</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
<maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
<!-- 看看咋放到 bom 里 -->
<lombok.version>1.18.36</lombok.version>
<spring.boot.version>3.4.1</spring.boot.version>
<mapstruct.version>1.6.3</mapstruct.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-dependencies</artifactId>
<version>${revision}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<!-- maven-surefire-plugin 插件,用于运行单元测试。 -->
<!-- 注意,需要使用 3.0.X+,因为要支持 Junit 5 版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<!-- maven-compiler-plugin 插件,解决 Lombok + MapStruct 组合 -->
<!-- https://stackoverflow.com/questions/33483697/re-run-spring-boot-configuration-annotation-processor-to-update-generated-metada -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring.boot.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
<!-- 编译参数写在 arg 内,解决 Spring Boot 3.2 的 Parameter Name Discovery 问题 -->
<debug>false</debug>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- 统一 revision 版本 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<flattenMode>oss</flattenMode>
<updatePomFile>true</updatePomFile>
</configuration>
<executions>
<execution>
<goals>
<goal>flatten</goal>
</goals>
<id>flatten</id>
<phase>process-resources</phase>
</execution>
<execution>
<goals>
<goal>clean</goal>
</goals>
<id>flatten.clean</id>
<phase>clean</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- 使用 huawei / aliyun 的 Maven 源,提升下载速度 -->
<repositories>
<repository>
<id>huaweicloud</id>
<name>huawei</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</repository>
<repository>
<id>aliyunmaven</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</project>

3
sql/db2/README.md Normal file
View File

@@ -0,0 +1,3 @@
暂未适配 IBM DB2 数据库,如果你有需要,可以微信联系 wangwenbin-server 一起建设。
你需要把表结构与数据导入到 DM 数据库我a来测试与适配代码。

284
sql/mysql/quartz.sql Normal file

File diff suppressed because one or more lines are too long

11205
sql/mysql/ruoyi-vue-pro.sql Normal file

File diff suppressed because it is too large Load Diff

8
sql/tools/.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
# 忽略python虚拟环境
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

130
sql/tools/README.md Normal file
View File

@@ -0,0 +1,130 @@
## 0. 友情提示
`sql/tools` 目录下我们提供一些数据库相关的工具包括测试数据库的快速启动、MySQL 转换其它数据库等等。
注意!所有的操作,必须在 `sql/tools` 目录下执行。
## 1. 测试数据库的快速启动
基于 Docker Compose快速启动 MySQL、Oracle、PostgreSQL、SQL Server 等数据库。
注意!使用 Docker Compose 启动完测试数据后,因为会自动导入项目的 SQL 脚本,所以可能需要等待 1-2 分钟。
### 1.1 MySQL
```Bash
docker compose up -d mysql
```
#### 1.2 Oracle
```Bash
## x86 版本
docker compose up -d oracle
## MacBook Apple Silicon
docker compose up -d oracle_m1
```
> 注意:如果使用 MacBook Apple Silicon 版本,它的 ORACLE_SID 不是 XE而是 FREE
### 1.3 PostgreSQL
```Bash
docker compose up -d postgres
```
### 1.4 SQL Server
```Bash
docker compose up -d sqlserver
# 注意:启动完 sqlserver 后,需要手动再执行如下命令,因为 SQL Server 不支持初始化脚本
docker compose exec sqlserver bash /tmp/create_schema.sh
```
### 1.5 DM 达梦
① 下载达梦 Docker 镜像:<https://eco.dameng.com/download/> 地址点击“Docker 镜像”选项,进行下载。
② 加载镜像文件,在镜像 tar 文件所在目录运行:
```Bash
docker load -i dm8_20240715_x86_rh6_rq_single.tar
```
③ 在项目 `sql/tools` 目录下运行:
```Bash
docker compose up -d dm8
# 注意:启动完 dm 后,需要手动再执行如下命令,因为 dm 不支持初始化脚本
docker compose exec dm8 bash -c '/opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql'
exit
```
### 1.6 KingbaseES 人大金仓
① 下载人大金仓 Docker 镜像:
* [x86_64 版本](https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar) 【Windows 选择这个】
* [aarch64 版本](https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/aarch64/kdb_aarch64_V009R001C001B0025.tar) 【MacBook Apple Silicon 选择这个】
② 加载镜像文件,在镜像 tar 文件所在目录运行:
```Bash
docker load -i kdb_x86_64_V009R001C001B0025.tar
```
③ 在项目 `sql/tools` 目录下运行:
```Bash
docker compose up -d kingbase
# 注意:启动完 kingbase 后,需要手动再执行如下命令
docker compose exec kingbase bash -c 'ksql -U $DB_USER -d test -f /tmp/schema.sql'
```
### 1.7 华为 OpenGauss
```Bash
docker compose up -d opengauss
# 注意:启动完 opengauss 后,需要手动再执行如下命令
docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql'
```
## 1.X 容器的销毁重建
开发测试过程中,有时候需要创建全新干净的数据库。由于测试数据 Docker 容器采用数据卷 Volume 挂载数据库实例的数据目录,因此销毁数据需要停止容器后,删除数据卷,然后再重新创建容器。
以 postgres 为例,操作如下:
```Bash
docker compose down postgres
docker volume rm ruoyi-vue-pro_postgres
```
## 2. MySQL 转换其它数据库
项目提供了 `sql/tools/convertor.py` 脚本,支持将 MySQL 转换为 Oracle、PostgreSQL、SQL Server、达梦、人大金仓、OpenGauss 等数据库的脚本。
### 2.1 实现原理
通过读取 MySQL 的 `sql/mysql/ruoyi-vue-pro.sql` 数据库文件,转换成对应的数据库脚本。
### 2.2 使用方法
① 安装依赖库 `simple-ddl-parser`
```bash
pip install simple-ddl-parser
# pip3 install simple-ddl-parser
```
② 在 `sql/tools/` 目录下,执行如下命令打印生成 postgres 的脚本内容,其他可选参数有:`oracle``sqlserver``dm8``kingbase``opengauss`
```Bash
python3 convertor.py postgres
# python3 convertor.py postgres > tmp.sql
```
程序将 SQL 脚本打印到终端,可以重定向到临时文件 `tmp.sql`
确认无误后,可以利用 IDEA 进行格式化。当然,也可以直接导入到数据库中。

844
sql/tools/convertor.py Normal file
View File

@@ -0,0 +1,844 @@
# encoding=utf8
"""芋道系统数据库迁移工具
Author: dhb52 (https://gitee.com/dhb52)
pip install simple-ddl-parser
"""
import argparse
import pathlib
import re
import time
from abc import ABC, abstractmethod
from typing import Dict, Generator, Optional, Tuple, Union
from simple_ddl_parser import DDLParser
PREAMBLE = """/*
Yudao Database Transfer Tool
Source Server Type : MySQL
Target Server Type : {db_type}
Date: {date}
*/
"""
def load_and_clean(sql_file: str) -> str:
"""加载源 SQL 文件,并清理内容方便下一步 ddl 解析
Args:
sql_file (str): sql文件路径
Returns:
str: 清理后的sql文件内容
"""
REPLACE_PAIR_LIST = (
(" CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ", " "),
(" KEY `", " INDEX `"),
("UNIQUE INDEX", "UNIQUE KEY"),
("b'0'", "'0'"),
("b'1'", "'1'"),
)
content = open(sql_file).read()
for replace_pair in REPLACE_PAIR_LIST:
content = content.replace(*replace_pair)
content = re.sub(r"ENGINE.*COMMENT", "COMMENT", content)
content = re.sub(r"ENGINE.*;", ";", content)
return content
class Convertor(ABC):
def __init__(self, src: str, db_type) -> None:
self.src = src
self.db_type = db_type
self.content = load_and_clean(self.src)
self.table_script_list = re.findall(r"CREATE TABLE [^;]*;", self.content)
@abstractmethod
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]) -> str:
"""字段类型转换
Args:
type (str): 字段类型
size (Optional[Union[int, Tuple[int]]]): 字段长度描述, 如varchar(255), decimal(10,2)
Returns:
str: 类型定义
"""
pass
@abstractmethod
def gen_create(self, table_ddl: Dict) -> str:
"""生成 create 脚本
Args:
table_ddl (Dict): 表DDL
Returns:
str: 生成脚本
"""
pass
@abstractmethod
def gen_pk(self, table_name: str) -> str:
"""生成主键定义
Args:
table_name (str): 表名
Returns:
str: 生成脚本
"""
pass
@abstractmethod
def gen_index(self, ddl: Dict) -> str:
"""生成索引定义
Args:
table_ddl (Dict): 表DDL
Returns:
str: 生成脚本
"""
pass
@abstractmethod
def gen_comment(self, table_sql: str, table_name: str) -> str:
"""生成字段/表注释
Args:
table_sql (str): 原始表SQL
table_name (str): 表名
Returns:
str: 生成脚本
"""
pass
@abstractmethod
def gen_insert(self, table_name: str) -> str:
"""生成 insert 语句块
Args:
table_name (str): 表名
Returns:
str: 生成脚本
"""
pass
def gen_dual(self) -> str:
"""生成虚拟 dual 表
Returns:
str: 生成脚本, 默认返回空脚本, 表示当前数据库无需手工创建
"""
return ""
@staticmethod
def inserts(table_name: str, script_content: str) -> Generator:
PREFIX = f"INSERT INTO `{table_name}`"
# 收集 `table_name` 对应的 insert 语句
for line in script_content.split("\n"):
if line.startswith(PREFIX):
head, tail = line.replace(PREFIX, "").split(" VALUES ", maxsplit=1)
head = head.strip().replace("`", "").lower()
tail = tail.strip().replace(r"\"", '"')
# tail = tail.replace("b'0'", "'0'").replace("b'1'", "'1'")
yield f"INSERT INTO {table_name.lower()} {head} VALUES {tail}"
@staticmethod
def index(ddl: Dict) -> Generator:
"""生成索引定义
Args:
ddl (Dict): 表DDL
Yields:
Generator[str]: create index 语句
"""
def generate_columns(columns):
keys = [
f"{col['name'].lower()}{' ' + col['order'].lower() if col['order'] != 'ASC' else ''}"
for col in columns[0]
]
return ", ".join(keys)
for no, index in enumerate(ddl["index"], 1):
columns = generate_columns(index["columns"])
table_name = ddl["table_name"].lower()
yield f"CREATE INDEX idx_{table_name}_{no:02d} ON {table_name} ({columns})"
@staticmethod
def filed_comments(table_sql: str) -> Generator:
for line in table_sql.split("\n"):
match = re.match(r"^`([^`]+)`.* COMMENT '([^']+)'", line.strip())
if match:
field = match.group(1)
comment_string = match.group(2).replace("\\n", "\n")
yield field, comment_string
def table_comment(self, table_sql: str) -> str:
match = re.search(r"COMMENT \= '([^']+)';", table_sql)
return match.group(1) if match else None
def print(self):
"""打印转换后的sql脚本到终端"""
print(
PREAMBLE.format(
db_type=self.db_type,
date=time.strftime("%Y-%m-%d %H:%M:%S"),
)
)
dual = self.gen_dual()
if dual:
print(
f"""-- ----------------------------
-- Table structure for dual
-- ----------------------------
{dual}
"""
)
error_scripts = []
for table_sql in self.table_script_list:
ddl = DDLParser(table_sql.replace("`", "")).run()
# 如果parse失败, 需要跟进
if len(ddl) == 0:
error_scripts.append(table_sql)
continue
table_ddl = ddl[0]
table_name = table_ddl["table_name"]
# 忽略 quartz 的内容
if table_name.lower().startswith("qrtz"):
continue
# 为每个表生成个5个基本部分
create = self.gen_create(table_ddl)
pk = self.gen_pk(table_name)
index = self.gen_index(table_ddl)
comment = self.gen_comment(table_sql, table_name)
inserts = self.gen_insert(table_name)
# 组合当前表的DDL脚本
script = f"""{create}
{pk}
{index}
{comment}
{inserts}
"""
# 清理
script = re.sub("\n{3,}", "\n\n", script).strip() + "\n"
print(script)
# 将parse失败的脚本打印出来
if error_scripts:
for script in error_scripts:
print(script)
class PostgreSQLConvertor(Convertor):
def __init__(self, src):
super().__init__(src, "PostgreSQL")
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]):
"""类型转换"""
type = type.lower()
if type == "varchar":
return f"varchar({size})"
if type == "int":
return "int4"
if type == "bigint" or type == "bigint unsigned":
return "int8"
if type == "datetime":
return "timestamp"
if type == "bit":
return "bool"
if type in ("tinyint", "smallint"):
return "int2"
if type == "text":
return "text"
if type in ("blob", "mediumblob"):
return "bytea"
if type == "decimal":
return (
f"numeric({','.join(str(s) for s in size)})" if len(size) else "numeric"
)
def gen_create(self, ddl: Dict) -> str:
"""生成 create"""
def _generate_column(col):
name = col["name"].lower()
if name == "deleted":
return "deleted int2 NOT NULL DEFAULT 0"
type = col["type"].lower()
full_type = self.translate_type(type, col["size"])
nullable = "NULL" if col["nullable"] else "NOT NULL"
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
return f"{name} {full_type} {nullable} {default}"
table_name = ddl["table_name"].lower()
columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]]
filed_def_list = ",\n ".join(columns)
script = f"""-- ----------------------------
-- Table structure for {table_name}
-- ----------------------------
DROP TABLE IF EXISTS {table_name};
CREATE TABLE {table_name} (
{filed_def_list}
);"""
return script
def gen_index(self, ddl: Dict) -> str:
return "\n".join(f"{script};" for script in self.index(ddl))
def gen_comment(self, table_sql: str, table_name: str) -> str:
"""生成字段及表的注释"""
script = ""
for field, comment_string in self.filed_comments(table_sql):
script += (
f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n"
)
table_comment = self.table_comment(table_sql)
if table_comment:
script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n"
return script
def gen_pk(self, table_name) -> str:
"""生成主键定义"""
return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n"
def gen_insert(self, table_name: str) -> str:
"""生成 insert 语句,以及根据最后的 insert id+1 生成 Sequence"""
inserts = list(Convertor.inserts(table_name, self.content))
## 生成 insert 脚本
script = ""
last_id = 0
if inserts:
inserts_lines = "\n".join(inserts)
script += f"""\n\n-- ----------------------------
-- Records of {table_name.lower()}
-- ----------------------------
-- @formatter:off
BEGIN;
{inserts_lines}
COMMIT;
-- @formatter:on"""
match = re.search(r"VALUES \((\d+),", inserts[-1])
if match:
last_id = int(match.group(1))
# 生成 Sequence
script += (
"\n\n"
+ f"""DROP SEQUENCE IF EXISTS {table_name}_seq;
CREATE SEQUENCE {table_name}_seq
START {last_id + 1};"""
)
return script
def gen_dual(self) -> str:
return """DROP TABLE IF EXISTS dual;
CREATE TABLE dual
(
id int2
);
COMMENT ON TABLE dual IS '数据库连接的表';
-- ----------------------------
-- Records of dual
-- ----------------------------
-- @formatter:off
INSERT INTO dual VALUES (1);
-- @formatter:on"""
class OracleConvertor(Convertor):
def __init__(self, src):
super().__init__(src, "Oracle")
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]):
"""类型转换"""
type = type.lower()
if type == "varchar":
return f"varchar2({size if size < 4000 else 4000})"
if type == "int":
return "number"
if type == "bigint" or type == "bigint unsigned":
return "number"
if type == "datetime":
return "date"
if type == "bit":
return "number(1,0)"
if type in ("tinyint", "smallint"):
return "smallint"
if type == "text":
return "clob"
if type in ("blob", "mediumblob"):
return "blob"
if type == "decimal":
return (
f"number({','.join(str(s) for s in size)})" if len(size) else "number"
)
def gen_create(self, ddl) -> str:
"""生成 CREATE 语句"""
def generate_column(col):
name = col["name"].lower()
if name == "deleted":
return "deleted number(1,0) DEFAULT 0 NOT NULL"
type = col["type"].lower()
full_type = self.translate_type(type, col["size"])
nullable = "NULL" if col["nullable"] else "NOT NULL"
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
# Oracle 中 size 不能作为字段名
field_name = '"size"' if name == "size" else name
# Oracle DEFAULT 定义在 NULLABLE 之前
return f"{field_name} {full_type} {default} {nullable}"
table_name = ddl["table_name"].lower()
columns = [f"{generate_column(col).strip()}" for col in ddl["columns"]]
field_def_list = ",\n ".join(columns)
script = f"""-- ----------------------------
-- Table structure for {table_name}
-- ----------------------------
CREATE TABLE {table_name} (
{field_def_list}
);"""
# oracle INSERT '' 不能通过 NOT NULL 校验
script = script.replace("DEFAULT '' NOT NULL", "DEFAULT '' NULL")
return script
def gen_index(self, ddl: Dict) -> str:
return "\n".join(f"{script};" for script in self.index(ddl))
def gen_comment(self, table_sql: str, table_name: str) -> str:
script = ""
for field, comment_string in self.filed_comments(table_sql):
script += (
f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n"
)
table_comment = self.table_comment(table_sql)
if table_comment:
script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n"
return script
def gen_pk(self, table_name: str) -> str:
"""生成主键定义"""
return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n"
def gen_index(self, ddl: Dict) -> str:
return "\n".join(f"{script};" for script in self.index(ddl))
def gen_insert(self, table_name: str) -> str:
"""拷贝 INSERT 语句"""
inserts = []
for insert_script in Convertor.inserts(table_name, self.content):
# 对日期数据添加 TO_DATE 转换
insert_script = re.sub(
r"('\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}')",
r"to_date(\g<1>, 'SYYYY-MM-DD HH24:MI:SS')",
insert_script,
)
inserts.append(insert_script)
## 生成 insert 脚本
script = ""
last_id = 0
if inserts:
inserts_lines = "\n".join(inserts)
script += f"""\n\n-- ----------------------------
-- Records of {table_name.lower()}
-- ----------------------------
-- @formatter:off
{inserts_lines}
COMMIT;
-- @formatter:on"""
match = re.search(r"VALUES \((\d+),", inserts[-1])
if match:
last_id = int(match.group(1))
# 生成 Sequence
script += f"""
CREATE SEQUENCE {table_name}_seq
START WITH {last_id + 1};"""
return script
class SQLServerConvertor(Convertor):
"""_summary_
Args:
Convertor (_type_): _description_
"""
def __init__(self, src):
super().__init__(src, "Microsoft SQL Server")
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]):
"""类型转换"""
type = type.lower()
if type == "varchar":
return f"nvarchar({size if size < 4000 else 4000})"
if type == "int":
return "int"
if type == "bigint" or type == "bigint unsigned":
return "bigint"
if type == "datetime":
return "datetime2"
if type == "bit":
return "varchar(1)"
if type in ("tinyint", "smallint"):
return "tinyint"
if type == "text":
return "nvarchar(max)"
if type in ("blob", "mediumblob"):
return "varbinary(max)"
if type == "decimal":
return (
f"numeric({','.join(str(s) for s in size)})" if len(size) else "numeric"
)
def gen_create(self, ddl: Dict) -> str:
"""生成 create"""
def _generate_column(col):
name = col["name"].lower()
if name == "id":
return "id bigint NOT NULL PRIMARY KEY IDENTITY"
if name == "deleted":
return "deleted bit DEFAULT 0 NOT NULL"
type = col["type"].lower()
full_type = self.translate_type(type, col["size"])
nullable = "NULL" if col["nullable"] else "NOT NULL"
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
return f"{name} {full_type} {default} {nullable}"
table_name = ddl["table_name"].lower()
columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]]
filed_def_list = ",\n ".join(columns)
script = f"""-- ----------------------------
-- Table structure for {table_name}
-- ----------------------------
DROP TABLE IF EXISTS {table_name}
GO
CREATE TABLE {table_name} (
{filed_def_list}
)
GO"""
return script
def gen_comment(self, table_sql: str, table_name: str) -> str:
"""生成字段及表的注释"""
script = ""
for field, comment_string in self.filed_comments(table_sql):
script += f"""EXEC sp_addextendedproperty
'MS_Description', N'{comment_string}',
'SCHEMA', N'dbo',
'TABLE', N'{table_name}',
'COLUMN', N'{field}'
GO
"""
table_comment = self.table_comment(table_sql)
if table_comment:
script += f"""EXEC sp_addextendedproperty
'MS_Description', N'{table_comment}',
'SCHEMA', N'dbo',
'TABLE', N'{table_name}'
GO
"""
return script
def gen_pk(self, table_name: str) -> str:
"""生成主键定义"""
return ""
def gen_index(self, ddl: Dict) -> str:
"""生成 index"""
return "\n".join(f"{script}\nGO" for script in self.index(ddl))
def gen_insert(self, table_name: str) -> str:
"""生成 insert 语句"""
# 收集 `table_name` 对应的 insert 语句
inserts = []
for insert_script in Convertor.inserts(table_name, self.content):
# SQLServer: 字符串前加Nhack是否存在替换字符串内容的风险
insert_script = insert_script.replace(", '", ", N'").replace(
"VALUES ('", "VALUES (N')"
)
# 删除 insert 的结尾分号
insert_script = re.sub(";$", r"\nGO", insert_script)
inserts.append(insert_script)
## 生成 insert 脚本
script = ""
if inserts:
inserts_lines = "\n".join(inserts)
script += f"""\n\n-- ----------------------------
-- Records of {table_name.lower()}
-- ----------------------------
-- @formatter:off
BEGIN TRANSACTION
GO
SET IDENTITY_INSERT {table_name.lower()} ON
GO
{inserts_lines}
SET IDENTITY_INSERT {table_name.lower()} OFF
GO
COMMIT
GO
-- @formatter:on"""
return script
def gen_dual(self) -> str:
return """DROP TABLE IF EXISTS dual
GO
CREATE TABLE dual
(
id int
)
GO
EXEC sp_addextendedproperty
'MS_Description', N'数据库连接的表',
'SCHEMA', N'dbo',
'TABLE', N'dual'
GO
-- ----------------------------
-- Records of dual
-- ----------------------------
-- @formatter:off
INSERT INTO dual VALUES (1)
GO
-- @formatter:on"""
class DM8Convertor(Convertor):
def __init__(self, src):
super().__init__(src, "DM8")
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]):
"""类型转换"""
type = type.lower()
if type == "varchar":
return f"varchar({size})"
if type == "int":
return "int"
if type == "bigint" or type == "bigint unsigned":
return "bigint"
if type == "datetime":
return "datetime"
if type == "bit":
return "bit"
if type in ("tinyint", "smallint"):
return "smallint"
if type == "text":
return "text"
if type == "blob":
return "blob"
if type == "mediumblob":
return "varchar(10240)"
if type == "decimal":
return (
f"decimal({','.join(str(s) for s in size)})" if len(size) else "decimal"
)
def gen_create(self, ddl) -> str:
"""生成 CREATE 语句"""
def generate_column(col):
name = col["name"].lower()
if name == "id":
return "id bigint NOT NULL PRIMARY KEY IDENTITY"
type = col["type"].lower()
full_type = self.translate_type(type, col["size"])
nullable = "NULL" if col["nullable"] else "NOT NULL"
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
return f"{name} {full_type} {default} {nullable}"
table_name = ddl["table_name"].lower()
columns = [f"{generate_column(col).strip()}" for col in ddl["columns"]]
field_def_list = ",\n ".join(columns)
script = f"""-- ----------------------------
-- Table structure for {table_name}
-- ----------------------------
CREATE TABLE {table_name} (
{field_def_list}
);"""
# oracle INSERT '' 不能通过 NOT NULL 校验
script = script.replace("DEFAULT '' NOT NULL", "DEFAULT '' NULL")
return script
def gen_index(self, ddl: Dict) -> str:
return "\n".join(f"{script};" for script in self.index(ddl))
def gen_comment(self, table_sql: str, table_name: str) -> str:
script = ""
for field, comment_string in self.filed_comments(table_sql):
script += (
f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n"
)
table_comment = self.table_comment(table_sql)
if table_comment:
script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n"
return script
def gen_pk(self, table_name: str) -> str:
"""生成主键定义"""
return ""
def gen_index(self, ddl: Dict) -> str:
return "\n".join(f"{script};" for script in self.index(ddl))
def gen_insert(self, table_name: str) -> str:
"""拷贝 INSERT 语句"""
inserts = list(Convertor.inserts(table_name, self.content))
## 生成 insert 脚本
script = ""
if inserts:
inserts_lines = "\n".join(inserts)
script += f"""\n\n-- ----------------------------
-- Records of {table_name.lower()}
-- ----------------------------
-- @formatter:off
SET IDENTITY_INSERT {table_name.lower()} ON;
{inserts_lines}
COMMIT;
SET IDENTITY_INSERT {table_name.lower()} OFF;
-- @formatter:on"""
return script
class KingbaseConvertor(PostgreSQLConvertor):
def __init__(self, src):
super().__init__(src)
self.db_type = "Kingbase"
def gen_create(self, ddl: Dict) -> str:
"""生成 create"""
def _generate_column(col):
name = col["name"].lower()
if name == "deleted":
return "deleted int2 NOT NULL DEFAULT 0"
type = col["type"].lower()
full_type = self.translate_type(type, col["size"])
nullable = "NULL" if col["nullable"] else "NOT NULL"
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
return f"{name} {full_type} {nullable} {default}"
table_name = ddl["table_name"].lower()
columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]]
filed_def_list = ",\n ".join(columns)
script = f"""-- ----------------------------
-- Table structure for {table_name}
-- ----------------------------
DROP TABLE IF EXISTS {table_name};
CREATE TABLE {table_name} (
{filed_def_list}
);"""
# Kingbase INSERT '' 不能通过 NOT NULL 校验
script = script.replace("NOT NULL DEFAULT ''", "NULL DEFAULT ''")
return script
class OpengaussConvertor(KingbaseConvertor):
def __init__(self, src):
super().__init__(src)
self.db_type = "OpenGauss"
def main():
parser = argparse.ArgumentParser(description="芋道系统数据库转换工具")
parser.add_argument(
"type",
type=str,
help="目标数据库类型",
choices=["postgres", "oracle", "sqlserver", "dm8", "kingbase", "opengauss"],
)
args = parser.parse_args()
sql_file = pathlib.Path("../mysql/ruoyi-vue-pro.sql").resolve().as_posix()
convertor = None
if args.type == "postgres":
convertor = PostgreSQLConvertor(sql_file)
elif args.type == "oracle":
convertor = OracleConvertor(sql_file)
elif args.type == "sqlserver":
convertor = SQLServerConvertor(sql_file)
elif args.type == "dm8":
convertor = DM8Convertor(sql_file)
elif args.type == "kingbase":
convertor = KingbaseConvertor(sql_file)
elif args.type == "opengauss":
convertor = OpengaussConvertor(sql_file)
else:
raise NotImplementedError(f"不支持目标数据库类型: {args.type}")
convertor.print()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,134 @@
name: ruoyi-vue-pro
volumes:
mysql: { }
postgres: { }
sqlserver: { }
dm8: { }
kingbase: { }
opengauss: { }
services:
mysql:
image: mysql:8.0.33
restart: unless-stopped
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: ruoyi-vue-pro
ports:
- "3306:3306"
volumes:
- mysql:/var/lib/mysql/
# 注入初始化脚本
- ./mysql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/init.sql:ro
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
postgres:
image: postgres:14.2
restart: unless-stopped
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: 123456
POSTGRES_DB: ruoyi-vue-pro
ports:
- "5432:5432"
volumes:
- postgres:/var/lib/postgresql/data
# 注入初始化脚本
- ../postgresql/quartz.sql:/docker-entrypoint-initdb.d/quartz.sql:ro
- ../postgresql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/ruoyi-vue-pro.sql:ro
oracle:
image: gvenzl/oracle-xe:18-slim-faststart
restart: unless-stopped
environment:
## 登录信息 SID: XE user: system password: oracle
ORACLE_PASSWORD: oracle
ports:
- "1521:1521"
volumes:
- ../oracle/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
# 创建app用户: ROOT/123456@//localhost/XEPDB1
- ./oracle/1_create_user.sql:/docker-entrypoint-initdb.d/1_create_user.sql:ro
- ./oracle/2_create_schema.sh:/docker-entrypoint-initdb.d/2_create_schema.sh:ro
oracle_m1:
image: einslib/oracle-19c:19.3.0-ee-slim-faststart
restart: unless-stopped
environment:
## 登录信息 SID: FREE user: system password: oracle
ORACLE_PASSWORD: oracle
ports:
- "1521:1521"
volumes:
- ../oracle/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
# 创建app用户: ROOT/123456@//localhost/XEPDB1
- ./oracle/1_create_user.sql:/docker-entrypoint-initdb.d/1_create_user.sql:ro
- ./oracle/2_create_schema.sh:/docker-entrypoint-initdb.d/2_create_schema.sh:ro
sqlserver:
image: mcr.microsoft.com/mssql/server:2017-latest
restart: unless-stopped
environment:
TZ: Asia/Shanghai
ACCEPT_EULA: "Y"
SA_PASSWORD: "Yudao@2024"
ports:
- "1433:1433"
volumes:
- sqlserver:/var/opt/mssql
- ../sqlserver/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
# docker compose exec sqlserver bash /tmp/create_schema.sh
- ./sqlserver/create_schema.sh:/tmp/create_schema.sh:ro
dm8:
# docker load -i dm8_20240715_x86_rh6_rq_single.tar
image: dm8_single:dm8_20240715_rev232765_x86_rh6_64
restart: unless-stopped
environment:
PAGE_SIZE: 16
LD_LIBRARY_PATH: /opt/dmdbms/bin
EXTENT_SIZE: 32
BLANK_PAD_MODE: 1
LOG_SIZE: 1024
UNICODE_FLAG: 1
LENGTH_IN_CHAR: 1
INSTANCE_NAME: dm8_test
ports:
- "5236:5236"
volumes:
- dm8:/opt/dmdbms/data
- ../dm/ruoyi-vue-pro-dm8.sql:/tmp/schema.sql:ro
kingbase:
image: kingbase_v009r001c001b0025_single_x86:v1
# image: kingbase_v009r001c001b0025_single_arm:v1
restart: unless-stopped
environment:
DB_USER: root
DB_PASSWORD: 123456
ports:
- "54321:54321"
volumes:
- kingbase:/home/kingbase/userdata
- ../kingbase/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
opengauss:
image: opengauss/opengauss:5.0.0
restart: unless-stopped
environment:
GS_USERNAME: root
GS_PASSWORD: Yudao@2024
LD_LIBRARY_PATH: /usr/local/opengauss/lib:/usr/lib
ports:
- "5432:5432"
volumes:
- opengauss:/var/lib/opengauss
- ../opengauss/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
# docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql'

View File

@@ -0,0 +1,3 @@
ALTER SESSION SET CONTAINER=XEPDB1;
CREATE USER ROOT IDENTIFIED BY 123456 QUOTA UNLIMITED ON USERS;
GRANT CONNECT, RESOURCE TO ROOT;

View File

@@ -0,0 +1 @@
sqlplus -s ROOT/123456@//localhost/XEPDB1 @/tmp/schema.sql

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P ${SA_PASSWORD} -Q "CREATE DATABASE [ruoyi-vue-pro];
GO"
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P ${SA_PASSWORD} -d 'ruoyi-vue-pro' -i /tmp/schema.sql

663
tashow-dependencies/pom.xml Normal file
View File

@@ -0,0 +1,663 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-dependencies</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
<description>基础 bom 文件,管理整个项目的依赖版本</description>
<properties>
<revision>1.0.0</revision>
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
<!-- 统一依赖管理 -->
<spring.boot.version>3.4.1</spring.boot.version>
<spring.cloud.version>2024.0.0</spring.cloud.version>
<spring.cloud.alibaba.version>2023.0.3.2</spring.cloud.alibaba.version>
<!-- DB 相关 -->
<druid.version>1.2.24</druid.version>
<mybatis.version>3.5.17</mybatis.version>
<mybatis-plus.version>3.5.9</mybatis-plus.version>
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
<mybatis-plus-join.version>1.4.13</mybatis-plus-join.version>
<easy-trans.version>3.0.6</easy-trans.version>
<redisson.version>3.41.0</redisson.version>
<dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
<kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
<opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
<!-- 消息队列 -->
<rocketmq-spring.version>2.3.1</rocketmq-spring.version>
<!-- RPC 相关 -->
<!-- Config 配置中心相关 -->
<!-- Job 定时任务相关 -->
<xxl-job.version>2.4.0</xxl-job.version>
<!-- 服务保障相关 -->
<lock4j.version>2.2.7</lock4j.version>
<!-- 监控相关 -->
<skywalking.version>9.0.0</skywalking.version>
<spring-boot-admin.version>3.4.1</spring-boot-admin.version>
<opentracing.version>0.33.0</opentracing.version>
<!-- Test 测试相关 -->
<podam.version>8.0.2.RELEASE</podam.version>
<jedis-mock.version>1.1.4</jedis-mock.version>
<mockito-inline.version>5.2.0</mockito-inline.version>
<!-- Bpm 工作流相关 -->
<flowable.version>7.0.1</flowable.version>
<!-- 工具类相关 -->
<captcha-plus.version>2.0.3</captcha-plus.version>
<jsoup.version>1.18.1</jsoup.version>
<lombok.version>1.18.36</lombok.version>
<mapstruct.version>1.6.3</mapstruct.version>
<hutool-5.version>5.8.35</hutool-5.version>
<hutool-6.version>6.0.0-M19</hutool-6.version>
<easyexcel.verion>4.0.3</easyexcel.verion>
<velocity.version>2.4.1</velocity.version>
<fastjson.version>1.2.83</fastjson.version>
<guava.version>33.4.0-jre</guava.version>
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
<commons-net.version>3.11.1</commons-net.version>
<jsch.version>0.1.55</jsch.version>
<tika-core.version>2.9.2</tika-core.version>
<ip2region.version>2.7.0</ip2region.version>
<bizlog-sdk.version>3.0.6</bizlog-sdk.version>
<reflections.version>0.10.2</reflections.version>
<netty.version>4.1.116.Final</netty.version>
<!-- 三方云服务相关 -->
<commons-io.version>2.17.0</commons-io.version>
<commons-compress.version>1.27.1</commons-compress.version>
<aws-java-sdk-s3.version>1.12.777</aws-java-sdk-s3.version>
<justauth.version>2.0.5</justauth.version>
<jimureport.version>1.8.1</jimureport.version>
<weixin-java.version>4.6.0</weixin-java.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- 统一依赖管理 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>${netty.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>io.github.mouzt</groupId>
<artifactId>bizlog-sdk</artifactId>
<version>${bizlog-sdk.version}</version>
<exclusions>
<exclusion> <!-- 排除掉springboot依赖使用项目的 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-system-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-module-system</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-infra-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-module-infra</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-tenant</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-data-permission</artifactId>
<version>${revision}</version>
</dependency>
<!-- Spring 核心 -->
<dependency>
<!-- 用于生成自定义的 Spring @ConfigurationProperties 配置类的说明文件 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-env</artifactId>
<version>${revision}</version>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-web</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-security</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-websocket</artifactId>
<version>${revision}</version>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-data-mybatis</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId> <!-- 多数据源 -->
<version>${dynamic-datasource.version}</version>
</dependency>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
<version>${mybatis-plus-join.version}</version>
</dependency>
<dependency>
<groupId>com.fhs-opensource</groupId> <!-- VO 数据翻译 -->
<artifactId>easy-trans-spring-boot-starter</artifactId>
<version>${easy-trans.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-mybatis-plus-extend</artifactId>
<version>${easy-trans.version}</version>
</dependency>
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-anno</artifactId>
<version>${easy-trans.version}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-data-redis</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.dameng</groupId>
<artifactId>DmJdbcDriver18</artifactId>
<version>${dm8.jdbc.version}</version>
</dependency>
<dependency>
<groupId>org.opengauss</groupId>
<artifactId>opengauss-jdbc</artifactId>
<version>${opengauss.jdbc.version}</version>
</dependency>
<dependency>
<groupId>cn.com.kingbase</groupId>
<artifactId>kingbase8</artifactId>
<version>${kingbase.jdbc.version}</version>
</dependency>
<!-- RPC 远程调用相关 -->
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-rpc</artifactId>
<version>${revision}</version>
</dependency>
<!-- Registry 注册中心相关 -->
<!-- Config 配置中心相关 -->
<!-- Job 定时任务相关 -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${xxl-job.version}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-job</artifactId>
<version>${revision}</version>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-mq</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>${rocketmq-spring.version}</version>
</dependency>
<!-- 服务保障相关 -->
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-protection</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
<version>${lock4j.version}</version>
<exclusions>
<exclusion>
<artifactId>redisson-spring-boot-starter</artifactId>
<groupId>org.redisson</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 监控相关 -->
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-framework-monitor</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>${skywalking.version}</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>${skywalking.version}</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-opentracing</artifactId>
<version>${skywalking.version}</version>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <artifactId>opentracing-api</artifactId>-->
<!-- <groupId>io.opentracing</groupId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <artifactId>opentracing-util</artifactId>-->
<!-- <groupId>io.opentracing</groupId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-api</artifactId>
<version>${opentracing.version}</version>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-util</artifactId>
<version>${opentracing.version}</version>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-noop</artifactId>
<version>${opentracing.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId> <!-- 实现 Spring Boot Admin Server 服务端 -->
<version>${spring-boot-admin.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId> <!-- 实现 Spring Boot Admin Server 服务端 -->
<version>${spring-boot-admin.version}</version>
</dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito-inline.version}</version> <!-- 支持 Mockito 的 final 类与 static 方法的 mock -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<artifactId>asm</artifactId>
<groupId>org.ow2.asm</groupId>
</exclusion>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.fppt</groupId> <!-- 单元测试,我们采用内嵌的 Redis 数据库 -->
<artifactId>jedis-mock</artifactId>
<version>${jedis-mock.version}</version>
</dependency>
<dependency>
<groupId>uk.co.jemos.podam</groupId> <!-- 单元测试,随机生成 POJO 类 -->
<artifactId>podam</artifactId>
<version>${podam.version}</version>
</dependency>
<!-- 工作流相关 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-process</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-actuator</artifactId>
<version>${flowable.version}</version>
</dependency>
<!-- 工作流相关结束 -->
<!-- 工具类相关 -->
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-common</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-data-excel</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-5.version}</version>
</dependency>
<dependency>
<groupId>org.dromara.hutool</groupId>
<artifactId>hutool-extra</artifactId>
<version>${hutool-6.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.verion}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId> <!-- 文件类型的识别 -->
<version>${tika-core.version}</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId> <!-- 解决 ThreadLocal 父子线程的传值问题 -->
<version>${transmittable-thread-local.version}</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId> <!-- 解决 ftp 连接 -->
<version>${commons-net.version}</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId> <!-- 解决 sftp 连接 -->
<version>${jsch.version}</version>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId>
<version>${captcha-plus.version}</version>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>${reflections.version}</version>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>${aws-java-sdk-s3.version}</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>${weixin-java.version}</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>${weixin-java.version}</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>${weixin-java.version}</version>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
<version>${justauth.version}</version>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 积木报表-->
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot3-starter-fastjson2</artifactId>
<version>${jimureport.version}</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!-- 统一 revision 版本 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<flattenMode>bom</flattenMode>
<updatePomFile>true</updatePomFile>
</configuration>
<executions>
<execution>
<goals>
<goal>flatten</goal>
</goals>
<id>flatten</id>
<phase>process-resources</phase>
</execution>
<execution>
<goals>
<goal>clean</goal>
</goals>
<id>flatten.clean</id>
<phase>clean</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

19
tashow-feign/pom.xml Normal file
View File

@@ -0,0 +1,19 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-platform</artifactId>
<version>${revision}</version>
</parent>
<artifactId>tashow-feign</artifactId>
<packaging>pom</packaging>
<modules>
<module>tashow-infra-api</module>
<module>tashow-system-api</module>
<module>tashow-product-api</module>
</modules>
</project>

View File

@@ -0,0 +1,40 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-feign</artifactId>
<version>${revision}</version>
</parent>
<artifactId>tashow-infra-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
infra 模块 API暴露给其它模块调用
</description>
<dependencies>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-common</artifactId>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
<!-- RPC 远程调用相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,18 @@
package com.tashow.cloud.infraapi.api.config;
import com.tashow.cloud.common.pojo.CommonResult;
import com.tashow.cloud.infraapi.enums.ApiConstants;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
/** RPC 服务 - 参数配置 */
public interface ConfigApi {
String PREFIX = ApiConstants.PREFIX + "/config";
/** 根据参数键查询参数值 */
@GetMapping(PREFIX + "/get-value-by-key")
CommonResult<String> getConfigValueByKey(@RequestParam("key") String key);
}

View File

@@ -0,0 +1,58 @@
package com.tashow.cloud.infraapi.api.file;
import com.tashow.cloud.common.pojo.CommonResult;
import com.tashow.cloud.infraapi.api.file.dto.FileCreateReqDTO;
import com.tashow.cloud.infraapi.enums.ApiConstants;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
/** RPC 服务 - 文件 */
public interface FileApi {
String PREFIX = ApiConstants.PREFIX + "/file";
/**
* 保存文件,并返回文件的访问路径
*
* @param content 文件内容
* @return 文件路径
*/
default String createFile(byte[] content) {
return createFile(null, null, content);
}
/**
* 保存文件,并返回文件的访问路径
*
* @param path 文件路径
* @param content 文件内容
* @return 文件路径
*/
default String createFile(String path, byte[] content) {
return createFile(null, path, content);
}
/**
* 保存文件,并返回文件的访问路径
*
* @param name 原文件名称
* @param path 文件路径
* @param content 文件内容
* @return 文件路径
*/
default String createFile(
@RequestParam("name") String name,
@RequestParam("path") String path,
@RequestParam("content") byte[] content) {
return createFile(new FileCreateReqDTO().setName(name).setPath(path).setContent(content))
.getCheckedData();
}
@PostMapping(PREFIX + "/create")
/** 保存文件,并返回文件的访问路径 */
CommonResult<String> createFile(@Valid @RequestBody FileCreateReqDTO createReqDTO);
}

View File

@@ -0,0 +1,21 @@
package com.tashow.cloud.infraapi.api.file.dto;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
/** RPC 服务 - 文件创建 Request DTO */
@Data
public class FileCreateReqDTO {
/** 原文件名称 */
private String name;
/** 文件路径 */
private String path;
/**
* 文件内容
*/
@NotEmpty(message = "文件内容不能为空")
private byte[] content;
}

View File

@@ -0,0 +1,31 @@
package com.tashow.cloud.infraapi.api.logger;
import com.tashow.cloud.common.pojo.CommonResult;
import com.tashow.cloud.infraapi.api.logger.dto.ApiAccessLogCreateReqDTO;
import com.tashow.cloud.infraapi.enums.ApiConstants;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
/** RPC 服务 - API 访问日志 */
public interface ApiAccessLogApi {
String PREFIX = ApiConstants.PREFIX + "/api-access-log";
@PostMapping(PREFIX + "/create")
/** 创建 API 访问日志 */
CommonResult<Boolean> createApiAccessLog(@Valid @RequestBody ApiAccessLogCreateReqDTO createDTO);
/**
* 【异步】创建 API 访问日志
*
* @param createDTO 访问日志 DTO
*/
@Async
default void createApiAccessLogAsync(ApiAccessLogCreateReqDTO createDTO) {
createApiAccessLog(createDTO).checkError();
}
}

View File

@@ -0,0 +1,31 @@
package com.tashow.cloud.infraapi.api.logger;
import com.tashow.cloud.common.pojo.CommonResult;
import com.tashow.cloud.infraapi.api.logger.dto.ApiErrorLogCreateReqDTO;
import com.tashow.cloud.infraapi.enums.ApiConstants;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
/** RPC 服务 - API 异常日志 */
public interface ApiErrorLogApi {
String PREFIX = ApiConstants.PREFIX + "/api-error-log";
@PostMapping(PREFIX + "/create")
/** 创建 API 异常日志 */
CommonResult<Boolean> createApiErrorLog(@Valid @RequestBody ApiErrorLogCreateReqDTO createDTO);
/**
* 【异步】创建 API 异常日志
*
* @param createDTO 异常日志 DTO
*/
@Async
default void createApiErrorLogAsync(ApiErrorLogCreateReqDTO createDTO) {
createApiErrorLog(createDTO).checkError();
}
}

View File

@@ -0,0 +1,81 @@
package com.tashow.cloud.infraapi.api.logger.dto;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import lombok.Data;
/** RPC 服务 - API 访问日志创建 Request DTO */
@Data
public class ApiAccessLogCreateReqDTO {
/** 链路追踪编号 */
private String traceId;
/** 用户编号" */
private Long userId;
/** 用户类型" */
private Integer userType;
/** 应用名" */
@NotNull(message = "应用名不能为空")
private String applicationName;
/** 请求方法名" */
@NotNull(message = "http 请求方法不能为空")
private String requestMethod;
/** 请求地址", example = "/xxx/yyy */
@NotNull(message = "访问地址不能为空")
private String requestUrl;
/** 请求参数 */
private String requestParams;
/** 响应结果 */
private String responseBody;
/** 用户 IP" */
@NotNull(message = "ip 不能为空")
private String userIp;
/** 浏览器 UserAgent" */
@NotNull(message = "User-Agent 不能为空")
private String userAgent;
/** 操作模块", example = "商品模块 */
private String operateModule;
/** 操作名", example = "商品新增 */
private String operateName;
/** 操作分类" */
private Integer operateType; // 参见 OperateTypeEnum 枚举
/**
* 开始时间
*/
@NotNull(message = "开始请求时间不能为空")
private LocalDateTime beginTime;
/**
* 结束时间
*/
@NotNull(message = "结束请求时间不能为空")
private LocalDateTime endTime;
/**
* 执行时长,单位:毫秒
*/
@NotNull(message = "执行时长不能为空")
private Integer duration;
/**
* 结果码
*/
@NotNull(message = "错误码不能为空")
private Integer resultCode;
/** 结果提示 */
private String resultMsg;
}

View File

@@ -0,0 +1,99 @@
package com.tashow.cloud.infraapi.api.logger.dto;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import lombok.Data;
/** RPC 服务 - API 错误日志创建 Request DTO */
@Data
public class ApiErrorLogCreateReqDTO {
/** 链路追踪编号 */
private String traceId;
/** 用户编号" */
private Long userId;
/** 用户类型" */
private Integer userType;
/** 应用名" */
@NotNull(message = "应用名不能为空")
private String applicationName;
/** 请求方法名" */
@NotNull(message = "http 请求方法不能为空")
private String requestMethod;
/** 请求地址", example = "/xxx/yyy */
@NotNull(message = "访问地址不能为空")
private String requestUrl;
/**
* 请求参数
*/
@NotNull(message = "请求参数不能为空")
private String requestParams;
/** 用户 IP" */
@NotNull(message = "ip 不能为空")
private String userIp;
/** 浏览器 UserAgent" */
@NotNull(message = "User-Agent 不能为空")
private String userAgent;
/**
* 异常时间
*/
@NotNull(message = "异常时间不能为空")
private LocalDateTime exceptionTime;
/**
* 异常名
*/
@NotNull(message = "异常名不能为空")
private String exceptionName;
/**
* 异常发生的类全名
*/
@NotNull(message = "异常发生的类全名不能为空")
private String exceptionClassName;
/**
* 异常发生的类文件
*/
@NotNull(message = "异常发生的类文件不能为空")
private String exceptionFileName;
/**
* 异常发生的方法名
*/
@NotNull(message = "异常发生的方法名不能为空")
private String exceptionMethodName;
/**
* 异常发生的方法所在行
*/
@NotNull(message = "异常发生的方法所在行不能为空")
private Integer exceptionLineNumber;
/**
* 异常的栈轨迹异常的栈轨迹
*/
@NotNull(message = "异常的栈轨迹不能为空")
private String exceptionStackTrace;
/**
* 异常导致的根消息
*/
@NotNull(message = "异常导致的根消息不能为空")
private String exceptionRootCauseMessage;
/**
* 异常导致的消息
*/
@NotNull(message = "异常导致的消息不能为空")
private String exceptionMessage;
}

View File

@@ -0,0 +1,4 @@
/**
* infra API 包,定义暴露给其它模块的 API
*/
package com.tashow.cloud.infraapi.api;

View File

@@ -0,0 +1,82 @@
package com.tashow.cloud.infraapi.api.websocket;
import com.tashow.cloud.common.pojo.CommonResult;
import com.tashow.cloud.common.util.json.JsonUtils;
import com.tashow.cloud.infraapi.api.websocket.dto.WebSocketSendReqDTO;
import com.tashow.cloud.infraapi.enums.ApiConstants;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
/** RPC 服务 - WebSocket 发送器的 */
// 对 WebSocketMessageSender 进行封装,提供给其它模块使用
public interface WebSocketSenderApi {
String PREFIX = ApiConstants.PREFIX + "/websocket";
@PostMapping(PREFIX + "/send")
/** 发送 WebSocket 消息 */
CommonResult<Boolean> send(@Valid @RequestBody WebSocketSendReqDTO message);
/**
* 发送消息给指定用户
*
* @param userType 用户类型
* @param userId 用户编号
* @param messageType 消息类型
* @param messageContent 消息内容JSON 格式
*/
default void send(Integer userType, Long userId, String messageType, String messageContent) {
send(new WebSocketSendReqDTO()
.setUserType(userType)
.setUserId(userId)
.setMessageType(messageType)
.setMessageContent(messageContent))
.checkError();
}
/**
* 发送消息给指定用户类型
*
* @param userType 用户类型
* @param messageType 消息类型
* @param messageContent 消息内容JSON 格式
*/
default void send(Integer userType, String messageType, String messageContent) {
send(new WebSocketSendReqDTO()
.setUserType(userType)
.setMessageType(messageType)
.setMessageContent(messageContent))
.checkError();
}
/**
* 发送消息给指定 Session
*
* @param sessionId Session 编号
* @param messageType 消息类型
* @param messageContent 消息内容JSON 格式
*/
default void send(String sessionId, String messageType, String messageContent) {
send(new WebSocketSendReqDTO()
.setSessionId(sessionId)
.setMessageType(messageType)
.setMessageContent(messageContent))
.checkError();
}
default void sendObject(
Integer userType, Long userId, String messageType, Object messageContent) {
send(userType, userId, messageType, JsonUtils.toJsonString(messageContent));
}
default void sendObject(Integer userType, String messageType, Object messageContent) {
send(userType, messageType, JsonUtils.toJsonString(messageContent));
}
default void sendObject(String sessionId, String messageType, Object messageContent) {
send(sessionId, messageType, JsonUtils.toJsonString(messageContent));
}
}

View File

@@ -0,0 +1,26 @@
package com.tashow.cloud.infraapi.api.websocket.dto;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
/** RPC 服务 - WebSocket 消息发送 Request DTO */
@Data
public class WebSocketSendReqDTO {
/** Session 编号 */
private String sessionId;
/** 用户编号 */
private Long userId;
/** 用户类型 */
private Integer userType;
/** 消息类型 */
@NotEmpty(message = "消息类型不能为空")
private String messageType;
/** 消息内容 */
@NotEmpty(message = "消息内容不能为空")
private String messageContent;
}

View File

@@ -0,0 +1,24 @@
package com.tashow.cloud.infraapi.enums;
import com.tashow.cloud.common.enums.RpcConstants;
/**
* API 相关的枚举
*
* @author 芋道源码
*/
public class ApiConstants {
/**
* 服务名
*
* 注意,需要保证和 spring.application.name 保持一致
*/
public static final String NAME = "infra-server";
public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/infra";
public static final String VERSION = "1.0.0";
}

View File

@@ -0,0 +1,20 @@
package com.tashow.cloud.infraapi.enums;
/**
* Infra 字典类型的枚举类
*
* @author 芋道源码
*/
public interface DictTypeConstants {
String JOB_STATUS = "infra_job_status"; // 定时任务状态的枚举
String JOB_LOG_STATUS = "infra_job_log_status"; // 定时任务日志状态的枚举
String API_ERROR_LOG_PROCESS_STATUS = "infra_api_error_log_process_status"; // API 错误日志的处理状态的枚举
String CONFIG_TYPE = "infra_config_type"; // 参数配置类型
String BOOLEAN_STRING = "infra_boolean_string"; // Boolean 是否类型
String OPERATE_TYPE = "infra_operate_type"; // 操作类型
}

View File

@@ -0,0 +1,72 @@
package com.tashow.cloud.infraapi.enums;
import com.tashow.cloud.common.exception.ErrorCode;
/**
* Infra 错误码枚举类
*
* infra 系统,使用 1-001-000-000 段
*/
public interface ErrorCodeConstants {
// ========== 参数配置 1-001-000-000 ==========
ErrorCode CONFIG_NOT_EXISTS = new ErrorCode(1_001_000_001, "参数配置不存在");
ErrorCode CONFIG_KEY_DUPLICATE = new ErrorCode(1_001_000_002, "参数配置 key 重复");
ErrorCode CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE = new ErrorCode(1_001_000_003, "不能删除类型为系统内置的参数配置");
ErrorCode CONFIG_GET_VALUE_ERROR_IF_VISIBLE = new ErrorCode(1_001_000_004, "获取参数配置失败,原因:不允许获取不可见配置");
// ========== 定时任务 1-001-001-000 ==========
ErrorCode JOB_NOT_EXISTS = new ErrorCode(1_001_001_000, "定时任务不存在");
ErrorCode JOB_HANDLER_EXISTS = new ErrorCode(1_001_001_001, "定时任务的处理器已经存在");
ErrorCode JOB_CHANGE_STATUS_INVALID = new ErrorCode(1_001_001_002, "只允许修改为开启或者关闭状态");
ErrorCode JOB_CHANGE_STATUS_EQUALS = new ErrorCode(1_001_001_003, "定时任务已经处于该状态,无需修改");
ErrorCode JOB_UPDATE_ONLY_NORMAL_STATUS = new ErrorCode(1_001_001_004, "只有开启状态的任务,才可以修改");
ErrorCode JOB_CRON_EXPRESSION_VALID = new ErrorCode(1_001_001_005, "CRON 表达式不正确");
ErrorCode JOB_HANDLER_BEAN_NOT_EXISTS = new ErrorCode(1_001_001_006, "定时任务的处理器 Bean 不存在,注意 Bean 默认首字母小写");
ErrorCode JOB_HANDLER_BEAN_TYPE_ERROR = new ErrorCode(1_001_001_007, "定时任务的处理器 Bean 类型不正确,未实现 JobHandler 接口");
// ========== API 错误日志 1-001-002-000 ==========
ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1_001_002_000, "API 错误日志不存在");
ErrorCode API_ERROR_LOG_PROCESSED = new ErrorCode(1_001_002_001, "API 错误日志已处理");
// ========= 文件相关 1-001-003-000 =================
ErrorCode FILE_PATH_EXISTS = new ErrorCode(1_001_003_000, "文件路径已存在");
ErrorCode FILE_NOT_EXISTS = new ErrorCode(1_001_003_001, "文件不存在");
ErrorCode FILE_IS_EMPTY = new ErrorCode(1_001_003_002, "文件为空");
// ========== 代码生成器 1-001-004-000 ==========
ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1_001_004_002, "表定义已经存在");
ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1_001_004_001, "导入的表不存在");
ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1_001_004_002, "导入的字段不存在");
ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_004, "表定义不存在");
ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_005, "字段义不存在");
ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1_001_004_006, "同步的字段不存在");
ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1_001_004_007, "同步失败,不存在改变");
ErrorCode CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL = new ErrorCode(1_001_004_008, "数据库的表注释未填写");
ErrorCode CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL = new ErrorCode(1_001_004_009, "数据库的表字段({})注释未填写");
ErrorCode CODEGEN_MASTER_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_010, "主表(id={})定义不存在,请检查");
ErrorCode CODEGEN_SUB_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_011, "子表的字段(id={})不存在,请检查");
ErrorCode CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE = new ErrorCode(1_001_004_012, "主表生成代码失败,原因:它没有子表");
// ========== 文件配置 1-001-006-000 ==========
ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_006_000, "文件配置不存在");
ErrorCode FILE_CONFIG_DELETE_FAIL_MASTER = new ErrorCode(1_001_006_001, "该文件配置不允许删除,原因:它是主配置,删除会导致无法上传文件");
// ========== 数据源配置 1-001-007-000 ==========
ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_007_000, "数据源配置不存在");
ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1_001_007_001, "数据源配置不正确,无法进行连接");
// ========== 学生 1-001-201-000 ==========
ErrorCode DEMO01_CONTACT_NOT_EXISTS = new ErrorCode(1_001_201_000, "示例联系人不存在");
ErrorCode DEMO02_CATEGORY_NOT_EXISTS = new ErrorCode(1_001_201_001, "示例分类不存在");
ErrorCode DEMO02_CATEGORY_EXITS_CHILDREN = new ErrorCode(1_001_201_002, "存在存在子示例分类,无法删除");
ErrorCode DEMO02_CATEGORY_PARENT_NOT_EXITS = new ErrorCode(1_001_201_003,"父级示例分类不存在");
ErrorCode DEMO02_CATEGORY_PARENT_ERROR = new ErrorCode(1_001_201_004, "不能设置自己为父示例分类");
ErrorCode DEMO02_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_001_201_005, "已经存在该名字的示例分类");
ErrorCode DEMO02_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_001_201_006, "不能设置自己的子示例分类为父示例分类");
ErrorCode DEMO03_STUDENT_NOT_EXISTS = new ErrorCode(1_001_201_007, "学生不存在");
ErrorCode DEMO03_GRADE_NOT_EXISTS = new ErrorCode(1_001_201_008, "学生班级不存在");
ErrorCode DEMO03_GRADE_EXISTS = new ErrorCode(1_001_201_009, "学生班级已存在");
}

View File

@@ -0,0 +1,90 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-feign</artifactId>
<version>${revision}</version>
</parent>
<artifactId>tashow-product-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
infra 模块 API暴露给其它模块调用
</description>
<dependencies>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-common</artifactId>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<!-- RPC 远程调用相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version> <!-- 推荐使用最新稳定版本 -->
</dependency>
<!-- 防止进入swagger页面报类型转换错误排除3.0.0中的引用手动增加1.6.2版本 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.2</version>
</dependency>
<!-- Swagger Core -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-core</artifactId>
<version>2.2.20</version>
</dependency>
<!-- Swagger Models -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models</artifactId>
<version>2.2.20</version>
</dependency>
<!-- EasyExcel 核心库 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>3.5.9</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.tashow.cloud</groupId>
<artifactId>tashow-data-mybatis</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,4 @@
/**
* infra API 包,定义暴露给其它模块的 API
*/
package com.tashow.cloud.productapi.api;

View File

@@ -0,0 +1,24 @@
package com.tashow.cloud.productapi.api.product;
import com.tashow.cloud.productapi.api.product.dto.CategoryDO;
import com.tashow.cloud.productapi.api.product.dto.CategoryDto;
import com.tashow.cloud.productapi.enums.ApiConstants;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
/** RPC 服务 - 参数配置 */
public interface CategoryApi {
String PREFIX = ApiConstants.PREFIX + "/category";
/** 根据参数键查询参数值 */
@GetMapping(PREFIX + "/categoryList")
List<CategoryDO> categoryList(@RequestParam(value = "grade", required = false) Integer grade,
@RequestParam(value = "categoryId", required = false) Long categoryId,
@RequestParam(value = "categoryName", required = false) String categoryName,
@RequestParam(value = "status", required = false) Integer status);
}

View File

@@ -0,0 +1,83 @@
package com.tashow.cloud.productapi.api.product.dto;
import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO;
import com.tashow.cloud.productapi.general.StringListTypeHandler;
import lombok.*;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.List;
/**
* 产品类目 DO
*
* @author 芋道源码
*/
@TableName("tz_category")
@KeySequence("tz_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CategoryDO extends BaseDO {
/**
* 类目ID
*/
@TableId
private Long categoryId;
/**
* 店铺ID
*/
private Long shopId;
/**
* 父节点
*/
private Long parentId;
/**
* 父节名称
*/
private String parentName;
/**
* 产品类目名称
*/
private String categoryName;
/**
* 类目图标
*/
private String icon;
/**
* 类目的显示图片
*/
private String pic;
/**
* 类目描述
*/
private String description;
/**
* 标签
*/
@TableField(typeHandler = StringListTypeHandler.class)
private List<String> tag;
/**
* 排序
*/
private Integer sort;
/**
* 默认是1表示正常状态,0为下线状态
*/
private Integer status;
/**
* 分类层级 1、2、3级
*/
private Integer grade;
}

View File

@@ -0,0 +1,72 @@
package com.tashow.cloud.productapi.api.product.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.tashow.cloud.productapi.general.StringListTypeHandler;
import lombok.*;
import java.util.List;
/**
* 产品类目 DO
*
* @author 芋道源码
*/
@Data
public class CategoryDto {
/**
* 类目ID
*/
private Long categoryId;
/**
* 店铺ID
*/
private Long shopId;
/**
* 父节点
*/
private Long parentId;
/**
* 父节名称
*/
private String parentName;
/**
* 产品类目名称
*/
private String categoryName;
/**
* 类目图标
*/
private String icon;
/**
* 类目的显示图片
*/
private String pic;
/**
* 类目描述
*/
private String description;
/**
* 标签
*/
@TableField(typeHandler = StringListTypeHandler.class)
private List<String> tag;
/**
* 排序
*/
private Integer sort;
/**
* 默认是1表示正常状态,0为下线状态
*/
private Integer status;
/**
* 分类层级 1、2、3级
*/
private Integer grade;
}

Some files were not shown because too many files have changed in this diff Show More