Compare commits

...

43 Commits

Author SHA1 Message Date
weike6538 d2ae17a538 build: 添加 nacos-client 依赖
continuous-integration/drone Build is passing Details
- 在 pom.xml 文件中添加了 nacos-client 依赖
- 组ID:com.alibaba.nacos
- 软件包ID:nacos-client
- 版本:1.4.1
2025-07-10 15:12:26 +08:00
gitea 4d72d4ee0e 更新 yudao-gateway/src/main/resources/application-dev.yaml
continuous-integration/drone Build is passing Details
fix:修改nacos配置
2025-07-10 11:41:03 +08:00
gitea 41d0f0d23d 更新 yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml
fix:修改nacos配置
2025-07-10 11:40:30 +08:00
gitea 72091b7609 更新 yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-dev.yaml
fix:修改nacos配置
2025-07-10 11:38:59 +08:00
gitea d5a64de89f 更新 yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-dev.yaml
continuous-integration/drone Build is passing Details
fix:修改infra的nacos配置
2025-07-10 11:17:37 +08:00
gitea e4f14d78f2 更新 yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml
fix:修改system的nacos配置
2025-07-10 11:16:17 +08:00
gitea 9d1adbcfce 更新 yudao-gateway/src/main/resources/application-dev.yaml
fix:修改gateway的nacos配置
2025-07-10 11:14:00 +08:00
gitea 24e4e405f3 更新 yudao-gateway/src/main/resources/application-dev.yaml
continuous-integration/drone Build is passing Details
fix:修改nacos配置
2025-07-09 20:03:59 +08:00
gitea b83b5a6bc5 更新 yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-dev.yaml
fix:修改数据库配置
2025-07-09 20:01:06 +08:00
gitea bb5e643ced 更新 yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml
fix:修改数据库配置
2025-07-09 19:48:40 +08:00
gitea 86ce3c911c 更新 yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml
fix:修改数据库配置
2025-07-09 19:45:06 +08:00
gitea 7a84183af0 Update file content
continuous-integration/drone Build is passing Details
2025-07-09 11:21:55 +08:00
gitea b37f856d60 Update file content 2025-07-09 11:21:55 +08:00
gitea fd98af06d1 Update file content 2025-07-09 11:21:55 +08:00
gitea e5b51fcf21 Update file content 2025-07-09 11:21:54 +08:00
gitea f0cceb3354 Update file content 2025-07-09 11:21:53 +08:00
gitea 5ed9ead855 Update file content 2025-07-09 11:21:53 +08:00
gitea 9cf9cf3da1 Update file content 2025-07-09 11:21:53 +08:00
lujianxin 6a6f6ed005 style(yudao-module-system-biz): 调整 Redis 配置参数格式
- 移除了 Redis 配置中的 database 和 password 参数后的换行符
-保持了其他配置参数的格式不变
2025-07-04 09:53:33 +08:00
lujianxin 458af951cb Merge remote-tracking branch 'origin/dev-feature/v1.1' into dev-feature/v1.1 2025-07-03 11:23:40 +08:00
lujianxin 0dbf3568ae feat(system): 关闭演示模式- 将 yudao.demo配置项从 true 修改为 false,关闭演示模式 2025-07-03 11:23:22 +08:00
weike6538 318eeae8e8 feat(system): 在 AdminUserRespDTO 中添加 tenantId 字段
- 在 AdminUserRespDTO 类中添加 tenantId 字段,用于表示租户 ID
- 该字段使用 @Schema 注解进行描述,包括 requiredMode 和 example 属性
2025-07-03 10:55:30 +08:00
weike6538 f8fb95130b Merge remote-tracking branch 'origin/dev-feature/v1.1' into dev-feature/v1.1 2025-06-26 18:27:32 +08:00
weike6538 25d4f4cf02 feat(security): 修复多租户环境下用户切换问题
- 在 TokenAuthenticationFilter 中添加逻辑,为没有 tenantId 的用户动态设置 tenantId
- 通过 AdminUserApi 获取用户信息,确保跨租户切换时能够正确获取目标租户信息
2025-06-26 18:27:23 +08:00
lujianxin 9676cb02d5 ci:优化 Docker 部署流程
- 添加步骤停止和删除现有容器及镜像
- 修正 docker-compose.yml 中的容器名称
- 更改 Dockerfile 中的 Spring 配置文件
2025-06-25 10:33:43 +08:00
lujianxin fb6853f57c ci(drone): 优化 Drone构建流程
- 重构构建步骤,提高流程清晰度
- 添加文件存在性检查和错误处理,增强构建鲁棒性
- 优化目录结构创建方式
- 更新 Docker 镜像构建步骤
- 调整 Docker Compose 文件处理方式
- 移除未使用的触发配置
2025-06-24 18:10:14 +08:00
lujianxin a8c3996cfa build(drone): 更新 Drone 构建配置和 Docker 部署文件
- 修改 .drone.yml 中的 Maven 构建命令,使用新的模块路径
- 更新模块路径为 yudao-module-system/yudao-module-system-biz 和 yudao-module-infra/yudao-module-infra-biz
- 修改 Docker 镜像名称,使用 yudao 前缀替代 ruoyi
- 更新 docker-compose.yml 中的服务定义,使用新的镜像名称和容器名称
2025-06-24 09:12:19 +08:00
lujianxin e720e17d76 ci(drone): 更新构建配置以支持 Maven 构建
- 新增 maven-build 步骤,使用 Maven 进行项目构建- 更新 build-jar 步骤中的 JAR 文件路径
-优化构建流程,提高构建效率
2025-06-23 18:00:12 +08:00
lujianxin 9389fee8bd build:移除环境变量并关闭演示模式
- 从 .drone.yml 中移除了 APP_VERSION 环境变量
-将 yudao-module-infra 的演示模式设置为 false
2025-06-23 15:29:57 +08:00
lujianxin c2ff984c12 ci:重构 Drone CI/CD 流程
- 更新 .drone.yml 文件,增加多服务构建和部署步骤
- 修改 Dockerfile,简化为单层结构并直接运行 JAR 文件
- 新增 docker-compose.yml 文件,定义多服务部署配置
- 优化 CI/CD 流程,支持多服务同时构建和部署
2025-06-23 14:37:06 +08:00
weike001 dea7db83b9 feat(system): 修改验证码默认配置为关闭
- 将 captchaEnable属性的默认值从 true 修改为 false
- 此修改旨在减少不必要的麻烦,提升用户体验
2025-06-13 17:32:48 +08:00
weike001 29ce6e4d92 Merge remote-tracking branch 'origin/dev-feature/v1.1' into dev-feature/v1.1 2025-06-13 10:23:15 +08:00
weike001 80b621127f build:切换配置文件至开发环境
- 将所有模块的 application.yaml 文件中的 profiles.active从 local 改为 dev
- 更新多个模块的 application-dev.yaml 文件中的 Nacos 服务器地址、数据库连接信息和 Redis 配置
2025-06-13 10:22:50 +08:00
qihai 878150b384 ci: 添加 Drone CI 配置文件和 Docker 部署脚本
- 新增 .drone.yml 文件,配置 Maven 构建和 Docker 部署流程- 添加 docker.sh 脚本,用于构建和运行 Docker镜像
- 创建 Dockerfile,定义基于 OpenJDK 17 的 Docker 镜像
- 编写 start.sh 脚本,启动 Java 应用
2025-06-09 15:41:26 +08:00
weike001 3be96d9bfc Merge remote-tracking branch 'refs/remotes/origin/dev-feature/ai-v1.0' into dev-feature/v1.1 2025-05-26 15:39:26 +08:00
ganliang5722 04b6793941 1.添加模型应用及对话内容 2025-03-05 15:01:12 +08:00
linhuan1357 e36c60af92 fix: chataipom依赖 2025-03-04 09:24:55 +08:00
linhuan1357 dab9fa382a fix: chatai代码迁移及修改 2025-03-03 09:28:33 +08:00
zhangjiahao 27a28c6817 fix: langchat迁移 2025-02-24 17:20:24 +08:00
linhuan1357 3045d49e27 fix: chatai代码迁移 2025-02-24 14:44:50 +08:00
weike001 6bd0b2f0e0 feat(mybatis): 添加通用查询和分页功能
- 新增 AutoQueryUtil 工具类,实现自动查询功能
- 添加 BaseEntity基类,包含通用的创建和更新字段
- 修改 DefaultDBFieldHandler,支持 BaseEntity 的字段填充
- 新增 PageQuery 类,用于构建分页查询对象
- 添加 TableDataInfo 类,用于封装分页查询结果
- 在 ServletUtils 中增加 getHeader 方法,用于获取请求头信息
2025-02-20 15:01:49 +08:00
ganliang 08a2789aad 1.添加本地nacos 2025-02-19 10:35:08 +08:00
weike001 b62b7c75f5 feat: 应用程序前后端代码生成 2024-12-27 17:29:02 +08:00
210 changed files with 13362 additions and 182 deletions

85
.drone.yml Normal file
View File

@ -0,0 +1,85 @@
kind: pipeline
type: docker
name: yd-yunxing-server # 服务名成可与jar包名保持一致
steps:
- name: maven-build
image: maven:3.8.5-openjdk-17
volumes:
- name: maven-cache
path: /root/.m2
- name: build-output
path: /home/app/build
commands:
- cd /drone/src
- mvn clean package -DskipTests=true -pl yudao-gateway,yudao-module-system/yudao-module-system-biz,yudao-module-infra/yudao-module-infra-biz -am
- name: copy-jars
image: alpine
volumes:
- name: build-output
path: /home/app/build
commands:
- mkdir -p /home/app/build/gateway
- mkdir -p /home/app/build/system
- mkdir -p /home/app/build/infra
- ls -l yudao-gateway/target/ # 检查源文件是否存在
- cp yudao-gateway/target/yudao-gateway.jar /home/app/build/gateway/app.jar || echo "Failed to copy gateway jar"
- cp yudao-module-system/yudao-module-system-biz/target/yudao-module-system-biz.jar /home/app/build/system/app.jar || echo "Failed to copy system biz jar"
- cp yudao-module-infra/yudao-module-infra-biz/target/yudao-module-infra-biz.jar /home/app/build/infra/app.jar || echo "Failed to copy infra biz jar"
- cp Dockerfile /home/app/build/
- cp docker-compose.yml /home/app/build/
- name: build-docker-images
image: docker
volumes:
- name: build-output
path: /home/app/build
- name: docker
path: /var/run/docker.sock
commands:
- # 停止容器(如果存在)
- docker inspect --type=container yudao-gateway >/dev/null 2>&1 && docker stop yudao-gateway || true
- docker inspect --type=container yudao-module-system >/dev/null 2>&1 && docker stop yudao-module-system || true
- docker inspect --type=container yudao-module-infra >/dev/null 2>&1 && docker stop yudao-module-infra || true
- # 删除容器(如果存在)
- docker inspect --type=container yudao-gateway >/dev/null 2>&1 && docker rm yudao-gateway || true
- docker inspect --type=container yudao-module-system >/dev/null 2>&1 && docker rm yudao-module-system || true
- docker inspect --type=container yudao-module-infra >/dev/null 2>&1 && docker rm yudao-module-infra || true
- # 删除镜像(如果存在)
- docker inspect --type=image yudao-gateway >/dev/null 2>&1 && docker rmi yudao-gateway || true
- docker inspect --type=image yudao-module-system >/dev/null 2>&1 && docker rmi yudao-module-system || true
- docker inspect --type=image yudao-module-infra >/dev/null 2>&1 && docker rmi yudao-module-infra || true
- cd /home/app/build
- cd gateway && docker build -t yudao-gateway:v1.0 -f ../Dockerfile .
- cd ../system && docker build -t yudao-module-system:v1.0 -f ../Dockerfile .
- cd ../infra && docker build -t yudao-module-infra:v1.0 -f ../Dockerfile .
- name: deploy-with-compose
image: docker/compose:1.29.2
environment:
APP_VERSION: v1.0
volumes:
- name: build-output
path: /home/app/build
- name: docker
path: /var/run/docker.sock
commands:
- cd /home/app/build
- sed -i "s/v1.0/v1.0/g" docker-compose.yml
- docker-compose -f docker-compose.yml up -d
volumes:
- name: maven-cache
host:
path: /home/data/maven/cache
- name: build-output
host:
path: /home/data/maven/build
- name: docker
host:
path: /var/run/docker.sock

8
Dockerfile Normal file
View File

@ -0,0 +1,8 @@
# 目前制作docker镜像依赖的jdk基线项目使用jdk17
FROM openjdk:17.0.2-oraclelinux8
WORKDIR /home/app
COPY app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=dev"]

26
docker-compose.yml Normal file
View File

@ -0,0 +1,26 @@
version: '3.8'
services:
gateway:
image: yudao-gateway:v1.0
container_name: yudao-gateway
ports:
- "48080:48080"
environment:
SPRING_PROFILES_ACTIVE: dev
system:
image: yudao-module-system:v1.0
container_name: yudao-module-system
ports:
- "48081:48081"
environment:
SPRING_PROFILES_ACTIVE: dev
infra:
image: yudao-module-infra:v1.0
container_name: yudao-module-infra
ports:
- "48082:48082"
environment:
SPRING_PROFILES_ACTIVE: dev

22
docker.sh Normal file
View File

@ -0,0 +1,22 @@
#!/bin/sh
# 定义应用组名
group_name='test'
# 定义应用名称建议与drone中服务名和jar包名保持一致
app_name='yd-yunxing-server'
# 定义应用版本
app_version='1.0'
echo '----copy jar----'
docker stop ${app_name}
echo '----stop container----'
docker rm ${app_name}
echo '----rm container----'
docker rmi ${group_name}/${app_name}:${app_version}
echo '----rm image----'
# 打包编译docker镜像
docker build -t ${group_name}/${app_name}:${app_version} .
echo '----build image----'
docker run -p 48080:8094 --name ${app_name} \
-e TZ="Asia/Shanghai" \
-v /etc/localtime:/etc/localtime \
-d ${group_name}/${app_name}:${app_version}
echo '----start container----'

316
nacos/LICENSE Normal file
View File

@ -0,0 +1,316 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (properties) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
------
This product has a bundle logback, which is available under the EPL v1.0 License.
The source code of logback can be found at https://github.com/qos-ch/logback.
Logback LICENSE
---------------
Logback: the reliable, generic, fast and flexible logging framework.
Copyright (C) 1999-2015, QOS.ch. All rights reserved.
This program and the accompanying materials are dual-licensed under
either the terms of the Eclipse Public License v1.0 as published by
the Eclipse Foundation
or (per the licensee's choosing)
under the terms of the GNU Lesser General Public License version 2.1
as published by the Free Software Foundation.
------
This product has a bundle slf4j, which is available under the MIT License.
The source code of slf4j can be found at https://github.com/qos-ch/slf4j.
Copyright (c) 2004-2017 QOS.ch
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------
This product has a bundle javassist, which is available under the ASL2 License.
The source code of javassist can be found at https://github.com/jboss-javassist/javassist.
Copyright (C) 1999- by Shigeru Chiba, All rights reserved.
Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation simple.
It is a class library for editing bytecodes in Java; it enables Java programs to define a new class
at runtime and to modify a class file when the JVM loads it. Unlike other similar bytecode editors,
Javassist provides two levels of API: source level and bytecode level. If the users use the source- level API,
they can edit a class file without knowledge of the specifications of the Java bytecode.
The whole API is designed with only the vocabulary of the Java language.
You can even specify inserted bytecode in the form of source text; Javassist compiles it on the fly.
On the other hand, the bytecode-level API allows the users to directly edit a class file as other editors.
This software is distributed under the Mozilla Public License Version 1.1,
the GNU Lesser General Public License Version 2.1 or later, or the Apache License Version 2.0.
------
This product has a bundle jna, which is available under the ASL2 License.
The source code of jna can be found at https://github.com/java-native-access/jna.
This copy of JNA is licensed under the
Apache (Software) License, version 2.0 ("the License").
See the License for details about distribution rights, and the
specific rights regarding derivate works.
You may obtain a copy of the License at:
http://www.apache.org/licenses/
A copy is also included in the downloadable source code package
containing JNA, in file "AL2.0", under the same directory
as this file.
------
This product has a bundle guava, which is available under the ASL2 License.
The source code of guava can be found at https://github.com/google/guava.
Copyright (C) 2007 The Guava authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
------
This product has a bundle OpenMessaging, which is available under the ASL2 License.
The source code of OpenMessaging can be found at https://github.com/openmessaging/openmessaging.
Copyright (C) 2017 The OpenMessaging authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

36
nacos/NOTICE Normal file
View File

@ -0,0 +1,36 @@
Nacos
Copyright 2018-2019 The Apache Software Foundation
This product includes software developed at
The Alibaba MiddleWare Group.
------
This product has a bundle netty:
The Spring oot Project
=================
Please visit the Netty web site for more information:
* http://netty.io/
Copyright 2014 The Netty Project
The Netty Project licenses this file to you under the Apache License,
version 2.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Also, please refer to each LICENSE.<component>.txt file, which is located in
the 'license' directory of the distribution file, for the license terms of the
components that this product depends on.
------
This product has a bundle commons-lang, which includes software from the Spring Framework,
under the Apache License 2.0 (see: StringUtils.containsWhitespace())

40
nacos/bin/shutdown.cmd Normal file
View File

@ -0,0 +1,40 @@
@echo off
:: Copyright 1999-2018 Alibaba Group Holding Ltd.
:: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License.
:: You may obtain a copy of the License at
::
:: http://www.apache.org/licenses/LICENSE-2.0
::
:: Unless required by applicable law or agreed to in writing, software
:: distributed under the License is distributed on an "AS IS" BASIS,
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
:: See the License for the specific language governing permissions and
:: limitations under the License.
if not exist "%JAVA_HOME%\bin\jps.exe" (
echo Please set the JAVA_HOME variable in your environment to the correct JDK directory.
echo JDK8 or later is recommended!
EXIT /B 1
)
setlocal
set "PATH=%JAVA_HOME%\bin;%PATH%"
echo Killing Nacos server...
:: Find and kill Nacos server process
set "NACOS_RUNNING=false"
for /f "tokens=1" %%i in ('jps -m ^| find "nacos.nacos"') do (
set "NACOS_RUNNING=true"
taskkill /F /PID %%i
)
if "%NACOS_RUNNING%"=="true" (
echo Nacos server stopped.
) else (
echo Nacos server is not running.
)
echo Done!

28
nacos/bin/shutdown.sh Normal file
View File

@ -0,0 +1,28 @@
#!/bin/bash
# Copyright 1999-2018 Alibaba Group Holding Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cd `dirname $0`/../target
target_dir=`pwd`
pid=`pgrep -f nacos.nacos`
if [ -z "$pid" ] ; then
echo "No nacosServer running."
exit -1;
fi
echo "The nacosServer(${pid}) is running..."
kill ${pid}
echo "Send shutdown request to nacosServer(${pid}) OK"

96
nacos/bin/startup.cmd Normal file
View File

@ -0,0 +1,96 @@
@echo off
rem Copyright 1999-2018 Alibaba Group Holding Ltd.
rem Licensed under the Apache License, Version 2.0 (the "License");
rem you may not use this file except in compliance with the License.
rem You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.
if not exist "%JAVA_HOME%\bin\java.exe" echo Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better! & EXIT /B 1
set "JAVA=%JAVA_HOME%\bin\java.exe"
setlocal enabledelayedexpansion
set BASE_DIR=%~dp0
rem added double quotation marks to avoid the issue caused by the folder names containing spaces.
rem removed the last 5 chars(which means \bin\) to get the base DIR.
set BASE_DIR="%BASE_DIR:~0,-5%"
set CUSTOM_SEARCH_LOCATIONS=file:%BASE_DIR%/conf/
set MODE="cluster"
set FUNCTION_MODE="all"
set SERVER=nacos-server
set MODE_INDEX=-1
set FUNCTION_MODE_INDEX=-1
set SERVER_INDEX=-1
set EMBEDDED_STORAGE_INDEX=-1
set EMBEDDED_STORAGE=""
set i=0
for %%a in (%*) do (
if "%%a" == "-m" ( set /a MODE_INDEX=!i!+1 )
if "%%a" == "-f" ( set /a FUNCTION_MODE_INDEX=!i!+1 )
if "%%a" == "-s" ( set /a SERVER_INDEX=!i!+1 )
if "%%a" == "-p" ( set /a EMBEDDED_STORAGE_INDEX=!i!+1 )
set /a i+=1
)
set i=0
for %%a in (%*) do (
if %MODE_INDEX% == !i! ( set MODE="%%a" )
if %FUNCTION_MODE_INDEX% == !i! ( set FUNCTION_MODE="%%a" )
if %SERVER_INDEX% == !i! (set SERVER="%%a")
if %EMBEDDED_STORAGE_INDEX% == !i! (set EMBEDDED_STORAGE="%%a")
set /a i+=1
)
rem if nacos startup mode is standalone
if %MODE% == "standalone" (
echo "nacos is starting with standalone"
set "NACOS_OPTS=-Dnacos.standalone=true"
if "%CUSTOM_NACOS_MEMORY%"=="" ( set "CUSTOM_NACOS_MEMORY=-Xms512m -Xmx512m -Xmn256m" )
set "NACOS_JVM_OPTS=%CUSTOM_NACOS_MEMORY%"
)
rem if nacos startup mode is cluster
if %MODE% == "cluster" (
echo "nacos is starting with cluster"
if %EMBEDDED_STORAGE% == "embedded" (
set "NACOS_OPTS=-DembeddedStorage=true"
)
if "%CUSTOM_NACOS_MEMORY%"=="" ( set "CUSTOM_NACOS_MEMORY=-Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m" )
set "NACOS_JVM_OPTS=-server %CUSTOM_NACOS_MEMORY% -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%BASE_DIR%\logs\java_heapdump.hprof -XX:-UseLargePages"
)
rem set nacos's functionMode
if %FUNCTION_MODE% == "config" (
set "NACOS_OPTS=%NACOS_OPTS% -Dnacos.functionMode=config"
)
if %FUNCTION_MODE% == "naming" (
set "NACOS_OPTS=%NACOS_OPTS% -Dnacos.functionMode=naming"
)
rem set nacos options
set "NACOS_OPTS=%NACOS_OPTS% -Dloader.path=%BASE_DIR%/plugins,%BASE_DIR%/plugins/health,%BASE_DIR%/plugins/cmdb,%BASE_DIR%/plugins/selector"
set "NACOS_OPTS=%NACOS_OPTS% -Dnacos.home=%BASE_DIR%"
set "NACOS_OPTS=%NACOS_OPTS% -jar %BASE_DIR%\target\%SERVER%.jar"
rem set nacos spring config location
set "NACOS_CONFIG_OPTS=--spring.config.additional-location=%CUSTOM_SEARCH_LOCATIONS%"
rem set nacos log4j file location
set "NACOS_LOG4J_OPTS=--logging.config=%BASE_DIR%/conf/nacos-logback.xml"
set COMMAND="%JAVA%" %NACOS_JVM_OPTS% %NACOS_OPTS% %NACOS_CONFIG_OPTS% %NACOS_LOG4J_OPTS% nacos.nacos %*
rem start nacos command
%COMMAND%

153
nacos/bin/startup.sh Normal file
View File

@ -0,0 +1,153 @@
#!/bin/bash
# Copyright 1999-2018 Alibaba Group Holding Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cygwin=false
darwin=false
os400=false
case "`uname`" in
CYGWIN*) cygwin=true;;
Darwin*) darwin=true;;
OS400*) os400=true;;
esac
error_exit ()
{
echo "ERROR: $1 !!"
exit 1
}
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/opt/taobao/java
[ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME
if [ -z "$JAVA_HOME" ]; then
if $darwin; then
if [ -x '/usr/libexec/java_home' ] ; then
export JAVA_HOME=`/usr/libexec/java_home`
elif [ -d "/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home" ]; then
export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home"
fi
else
JAVA_PATH=`dirname $(readlink -f $(which javac))`
if [ "x$JAVA_PATH" != "x" ]; then
export JAVA_HOME=`dirname $JAVA_PATH 2>/dev/null`
fi
fi
if [ -z "$JAVA_HOME" ]; then
JAVA_PATH=$(which java)
if [ -z "$JAVA_PATH" ]; then
error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better!"
fi
JAVA_HOME=$(dirname "$JAVA_PATH")/..
export JAVA_HOME=$(cd "$JAVA_HOME" && pwd)
fi
fi
export SERVER="nacos-server"
export MODE="cluster"
export FUNCTION_MODE="all"
export MEMBER_LIST=""
export EMBEDDED_STORAGE=""
while getopts ":m:f:s:c:p:" opt
do
case $opt in
m)
MODE=$OPTARG;;
f)
FUNCTION_MODE=$OPTARG;;
s)
SERVER=$OPTARG;;
c)
MEMBER_LIST=$OPTARG;;
p)
EMBEDDED_STORAGE=$OPTARG;;
?)
echo "Unknown parameter"
exit 1;;
esac
done
export JAVA_HOME
export JAVA="$JAVA_HOME/bin/java"
export BASE_DIR=`cd $(dirname $0)/..; pwd`
export CUSTOM_SEARCH_LOCATIONS=file:${BASE_DIR}/conf/
#===========================================================================================
# JVM Configuration
#===========================================================================================
if [[ "${MODE}" == "standalone" ]]; then
JAVA_OPT="${JAVA_OPT} ${CUSTOM_NACOS_MEMORY:- -Xms512m -Xmx512m -Xmn256m}"
JAVA_OPT="${JAVA_OPT} -Dnacos.standalone=true"
else
if [[ "${EMBEDDED_STORAGE}" == "embedded" ]]; then
JAVA_OPT="${JAVA_OPT} -DembeddedStorage=true"
fi
JAVA_OPT="${JAVA_OPT} -server ${CUSTOM_NACOS_MEMORY:- -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m}"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
fi
if [[ "${FUNCTION_MODE}" == "config" ]]; then
JAVA_OPT="${JAVA_OPT} -Dnacos.functionMode=config"
elif [[ "${FUNCTION_MODE}" == "naming" ]]; then
JAVA_OPT="${JAVA_OPT} -Dnacos.functionMode=naming"
fi
JAVA_OPT="${JAVA_OPT} -Dnacos.member.list=${MEMBER_LIST}"
JAVA_MAJOR_VERSION=$($JAVA -version 2>&1 | sed -E -n 's/.* version "([0-9]*).*$/\1/p')
if [[ "$JAVA_MAJOR_VERSION" -ge "9" ]] ; then
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${BASE_DIR}/logs/nacos_gc.log:time,tags:filecount=10,filesize=100m"
else
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 "
JAVA_OPT_EXT_FIX="-Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext"
JAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR}/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
fi
JAVA_OPT="${JAVA_OPT} -Dloader.path=${BASE_DIR}/plugins,${BASE_DIR}/plugins/health,${BASE_DIR}/plugins/cmdb,${BASE_DIR}/plugins/selector"
JAVA_OPT="${JAVA_OPT} -Dnacos.home=${BASE_DIR}"
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/target/${SERVER}.jar"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} --spring.config.additional-location=${CUSTOM_SEARCH_LOCATIONS}"
JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/conf/nacos-logback.xml"
JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288"
if [ ! -d "${BASE_DIR}/logs" ]; then
mkdir ${BASE_DIR}/logs
fi
echo "$JAVA $JAVA_OPT_EXT_FIX ${JAVA_OPT}"
if [[ "${MODE}" == "standalone" ]]; then
echo "nacos is starting with standalone"
else
echo "nacos is starting with cluster"
fi
# check the start.out log output file
if [ ! -f "${BASE_DIR}/logs/start.out" ]; then
touch "${BASE_DIR}/logs/start.out"
fi
# start
echo "$JAVA $JAVA_OPT_EXT_FIX ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
if [[ "$JAVA_OPT_EXT_FIX" == "" ]]; then
nohup "$JAVA" ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &
else
nohup "$JAVA" "$JAVA_OPT_EXT_FIX" ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &
fi
echo "nacos is starting. you can check the ${BASE_DIR}/logs/start.out"

View File

@ -0,0 +1,27 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
ALTER TABLE `config_info_tag`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `his_config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL AFTER `src_user`;
ALTER TABLE `config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `config_info_beta`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;

View File

@ -0,0 +1 @@
Authentication has not been enabled in cluster, please refer to <a href="https://nacos.io/en-us/docs/v2/guide/user/auth.html">Documentation</a> to enable~

View File

@ -0,0 +1 @@
当前集群没有开启鉴权,请参考<a href="https://nacos.io/zh-cn/docs/v2/guide/user/auth.html">文档</a>开启鉴权~

View File

@ -0,0 +1,297 @@
#
# Copyright 1999-2021 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#*************** Spring Boot Related Configurations ***************#
### Default web context path:
server.servlet.contextPath=/nacos
### Include message field
server.error.include-message=ALWAYS
### Default web server port:
server.port=8848
#*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false
### Specify local server's IP:
# nacos.inetutils.ip-address=
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
# spring.datasource.platform=mysql
spring.sql.init.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.0.17:3306/ruoyi-vue-pro?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
### the maximum retry times for push
nacos.config.push.maxRetryTime=50
#*************** Naming Module Related Configurations ***************#
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true
### If enable the instance auto expiration, kind like of health check of instance:
# nacos.naming.expireInstance=true
### Add in 2.0.0
### The interval to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.interval=60000
### The expired time to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.expired-time=60000
### The interval to clean expired metadata, unit: milliseconds.
# nacos.naming.clean.expired-metadata.interval=5000
### The expired time to clean metadata, unit: milliseconds.
# nacos.naming.clean.expired-metadata.expired-time=60000
### The delay time before push task to execute from service changed, unit: milliseconds.
# nacos.naming.push.pushTaskDelay=500
### The timeout for push task execute, unit: milliseconds.
# nacos.naming.push.pushTaskTimeout=5000
### The delay time for retrying failed push task, unit: milliseconds.
# nacos.naming.push.pushTaskRetryDelay=1000
### Since 2.0.3
### The expired time for inactive client, unit: milliseconds.
# nacos.naming.client.expired.time=180000
#*************** CMDB Module Related Configurations ***************#
### The interval to dump external CMDB in seconds:
# nacos.cmdb.dumpTaskInterval=3600
### The interval of polling data change event in seconds:
# nacos.cmdb.eventTaskInterval=10
### The interval of loading labels in seconds:
# nacos.cmdb.labelTaskInterval=300
### If turn on data loading task:
# nacos.cmdb.loadDataAtStart=false
#***********Metrics for tomcat **************************#
server.tomcat.mbeanregistry.enabled=true
#***********Expose prometheus and health **************************#
#management.endpoints.web.exposure.include=prometheus,health
### Metrics for elastic search
management.metrics.export.elastic.enabled=false
#management.metrics.export.elastic.host=http://localhost:9200
### Metrics for influx
management.metrics.export.influx.enabled=false
#management.metrics.export.influx.db=springboot
#management.metrics.export.influx.uri=http://localhost:8086
#management.metrics.export.influx.auto-create-db=true
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true
#*************** Access Log Related Configurations ***************#
### If turn on the access log:
server.tomcat.accesslog.enabled=true
### file name pattern, one file per hour
server.tomcat.accesslog.rotate=true
server.tomcat.accesslog.file-date-format=.yyyy-MM-dd-HH
### The access log pattern:
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
### The directory of access log:
server.tomcat.basedir=file:.
#*************** Access Control Related Configurations ***************#
### If enable spring security, this option is deprecated in 1.2.0:
#spring.security.enabled=false
### The ignore urls of auth
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=false
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true
### Since 1.4.1, Turn on/off white auth for user-agent: nacos-server, only for upgrade from old version.
nacos.core.auth.enable.userAgentAuthWhite=false
### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
nacos.core.auth.server.identity.key=
nacos.core.auth.server.identity.value=
### worked when nacos.core.auth.system.type=nacos
### The token expiration in seconds:
nacos.core.auth.plugin.nacos.token.cache.enable=false
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=
### worked when nacos.core.auth.system.type=ldap\uFF0C{0} is Placeholder,replace login username
#nacos.core.auth.ldap.url=ldap://localhost:389
#nacos.core.auth.ldap.basedc=dc=example,dc=org
#nacos.core.auth.ldap.userDn=cn=admin,${nacos.core.auth.ldap.basedc}
#nacos.core.auth.ldap.password=admin
#nacos.core.auth.ldap.userdn=cn={0},dc=example,dc=org
#nacos.core.auth.ldap.filter.prefix=uid
#nacos.core.auth.ldap.case.sensitive=true
#nacos.core.auth.ldap.ignore.partial.result.exception=false
#*************** Control Plugin Related Configurations ***************#
# plugin type
#nacos.plugin.control.manager.type=nacos
# local control rule storage dir, default ${nacos.home}/data/connection and ${nacos.home}/data/tps
#nacos.plugin.control.rule.local.basedir=${nacos.home}
# external control rule storage type, if exist
#nacos.plugin.control.rule.external.storage=
#*************** Config Change Plugin Related Configurations ***************#
# webhook
#nacos.core.config.plugin.webhook.enabled=false
# It is recommended to use EB https://help.aliyun.com/document_detail/413974.html
#nacos.core.config.plugin.webhook.url=http://localhost:8080/webhook/send?token=***
# The content push max capacity ,byte
#nacos.core.config.plugin.webhook.contentMaxCapacity=102400
# whitelist
#nacos.core.config.plugin.whitelist.enabled=false
# The import file suffixs
#nacos.core.config.plugin.whitelist.suffixs=xml,text,properties,yaml,html
# fileformatcheck,which validate the import file of type and content
#nacos.core.config.plugin.fileformatcheck.enabled=false
#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
nacos.istio.mcp.server.enabled=false
#*************** Core Related Configurations ***************#
### set the WorkerID manually
# nacos.core.snowflake.worker-id=
### Member-MetaData
# nacos.core.member.meta.site=
# nacos.core.member.meta.adweight=
# nacos.core.member.meta.weight=
### MemberLookup
### Addressing pattern category, If set, the priority is highest
# nacos.core.member.lookup.type=[file,address-server]
## Set the cluster list with a configuration file or command-line argument
# nacos.member.list=192.168.16.101:8847?raft_port=8807,192.168.16.101?raft_port=8808,192.168.16.101:8849?raft_port=8809
## for AddressServerMemberLookup
# Maximum number of retries to query the address server upon initialization
# nacos.core.address-server.retry=5
## Server domain name address of [address-server] mode
# address.server.domain=jmenv.tbsite.net
## Server port of [address-server] mode
# address.server.port=8080
## Request address of [address-server] mode
# address.server.url=/nacos/serverlist
#*************** JRaft Related Configurations ***************#
### Sets the Raft cluster election timeout, default value is 5 second
# nacos.core.protocol.raft.data.election_timeout_ms=5000
### Sets the amount of time the Raft snapshot will execute periodically, default is 30 minute
# nacos.core.protocol.raft.data.snapshot_interval_secs=30
### raft internal worker threads
# nacos.core.protocol.raft.data.core_thread_num=8
### Number of threads required for raft business request processing
# nacos.core.protocol.raft.data.cli_service_thread_num=4
### raft linear read strategy. Safe linear reads are used by default, that is, the Leader tenure is confirmed by heartbeat
# nacos.core.protocol.raft.data.read_index_type=ReadOnlySafe
### rpc request timeout, default 5 seconds
# nacos.core.protocol.raft.data.rpc_request_timeout_ms=5000
#*************** Distro Related Configurations ***************#
### Distro data sync delay time, when sync task delayed, task will be merged for same data key. Default 1 second.
# nacos.core.protocol.distro.data.sync.delayMs=1000
### Distro data sync timeout for one sync data, default 3 seconds.
# nacos.core.protocol.distro.data.sync.timeoutMs=3000
### Distro data sync retry delay time when sync data failed or timeout, same behavior with delayMs, default 3 seconds.
# nacos.core.protocol.distro.data.sync.retryDelayMs=3000
### Distro data verify interval time, verify synced data whether expired for a interval. Default 5 seconds.
# nacos.core.protocol.distro.data.verify.intervalMs=5000
### Distro data verify timeout for one verify, default 3 seconds.
# nacos.core.protocol.distro.data.verify.timeoutMs=3000
### Distro data load retry delay when load snapshot data failed, default 30 seconds.
# nacos.core.protocol.distro.data.load.retryDelayMs=30000
### enable to support prometheus service discovery
#nacos.prometheus.metrics.enabled=true
### Since 2.3
#*************** Grpc Configurations ***************#
## sdk grpc(between nacos server and client) configuration
## Sets the maximum message size allowed to be received on the server.
#nacos.remote.server.grpc.sdk.max-inbound-message-size=10485760
## Sets the time(milliseconds) without read activity before sending a keepalive ping. The typical default is two hours.
#nacos.remote.server.grpc.sdk.keep-alive-time=7200000
## Sets a time(milliseconds) waiting for read activity after sending a keepalive ping. Defaults to 20 seconds.
#nacos.remote.server.grpc.sdk.keep-alive-timeout=20000
## Sets a time(milliseconds) that specify the most aggressive keep-alive time clients are permitted to configure. The typical default is 5 minutes
#nacos.remote.server.grpc.sdk.permit-keep-alive-time=300000
## cluster grpc(inside the nacos server) configuration
#nacos.remote.server.grpc.cluster.max-inbound-message-size=10485760
## Sets the time(milliseconds) without read activity before sending a keepalive ping. The typical default is two hours.
#nacos.remote.server.grpc.cluster.keep-alive-time=7200000
## Sets a time(milliseconds) waiting for read activity after sending a keepalive ping. Defaults to 20 seconds.
#nacos.remote.server.grpc.cluster.keep-alive-timeout=20000
## Sets a time(milliseconds) that specify the most aggressive keep-alive time clients are permitted to configure. The typical default is 5 minutes
#nacos.remote.server.grpc.cluster.permit-keep-alive-time=300000
## open nacos default console ui
#nacos.console.ui.enabled=true

View File

@ -0,0 +1,271 @@
#
# Copyright 1999-2021 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#*************** Spring Boot Related Configurations ***************#
### Default web context path:
server.servlet.contextPath=/nacos
### Include message field
server.error.include-message=ALWAYS
### Default web server port:
server.port=8848
#*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false
### Specify local server's IP:
# nacos.inetutils.ip-address=
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
# spring.datasource.platform=mysql
# spring.sql.init.platform=mysql
### Count of DB:
# db.num=1
### Connect URL of DB:
# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
# db.user.0=nacos
# db.password.0=nacos
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
### the maximum retry times for push
nacos.config.push.maxRetryTime=50
#*************** Naming Module Related Configurations ***************#
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true
### If enable the instance auto expiration, kind like of health check of instance:
# nacos.naming.expireInstance=true
### will be removed and replaced by `nacos.naming.clean` properties
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000
### Add in 2.0.0
### The interval to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.interval=60000
### The expired time to clean empty service, unit: milliseconds.
# nacos.naming.clean.empty-service.expired-time=60000
### The interval to clean expired metadata, unit: milliseconds.
# nacos.naming.clean.expired-metadata.interval=5000
### The expired time to clean metadata, unit: milliseconds.
# nacos.naming.clean.expired-metadata.expired-time=60000
### The delay time before push task to execute from service changed, unit: milliseconds.
# nacos.naming.push.pushTaskDelay=500
### The timeout for push task execute, unit: milliseconds.
# nacos.naming.push.pushTaskTimeout=5000
### The delay time for retrying failed push task, unit: milliseconds.
# nacos.naming.push.pushTaskRetryDelay=1000
### Since 2.0.3
### The expired time for inactive client, unit: milliseconds.
# nacos.naming.client.expired.time=180000
#*************** CMDB Module Related Configurations ***************#
### The interval to dump external CMDB in seconds:
# nacos.cmdb.dumpTaskInterval=3600
### The interval of polling data change event in seconds:
# nacos.cmdb.eventTaskInterval=10
### The interval of loading labels in seconds:
# nacos.cmdb.labelTaskInterval=300
### If turn on data loading task:
# nacos.cmdb.loadDataAtStart=false
#*************** Metrics Related Configurations ***************#
### Metrics for prometheus
#management.endpoints.web.exposure.include=*
### Metrics for elastic search
management.metrics.export.elastic.enabled=false
#management.metrics.export.elastic.host=http://localhost:9200
### Metrics for influx
management.metrics.export.influx.enabled=false
#management.metrics.export.influx.db=springboot
#management.metrics.export.influx.uri=http://localhost:8086
#management.metrics.export.influx.auto-create-db=true
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true
#*************** Access Log Related Configurations ***************#
### If turn on the access log:
server.tomcat.accesslog.enabled=true
### The access log pattern:
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
### The directory of access log:
server.tomcat.basedir=file:.
#*************** Access Control Related Configurations ***************#
### If enable spring security, this option is deprecated in 1.2.0:
#spring.security.enabled=false
### The ignore urls of auth, is deprecated in 1.2.0:
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=false
### worked when nacos.core.auth.system.type=ldap{0} is Placeholder,replace login username
#nacos.core.auth.system.type=ldap
#nacos.core.auth.ldap.url=ldap://localhost:389
#nacos.core.auth.ldap.basedc=dc=example,dc=org
#nacos.core.auth.ldap.userDn=cn=admin,${nacos.core.auth.ldap.basedc}
#nacos.core.auth.ldap.password=admin
#nacos.core.auth.ldap.userdn=cn={0},dc=example,dc=org
#nacos.core.auth.ldap.filter.prefix=uid
#nacos.core.auth.ldap.case.sensitive=true
#nacos.core.auth.ldap.ignore.partial.result.exception=false
### worked when nacos.core.auth.system.type=nacos
### The token expiration in seconds:
nacos.core.auth.plugin.nacos.token.cache.enable=false
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true
### Since 1.4.1, Turn on/off white auth for user-agent: nacos-server, only for upgrade from old version.
nacos.core.auth.enable.userAgentAuthWhite=false
### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
#nacos.core.auth.server.identity.key=example
#nacos.core.auth.server.identity.value=example
#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
nacos.istio.mcp.server.enabled=false
#*************** Core Related Configurations ***************#
### set the WorkerID manually
# nacos.core.snowflake.worker-id=
### Member-MetaData
# nacos.core.member.meta.site=
# nacos.core.member.meta.adweight=
# nacos.core.member.meta.weight=
### MemberLookup
### Addressing pattern category, If set, the priority is highest
# nacos.core.member.lookup.type=[file,address-server]
## Set the cluster list with a configuration file or command-line argument
# nacos.member.list=192.168.16.101:8847?raft_port=8807,192.168.16.101?raft_port=8808,192.168.16.101:8849?raft_port=8809
## for AddressServerMemberLookup
# Maximum number of retries to query the address server upon initialization
# nacos.core.address-server.retry=5
## Server domain name address of [address-server] mode
# address.server.domain=jmenv.tbsite.net
## Server port of [address-server] mode
# address.server.port=8080
## Request address of [address-server] mode
# address.server.url=/nacos/serverlist
#*************** JRaft Related Configurations ***************#
### Sets the Raft cluster election timeout, default value is 5 second
# nacos.core.protocol.raft.data.election_timeout_ms=5000
### Sets the amount of time the Raft snapshot will execute periodically, default is 30 minute
# nacos.core.protocol.raft.data.snapshot_interval_secs=30
### raft internal worker threads
# nacos.core.protocol.raft.data.core_thread_num=8
### Number of threads required for raft business request processing
# nacos.core.protocol.raft.data.cli_service_thread_num=4
### raft linear read strategy. Safe linear reads are used by default, that is, the Leader tenure is confirmed by heartbeat
# nacos.core.protocol.raft.data.read_index_type=ReadOnlySafe
### rpc request timeout, default 5 seconds
# nacos.core.protocol.raft.data.rpc_request_timeout_ms=5000
#*************** Distro Related Configurations ***************#
### Distro data sync delay time, when sync task delayed, task will be merged for same data key. Default 1 second.
# nacos.core.protocol.distro.data.sync.delayMs=1000
### Distro data sync timeout for one sync data, default 3 seconds.
# nacos.core.protocol.distro.data.sync.timeoutMs=3000
### Distro data sync retry delay time when sync data failed or timeout, same behavior with delayMs, default 3 seconds.
# nacos.core.protocol.distro.data.sync.retryDelayMs=3000
### Distro data verify interval time, verify synced data whether expired for a interval. Default 5 seconds.
# nacos.core.protocol.distro.data.verify.intervalMs=5000
### Distro data verify timeout for one verify, default 3 seconds.
# nacos.core.protocol.distro.data.verify.timeoutMs=3000
### Distro data load retry delay when load snapshot data failed, default 30 seconds.
# nacos.core.protocol.distro.data.load.retryDelayMs=30000
### enable to support prometheus service discovery
#nacos.prometheus.metrics.enabled=true
### Since 2.3
#*************** Grpc Configurations ***************#
## sdk grpc(between nacos server and client) configuration
## Sets the maximum message size allowed to be received on the server.
#nacos.remote.server.grpc.sdk.max-inbound-message-size=10485760
## Sets the time(milliseconds) without read activity before sending a keepalive ping. The typical default is two hours.
#nacos.remote.server.grpc.sdk.keep-alive-time=7200000
## Sets a time(milliseconds) waiting for read activity after sending a keepalive ping. Defaults to 20 seconds.
#nacos.remote.server.grpc.sdk.keep-alive-timeout=20000
## Sets a time(milliseconds) that specify the most aggressive keep-alive time clients are permitted to configure. The typical default is 5 minutes
#nacos.remote.server.grpc.sdk.permit-keep-alive-time=300000
## cluster grpc(inside the nacos server) configuration
#nacos.remote.server.grpc.cluster.max-inbound-message-size=10485760
## Sets the time(milliseconds) without read activity before sending a keepalive ping. The typical default is two hours.
#nacos.remote.server.grpc.cluster.keep-alive-time=7200000
## Sets a time(milliseconds) waiting for read activity after sending a keepalive ping. Defaults to 20 seconds.
#nacos.remote.server.grpc.cluster.keep-alive-timeout=20000
## Sets a time(milliseconds) that specify the most aggressive keep-alive time clients are permitted to configure. The typical default is 5 minutes
#nacos.remote.server.grpc.cluster.permit-keep-alive-time=300000

View File

@ -0,0 +1,21 @@
#
# Copyright 1999-2021 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#it is ip
#example
192.168.16.101:8847
192.168.16.102
192.168.16.103

View File

@ -0,0 +1 @@
当前节点已关闭Nacos开源控制台使用请修改application.properties中的nacos.console.ui.enabled参数为true打开开源控制台使用详情查看<a href="https://nacos.io/zh-cn/docs/v2/guide/admin/console-guide.html">文档</a>中关于<code>关闭默认控制台部分</code>。

227
nacos/conf/derby-schema.sql Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
CREATE SCHEMA nacos AUTHORIZATION nacos;
CREATE TABLE config_info (
id bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
app_name varchar(128),
content CLOB,
md5 varchar(32) DEFAULT NULL,
gmt_create timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
src_user varchar(128) DEFAULT NULL,
src_ip varchar(50) DEFAULT NULL,
c_desc varchar(256) DEFAULT NULL,
c_use varchar(64) DEFAULT NULL,
effect varchar(64) DEFAULT NULL,
type varchar(64) DEFAULT NULL,
c_schema LONG VARCHAR DEFAULT NULL,
encrypted_data_key LONG VARCHAR DEFAULT NULL,
constraint configinfo_id_key PRIMARY KEY (id),
constraint uk_configinfo_datagrouptenant UNIQUE (data_id,group_id,tenant_id));
CREATE INDEX configinfo_dataid_key_idx ON config_info(data_id);
CREATE INDEX configinfo_groupid_key_idx ON config_info(group_id);
CREATE INDEX configinfo_dataid_group_key_idx ON config_info(data_id, group_id);
CREATE TABLE his_config_info (
id bigint NOT NULL,
nid bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
app_name varchar(128),
content CLOB,
md5 varchar(32) DEFAULT NULL,
gmt_create timestamp NOT NULL DEFAULT '2010-05-05 00:00:00.000',
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00.000',
src_user varchar(128),
src_ip varchar(50) DEFAULT NULL,
op_type char(10) DEFAULT NULL,
encrypted_data_key LONG VARCHAR DEFAULT NULL,
constraint hisconfiginfo_nid_key PRIMARY KEY (nid));
CREATE INDEX hisconfiginfo_dataid_key_idx ON his_config_info(data_id);
CREATE INDEX hisconfiginfo_gmt_create_idx ON his_config_info(gmt_create);
CREATE INDEX hisconfiginfo_gmt_modified_idx ON his_config_info(gmt_modified);
CREATE TABLE config_info_beta (
id bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
app_name varchar(128),
content CLOB,
beta_ips varchar(1024),
md5 varchar(32) DEFAULT NULL,
gmt_create timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
src_user varchar(128),
src_ip varchar(50) DEFAULT NULL,
encrypted_data_key LONG VARCHAR DEFAULT NULL,
constraint configinfobeta_id_key PRIMARY KEY (id),
constraint uk_configinfobeta_datagrouptenant UNIQUE (data_id,group_id,tenant_id));
CREATE TABLE config_info_tag (
id bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
tag_id varchar(128) NOT NULL,
app_name varchar(128),
content CLOB,
md5 varchar(32) DEFAULT NULL,
gmt_create timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
src_user varchar(128),
src_ip varchar(50) DEFAULT NULL,
constraint configinfotag_id_key PRIMARY KEY (id),
constraint uk_configinfotag_datagrouptenanttag UNIQUE (data_id,group_id,tenant_id,tag_id));
CREATE TABLE config_info_aggr (
id bigint NOT NULL generated by default as identity,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) default '',
datum_id varchar(255) NOT NULL,
app_name varchar(128),
content CLOB,
gmt_modified timestamp NOT NULL DEFAULT '2010-05-05 00:00:00',
constraint configinfoaggr_id_key PRIMARY KEY (id),
constraint uk_configinfoaggr_datagrouptenantdatum UNIQUE (data_id,group_id,tenant_id,datum_id));
CREATE TABLE app_list (
id bigint NOT NULL generated by default as identity,
app_name varchar(128) NOT NULL,
is_dynamic_collect_disabled smallint DEFAULT 0,
last_sub_info_collected_time timestamp DEFAULT '1970-01-01 08:00:00.0',
sub_info_lock_owner varchar(128),
sub_info_lock_time timestamp DEFAULT '1970-01-01 08:00:00.0',
constraint applist_id_key PRIMARY KEY (id),
constraint uk_appname UNIQUE (app_name));
CREATE TABLE app_configdata_relation_subs (
id bigint NOT NULL generated by default as identity,
app_name varchar(128) NOT NULL,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
gmt_modified timestamp DEFAULT '2010-05-05 00:00:00',
constraint configdatarelationsubs_id_key PRIMARY KEY (id),
constraint uk_app_sub_config_datagroup UNIQUE (app_name, data_id, group_id));
CREATE TABLE app_configdata_relation_pubs (
id bigint NOT NULL generated by default as identity,
app_name varchar(128) NOT NULL,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
gmt_modified timestamp DEFAULT '2010-05-05 00:00:00',
constraint configdatarelationpubs_id_key PRIMARY KEY (id),
constraint uk_app_pub_config_datagroup UNIQUE (app_name, data_id, group_id));
CREATE TABLE config_tags_relation (
id bigint NOT NULL,
tag_name varchar(128) NOT NULL,
tag_type varchar(64) DEFAULT NULL,
data_id varchar(255) NOT NULL,
group_id varchar(128) NOT NULL,
tenant_id varchar(128) DEFAULT '',
nid bigint NOT NULL generated by default as identity,
constraint config_tags_id_key PRIMARY KEY (nid),
constraint uk_configtagrelation_configidtag UNIQUE (id, tag_name, tag_type));
CREATE INDEX config_tags_tenant_id_idx ON config_tags_relation(tenant_id);
CREATE TABLE group_capacity (
id bigint NOT NULL generated by default as identity,
group_id varchar(128) DEFAULT '',
quota int DEFAULT 0,
usage int DEFAULT 0,
max_size int DEFAULT 0,
max_aggr_count int DEFAULT 0,
max_aggr_size int DEFAULT 0,
max_history_count int DEFAULT 0,
gmt_create timestamp DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp DEFAULT '2010-05-05 00:00:00',
constraint group_capacity_id_key PRIMARY KEY (id),
constraint uk_group_id UNIQUE (group_id));
CREATE TABLE tenant_capacity (
id bigint NOT NULL generated by default as identity,
tenant_id varchar(128) DEFAULT '',
quota int DEFAULT 0,
usage int DEFAULT 0,
max_size int DEFAULT 0,
max_aggr_count int DEFAULT 0,
max_aggr_size int DEFAULT 0,
max_history_count int DEFAULT 0,
gmt_create timestamp DEFAULT '2010-05-05 00:00:00',
gmt_modified timestamp DEFAULT '2010-05-05 00:00:00',
constraint tenant_capacity_id_key PRIMARY KEY (id),
constraint uk_tenant_id UNIQUE (tenant_id));
CREATE TABLE tenant_info (
id bigint NOT NULL generated by default as identity,
kp varchar(128) NOT NULL,
tenant_id varchar(128) DEFAULT '',
tenant_name varchar(128) DEFAULT '',
tenant_desc varchar(256) DEFAULT NULL,
create_source varchar(32) DEFAULT NULL,
gmt_create bigint NOT NULL,
gmt_modified bigint NOT NULL,
constraint tenant_info_id_key PRIMARY KEY (id),
constraint uk_tenant_info_kptenantid UNIQUE (kp,tenant_id));
CREATE INDEX tenant_info_tenant_id_idx ON tenant_info(tenant_id);
CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL DEFAULT true
);
CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL,
constraint uk_username_role UNIQUE (username,role)
);
CREATE TABLE permissions (
role varchar(50) NOT NULL,
resource varchar(512) NOT NULL,
action varchar(8) NOT NULL,
constraint uk_role_permission UNIQUE (role,resource,action)
);
/******************************************/
/* ipv6 support */
/******************************************/
ALTER TABLE `config_info_tag`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `his_config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL AFTER `src_user`;
ALTER TABLE `config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `config_info_beta`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;

210
nacos/conf/mysql-schema.sql Normal file
View File

@ -0,0 +1,210 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/******************************************/
/* 表名称 = config_info */
/******************************************/
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',
`c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',
`effect` varchar(64) DEFAULT NULL COMMENT '配置生效的描述',
`type` varchar(64) DEFAULT NULL COMMENT '配置的类型',
`c_schema` text COMMENT '配置的模式',
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
/******************************************/
/* 表名称 = config_info_aggr */
/******************************************/
CREATE TABLE `config_info_aggr` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
`content` longtext NOT NULL COMMENT '内容',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';
/******************************************/
/* 表名称 = config_info_beta */
/******************************************/
CREATE TABLE `config_info_beta` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';
/******************************************/
/* 表名称 = config_info_tag */
/******************************************/
CREATE TABLE `config_info_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';
/******************************************/
/* 表名称 = config_tags_relation */
/******************************************/
CREATE TABLE `config_tags_relation` (
`id` bigint(20) NOT NULL COMMENT 'id',
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增长标识',
PRIMARY KEY (`nid`),
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
/******************************************/
/* 表名称 = group_capacity */
/******************************************/
CREATE TABLE `group_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID空字符表示整个集群',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限单位为字节0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数0表示使用默认值',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限单位为字节0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
/******************************************/
/* 表名称 = his_config_info */
/******************************************/
CREATE TABLE `his_config_info` (
`id` bigint(20) unsigned NOT NULL COMMENT 'id',
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增标识',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`op_type` char(10) DEFAULT NULL COMMENT 'operation type',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
PRIMARY KEY (`nid`),
KEY `idx_gmt_create` (`gmt_create`),
KEY `idx_gmt_modified` (`gmt_modified`),
KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
/******************************************/
/* 表名称 = tenant_capacity */
/******************************************/
CREATE TABLE `tenant_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限单位为字节0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限单位为字节0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
CREATE TABLE `tenant_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`kp` varchar(128) NOT NULL COMMENT 'kp',
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
CREATE TABLE `users` (
`username` varchar(50) NOT NULL PRIMARY KEY COMMENT 'username',
`password` varchar(500) NOT NULL COMMENT 'password',
`enabled` boolean NOT NULL COMMENT 'enabled'
);
CREATE TABLE `roles` (
`username` varchar(50) NOT NULL COMMENT 'username',
`role` varchar(50) NOT NULL COMMENT 'role',
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);
CREATE TABLE `permissions` (
`role` varchar(50) NOT NULL COMMENT 'role',
`resource` varchar(128) NOT NULL COMMENT 'resource',
`action` varchar(8) NOT NULL COMMENT 'action',
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

View File

@ -0,0 +1,797 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2018 Alibaba Group Holding Ltd.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<configuration scan="true" scanPeriod="10 seconds">
<springProperty scope="context" name="logPath" source="nacos.logs.path" defaultValue="${nacos.home}/logs"/>
<property name="LOG_HOME" value="${logPath}"/>
<appender name="cmdb-main"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${nacos.home}/logs/cmdb-main.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${nacos.home}/logs/cmdb-main.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="naming-server"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-server.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-server.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="async-naming-server" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="naming-server"/>
</appender>
<appender name="naming-raft"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-raft.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-raft.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="async-naming-raft" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="naming-raft"/>
</appender>
<appender name="naming-distro"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-distro.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-distro.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="async-naming-distro" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="naming-distro"/>
</appender>
<appender name="naming-event"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-event.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-event.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="async-naming-event" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="naming-event"/>
</appender>
<appender name="naming-push"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-push.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-push.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="naming-rt"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-rt.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-rt.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="naming-performance"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/naming-performance.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/naming-performance.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--config module logback config-->
<appender name="dumpFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-dump.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-dump.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="pullFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-pull.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-pull.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>128MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="fatalFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-fatal.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-fatal.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>128MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="memoryFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-memory.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-memory.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>128MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="pullCheckFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-pull-check.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-pull-check.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="clientLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-client-request.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-client-request.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date|%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="traceLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-trace.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-trace.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date|%msg%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="notifyLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-notify.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-notify.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>1GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="startLog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/config-server.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/config-server.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>512MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="rootFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/nacos.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>512MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="nacos-address"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos-address.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/nacos-address.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="istio-main"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/istio-main.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/istio-main.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="core-auth"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/core-auth.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/core-auth.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="protocol-raft"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/protocol-raft.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/protocol-raft.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="protocol-distro"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/protocol-distro.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/protocol-distro.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="nacos-cluster"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos-cluster.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/nacos-cluster.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="alipay-jraft"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/alipay-jraft.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/alipay-jraft.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--TPS control -->
<appender name="plugin-control-connection"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/plugin-control-connection.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/plugin-control-connection.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>2GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="plugin-control-tps"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/plugin-control-tps.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/plugin-control-tps.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>2GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="plugin-control"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/plugin-control.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/plugin-control.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>14</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="remote"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/remote.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/remote.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="remote-digest"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/remote-digest.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/remote-digest.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="remote-push"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/remote-push.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/remote-push.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="nacos-persistence"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos-persistence.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/nacos-persistence.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxFileSize>2GB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>7GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>%date %level %msg%n%n</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<logger name="com.alibaba.nacos.address.main" additivity="false">
<level value="INFO"/>
<appender-ref ref="nacos-address"/>
</logger>
<logger name="com.alibaba.nacos.cmdb.main" additivity="false">
<level value="INFO"/>
<appender-ref ref="cmdb-main"/>
</logger>
<logger name="com.alibaba.nacos.core.remote" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="remote"/>
</logger>
<logger name="com.alibaba.nacos.core.remote.push" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="remote-push"/>
</logger>
<logger name="com.alibaba.nacos.core.remote.digest" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="remote-digest"/>
</logger>
<!-- TPS Control-->
<logger name="com.alibaba.nacos.plugin.control" additivity="false">
<level value="INFO"/>
<appender-ref ref="plugin-control"/>
</logger>
<logger name="com.alibaba.nacos.plugin.control.tps" additivity="false">
<level value="INFO"/>
<appender-ref ref="plugin-control-tps"/>
</logger>
<logger name="com.alibaba.nacos.plugin.control.connection" additivity="false">
<level value="INFO"/>
<appender-ref ref="plugin-control-connection"/>
</logger>
<logger name="com.alibaba.nacos.naming.main" additivity="false">
<level value="INFO"/>
<appender-ref ref="async-naming-server"/>
</logger>
<logger name="com.alibaba.nacos.naming.raft" additivity="false">
<level value="INFO"/>
<appender-ref ref="async-naming-raft"/>
</logger>
<logger name="com.alibaba.nacos.naming.distro" additivity="false">
<level value="INFO"/>
<appender-ref ref="async-naming-distro"/>
</logger>
<logger name="com.alibaba.nacos.naming.event" additivity="false">
<level value="INFO"/>
<appender-ref ref="async-naming-event"/>
</logger>
<logger name="com.alibaba.nacos.naming.push" additivity="false">
<level value="INFO"/>
<appender-ref ref="naming-push"/>
</logger>
<logger name="com.alibaba.nacos.naming.rt" additivity="false">
<level value="INFO"/>
<appender-ref ref="naming-rt"/>
</logger>
<logger name="com.alibaba.nacos.naming.performance" additivity="false">
<level value="INFO"/>
<appender-ref ref="naming-performance"/>
</logger>
<logger name="com.alibaba.nacos.config.dumpLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="dumpFile"/>
</logger>
<logger name="com.alibaba.nacos.config.pullLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="pullFile"/>
</logger>
<logger name="com.alibaba.nacos.config.pullCheckLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="pullCheckFile"/>
</logger>
<logger name="com.alibaba.nacos.config.fatal" additivity="false">
<level value="INFO"/>
<appender-ref ref="fatalFile"/>
</logger>
<logger name="com.alibaba.nacos.config.monitorLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="memoryFile"/>
</logger>
<logger name="com.alibaba.nacos.config.clientLog" additivity="false">
<level value="info"/>
<appender-ref ref="clientLog"/>
</logger>
<logger name="com.alibaba.nacos.config.notifyLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="notifyLog"/>
</logger>
<logger name="com.alibaba.nacos.config.traceLog" additivity="false">
<level value="info"/>
<appender-ref ref="traceLog"/>
</logger>
<logger name="com.alibaba.nacos.config.startLog" additivity="false">
<level value="INFO"/>
<appender-ref ref="startLog"/>
</logger>
<logger name="com.alibaba.nacos.istio.main" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="istio-main"/>
</logger>
<logger name="com.alibaba.nacos.core.auth" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="core-auth"/>
</logger>
<logger name="com.alibaba.nacos.core.protocol.raft" additivity="false">
<level value="INFO"/>
<appender-ref ref="protocol-raft"/>
</logger>
<logger name="com.alipay.sofa.jraft" additivity="false">
<level value="INFO"/>
<appender-ref ref="alipay-jraft"/>
</logger>
<logger name="com.alibaba.nacos.core.protocol.distro" additivity="false">
<level value="INFO"/>
<appender-ref ref="protocol-distro"/>
</logger>
<logger name="com.alibaba.nacos.core.cluster" additivity="false">
<level value="INFO"/>
<appender-ref ref="nacos-cluster"/>
</logger>
<logger name="com.alibaba.nacos.persistence" additivity="false">
<level value="INFO"/>
<appender-ref ref="nacos-persistence"/>
</logger>
<springProfile name="standalone">
<logger name="org.springframework">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="org.apache.catalina.startup.DigesterFactory">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="org.apache.catalina.util.LifecycleBase">
<appender-ref ref="CONSOLE"/>
<level value="ERROR"/>
</logger>
<logger name="org.apache.coyote.http11.Http11NioProtocol">
<appender-ref ref="CONSOLE"/>
<level value="WARN"/>
</logger>
<logger name="org.apache.tomcat.util.net.NioSelectorPool">
<appender-ref ref="CONSOLE"/>
<level value="WARN"/>
</logger>
</springProfile>
<logger name="com.alibaba.nacos.core.listener.StartingApplicationListener">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="com.alibaba.nacos.common.notify.NotifyCenter">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="com.alibaba.nacos.sys.file.WatchFileCenter">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<logger name="com.alibaba.nacos.common.executor.ThreadPoolManager">
<appender-ref ref="CONSOLE"/>
<level value="INFO"/>
</logger>
<root>
<level value="INFO"/>
<appender-ref ref="rootFile"/>
</root>
</configuration>

View File

@ -22,6 +22,7 @@
<module>yudao-module-mall</module>
<module>yudao-module-erp</module>
<module>yudao-module-crm</module>
<module>yudao-module-langchat</module>
<!-- 友情提示:基于 Spring AI 实现 LLM 大模型的接入,需要使用 JDK17 版本,详细可见 https://doc.iocoder.cn/ai/build/ -->
<!-- <module>yudao-module-ai</module>-->
</modules>
@ -33,7 +34,7 @@
<properties>
<revision>2.3.0-jdk8-SNAPSHOT</revision>
<!-- Maven 相关 -->
<java.version>1.8</java.version>
<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.0.0-M5</maven-surefire-plugin.version>
@ -55,6 +56,11 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
</dependencyManagement>

8
start.sh Normal file
View File

@ -0,0 +1,8 @@
#!/bin/sh
## jar包名与之前服务名保持一致
java -Xms128m -Xmx128m -jar /home/app/yd-yunxing-server.jar --spring.profiles.active=dev
if [ $? != 0 ]; then
echo Failed to start java >&2
exit 1
fi

View File

@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@ -13,6 +14,8 @@ import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
@ -59,6 +62,28 @@ public class ServletUtils {
return ua != null ? ua : "";
}
public static String getHeader(HttpServletRequest request, String name){
String value = request.getHeader(name);
if (StringUtils.isEmpty(value)) {
return StringUtils.EMPTY;
}
return urlDecode(value);
}
/**
* 内容解码
*
* @param str 内容
* @return 解码后的内容
*/
public static String urlDecode(String str) {
try {
return URLDecoder.decode(str,"UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* 获得请求
*

View File

@ -0,0 +1,71 @@
package cn.iocoder.yudao.framework.mybatis.core.dataobject;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Entity基类
*
* @author Lion Li
*/
@Data
public class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 搜索值
*/
@JsonIgnore
@TableField(exist = false)
private String searchValue;
// /**
// * 创建部门
// */
// @TableField(fill = FieldFill.INSERT)
// private Long deptId;
/**
* 创建者
*/
@TableField(fill = FieldFill.INSERT)
private Long createBy;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 更新者
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateBy;
/**
* 更新时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 请求参数
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@TableField(exist = false)
private Map<String, Object> params = new HashMap<>();
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.framework.mybatis.core.handler;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseEntity;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
@ -41,6 +42,28 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getUpdater())) {
baseDO.setUpdater(userId.toString());
}
}else if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity) {
BaseEntity baseEntity = (BaseEntity) metaObject.getOriginalObject();
LocalDateTime current = LocalDateTime.now();
// 创建时间为空则以当前时间为插入时间
if (Objects.isNull(baseEntity.getCreateTime())) {
baseEntity.setCreateTime(current);
}
// 更新时间为空则以当前时间为更新时间
if (Objects.isNull(baseEntity.getUpdateTime())) {
baseEntity.setUpdateTime(current);
}
Long userId = WebFrameworkUtils.getLoginUserId();
// 当前登录用户不为空创建人为空则当前登录用户为创建人
if (Objects.nonNull(userId) && Objects.isNull(baseEntity.getCreateBy())) {
baseEntity.setCreateBy(userId);
}
// 当前登录用户不为空更新人为空则当前登录用户为更新人
if (Objects.nonNull(userId) && Objects.isNull(baseEntity.getUpdateBy())) {
baseEntity.setUpdateBy(userId);
}
}
}
@ -51,12 +74,20 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
if (Objects.isNull(modifyTime)) {
setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
// 当前登录用户不为空更新人为空则当前登录用户为更新人
Object modifier = getFieldValByName("updater", metaObject);
Long userId = WebFrameworkUtils.getLoginUserId();
if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
setFieldValByName("updater", userId.toString(), metaObject);
}
}else if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity) {
// 当前登录用户不为空更新人为空则当前登录用户为更新人
Object modifier = getFieldValByName("updateBy", metaObject);
Long userId = WebFrameworkUtils.getLoginUserId();
if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
setFieldValByName("updateBy", userId, metaObject);
}
}
}
}

View File

@ -0,0 +1,141 @@
package cn.iocoder.yudao.framework.mybatis.core.page;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 分页查询实体类
*
* @author Lion Li
*/
@Data
public class PageQuery implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 分页大小
*/
private Integer pageSize;
/**
* 当前页数
*/
private Integer pageNum;
/**
* 排序列
*/
private String orderByColumn;
/**
* 排序的方向desc或者asc
*/
private String isAsc;
/**
* 当前记录起始索引 默认值
*/
public static final int DEFAULT_PAGE_NUM = 1;
/**
* 每页显示记录数 默认值 默认查全部
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
/**
* 仅支持字母数字下划线空格逗号小数点支持多个字段排序
*/
public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
public static final String SEPARATOR = ",";
/**
* 构建分页对象
*/
public <T> Page<T> build() {
Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
List<OrderItem> orderItems = buildOrderItem();
if (CollUtil.isNotEmpty(orderItems)) {
page.addOrder(orderItems);
}
return page;
}
/**
* 构建排序
*
* 支持的用法如下:
* {isAsc:"asc",orderByColumn:"id"} order by id asc
* {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc
* {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc
* {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc
*/
private List<OrderItem> buildOrderItem() {
if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) {
return null;
}
String orderBy = escapeOrderBySql(orderByColumn);
orderBy = StrUtil.toUnderlineCase(orderBy);
// 兼容前端排序类型
isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"});
String[] orderByArr = orderBy.split(SEPARATOR);
String[] isAscArr = isAsc.split(SEPARATOR);
if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) {
throw new ServiceException(500,"排序参数有误");
}
List<OrderItem> list = new ArrayList<>();
// 每个字段各自排序
for (int i = 0; i < orderByArr.length; i++) {
String orderByStr = orderByArr[i];
String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i];
if ("asc".equals(isAscStr)) {
list.add(OrderItem.asc(orderByStr));
} else if ("desc".equals(isAscStr)) {
list.add(OrderItem.desc(orderByStr));
} else {
throw new ServiceException(500,"排序参数有误");
}
}
return list;
}
public Integer getFirstNum() {
return (pageNum - 1) * pageSize;
}
/**
* 检查字符防止注入绕过
*/
public static String escapeOrderBySql(String value) {
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) {
throw new IllegalArgumentException("参数不符合规范,不能进行查询");
}
return value;
}
/**
* 验证 order by 语法是否符合规范
*/
public static boolean isValidOrderBySql(String value) {
return value.matches(SQL_PATTERN);
}
}

View File

@ -0,0 +1,70 @@
package cn.iocoder.yudao.framework.mybatis.core.page;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* 表格分页数据对象
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
public class TableDataInfo<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总记录数
*/
private long total;
/**
* 列表数据
*/
private List<T> list;
/**
* 分页
*
* @param list 列表数据
* @param total 总记录数
*/
public TableDataInfo(List<T> list, long total) {
this.list = list;
this.total = total;
}
/**
* 根据分页对象构建表格分页数据对象
*/
public static <T> TableDataInfo<T> build(IPage<T> page) {
TableDataInfo<T> rspData = new TableDataInfo<>();
rspData.setList(page.getRecords());
rspData.setTotal(page.getTotal());
return rspData;
}
/**
* 根据数据列表构建表格分页数据对象
*/
public static <T> TableDataInfo<T> build(List<T> list) {
TableDataInfo<T> rspData = new TableDataInfo<>();
rspData.setList(list);
rspData.setTotal(list.size());
return rspData;
}
/**
* 构建表格分页数据对象
*/
public static <T> TableDataInfo<T> build() {
TableDataInfo<T> rspData = new TableDataInfo<>();
return rspData;
}
}

View File

@ -0,0 +1,166 @@
package cn.iocoder.yudao.framework.mybatis.core.util;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.*;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class AutoQueryUtil {
private static final Logger log = LoggerFactory.getLogger(AutoQueryUtil.class);
/**
* 根据实体类的属性值是否为空自动创建LambdaQueryWrapper
*
* @param entity 实体对象
* @param <T> 实体类型
* @return LambdaQueryWrapper
*/
public static <T> QueryWrapper<T> autoQuery(T entity) {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
if (entity == null) {
return queryWrapper;
}
Class<?> clazz = entity.getClass();
// 遍历当前类和所有父类的字段
while (clazz != null) {
Map<String, Method> getterMethods = new HashMap<>();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
Class<?> finalClazz = clazz;
Method getterMethod = getterMethods.computeIfAbsent(
"get" + capitalize(fieldName),
k -> {
try {
return MethodUtils.getAccessibleMethod(finalClazz, k, (Class<?>[]) null);
} catch (Exception e) {
log.error("No such getter method: {}", k, e);
return null;
}
}
);
if (getterMethod != null) {
try {
Object value = getterMethod.invoke(entity);
if (value != null && !"".equals(value)) {
handleFieldValue(queryWrapper, field, value);
}
} catch (Exception e) {
log.error("Error invoking getter method: {}", getterMethod.getName(), e);
}
}
}
// 获取父类继续遍历父类的字段
clazz = clazz.getSuperclass();
}
return queryWrapper;
}
public static String getTenantId(){
HttpServletRequest request = ServletUtils.getRequest();
if (null != request) {
// 获取request的header中的x-tenant-id
String tenantId = ServletUtils.getHeader(request, "x-tenant-id");
if (StringUtils.isNotBlank(tenantId)) {
return tenantId;
}
}
return null;
}
private static void handleFieldValue(QueryWrapper<?> queryWrapper, Field field, Object value) {
String fieldName = field.getName();
if (String.class.isAssignableFrom(field.getType())) {
queryWrapper.like(StrUtil.toUnderlineCase(fieldName), value);
} else if (Integer.class.isAssignableFrom(field.getType()) ||
Long.class.isAssignableFrom(field.getType()) ||
Double.class.isAssignableFrom(field.getType()) ||
Float.class.isAssignableFrom(field.getType()) ||
Boolean.class.isAssignableFrom(field.getType()) ||
Short.class.isAssignableFrom(field.getType()) ||
Byte.class.isAssignableFrom(field.getType()) ||
Character.class.isAssignableFrom(field.getType()) ||
Date.class.isAssignableFrom(field.getType()) ||
LocalDateTime.class.isAssignableFrom(field.getType()) ||
LocalDate.class.isAssignableFrom(field.getType()) ||
LocalTime.class.isAssignableFrom(field.getType()) ||
ZonedDateTime.class.isAssignableFrom(field.getType()) ||
Instant.class.isAssignableFrom(field.getType())) {
queryWrapper.eq(StrUtil.toUnderlineCase(fieldName), String.valueOf(value));
} else {
// 如果是其他类型可以添加更多条件或者忽略
log.warn("Unsupported field type: {}", field.getType().getName());
}
}
/**
* 获取 pageReqVO 中所有 LocalDate[]LocalDateTime[] Date[] 类型字段的名称
*/
public static String[] getDateRangeFieldNames(Object pageReqVO) {
return Arrays.stream(pageReqVO.getClass().getDeclaredFields())
.filter(field -> field.getType().equals(LocalDate[].class)
|| field.getType().equals(LocalDateTime[].class)
|| field.getType().equals(Date[].class))
.map(Field::getName)
.toArray(String[]::new);
}
/**
* 动态处理 pageReqVO 中所有 LocalDate[]LocalDateTime[] Date[] 类型字段设置时间段查询条件
*/
public static void handleDateRangeFields(Object pageReqVO, QueryWrapper<?> queryWrapper) {
for (Field field : pageReqVO.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
Object fieldValue = field.get(pageReqVO);
if (fieldValue == null) {
continue; // 跳过值为 null 的字段
}
if (field.getType().equals(LocalDate[].class)) {
LocalDate[] dateRange = (LocalDate[]) fieldValue;
if (dateRange.length == 2) {
String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
queryWrapper.between(columnName, dateRange[0], dateRange[1]);
}
} else if (field.getType().equals(LocalDateTime[].class)) {
LocalDateTime[] dateTimeRange = (LocalDateTime[]) fieldValue;
if (dateTimeRange.length == 2) {
String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
queryWrapper.between(columnName, dateTimeRange[0], dateTimeRange[1]);
}
} else if (field.getType().equals(Date[].class)) {
Date[] range = (Date[]) fieldValue;
if (range.length == 2) {
String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
queryWrapper.between(columnName, range[0], range[1]);
}
}
} catch (IllegalAccessException e) {
throw new ServiceException(500,"Failed to access field " + field.getName() + ": " + e.getMessage());
}
}
}
private static String capitalize(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}

View File

@ -13,12 +13,16 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import cn.iocoder.yudao.module.system.api.tenant.TenantApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -43,6 +47,9 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
private final OAuth2TokenApi oauth2TokenApi;
@Resource
private AdminUserApi adminUserApi;
@Override
@SuppressWarnings("NullableProblems")
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
@ -74,6 +81,11 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
// 设置当前用户
if (loginUser != null) {
if(null == loginUser.getTenantId()){
CommonResult<AdminUserRespDTO> user = adminUserApi.getUser(loginUser.getId());
loginUser.setTenantId(user.getData().getTenantId());
}
SecurityFrameworkUtils.setLoginUser(loginUser, request);
}
// 继续过滤链

View File

@ -3,9 +3,9 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.0.152:9060 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
password: T7@pL9vQ # Nacos 密码
discovery: # 【配置中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项

View File

@ -3,7 +3,7 @@ spring:
name: gateway-server
profiles:
active: local
active: dev
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -55,19 +55,19 @@ spring:
primary: master
datasource:
master:
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
url: jdbc:mysql://192.168.1.101:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: xmuser
password: chinasoft@123
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
url: jdbc:mysql://192.168.1.101:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: xmuser
password: chinasoft@123
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis:
host: 400-infra.server.iocoder.cn # 地址
host: 10.31.0.128 # 地址
port: 6379 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项

View File

@ -3,7 +3,7 @@ spring:
name: ai-server
profiles:
active: local
active: dev
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -56,21 +56,21 @@ spring:
primary: master
datasource:
master:
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
url: jdbc:mysql://192.168.1.101:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: xmuser
password: chinasoft@123
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
url: jdbc:mysql://192.168.1.101:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: xmuser
password: chinasoft@123
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 400-infra.server.iocoder.cn # 地址
host: 192.168.1.103 # 地址
port: 6379 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
password: redis_r2GyW5 # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -77,7 +77,7 @@ spring:
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 10.31.0.128 # 地址
host: 192.168.1.103 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
# password: 123456 # 密码,建议生产环境开启

View File

@ -3,7 +3,7 @@ spring:
name: bpm-server
profiles:
active: local
active: dev
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -55,18 +55,18 @@ spring:
primary: master
datasource:
master:
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
url: jdbc:mysql://192.168.1.101:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: xmuser
password: chinasoft@123
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
url: jdbc:mysql://192.168.1.101:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: xmuser
password: chinasoft@123
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
host: 400-infra.server.iocoder.cn # 地址
host: 10.31.0.128 # 地址
port: 6379 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -76,7 +76,7 @@ spring:
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 10.31.0.128 # 地址
host: 192.168.1.103 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
# password: 123456 # 密码,建议生产环境开启

View File

@ -3,7 +3,7 @@ spring:
name: crm-server
profiles:
active: local
active: dev
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -55,21 +55,21 @@ spring:
primary: master
datasource:
master:
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
url: jdbc:mysql://192.168.1.101:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: xmuser
password: chinasoft@123
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
url: jdbc:mysql://192.168.1.101:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: xmuser
password: chinasoft@123
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 400-infra.server.iocoder.cn # 地址
host: 192.168.1.103 # 地址
port: 6379 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
password: redis_r2GyW5 # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.1.101:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -76,7 +76,7 @@ spring:
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 10.31.0.128 # 地址
host: 192.168.1.103 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
# password: 123456 # 密码,建议生产环境开启

View File

@ -3,7 +3,7 @@ spring:
name: erp-server
profiles:
active: local
active: dev
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。

View File

@ -25,11 +25,13 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
@ -148,4 +150,21 @@ public class CodegenController {
writeAttachment(response, "codegen.zip", outputStream.toByteArray());
}
/**
* 应用程序前后端代码生成并解压到配置的路径
*
* @param tableIdStr 表ID串
*/
@Operation(summary = "应用程序前后端代码生成")
@Parameters({
@Parameter(name = "tableIdStr", description = "表编号", required = true, example = "1024,1025"),
@Parameter(name = "appName", description = "应用名称", required = true, example = "testApp")
})
@GetMapping("/genAppCode")
@PermitAll
// @PreAuthorize("@ss.hasPermission('infra:codegen:genappcode')")
public CommonResult<String> genAppCode( String tableIdStr, String appName){
return success(codegenService.genAppCode(tableIdStr, appName));
}
}

View File

@ -98,4 +98,12 @@ public interface CodegenService {
*/
List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment);
/**
* 应用程序前后端代码生成并解压到配置的路径
* @param tableIdStr
* @param appName
* @return
*/
String genAppCode(String tableIdStr, String appName);
}

View File

@ -1,7 +1,12 @@
package cn.iocoder.yudao.module.infra.service.codegen;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
@ -18,29 +23,51 @@ import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
import cn.iocoder.yudao.module.infra.util.DistributedLock;
import cn.iocoder.yudao.module.infra.util.InputStreamConverter;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.alibaba.excel.util.DateUtils;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.google.common.annotations.VisibleForTesting;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.zip.ZipInputStream;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;
/**
* 代码生成 Service 实现类
*
* @author 芋道源码
*/
@Slf4j
@Service
public class CodegenServiceImpl implements CodegenService {
@ -63,6 +90,31 @@ public class CodegenServiceImpl implements CodegenService {
@Resource
private CodegenProperties codegenProperties;
@Autowired
private DataSource dataSource;
@Value("${runsystem.project.basedir.unzip}")
private String unzipPath;
@Value("${runsystem.project.basedir.menusql}")
private String menuSqlPath;
@Value("${runsystem.project.basedir.shell}")
private String shellPath;
@Value("${runsystem.project.basedir.config}")
private String configPath;
@Value("${runsystem.project.basedir.nginx}")
private String nginxPath;
@Autowired
private DistributedLock distributedLock;
@Value("${runsystem.project.host}")
private String host;
@Override
@Transactional(rollbackFor = Exception.class)
public List<Long> createCodegenList(Long userId, CodegenCreateListReqVO reqVO) {
@ -293,4 +345,243 @@ public class CodegenServiceImpl implements CodegenService {
return BeanUtils.toBean(tables, DatabaseTableRespVO.class);
}
/**
* 应用程序前后端代码生成并解压到配置的路径
*/
@Override
public String genAppCode(String tableIdStr, String appName) {
appName = appName.toLowerCase().replaceAll("[^a-zA-Z0-9]", "");
log.info("应用程序前后端代码生成开始tableIdStr:{},appName:{}", tableIdStr, appName);
String lockKey = "genAppCode:" + ":" + appName;
if (!distributedLock.lock(lockKey, 10, TimeUnit.MINUTES)) {
log.error("Failed to acquire lock for appName: {}", appName);
throw new ServiceException(500,appName + " Failed to acquire lock");
}
Long[] tableIds = Convert.toLongArray(tableIdStr);
try {
String appDir = "/" + appName + "-" + DateUtils.DATE_FORMAT_10;
String savePath = unzipPath + appDir;
String url = "";
Map<String,String> codeResult=new HashMap<String, String>();
// 生成代码
for (Long tableId : tableIds) {
Map<String, String> codes = this.generationCodes(tableId);
codeResult.putAll(codes);
}
// 构建 zip
String[] paths = codeResult.keySet().toArray(new String[0]);
ByteArrayInputStream[] ins = codeResult.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
// 解压ZIP文件内容到目标文件夹
File targetFolder = new File(savePath);
if (!targetFolder.exists()) {
targetFolder.mkdirs();
} else {
FileUtils.deleteDirectory(targetFolder);
}
InputStream bais = InputStreamConverter.convertByteArrayInputStreamArrayToInputStream(ins);
ZipInputStream zis = new ZipInputStream(bais);
ZipUtil.unzip(zis, targetFolder);
//运行系统-执行菜单文件夹中的SQL脚本
Connection connection = dataSource.getConnection();
String menuScriptsDir = savePath + menuSqlPath;
if (null != connection) {
executeMenuScripts(menuScriptsDir, savePath);
}
//运行系统
executeRunSystemShell(appName, savePath);
//构建nginx配置文件
url = buildNginxConf(appName, savePath);
// 返回成功信息
log.info("代码生成成功,已保存到: " + savePath, "运行系统url地址" + url);
return StringUtils.isNotBlank(url) ? url : "应用容器启动失败";
} catch (Exception e) {
log.error("Failed to generate app code: {}", e.getMessage());
return "应用容器启动失败:" + e.getMessage();
} finally {
distributedLock.unlock(lockKey);
log.info("Lock released for tableIdStr: {}, appName: {}", tableIdStr, appName);
//删除gen_table和gen_table_column中table_id相关的数据
codegenTableMapper.deleteByIds(Arrays.asList(tableIds));
}
}
/**
* 执行菜单脚本并合并为一个文件
*/
private static void executeMenuScripts(String menuScriptsDir, String targetDir) throws IOException {
File dir = new File(menuScriptsDir);
if (!dir.exists() || !dir.isDirectory()) {
throw new IllegalArgumentException("指定的目录不存在或不是一个文件夹: " + menuScriptsDir);
}
File[] sqlFiles = dir.listFiles((dir1, name) -> name.toLowerCase().endsWith(".sql"));
if (sqlFiles == null || sqlFiles.length == 0) {
System.out.println("没有找到 SQL 脚本文件");
return;
}
Arrays.sort(sqlFiles); // 按文件名排序
StringBuilder combinedSql = new StringBuilder();
for (File sqlFile : sqlFiles) {
String sqlContent = readFile(sqlFile);
combinedSql.append(sqlContent).append(";\n");
}
// 将合并后的 SQL 内容写入目标文件
String targetFilePath = targetDir + File.separator + "menu.sql";
Path targetPath = Paths.get(targetFilePath);
Files.createDirectories(targetPath.getParent());
Files.write(targetPath, combinedSql.toString().getBytes());
System.out.println("合并后的menu SQL脚本已保存到: " + targetFilePath);
}
private static String readFile(File file) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
return reader.lines().collect(Collectors.joining("\n"));
}
}
/**
* 执行运行系统shell脚本
*
* @param appName
* @return
*/
private String executeRunSystemShell(String appName, String savePath) {
String result = "";
try {
// 组合命令和参数
// String[] command = {"/bin/sh", "bash "+savePath + shellPath + "/runSystem.sh", appName};
// 执行Shell脚本
Process process = Runtime.getRuntime().exec("sh " + savePath + shellPath + "/runSystem.sh " + appName);
// 读取脚本的输出
BufferedReader reader = new BufferedReader(new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("ls").getInputStream())));
String line;
while ((line = reader.readLine()) != null) {
result += line;
}
// 等待脚本执行完成
// process.waitFor();
int exitCode = process.waitFor();
log.info("Script runSystem executed with exit code: " + exitCode);
// Thread.sleep(15000);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return result;
}
@SneakyThrows
private String buildNginxConf(String appName, String savePath) {
String url = "";
// 读取nginx.conf文件内容并替换{port}{host_ip}
// 读取文件内容
StringBuilder contentBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(savePath + configPath + "/nginx.conf"))) {
String line;
while ((line = reader.readLine()) != null) {
contentBuilder.append(line).append("\n");
}
}
String hostIp = executeSelectIpShell(appName, savePath);
String port = getPortSequence().toString();
if (ObjectUtil.isAllNotEmpty(hostIp, port)) {
String content = contentBuilder.toString();
content = content.replace("{port}", port);
content = content.replace("{host_ip}", hostIp);
// 构建输出文件路径
File outputDir = new File(nginxPath);
if (!outputDir.exists()) {
outputDir.mkdirs(); // 如果目录不存在则创建目录
}
File outputFile = new File(outputDir, appName + ".conf");
// 写入替换后的内容到新文件
try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) {
writer.write(content);
}
log.info("文件内容已成功替换并保存到: " + outputFile.getAbsolutePath());
url = host + ":" + port;
}
// 替换 {port} {host_ip}
Runtime.getRuntime().exec("nginx -s reload");
return url;
}
/**
* 执行查找ip shell脚本
*
* @param appName
* @return
*/
private String executeSelectIpShell(String appName, String savePath) {
String result = "";
try {
// 执行Shell脚本
Process process = Runtime.getRuntime().exec("sh " + savePath + shellPath + "/selectIp.sh " + appName);
// 读取脚本的输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
result += line;
}
// 等待脚本执行完成
int exitCode = process.waitFor();
log.info("Script selectIp executed with exit code: " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return result;
}
/**
* 获取端口号序列值
*
* @return
* @throws SQLException
*/
private Long getPortSequence() throws SQLException {
Long port = 10000L;
Connection connection = dataSource.getConnection();
CallableStatement callableStatement = connection.prepareCall("{call get_next_sequence()}");
boolean hasResult = callableStatement.execute();
if (hasResult) {
ResultSet resultSet = callableStatement.getResultSet();
if (resultSet.next()) {
port = resultSet.getLong(1);
log.info("Next sequence value: " + port);
}
}
return port;
}
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.infra.util;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Component
public class DistributedLock {
@Resource
private StringRedisTemplate stringRedisTemplate;
public boolean lock(String key, long timeout, TimeUnit unit) {
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(key, "locked", timeout, unit);
return result != null && result;
}
public void unlock(String key) {
stringRedisTemplate.delete(key);
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.infra.util;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;
public class InputStreamConverter {
public static InputStream convertByteArrayInputStreamArrayToInputStream(ByteArrayInputStream[] ins) {
Vector<InputStream> inputStreams = new Vector<>();
for (ByteArrayInputStream byteArrayInputStream : ins) {
inputStreams.add(byteArrayInputStream);
}
return new SequenceInputStream(new Enumeration<InputStream>() {
private final Enumeration<InputStream> enumeration = inputStreams.elements();
@Override
public boolean hasMoreElements() {
return enumeration.hasMoreElements();
}
@Override
public InputStream nextElement() {
return enumeration.nextElement();
}
});
}
}

View File

@ -3,9 +3,9 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.0.152:9060 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
password: T7@pL9vQ # Nacos 密码
discovery: # 【配置中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
@ -56,21 +56,21 @@ spring:
primary: master
datasource:
master:
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
url: jdbc:mysql://192.168.0.173:9081/yd-yunxing?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
password: chinasoft@123
password: s8K@d3M1
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
url: jdbc:mysql://192.168.0.173:9081/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
password: chinasoft@123
password: s8K@d3M1
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 400-infra.server.iocoder.cn # 地址
port: 6379 # 端口
host: 192.168.0.31 # 地址
port: 9072 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
password: 5R@xY2fP # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################
@ -127,4 +127,4 @@ spring:
# 芋道配置项,设置当前项目所有自定义的配置
yudao:
demo: true # 开启演示模式
demo: false # 开启演示模式

View File

@ -3,7 +3,7 @@
spring:
cloud:
nacos:
server-addr: 10.31.0.128:8848 # Nacos 服务器地址
server-addr: 192.168.0.17:8848 # Nacos 服务器地址
username: nacos # Nacos 账号
password: nacos # Nacos 密码
discovery: # 【配置中心】配置项
@ -61,30 +61,30 @@ spring:
primary: master
datasource:
master:
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
url: jdbc:mysql://192.168.0.17:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例
# url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro # SQLServer 连接的示例
# url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
username: root
password: chinasoft@123
password: root
# username: sa # SQL Server 连接的示例
# password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W # SQL Server 连接的示例
# username: SYSDBA # DM 连接的示例
# password: SYSDBA # DM 连接的示例
slave: # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://10.31.0.128:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
url: jdbc:mysql://192.168.0.17:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
username: root
password: chinasoft@123
password: root
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 10.31.0.128 # 地址
host: 192.168.0.17 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
password: 123456 # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################

View File

@ -3,7 +3,7 @@ spring:
name: infra-server
profiles:
active: local
active: dev
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
@ -179,3 +179,27 @@ yudao:
- infra_data_source_config
debug: false
#应用运行系统基线项目文件地址
runsystem:
project:
host: 10.31.0.172
basedir:
# 基线项目根目录 服务器路径:/root/RunSystemBaseLineProject
# source: D:/RunSystemBaseLineProject
source: /root/RunSystemBaseLineProject
# java源文件路径
java: /app/icss-xm-app/ruoyi-modules/ruoyi-system/src/
# web源文件路径
web: /web/icss-xm-app-web/src/
# 运行系统解压路径 服务器路径:/root/dockerTest
# unzip: D:/RunSystemSavePath
unzip: /root/dockerTest
# 菜单sql文件路径
menusql: /app/icss-xm-app/ruoyi-modules/ruoyi-system/src/main/resources/menusql
# shell脚本路径
shell:
# config文件路径
config: /app/icss-xm-app/script/config
# nginx配置文件路径 服务器路径:/etc/nginx/conf.d
# nginx: D:/code/icss-xm-app/script/nginx
nginx: /etc/nginx/conf.d

View File

@ -22,7 +22,7 @@ spring:
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 10.31.0.128 # 地址
host: 192.168.1.103 # 地址
port: 16379 # 端口(单元测试,使用 16379 端口)
database: 0 # 数据库索引

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<description>芋道项目基础脚手架</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro/yudao-module-langchat</url>
<dependencies>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-env</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-redis</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-rpc</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.0.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mq</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.7.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
</dependency>
</dependencies>
<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>
</repositories>
</project>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>yudao-module-langchat-api</module>
<module>yudao-module-langchat-biz</module>
</modules>
<artifactId>yudao-module-langchat</artifactId>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
<description>
</description>
</project>

View File

@ -0,0 +1,27 @@
<?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>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat</artifactId>
<version>${revision}</version>
</parent>
<artifactId>yudao-module-langchat-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
langchat 模块 API暴露给其它模块调用
</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
/**
* @author tycoding
* @since 2024/1/15
*/
public interface CacheConst {
/**
* 系统所有Redis缓存Key前缀 prefix
*/
String REDIS_KEY_PREFIX = "langchat:";
/**
* Auth缓存前缀
*/
String AUTH_PREFIX = REDIS_KEY_PREFIX + "auth:";
/**
* Auth Session缓存前缀
*/
String AUTH_SESSION_PREFIX = AUTH_PREFIX + "session:";
/**
* Auth Session缓存变量前缀
*/
String AUTH_USER_INFO_KEY = "USER_INFO";
/**
* Auth Token缓存变量前缀
*/
String AUTH_TOKEN_INFO_KEY = "TOKEN_INFO";
/**
* 用户信息缓存
*/
String USER_DETAIL_KEY = REDIS_KEY_PREFIX + "user_details";
/**
* 验证码缓存前缀
*/
String CAPTCHA_PREFIX = REDIS_KEY_PREFIX + "auth:captcha:";
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.langchat.enums;
import lombok.AllArgsConstructor;
/**
* @author GB
* @desc
* @since 2024-08-21
*/
@AllArgsConstructor
public enum ChatErrorEnum {
API_KEY_IS_NULL(1000, "模型 %s %s api key 为空,请检查配置"),
BASE_URL_IS_NULL(1003, "模型 %s %s base url 为空,请检查配置"),
SECRET_KEY_IS_NULL(1005, "模型 %s %s base secret Key 为空,请检查配置"),
;
/**
* 错误码
*/
private int errorCode;
/**
* 错误描述用于展示给用户
*/
private String errorDesc;
public int getErrorCode() {
return this.errorCode;
}
public String getErrorDesc(String modelName, String type) {
return this.errorDesc.formatted(modelName, type);
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
/**
* @author tycoding
* @since 2024/6/6
*/
public interface EmbedConst {
String ORIGIN_TYPE_INPUT = "INPUT";
String ORIGIN_TYPE_UPLOAD = "UPLOAD";
String KNOWLEDGE = "knowledgeId";
String FILENAME = "docsName";
String CLAZZ_NAME_OPENAI = "OpenAiEmbeddingModel";
String CLAZZ_NAME_QIANFAN = "QianfanEmbeddingModel";
String CLAZZ_NAME_QIANWEN = "QwenEmbeddingModel";
String CLAZZ_NAME_ZHIPU = "ZhipuAiEmbeddingModel";
String CLAZZ_NAME_OLLAMA = "OllamaEmbeddingModel";
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
import lombok.Getter;
/**
* @author tycoding
* @since 2024/10/28
*/
@Getter
public enum EmbedStoreEnum {
REDIS,
PGVECTOR,
MILVUS,
;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
/**
* @author tycoding
* @since 2024/1/6
*/
public interface ModelConst {
String TEXT_SUFFIX = "_text";
String IMAGE_SUFFIX = "_image";
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.enums;
import lombok.Getter;
/**
* @author tycoding
* @since 2024/6/16
*/
@Getter
public enum ProviderEnum {
OPENAI,
AZURE_OPENAI,
GEMINI,
OLLAMA,
CLAUDE,
Q_FAN,
Q_WEN,
ZHIPU,
YI,
DOUYIN,
DEEPSEEK,
SILICON,
SPARK,
;
}

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat-biz</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<description>芋道项目基础脚手架</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro/yudao-module-langchat-biz</url>
<dependencies>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-env</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-redis</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-rpc</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.0.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mq</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.7.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId>
<version>1.0.8</version>
<scope>compile</scope>
</dependency>
</dependencies>
<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>
</repositories>
</project>

View File

@ -0,0 +1,258 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-langchat-biz</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<properties>
<langchain4j.version>1.0.0-beta1</langchain4j.version>
</properties>
<description>
</description>
<dependencies>
<!--langchat4j-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-core</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-redis</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-pgvector</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-milvus</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-document-parser-apache-tika</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-qianfan</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope</artifactId>
<version>${langchain4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-zhipu-ai</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<!-- OSS -->
<dependency>
<groupId>org.dromara.x-file-storage</groupId>
<artifactId>x-file-storage-core</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.12.1</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.16.1</version>
</dependency>
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.137</version>
</dependency>
<!-- Spring Cloud 基础 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-env</artifactId>
</dependency>
<!-- 依赖服务 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-langchat-api</artifactId>
<version>2.3.0-jdk8-SNAPSHOT</version>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-redis</artifactId>
</dependency>
<!-- RPC 远程调用相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-rpc</artifactId>
</dependency>
<!-- Registry 注册中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Config 配置中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Job 定时任务相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-mq</artifactId>
</dependency>
<!-- 服务保障相关 TODO 芋艿:暂时去掉 -->
<!-- <dependency>-->
<!-- <groupId>cn.iocoder.cloud</groupId>-->
<!-- <artifactId>yudao-spring-boot-starter-protection</artifactId>-->
<!-- </dependency>-->
<!-- Test 测试相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 监控相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId> <!-- 微信登录(公众号) -->
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId> <!-- 微信登录(小程序) -->
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency>
</dependencies>
<build>
<!-- 设置构建的 jar 包名 -->
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- 打包 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat;
import cn.iocoder.yudao.module.langchat.config.EnableFileStorage;
import cn.iocoder.yudao.module.langchat.config.SpringFileStorageProperties;
import cn.iocoder.yudao.module.langchat.properties.ChatProps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* @author tycoding
* @since 2024/2/4
*/
@EnableFileStorage
@SpringBootApplication
@EnableConfigurationProperties({
SpringFileStorageProperties.class,
ChatProps.class
})
public class LangChatApplication {
public static void main(String[] args) {
SpringApplication.run(LangChatApplication.class, args);
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义日志记录切面注解
*
* @author tycoding
* @since 2024/4/15
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiLog {
String value() default "";
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.component;
import org.springframework.context.ApplicationEvent;
/**
* @author tycoding
* @since 2024/6/16
*/
public class EmbeddingRefreshEvent extends ApplicationEvent {
private static final long serialVersionUID = 4109980679877560773L;
public EmbeddingRefreshEvent(Object source) {
super(source);
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.component;
import lombok.Getter;
/**
* @author tycoding
* @since 2024/6/16
*/
@Getter
public enum ModelTypeEnum {
CHAT,
EMBEDDING,
TEXT_IMAGE,
WEB_SEARCH;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.component;
import org.springframework.context.ApplicationEvent;
/**
* @author tycoding
* @since 2024/6/16
*/
public class ProviderRefreshEvent extends ApplicationEvent {
private static final long serialVersionUID = 4109980679877560773L;
public ProviderRefreshEvent(Object source) {
super(source);
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.component;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Service;
/**
* @author tycoding
* @since 2024/1/19
*/
@Service
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static void publishEvent(ApplicationEvent event) {
if (applicationContext == null) {
return;
}
applicationContext.publishEvent(event);
}
public <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
public void registerBean(String beanName, Object beanInstance) {
BeanDefinitionRegistry beanDefinitionRegistry =
(BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition((Class<Object>) beanInstance.getClass(), () -> beanInstance);
BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
}
public void unregisterBean(String beanName) {
BeanDefinitionRegistry beanDefinitionRegistry =
(BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
if (beanDefinitionRegistry.containsBeanDefinition(beanName)) {
beanDefinitionRegistry.removeBeanDefinition(beanName);
}
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.config;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 启用文件存储会自动根据配置文件进行加载
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FileStorageAutoConfiguration.class, SpringFileStorageProperties.class})
public @interface EnableFileStorage {}

View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.config;
import cn.iocoder.yudao.module.langchat.wrapper.MultipartFileWrapperAdapter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileStorageService;
import org.dromara.x.file.storage.core.FileStorageServiceBuilder;
import org.dromara.x.file.storage.core.aspect.FileStorageAspect;
import org.dromara.x.file.storage.core.file.FileWrapperAdapter;
import org.dromara.x.file.storage.core.platform.FileStorage;
import org.dromara.x.file.storage.core.platform.FileStorageClientFactory;
import org.dromara.x.file.storage.core.recorder.DefaultFileRecorder;
import org.dromara.x.file.storage.core.recorder.FileRecorder;
import org.dromara.x.file.storage.core.tika.ContentTypeDetect;
import org.dromara.x.file.storage.core.tika.DefaultTikaFactory;
import org.dromara.x.file.storage.core.tika.TikaContentTypeDetect;
import org.dromara.x.file.storage.core.tika.TikaFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Configuration
@ConditionalOnMissingBean(FileStorageService.class)
public class FileStorageAutoConfiguration {
@Autowired
private SpringFileStorageProperties properties;
@Autowired
private ApplicationContext applicationContext;
/**
* 当没有找到 FileRecorder 时使用默认的 FileRecorder
*/
@Bean
@ConditionalOnMissingBean(FileRecorder.class)
public FileRecorder fileRecorder() {
log.warn("没有找到 FileRecorder 的实现类,文件上传之外的部分功能无法正常使用,必须实现该接口才能使用完整功能!");
return new DefaultFileRecorder();
}
/**
* Tika 工厂类型用于识别上传的文件的 MINE
*/
@Bean
@ConditionalOnMissingBean(TikaFactory.class)
public TikaFactory tikaFactory() {
return new DefaultTikaFactory();
}
/**
* 识别文件的 MIME 类型
*/
@Bean
@ConditionalOnMissingBean(ContentTypeDetect.class)
public ContentTypeDetect contentTypeDetect(TikaFactory tikaFactory) {
return new TikaContentTypeDetect(tikaFactory);
}
/**
* 文件存储服务
*/
@Bean(destroyMethod = "destroy")
public FileStorageService fileStorageService(
FileRecorder fileRecorder,
@Autowired(required = false) List<List<? extends FileStorage>> fileStorageLists,
@Autowired(required = false) List<FileStorageAspect> aspectList,
@Autowired(required = false) List<FileWrapperAdapter> fileWrapperAdapterList,
ContentTypeDetect contentTypeDetect,
@Autowired(required = false) List<List<FileStorageClientFactory<?>>> clientFactoryList) {
if (fileStorageLists == null) fileStorageLists = new ArrayList<>();
if (aspectList == null) aspectList = new ArrayList<>();
if (fileWrapperAdapterList == null) fileWrapperAdapterList = new ArrayList<>();
if (clientFactoryList == null) clientFactoryList = new ArrayList<>();
FileStorageServiceBuilder builder = FileStorageServiceBuilder.create(properties.toFileStorageProperties())
.setFileRecorder(fileRecorder)
.setAspectList(aspectList)
.setContentTypeDetect(contentTypeDetect)
.setFileWrapperAdapterList(fileWrapperAdapterList)
.setClientFactoryList(clientFactoryList);
fileStorageLists.forEach(builder::addFileStorage);
if (properties.getEnableByteFileWrapper()) {
builder.addByteFileWrapperAdapter();
}
if (properties.getEnableUriFileWrapper()) {
builder.addUriFileWrapperAdapter();
}
if (properties.getEnableInputStreamFileWrapper()) {
builder.addInputStreamFileWrapperAdapter();
}
if (properties.getEnableLocalFileWrapper()) {
builder.addLocalFileWrapperAdapter();
}
if (properties.getEnableHttpServletRequestFileWrapper()) {
if (FileStorageServiceBuilder.doesNotExistClass("javax.servlet.http.HttpServletRequest")
&& FileStorageServiceBuilder.doesNotExistClass("jakarta.servlet.http.HttpServletRequest")) {
log.warn(
"当前未检测到 Servlet 环境,无法加载 HttpServletRequest 的文件包装适配器请将参数【dromara.x-file-storage.enable-http-servlet-request-file-wrapper】设置为 【false】来消除此警告");
} else {
builder.addHttpServletRequestFileWrapperAdapter();
}
}
if (properties.getEnableMultipartFileWrapper()) {
if (FileStorageServiceBuilder.doesNotExistClass("org.springframework.web.multipart.MultipartFile")) {
log.warn(
"当前未检测到 SpringWeb 环境,无法加载 MultipartFile 的文件包装适配器请将参数【dromara.x-file-storage.enable-multipart-file-wrapper】设置为 【false】来消除此警告");
} else {
builder.addFileWrapperAdapter(new MultipartFileWrapperAdapter());
}
}
if (FileStorageServiceBuilder.doesNotExistClass("org.springframework.web.servlet.config.annotation.WebMvcConfigurer")) {
long localAccessNum = properties.getLocal().stream()
.filter(SpringFileStorageProperties.SpringLocalConfig::getEnableStorage)
.filter(SpringFileStorageProperties.SpringLocalConfig::getEnableAccess)
.count();
long localPlusAccessNum = properties.getLocalPlus().stream()
.filter(SpringFileStorageProperties.SpringLocalPlusConfig::getEnableStorage)
.filter(SpringFileStorageProperties.SpringLocalPlusConfig::getEnableAccess)
.count();
if (localAccessNum + localPlusAccessNum > 0) {
log.warn("当前未检测到 SpringWeb 环境,无法开启本地存储平台的本地访问功能,请将关闭本地访问来消除此警告");
}
}
return builder.build();
}
/**
* FileStorageService 注入自己的代理对象不然会导致针对 FileStorageService 的代理方法不生效
*/
@EventListener(ContextRefreshedEvent.class)
public void onContextRefreshedEvent() {
FileStorageService service = applicationContext.getBean(FileStorageService.class);
service.setSelf(service);
}
/**
* 本地存储文件访问自动配置类
*/
@Configuration
@ConditionalOnClass(name = "org.springframework.web.servlet.config.annotation.WebMvcConfigurer")
public static class FileStorageLocalFileAccessAutoConfiguration {
@Autowired
private SpringFileStorageProperties properties;
/**
* 配置本地存储的访问地址
*/
@Bean
public WebMvcConfigurer fileStorageWebMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(@NonNull ResourceHandlerRegistry registry) {
for (SpringFileStorageProperties.SpringLocalConfig local : properties.getLocal()) {
if (local.getEnableStorage() && local.getEnableAccess()) {
registry.addResourceHandler(local.getPathPatterns())
.addResourceLocations("file:" + local.getBasePath());
}
}
for (SpringFileStorageProperties.SpringLocalPlusConfig local : properties.getLocalPlus()) {
if (local.getEnableStorage() && local.getEnableAccess()) {
registry.addResourceHandler(local.getPathPatterns())
.addResourceLocations("file:" + local.getStoragePath());
}
}
}
};
}
}
}

View File

@ -0,0 +1,449 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.config;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.x.file.storage.core.FileStorageProperties;
import org.dromara.x.file.storage.core.FileStorageProperties.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Data
@Accessors(chain = true)
@Component
@ConditionalOnMissingBean(SpringFileStorageProperties.class)
@ConfigurationProperties(prefix = "langchat.oss")
public class SpringFileStorageProperties {
/**
* 默认存储平台
*/
private String defaultPlatform = "local";
/**
* 缩略图后缀例如.min.jpg.png
*/
private String thumbnailSuffix = ".min.jpg";
/**
* 上传时不支持元数据时抛出异常
*/
private Boolean uploadNotSupportMetadataThrowException = true;
/**
* 上传时不支持 ACL 时抛出异常
*/
private Boolean uploadNotSupportAclThrowException = true;
/**
* 复制时不支持元数据时抛出异常
*/
private Boolean copyNotSupportMetadataThrowException = true;
/**
* 复制时不支持 ACL 时抛出异常
*/
private Boolean copyNotSupportAclThrowException = true;
/**
* 移动时不支持元数据时抛出异常
*/
private Boolean moveNotSupportMetadataThrowException = true;
/**
* 移动时不支持 ACL 时抛出异常
*/
private Boolean moveNotSupportAclThrowException = true;
/**
* 启用 byte[] 文件包装适配器
*/
private Boolean enableByteFileWrapper = true;
/**
* 启用 URI 文件包装适配器包含 URL String
*/
private Boolean enableUriFileWrapper = true;
/**
* 启用 InputStream 文件包装适配器
*/
private Boolean enableInputStreamFileWrapper = true;
/**
* 启用本地文件包装适配器
*/
private Boolean enableLocalFileWrapper = true;
/**
* 启用 HttpServletRequest 文件包装适配器
*/
private Boolean enableHttpServletRequestFileWrapper = true;
/**
* 启用 MultipartFile 文件包装适配器
*/
private Boolean enableMultipartFileWrapper = true;
/**
* 本地存储
*/
@Deprecated
private List<? extends SpringLocalConfig> local = new ArrayList<>();
/**
* 本地存储
*/
private List<? extends SpringLocalPlusConfig> localPlus = new ArrayList<>();
/**
* 华为云 OBS
*/
private List<? extends SpringHuaweiObsConfig> huaweiObs = new ArrayList<>();
/**
* 阿里云 OSS
*/
private List<? extends SpringAliyunOssConfig> aliyunOss = new ArrayList<>();
/**
* 七牛云 Kodo
*/
private List<? extends SpringQiniuKodoConfig> qiniuKodo = new ArrayList<>();
/**
* 腾讯云 COS
*/
private List<? extends SpringTencentCosConfig> tencentCos = new ArrayList<>();
/**
* 百度云 BOS
*/
private List<? extends SpringBaiduBosConfig> baiduBos = new ArrayList<>();
/**
* 又拍云 USS
*/
private List<? extends SpringUpyunUssConfig> upyunUss = new ArrayList<>();
/**
* MinIO USS
*/
private List<? extends SpringMinioConfig> minio = new ArrayList<>();
/**
* Amazon S3
*/
private List<? extends SpringAmazonS3Config> amazonS3 = new ArrayList<>();
/**
* FTP
*/
private List<? extends SpringFtpConfig> ftp = new ArrayList<>();
/**
* FTP
*/
private List<? extends SpringSftpConfig> sftp = new ArrayList<>();
/**
* WebDAV
*/
private List<? extends SpringWebDavConfig> webdav = new ArrayList<>();
/**
* GoogleCloud Storage
*/
private List<? extends SpringGoogleCloudStorageConfig> googleCloudStorage = new ArrayList<>();
/**
* FastDFS
*/
private List<? extends SpringFastDfsConfig> fastdfs = new ArrayList<>();
/**
* Azure Blob Storage
*/
private List<? extends SpringAzureBlobStorageConfig> azureBlob = new ArrayList<>();
/**
* 转换成 FileStorageProperties 并过滤掉没有启用的存储平台
*/
public FileStorageProperties toFileStorageProperties() {
FileStorageProperties properties = new FileStorageProperties();
properties.setDefaultPlatform(defaultPlatform);
properties.setThumbnailSuffix(thumbnailSuffix);
properties.setUploadNotSupportMetadataThrowException(uploadNotSupportMetadataThrowException);
properties.setUploadNotSupportAclThrowException(uploadNotSupportAclThrowException);
properties.setCopyNotSupportMetadataThrowException(copyNotSupportMetadataThrowException);
properties.setCopyNotSupportAclThrowException(copyNotSupportAclThrowException);
properties.setMoveNotSupportMetadataThrowException(moveNotSupportMetadataThrowException);
properties.setMoveNotSupportAclThrowException(moveNotSupportAclThrowException);
properties.setLocal(
local.stream().filter(SpringLocalConfig::getEnableStorage).collect(Collectors.toList()));
properties.setLocalPlus(localPlus.stream()
.filter(SpringLocalPlusConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setHuaweiObs(huaweiObs.stream()
.filter(SpringHuaweiObsConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setAliyunOss(aliyunOss.stream()
.filter(SpringAliyunOssConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setQiniuKodo(qiniuKodo.stream()
.filter(SpringQiniuKodoConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setTencentCos(tencentCos.stream()
.filter(SpringTencentCosConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setBaiduBos(
baiduBos.stream().filter(SpringBaiduBosConfig::getEnableStorage).collect(Collectors.toList()));
properties.setUpyunUss(
upyunUss.stream().filter(SpringUpyunUssConfig::getEnableStorage).collect(Collectors.toList()));
properties.setMinio(
minio.stream().filter(SpringMinioConfig::getEnableStorage).collect(Collectors.toList()));
properties.setAmazonS3(
amazonS3.stream().filter(SpringAmazonS3Config::getEnableStorage).collect(Collectors.toList()));
properties.setFtp(ftp.stream().filter(SpringFtpConfig::getEnableStorage).collect(Collectors.toList()));
properties.setSftp(
sftp.stream().filter(SpringSftpConfig::getEnableStorage).collect(Collectors.toList()));
properties.setWebdav(
webdav.stream().filter(SpringWebDavConfig::getEnableStorage).collect(Collectors.toList()));
properties.setGoogleCloudStorage(googleCloudStorage.stream()
.filter(SpringGoogleCloudStorageConfig::getEnableStorage)
.collect(Collectors.toList()));
properties.setFastdfs(
fastdfs.stream().filter(SpringFastDfsConfig::getEnableStorage).collect(Collectors.toList()));
properties.setAzureBlob(azureBlob.stream()
.filter(SpringAzureBlobStorageConfig::getEnableStorage)
.collect(Collectors.toList()));
return properties;
}
/**
* 本地存储
*/
@Deprecated
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringLocalConfig extends LocalConfig {
/**
* 本地存储访问路径
*/
private String[] pathPatterns = new String[0];
/**
* 启用本地存储
*/
private Boolean enableStorage = false;
/**
* 启用本地访问
*/
private Boolean enableAccess = false;
}
/**
* 本地存储升级版
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringLocalPlusConfig extends LocalPlusConfig {
/**
* 本地存储访问路径
*/
private String[] pathPatterns = new String[0];
/**
* 启用本地存储
*/
private Boolean enableStorage = false;
/**
* 启用本地访问
*/
private Boolean enableAccess = false;
}
/**
* 华为云 OBS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringHuaweiObsConfig extends HuaweiObsConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 阿里云 OSS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringAliyunOssConfig extends AliyunOssConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 七牛云 Kodo
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringQiniuKodoConfig extends QiniuKodoConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 腾讯云 COS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringTencentCosConfig extends TencentCosConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 百度云 BOS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringBaiduBosConfig extends BaiduBosConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* 又拍云 USS
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringUpyunUssConfig extends UpyunUssConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* MinIO
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringMinioConfig extends MinioConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* Amazon S3
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringAmazonS3Config extends AmazonS3Config {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* FTP
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringFtpConfig extends FtpConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* SFTP
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringSftpConfig extends SftpConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* WebDAV
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringWebDavConfig extends WebDavConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* GoogleCloud Storage
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringGoogleCloudStorageConfig extends GoogleCloudStorageConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* FastDFS Storage
* @author XS <wanghaiqi@beeplay123.com>
* @date 2023/10/23
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringFastDfsConfig extends FastDfsConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
/**
* AzureBlob Storage
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public static class SpringAzureBlobStorageConfig extends AzureBlobStorageConfig {
/**
* 启用存储
*/
private Boolean enableStorage = false;
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.constant;
/**
* @author tycoding
* @since 2024/1/15
*/
public interface CommonConst {
/**
* UTF-8 编码
*/
String UTF_8 = "utf-8";
/**
* 菜单类型menu
*/
String MENU_TYPE_MENU = "menu";
/**
* 菜单类型button
*/
String MENU_TYPE_BUTTON = "button";
/**
* 菜单默认Icon图标
*/
String MENU_ICON = "alert";
String LAYOUT = "Layout";
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.lang.Dict;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.entity.AigcApp;
import cn.iocoder.yudao.module.langchat.entity.AigcAppApi;
import cn.iocoder.yudao.module.langchat.entity.AigcKnowledge;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcAppApiService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcAppService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcKnowledgeService;
import cn.iocoder.yudao.module.langchat.store.AppStore;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@RestController
@RequiredArgsConstructor
@RequestMapping("/aigc/app")
public class AigcAppController {
private final AigcAppService aigcAppService;
private final AigcAppApiService aigcAppApiService;
private final AppStore appStore;
private final AigcKnowledgeService knowledgeService;
@GetMapping("/channel/api/{appId}")
@TenantIgnore
public CommonResult<AigcAppApi> getApiChanel(@PathVariable String appId) {
List<AigcAppApi> list = aigcAppApiService.list(Wrappers.<AigcAppApi>lambdaQuery().eq(AigcAppApi::getAppId, appId));
return CommonResult.success(list.isEmpty() ? null : list.get(0));
}
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcApp>> list(AigcApp data) {
return CommonResult.success(aigcAppService.list(data));
}
@GetMapping("/page")
@TenantIgnore
public CommonResult<Dict> page(AigcApp data, QueryPage queryPage) {
return CommonResult.success(MybatisUtil.getData(aigcAppService.page(MybatisUtil.wrap(data, queryPage),
Wrappers.<AigcApp>lambdaQuery()
.like(StringUtils.isNotEmpty(data.getName()), AigcApp::getName, data.getName())
)));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcApp> findById(@PathVariable String id) {
AigcApp app = aigcAppService.getById(id);
return CommonResult.success(app);
}
@PostMapping
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:app:add')")
public CommonResult add(@RequestBody AigcApp data) {
data.setCreateTime(new Date());
data.setSaveTime(new Date());
aigcAppService.save(data);
appStore.init();
return CommonResult.success(null);
}
@PutMapping
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:app:update')")
public CommonResult update(@RequestBody AigcApp data) {
// 校验知识库是否是同纬度
List<String> knowledgeIds = data.getKnowledgeIds();
if (knowledgeIds != null && !knowledgeIds.isEmpty()) {
List<AigcKnowledge> list = knowledgeService.list(Wrappers.<AigcKnowledge>lambdaQuery().in(AigcKnowledge::getId, knowledgeIds));
Set<String> modelIds = new HashSet<>();
Set<String> storeIds = new HashSet<>();
list.forEach(know -> {
modelIds.add(know.getEmbedModelId());
storeIds.add(know.getEmbedStoreId());
});
if (modelIds.size() > 1) {
return CommonResult.error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "请选择相同向量库数据源配置的知识库");
}
if (storeIds.size() > 1) {
return CommonResult.error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "请选择相同向量模型配置的知识库");
// throw new ServiceException("请选择相同向量模型配置的知识库");
}
}
data.setSaveTime(new Date());
aigcAppService.updateById(data);
appStore.init();
return CommonResult.success(null);
}
@DeleteMapping("/{id}")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:app:delete')")
public CommonResult delete(@PathVariable String id) {
aigcAppService.removeById(id);
appStore.init();
return CommonResult.success(null);
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.entity.AigcDocs;
import cn.iocoder.yudao.module.langchat.mapper.AigcDocsMapper;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import cn.iocoder.yudao.module.langchat.service.core.EmbeddingService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/docs")
public class AigcDocsController {
private final AigcDocsMapper docsMapper;
private final EmbeddingService embeddingService;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcDocs>> list(AigcDocs data) {
return CommonResult.success(docsMapper.selectList(Wrappers.<AigcDocs>lambdaQuery().orderByDesc(AigcDocs::getCreateTime)));
}
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcDocs data, QueryPage queryPage) {
Page<AigcDocs> page = new Page<>(queryPage.getPageNo(), queryPage.getPageSize());
return CommonResult.success(MybatisUtil.getData(docsMapper.selectPage(page, Wrappers.<AigcDocs>lambdaQuery()
.eq(data.getKnowledgeId() != null, AigcDocs::getKnowledgeId, data.getKnowledgeId())
.eq(data.getSliceStatus() != null, AigcDocs::getSliceStatus, data.getSliceStatus())
.orderByDesc(AigcDocs::getCreateTime)
)));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcDocs> findById(@PathVariable String id) {
return CommonResult.success(docsMapper.selectById(id));
}
@PostMapping
@ApiLog("新增文档")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:add')")
public CommonResult add(@RequestBody AigcDocs data) {
docsMapper.insert(data);
return CommonResult.success("success");
}
@PutMapping
@ApiLog("修改文档")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:update')")
public CommonResult update(@RequestBody AigcDocs data) {
docsMapper.updateById(data);
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除文档")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:delete')")
@Transactional
public CommonResult delete(@PathVariable String id) {
// 删除切面数据
embeddingService.clearDocSlices(id);
// 删除文档
docsMapper.deleteById(id);
return CommonResult.success("success");
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.entity.AigcDocsSlice;
import cn.iocoder.yudao.module.langchat.mapper.AigcDocsSliceMapper;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/docs/slice")
public class AigcDocsSliceController {
private final AigcDocsSliceMapper docsSliceMapper;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcDocsSlice>> list(AigcDocsSlice data) {
return CommonResult.success(docsSliceMapper.selectList(Wrappers.<AigcDocsSlice>lambdaQuery().orderByDesc(AigcDocsSlice::getCreateTime)));
}
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcDocsSlice data, QueryPage queryPage) {
Page<AigcDocsSlice> page = new Page<>(queryPage.getPageNo(), queryPage.getPageSize());
return CommonResult.success(MybatisUtil.getData(docsSliceMapper.selectPage(page, Wrappers.<AigcDocsSlice>lambdaQuery()
.eq(data.getKnowledgeId() != null, AigcDocsSlice::getKnowledgeId, data.getKnowledgeId())
.eq(data.getDocsId() != null, AigcDocsSlice::getDocsId, data.getDocsId())
.orderByDesc(AigcDocsSlice::getCreateTime)
)));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcDocsSlice> findById(@PathVariable String id) {
return CommonResult.success(docsSliceMapper.selectById(id));
}
@PostMapping
@ApiLog("新增切片数据")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:slice:add')")
public CommonResult add(@RequestBody AigcDocsSlice data) {
data.setCreateTime(new Date());
docsSliceMapper.insert(data);
return CommonResult.success("success");
}
@PutMapping
@ApiLog("修改切片数据")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:slice:update')")
public CommonResult update(@RequestBody AigcDocsSlice data) {
docsSliceMapper.updateById(data);
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除切片数据")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:docs:slice:delete')")
public CommonResult delete(@PathVariable String id) {
docsSliceMapper.deleteById(id);
return CommonResult.success("success");
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.component.EmbeddingRefreshEvent;
import cn.iocoder.yudao.module.langchat.entity.AigcEmbedStore;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcEmbedStoreService;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.component.SpringContextHolder;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/embed-store")
public class AigcEmbedStoreController {
private final AigcEmbedStoreService embedStoreService;
private final SpringContextHolder contextHolder;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcEmbedStore>> list(AigcEmbedStore data) {
List<AigcEmbedStore> list = embedStoreService.list(Wrappers.lambdaQuery());
list.forEach(this::hide);
return CommonResult.success(list);
}
@GetMapping("/page")
@TenantIgnore
public CommonResult<Dict> page(AigcEmbedStore embedStore, QueryPage queryPage) {
IPage<AigcEmbedStore> page = embedStoreService.page(MybatisUtil.wrap(embedStore, queryPage),
Wrappers.lambdaQuery());
page.getRecords().forEach(this::hide);
return CommonResult.success(MybatisUtil.getData(page));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcEmbedStore> findById(@PathVariable String id) {
AigcEmbedStore store = embedStoreService.getById(id);
hide(store);
return CommonResult.success(store);
}
@PostMapping
@ApiLog("新增向量库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:embed-store:add')")
public CommonResult<AigcEmbedStore> add(@RequestBody AigcEmbedStore data) {
if (StrUtil.isNotBlank(data.getPassword()) && data.getPassword().contains("*")) {
data.setPassword(null);
}
embedStoreService.save(data);
SpringContextHolder.publishEvent(new EmbeddingRefreshEvent(data));
return CommonResult.success(data);
}
@PutMapping
@ApiLog("修改向量库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:embed-store:update')")
public CommonResult update(@RequestBody AigcEmbedStore data) {
if (StrUtil.isNotBlank(data.getPassword()) && data.getPassword().contains("*")) {
data.setPassword(null);
}
embedStoreService.updateById(data);
SpringContextHolder.publishEvent(new EmbeddingRefreshEvent(data));
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除向量库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:embed-store:delete')")
public CommonResult delete(@PathVariable String id) {
AigcEmbedStore store = embedStoreService.getById(id);
if (store != null) {
embedStoreService.removeById(id);
contextHolder.unregisterBean(id);
}
return CommonResult.success("success");
}
private void hide(AigcEmbedStore data) {
if (data == null || StrUtil.isBlank(data.getPassword())) {
return;
}
String key = StrUtil.hide(data.getPassword(), 0, data.getPassword().length());
data.setPassword(key);
}
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.entity.AigcDocs;
import cn.iocoder.yudao.module.langchat.entity.AigcEmbedStore;
import cn.iocoder.yudao.module.langchat.entity.AigcKnowledge;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.mapper.AigcDocsMapper;
import cn.iocoder.yudao.module.langchat.provider.KnowledgeStoreFactory;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcEmbedStoreService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcKnowledgeService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcModelService;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/knowledge")
public class AigcKnowledgeController {
private final AigcKnowledgeService kbService;
private final AigcDocsMapper docsMapper;
private final AigcEmbedStoreService embedStoreService;
private final AigcModelService modelService;
private final KnowledgeStoreFactory knowledgeStore;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcKnowledge>> list(AigcKnowledge data) {
List<AigcKnowledge> list = kbService.list(Wrappers.<AigcKnowledge>lambdaQuery().orderByDesc(AigcKnowledge::getCreateTime));
build(list);
return CommonResult.success(list);
}
private void build(List<AigcKnowledge> records) {
Map<String, List<AigcEmbedStore>> embedStoreMap = embedStoreService.list().stream().collect(Collectors.groupingBy(AigcEmbedStore::getId));
Map<String, List<AigcModel>> embedModelMap = modelService.list().stream().collect(Collectors.groupingBy(AigcModel::getId));
Map<String, List<AigcDocs>> docsMap = docsMapper.selectList(Wrappers.lambdaQuery()).stream().collect(Collectors.groupingBy(AigcDocs::getKnowledgeId));
records.forEach(item -> {
List<AigcDocs> docs = docsMap.get(item.getId());
if (docs != null) {
item.setDocsNum(docs.size());
item.setTotalSize(docs.stream().filter(d -> d.getSize() != null).mapToLong(AigcDocs::getSize).sum());
}
if (item.getEmbedModelId() != null) {
List<AigcModel> list = embedModelMap.get(item.getEmbedModelId());
item.setEmbedModel(list == null ? null : list.get(0));
}
if (item.getEmbedStoreId() != null) {
List<AigcEmbedStore> list = embedStoreMap.get(item.getEmbedStoreId());
item.setEmbedStore(list == null ? null : list.get(0));
}
});
}
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcKnowledge data, QueryPage queryPage) {
Page<AigcKnowledge> page = new Page<>(queryPage.getPageNo(), queryPage.getPageSize());
LambdaQueryWrapper<AigcKnowledge> queryWrapper = Wrappers.<AigcKnowledge>lambdaQuery()
.like(!StrUtil.isBlank(data.getName()), AigcKnowledge::getName, data.getName())
.orderByDesc(AigcKnowledge::getCreateTime);
Page<AigcKnowledge> iPage = kbService.page(page, queryWrapper);
build(iPage.getRecords());
return CommonResult.success(MybatisUtil.getData(iPage));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcKnowledge> findById(@PathVariable String id) {
AigcKnowledge knowledge = kbService.getById(id);
if (knowledge.getEmbedStoreId() != null) {
knowledge.setEmbedStore(embedStoreService.getById(knowledge.getEmbedStoreId()));
}
if (knowledge.getEmbedModelId() != null) {
knowledge.setEmbedModel(modelService.getById(knowledge.getEmbedModelId()));
}
return CommonResult.success(knowledge);
}
@PostMapping
@ApiLog("新增知识库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:knowledge:add')")
public CommonResult add(@RequestBody AigcKnowledge data) {
data.setCreateTime(String.valueOf(System.currentTimeMillis()));
kbService.save(data);
knowledgeStore.init();
return CommonResult.success("success");
}
@PutMapping
@ApiLog("更新知识库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:knowledge:update')")
public CommonResult update(@RequestBody AigcKnowledge data) {
kbService.updateById(data);
knowledgeStore.init();
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除知识库")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:knowledge:delete')")
public CommonResult delete(@PathVariable String id) {
kbService.removeKnowledge(id);
knowledgeStore.init();
return CommonResult.success("success");
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.entity.AigcMessage;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcMessageService;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
* @author tycoding
* @since 2024/1/19
*/
@RequestMapping("/chat/aigc/message")
@RestController
@AllArgsConstructor
public class AigcMessageController {
private final AigcMessageService aigcMessageService;
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcMessage data, QueryPage queryPage) {
LambdaQueryWrapper<AigcMessage> queryWrapper = Wrappers.<AigcMessage>lambdaQuery()
.like(!StrUtil.isBlank(data.getMessage()), AigcMessage::getMessage, data.getMessage())
.like(!StrUtil.isBlank(data.getUsername()), AigcMessage::getUsername, data.getUsername())
.eq(!StrUtil.isBlank(data.getRole()), AigcMessage::getRole, data.getRole())
.orderByDesc(AigcMessage::getCreateTime);
IPage<AigcMessage> iPage = aigcMessageService.page(MybatisUtil.wrap(data, queryPage), queryWrapper);
return CommonResult.success(MybatisUtil.getData(iPage));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult getById(@PathVariable String id) {
return CommonResult.success(aigcMessageService.getById(id));
}
@DeleteMapping("/{id}")
@ApiLog("删除会话消息")
@TenantIgnore
@PreAuthorize("@ss.hasPermission('aigc:message:delete')")
public CommonResult del(@PathVariable String id) {
return CommonResult.success(aigcMessageService.removeById(id));
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.component.ProviderRefreshEvent;
import cn.iocoder.yudao.module.langchat.component.SpringContextHolder;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcModelService;
import cn.iocoder.yudao.module.langchat.annotation.ApiLog;
import cn.iocoder.yudao.module.langchat.utils.MybatisUtil;
import cn.iocoder.yudao.module.langchat.utils.QueryPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/aigc/model")
public class AigcModelController {
private final AigcModelService modelService;
private final SpringContextHolder contextHolder;
@GetMapping("/list")
@TenantIgnore
public CommonResult<List<AigcModel>> list(AigcModel data) {
return CommonResult.success(modelService.list(data));
}
@GetMapping("/page")
@TenantIgnore
public CommonResult list(AigcModel data, QueryPage queryPage) {
Page<AigcModel> iPage = modelService.page(data, queryPage);
return CommonResult.success(MybatisUtil.getData(iPage));
}
@GetMapping("/{id}")
@TenantIgnore
public CommonResult<AigcModel> findById(@PathVariable String id) {
return CommonResult.success(modelService.selectById(id));
}
@PostMapping
@ApiLog("添加模型")
@PreAuthorize("@ss.hasPermission('aigc:model:add')")
@TenantIgnore
public CommonResult add(@RequestBody AigcModel data) {
if (StrUtil.isNotBlank(data.getApiKey()) && data.getApiKey().contains("*")) {
data.setApiKey(null);
}
if (StrUtil.isNotBlank(data.getSecretKey()) && data.getSecretKey().contains("*")) {
data.setSecretKey(null);
}
modelService.save(data);
SpringContextHolder.publishEvent(new ProviderRefreshEvent(data));
return CommonResult.success("success");
}
@PutMapping
@ApiLog("修改模型")
@PreAuthorize("@ss.hasPermission('aigc:model:update')")
@TenantIgnore
public CommonResult update(@RequestBody AigcModel data) {
if (StrUtil.isNotBlank(data.getApiKey()) && data.getApiKey().contains("*")) {
data.setApiKey(null);
}
if (StrUtil.isNotBlank(data.getSecretKey()) && data.getSecretKey().contains("*")) {
data.setSecretKey(null);
}
modelService.updateById(data);
SpringContextHolder.publishEvent(new ProviderRefreshEvent(data));
return CommonResult.success("success");
}
@DeleteMapping("/{id}")
@ApiLog("删除模型")
@PreAuthorize("@ss.hasPermission('aigc:model:delete')")
@TenantIgnore
public CommonResult delete(@PathVariable String id) {
modelService.removeById(id);
// Delete dynamically registered beans, according to ID
contextHolder.unregisterBean(id);
return CommonResult.success("success");
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.aigc;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.langchat.entity.AigcOss;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcOssService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* @author tycoding
* @since 2024/1/19
*/
@RequestMapping("/aigc/oss")
@RestController
@AllArgsConstructor
public class AigcOssController {
private final AigcOssService aigcOssService;
@GetMapping("/list")
public CommonResult list() {
List<AigcOss> list = aigcOssService.list(Wrappers.<AigcOss>lambdaQuery()
.eq(AigcOss::getUserId, SecurityFrameworkUtils.getLoginUserId())
.orderByDesc(AigcOss::getCreateTime)
);
return CommonResult.success(null);
}
@PostMapping("/upload")
public CommonResult upload(MultipartFile file) {
return CommonResult.success(aigcOssService.upload(file, String.valueOf(SecurityFrameworkUtils.getLoginUserId())));
}
@PutMapping
public CommonResult update(@RequestBody AigcOss data) {
aigcOssService.updateById(data);
return CommonResult.success(null);
}
@DeleteMapping("/{id}")
public CommonResult delete(@PathVariable String id) {
aigcOssService.removeById(id);
return CommonResult.success(null);
}
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.endpoint;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.langchat.dal.dto.ChatReq;
import cn.iocoder.yudao.module.langchat.dal.dto.ChatRes;
import cn.iocoder.yudao.module.langchat.dal.dto.ImageR;
import cn.iocoder.yudao.module.langchat.dal.dto.PromptConst;
import cn.iocoder.yudao.module.langchat.entity.AigcApp;
import cn.iocoder.yudao.module.langchat.entity.AigcMessage;
import cn.iocoder.yudao.module.langchat.entity.AigcModel;
import cn.iocoder.yudao.module.langchat.enums.RoleEnum;
import cn.iocoder.yudao.module.langchat.properties.ChatProps;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcAppService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcMessageService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcModelService;
import cn.iocoder.yudao.module.langchat.service.core.ChatService;
import cn.iocoder.yudao.module.langchat.service.core.impl.PersistentChatMemoryStore;
import cn.iocoder.yudao.module.langchat.utils.PromptUtil;
import cn.iocoder.yudao.module.langchat.utils.StreamEmitter;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author tycoding
* @since 2024/1/30
*/
@Slf4j
@RequestMapping("/aigc")
@RestController
@AllArgsConstructor
public class ChatEndpoint {
private final ChatService chatService;
private final AigcMessageService messageService;
private final AigcModelService aigcModelService;
private final AigcAppService appService;
private final ChatProps chatProps;
@PostMapping("/chat/completions")
public SseEmitter chat(@RequestBody ChatReq req) {
StreamEmitter emitter = new StreamEmitter();
req.setEmitter(emitter);
req.setUserId(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
req.setUsername(SecurityFrameworkUtils.getLoginUserNickname());
ExecutorService executor = Executors.newSingleThreadExecutor();
req.setExecutor(executor);
return emitter.streaming(executor, () -> {
chatService.chat(req);
});
}
@GetMapping("/app/info")
public CommonResult<AigcApp> appInfo(@RequestParam String appId, String conversationId) {
AigcApp app = appService.getById(appId);
if (StrUtil.isBlank(conversationId)) {
conversationId = app.getId();
}
if (StrUtil.isNotBlank(app.getPrompt())) {
// initialize chat memory
SystemMessage message = new SystemMessage(app.getPrompt());
PersistentChatMemoryStore.init(conversationId, message);
}
return CommonResult.success(app);
}
@GetMapping("/chat/messages/{conversationId}")
public CommonResult messages(@PathVariable String conversationId) {
List<AigcMessage> list = messageService.getMessages(conversationId, String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
// initialize chat memory
List<ChatMessage> chatMessages = new ArrayList<>();
list.forEach(item -> {
if (chatMessages.size() >= chatProps.getMemoryMaxMessage()) {
return;
}
if (item.getRole().equals(RoleEnum.ASSISTANT.getName())) {
chatMessages.add(new AiMessage(item.getMessage()));
} else {
chatMessages.add(new UserMessage(item.getMessage()));
}
});
PersistentChatMemoryStore.init(conversationId, chatMessages);
return CommonResult.success(list);
}
@DeleteMapping("/chat/messages/clean/{conversationId}")
public CommonResult cleanMessage(@PathVariable String conversationId) {
messageService.clearMessage(conversationId);
// clean chat memory
PersistentChatMemoryStore.clean(conversationId);
return CommonResult.success(null);
}
@PostMapping("/chat/mindmap")
public CommonResult mindmap(@RequestBody ChatReq req) {
req.setPrompt(PromptUtil.build(req.getMessage(), PromptConst.MINDMAP));
return CommonResult.success(new ChatRes(chatService.text(req)));
}
@PostMapping("/chat/image")
public CommonResult image(@RequestBody ImageR req) {
req.setPrompt(PromptUtil.build(req.getMessage(), PromptConst.IMAGE));
return CommonResult.success(chatService.image(req));
}
@GetMapping("/chat/getImageModels")
public CommonResult<List<AigcModel>> getImageModels() {
List<AigcModel> list = aigcModelService.getImageModels();
list.forEach(i -> {
i.setApiKey(null);
i.setSecretKey(null);
});
return CommonResult.success(list);
}
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.controller.admin.endpoint;
import ch.qos.logback.core.net.LoginAuthenticator;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.langchat.dal.dto.ChatReq;
import cn.iocoder.yudao.module.langchat.dal.dto.EmbeddingR;
import cn.iocoder.yudao.module.langchat.entity.AigcDocs;
import cn.iocoder.yudao.module.langchat.entity.AigcDocsSlice;
import cn.iocoder.yudao.module.langchat.entity.AigcOss;
import cn.iocoder.yudao.module.langchat.enums.EmbedConst;
import cn.iocoder.yudao.module.langchat.mapper.AigcDocsMapper;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcKnowledgeService;
import cn.iocoder.yudao.module.langchat.service.aigc.AigcOssService;
import cn.iocoder.yudao.module.langchat.service.core.EmbeddingService;
import cn.iocoder.yudao.module.langchat.service.core.LangEmbeddingService;
import cn.iocoder.yudao.module.langchat.task.TaskManager;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.concurrent.Executors;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/**
* @author tycoding
* @since 2024/4/25
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/chat/aigc/embedding")
public class EmbeddingEndpoint {
private final LangEmbeddingService langEmbeddingService;
private final AigcKnowledgeService aigcKnowledgeService;
private final AigcDocsMapper aigcDocsMapper;
private final AigcOssService aigcOssService;
private final EmbeddingService embeddingService;
@PostMapping("/text")
@PreAuthorize("@ss.hasPermission('aigc:embedding:text')")
@TenantIgnore
public CommonResult text(@RequestBody AigcDocs data) {
if (StrUtil.isBlankIfStr(data.getContent())) {
throw new ServiceException(-1003,"文档内容不能为空");
}
if (StrUtil.isBlank(data.getId())) {
aigcKnowledgeService.addDocs(data);
}
data.setType(EmbedConst.ORIGIN_TYPE_INPUT).setSliceStatus(false);
try {
EmbeddingR embeddingR = langEmbeddingService.embeddingText(
new ChatReq().setMessage(data.getContent())
.setDocsName(data.getType())
.setDocsId(data.getId())
.setKnowledgeId(data.getKnowledgeId()));
aigcKnowledgeService.addDocsSlice(new AigcDocsSlice()
.setKnowledgeId(data.getKnowledgeId())
.setDocsId(data.getId())
.setVectorId(embeddingR.getVectorId())
.setName(data.getName())
.setContent(embeddingR.getText())
);
aigcKnowledgeService.updateDocs(new AigcDocs().setId(data.getId()).setSliceStatus(true).setSliceNum(1));
} catch (Exception e) {
e.printStackTrace();
// del data
aigcKnowledgeService.removeSlicesOfDoc(data.getId());
}
return CommonResult.success("success");
}
@PostMapping("/docs/{knowledgeId}")
@PreAuthorize("@ss.hasPermission('aigc:embedding:docs')")
@TenantIgnore
public CommonResult docs(MultipartFile file, @PathVariable String knowledgeId) {
// 1.1 获得用户信息
String userId = getLoginUserId().toString();
AigcOss oss = aigcOssService.upload(file, userId);
AigcDocs data = new AigcDocs()
.setName(oss.getOriginalFilename())
.setSliceStatus(false)
.setUrl(oss.getUrl())
.setSize(file.getSize())
.setType(EmbedConst.ORIGIN_TYPE_UPLOAD)
.setKnowledgeId(knowledgeId);
aigcKnowledgeService.addDocs(data);
TaskManager.submitTask(userId, Executors.callable(() -> {
embeddingService.embedDocsSlice(data, oss.getUrl());
}));
return CommonResult.success("success");
}
@GetMapping("/re-embed/{docsId}")
@TenantIgnore
public CommonResult reEmbed(@PathVariable String docsId) {
String userId = getLoginUserId().toString();
AigcDocs docs = aigcDocsMapper.selectById(docsId);
if (docs == null) {
throw new ServiceException(-1003,"没有查询到文档数据");
}
if (EmbedConst.ORIGIN_TYPE_INPUT.equals(docs.getType())) {
text(docs);
}
if (EmbedConst.ORIGIN_TYPE_UPLOAD.equals(docs.getType())) {
// clear before re-embed
embeddingService.clearDocSlices(docsId);
TaskManager.submitTask(userId, Executors.callable(() -> {
embeddingService.embedDocsSlice(docs, docs.getUrl());
}));
}
return CommonResult.success("success");
}
@PostMapping("/search")
@TenantIgnore
public CommonResult search(@RequestBody AigcDocs data) {
return CommonResult.success(embeddingService.search(data));
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
import cn.iocoder.yudao.module.langchat.utils.StreamEmitter;
import dev.langchain4j.model.input.Prompt;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
/**
* @author tycoding
* @since 2024/1/30
*/
@Data
@Accessors(chain = true)
public class ChatReq {
private String appId;
private String modelId;
private String modelName;
private String modelProvider;
private String message;
private String conversationId;
private String userId;
private String username;
private String chatId;
private String promptText;
private String docsName;
private String knowledgeId;
private List<String> knowledgeIds = new ArrayList<>();
private String docsId;
private String url;
private String role;
private Prompt prompt;
private StreamEmitter emitter;
private Executor executor;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author tycoding
* @since 2024/1/29
*/
@Data
@Accessors(chain = true)
public class ChatRes {
private boolean isDone = false;
private String message;
private Integer usedToken;
private long time;
public ChatRes(String message) {
this.message = message;
}
public ChatRes(Integer usedToken, long startTime) {
this.isDone = true;
this.usedToken = usedToken;
this.time = System.currentTimeMillis() - startTime;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author tycoding
* @since 2024/4/26
*/
@Data
@Accessors(chain = true)
public class EmbeddingR {
/**
* 写入到vector store的ID
*/
private String vectorId;
/**
* 文档ID
*/
private String docsId;
/**
* 知识库ID
*/
private String knowledgeId;
/**
* Embedding后切片的文本
*/
private String text;
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
import dev.langchain4j.model.input.Prompt;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author tycoding
* @since 2024/1/6
*/
@Data
@Accessors(chain = true)
public class ImageR {
private String modelId;
private String modelName;
private String modelProvider;
private Prompt prompt;
/**
* 内容
*/
private String message;
/**
* 质量
*/
private String quality;
/**
* 尺寸
*/
private String size;
/**
* 风格
*/
private String style;
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.dal.dto;
/**
* @author tycoding
* @since 2024/3/1
*/
public interface PromptConst {
String QUESTION = "question";
String EMPTY = """
------
{{question}}
------
""";
String DOCUMENT = "You are good at analyzing documents. Please analyze my questions according to the following documents, question: [{{question}}], [docs]";
String MINDMAP = """
# Role
You are a Markdown outline format engineer who focuses on answering user questions. You can quickly and accurately convert user questions into refined Markdown outline titles, and refine the specific details of each title.
## Skills
### Skill 1: Identify user question intent
- Accurately understand the specific content and needs of user questions.
### Skill 2: Convert to Markdown outline
- Simplify user questions into Markdown outline-style titles.
### Skill 3: Return to user
- Return the optimized outline to the user.
## Constraints
- Only return the organized Markdown format content, without other explanation information
- Answer the question in the language used by the user.
- Return the answer in Markdown style, keep the main title as concise as possible; and refine the specific step information of each main title in the subtitle.
""";
String WRITE = """
# 角色
你是一名专业文案撰写师你擅长运用行业领域相关知识以专业的视角为用户生成Markdown文档
## 技能
### 技能 1: 写作
- 提取用户输入的主题和关键信息
### 技能 2: 专业知识应用
- 了解相关行业的相关知识
- 在撰写内容时运用专业的语言和视角
### 技能 3: 遵循Markdown格式
- 拆分文档内容以Markdown大纲格式分段内容更易于用户阅读
## 限制
- 只讨论写作相关的话题不要返回其他任何内容和解释
- 始终以用户输入的信息为主题撰写内容
""";
String IMAGE = """
Please generate the corresponding pictures according to the following requirements.
""";
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.ibatis.type.JdbcType;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author tycoding
* @since 2024/7/26
*/
@Data
@TableName(autoResultMap = true)
@Accessors(chain = true)
public class AigcApp implements Serializable {
private static final long serialVersionUID = -94917153262781949L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String modelId;
@TableField(typeHandler = FastjsonTypeHandler.class, jdbcType = JdbcType.VARCHAR)
private List<String> knowledgeIds;
/**
* 名称
*/
private String name;
private String cover;
/**
* Prompt
*/
private String prompt;
/**
* 应用描述
*/
private String des;
/**
* 创建时间
*/
private Date saveTime;
private Date createTime;
@TableField(exist = false)
private AigcModel model;
@TableField(exist = false)
private List<AigcKnowledge> knowledges = new ArrayList<>();
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/7/26
*/
@Data
@Accessors(chain = true)
public class AigcAppApi implements Serializable {
private static final long serialVersionUID = -94917153262781949L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String appId;
private String apiKey;
private String channel;
private Date createTime;
@TableField(exist = false)
private AigcApp app;
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/1/4
*/
@Data
@Accessors(chain = true)
public class AigcConversation implements Serializable {
private static final long serialVersionUID = -19545329638997333L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 提示词ID
*/
private String promptId;
/**
* 用户ID
*/
private String userId;
/**
* 会话标题
*/
private String title;
/**
* 创建时间
*/
private Date createTime;
/**
* 用户名
*/
@TableField(exist = false)
private String username;
/**
* 对话次数
*/
@TableField(exist = false)
private Integer chatTotal;
/**
* Token消耗量
*/
@TableField(exist = false)
private Integer tokenUsed;
/**
* 最后一次对话时间
*/
@TableField(exist = false)
private Date endTime;
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/4/15
*/
@Data
@Accessors(chain = true)
public class AigcDocs implements Serializable {
private static final long serialVersionUID = 548724967827903685L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 知识库ID
*/
private String knowledgeId;
/**
* 名称
*/
private String name;
/**
* 类型
*/
private String type;
/**
* 来源
*/
private String origin;
private String url;
/**
* 文件大小
*/
private Long size;
/**
* 切片数量
*/
private Integer sliceNum;
/**
* 切片状态
*/
private Boolean sliceStatus;
/**
* 文档内容
*/
private String content;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/4/15
*/
@Data
@Accessors(chain = true)
public class AigcDocsSlice implements Serializable {
private static final long serialVersionUID = -3093489071059867065L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 向量库的ID
*/
private String vectorId;
/**
* 文档ID
*/
private String docsId;
/**
* 知识库ID
*/
private String knowledgeId;
/**
* 文档名称
*/
private String name;
/**
* 切片内容
*/
private String content;
/**
* 字符数量
*/
private Integer wordNum;
/**
* 是否Embedding
*/
private Boolean status = false;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* @author tycoding
* @since 2024/10/28
*/
@Data
@TableName(autoResultMap = true)
public class AigcEmbedStore implements Serializable {
private static final long serialVersionUID = 548724967827903685L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String name;
private String provider;
private String host;
private Integer port;
private String username;
private String password;
private String databaseName;
private String tableName;
private Integer dimension;
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @author tycoding
* @since 2024/4/15
*/
@Data
@TableName(autoResultMap = true)
public class AigcKnowledge implements Serializable {
private static final long serialVersionUID = 548724967827903685L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String embedStoreId;
private String embedModelId;
/**
* 知识库名称
*/
private String name;
/**
* 封面
*/
private String cover;
/**
* 描述
*/
private String des;
/**
* 创建时间
*/
private String createTime;
@TableField(exist = false)
private Integer docsNum = 0;
@TableField(exist = false)
private Long totalSize = 0L;
@TableField(exist = false)
private List<AigcDocs> docs = new ArrayList<>();
@TableField(exist = false)
private AigcEmbedStore embedStore;
@TableField(exist = false)
private AigcModel embedModel;
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author tycoding
* @since 2024/1/4
*/
@Data
@Accessors(chain = true)
public class AigcMessage implements Serializable {
private static final long serialVersionUID = -19545329638997333L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 消息ID
*/
private String chatId;
/**
* 会话ID
*/
private String conversationId;
/**
* 用户ID
*/
private String userId;
/**
* 用户名
*/
private String username;
/**
* 请求IP
*/
private String ip;
private Integer tokens;
private Integer promptTokens;
/**
* 角色userassistant
*/
private String role;
/**
* 消息内容
*/
private String model;
/**
* 消息内容
*/
private String message;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author tycoding
* @since 2024/1/4
*/
@Data
@Accessors(chain = true)
public class AigcModel implements Serializable {
private static final long serialVersionUID = -19545329638997333L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String type;
private String model;
private String provider;
private String name;
private Integer responseLimit;
private Double temperature = 0.2;
private Double topP = 0.0;
private String apiKey;
private String secretKey;
private String baseUrl;
private String endpoint;
private String geminiLocation;
private String geminiProject;
private String azureDeploymentName;
private String imageSize;
private String imageQuality;
private String imageStyle;
private Integer dimension;
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @author tycoding
* @since 2024/1/6
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class AigcOss extends OssR {
private static final long serialVersionUID = -250127374910520163L;
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 用户ID
*/
private String userId;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.iocoder.yudao.module.langchat.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* OSS 文件对象
*
* @author tycoding
* @since 2024/1/30
*/
@Data
@Accessors(chain = true)
public class OssR implements Serializable {
private static final long serialVersionUID = 5117927170776709434L;
private String ossId;
private String url;
private Long size;
private String filename;
private String originalFilename;
private String basePath;
private String path;
private String ext;
private String contentType;
private String platform;
private Date createTime;
}

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