Compare commits

...

28 Commits

Author SHA1 Message Date
dengjie a5249db375 fix : 修改项目名称
continuous-integration/drone/push Build is failing Details
2023-08-02 10:16:39 +08:00
clay 9f524440e9 clay commit : workflow查看
continuous-integration/drone/push Build is failing Details
2023-05-12 13:42:25 +08:00
clay cb6a00c4b8 clay commit : workflow查看
continuous-integration/drone/push Build is failing Details
2023-05-12 12:53:14 +08:00
clay 3601965980 clay commit : workflow查看
continuous-integration/drone/push Build is failing Details
2023-05-11 14:58:45 +08:00
clay 91325c062b clay commit : 新内容编写 2023-05-10 23:56:56 +08:00
clay ba068cd992 clay commit : @Excel使用 2023-05-07 16:31:09 +08:00
clay 16a2cf35d0 更新
continuous-integration/drone/push Build is failing Details
2023-03-30 13:53:30 +08:00
clay 956333d270 clay commit : @Excel使用
continuous-integration/drone/push Build is passing Details
2023-02-03 23:30:17 +08:00
clay 43d433828c clay commit : @Excel使用
continuous-integration/drone/push Build is passing Details
2023-02-03 23:27:52 +08:00
clay 1148783dc3 clay commit : @Excel使用
continuous-integration/drone/push Build is passing Details
2023-01-30 23:13:51 +08:00
clay cedd346a7b clay commit : @Excel使用
continuous-integration/drone/push Build is passing Details
2023-01-30 23:06:14 +08:00
clay 7a81a6d761 clay commit : @Excel使用
continuous-integration/drone/push Build is passing Details
2023-01-30 23:05:03 +08:00
clay 64a388ea4c clay commit : @Excel使用
continuous-integration/drone/push Build is passing Details
2023-01-30 23:03:21 +08:00
clay f001dca4b0 clay commit : tree=util使用,sentinel dashboard简介 2023-01-30 23:02:35 +08:00
clay dade8a8c42 clay commit : tree=util使用,sentinel dashboard简介
continuous-integration/drone/push Build is passing Details
2023-01-29 17:17:39 +08:00
clay 0899b1b813 clay commit : tree=util使用,sentinel dashboard简介
continuous-integration/drone/push Build is passing Details
2023-01-29 16:56:52 +08:00
clay aec78ec5cb clay commit : tree=util使用,sentinel dashboard简介
continuous-integration/drone/push Build is passing Details
2023-01-28 16:33:54 +08:00
clay fe7b21ba53 clay commit : tree=util使用,sentinel dashboard简介
continuous-integration/drone/push Build is passing Details
2022-11-17 12:18:38 +08:00
clay eee3ad9298 clay commit : ci/cd相关软件安装
continuous-integration/drone/push Build is passing Details
2022-11-10 19:37:28 +08:00
clay ff7cef6835 clay commit : ci/cd相关软件安装
continuous-integration/drone/push Build is passing Details
2022-11-10 19:34:19 +08:00
clay e83d809db9 clay commit : ci/cd相关软件安装
continuous-integration/drone/push Build is passing Details
2022-11-10 18:58:44 +08:00
clay 610d1856a0 clay commit : ci/cd相关软件安装
continuous-integration/drone/push Build is passing Details
2022-11-08 15:55:37 +08:00
clay 07d5f497bd clay commit : ci/cd相关软件安装
continuous-integration/drone/push Build is passing Details
2022-11-08 15:54:18 +08:00
clay 60fb006a61 Merge remote-tracking branch 'origin/master'
continuous-integration/drone/push Build is passing Details
2022-11-08 15:24:28 +08:00
clay 14090f5965 clay commit : ci/cd相关软件安装 2022-11-08 15:24:02 +08:00
clay bec66ef460 dengjie commit :教程编写
continuous-integration/drone/push Build is passing Details
2022-11-08 15:19:13 +08:00
clay 0ce1729f6b clay commit : ci/cd相关软件安装
continuous-integration/drone/push Build is passing Details
2022-11-08 14:01:09 +08:00
clay 6594effa84 clay commit : ci/cd相关软件安装
continuous-integration/drone/push Build is passing Details
2022-11-08 13:47:42 +08:00
48 changed files with 2234 additions and 146 deletions

View File

@ -1,6 +1,6 @@
module.exports = {
title: "Cloud Security",// 文档标题,左上角显示
description: "Cloud Security",
title: "FateVerse",// 文档标题,左上角显示
description: "FateVerse | 缘境",
markdown: {
lineNumbers: true // 代码块显示行号
},
@ -20,30 +20,30 @@ module.exports = {
// {text: "简体中文", link: "/language/chinese"}
// ]
// },
{text: "博客", link: "https://blog.isww.cn/"}
{text: "博客", link: "https://blog.odliken.cn/"}
],
/**
* 设置侧边栏最大深度
* 一般是以单个md文件中的 # ## ### #### 这几个标题文字为锚点自动生成导航
* **/
sidebarDepth: 4,
sidebarDepth: 1,
// sidebarDepth: 0, //0读取1级标题 1读取1级和2级标题 2读取1级、2级、3级标题
// 设置侧边栏内容
sidebar: [
{
title: '教程',
collapsable: false,
children: [
'/document/',
// {
// title: '侧边栏组合',
// // collapsable: true,
// children: [
// '/second/child/'
// ]
// }
]
},
// {
// title: '本文档使用教程',
// collapsable: false,
// children: [
// '/document/',
// // {
// // title: '侧边栏组合',
// // // collapsable: true,
// // children: [
// // '/second/child/'
// // ]
// // }
// ]
// },
{
title: '文档',
collapsable: false,
@ -52,6 +52,50 @@ module.exports = {
'/wiki/back-build/'
] // 根据自己的需求来订对应自己在docs下的文件夹名默认首页是README.md
},
{
title: '模块介绍',
collapsable: false,
children: [
'/module/',
'/module/common/',
'/module/gateway/',
'/module/auth/',
'/module/umps/',
'/module/notice/',
// '/module/visual/',
'/module/code-gen/',
'/module/custom-query/',
'/module/visual/',
] // 根据自己的需求来订对应自己在docs下的文件夹名默认首页是README.md
},
{
title: '功能使用',
collapsable: false,
children: [
'/use/spring-amin/',
'/use/sentinel-dashboard/',
] // 根据自己的需求来订对应自己在docs下的文件夹名默认首页是README.md
},
{
title: '工具类使用',
collapsable: false,
children: [
'/util/tree-util/',
'/util/excel/',
] // 根据自己的需求来订对应自己在docs下的文件夹名默认首页是README.md
},
{
title: 'CI/CD',
collapsable: false,
children: [
'/ci-cd/',
'/ci-cd/gitea/',
'/ci-cd/drone/',
'/ci-cd/harbor/',
'/ci-cd/rancher/',
'/ci-cd/integration/',
] // 根据自己的需求来订对应自己在docs下的文件夹名默认首页是README.md
},
]
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -4,11 +4,11 @@ heroImage: /logo.png
actionText: 快速上手 →
actionLink: /wiki/introduce/
features:
- title: 简洁至上
details: 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作
- title: Vue驱动
details: 享受 Vue + webpack 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题
- title: 高性能
details: VuePress 为每个页面预渲染生成静态的 HTML同时在页面被加载的时候将作为 SPA 运行
footer: MIT Licensed | Copyright © 2018-present Evan You
- title: ebts-cloud快速开发系统
details: 以Spring Security作为核心搭建集群权限校验,多种功能模块提高开发效率
- title: 开发效率
details: 以权限管理为核心代码生成、自定义查询、服务监控、Swagger聚合文档、对象储存OSS的封装、Excel快速导出、Sentinel限流控制面板和Workflow工作流等模块为辅提高系统的效率
- title: 专注业务
details: 让开发人员更加关注系统业务的实现,花更多的时间在业务上
footer: Copyright © 2022-present Clay
---

55
docs/ci-cd/README.md Normal file
View File

@ -0,0 +1,55 @@
# 关于CI/CD
CI/CD 具有不同的含义, "CI"始终指持续集成,它属于开发人员的自动化流程。"CD"指的是持续交付和/或持续部署这些相关概念有时会交叉使用。在现在的devops模式下可以使用ci/cd持续集成对项目进行部署通过ci/cd中的一些环境变量则可以区分出对应的环境以便于软件开发流程的控制。
## CI 持续集成Continuous Integration
现代应用开发的目标是让多位开发人员同时处理同一应用的不同功能。但是,如果企业安排在一天内将所有分支源代码合并在一起(称为"合并日"最终可能造成工作繁琐、耗时而且需要手动完成。这是因为当一位独立工作的开发人员对应用进行更改时有可能会与其他开发人员同时进行的更改发生冲突。如果每个开发人员都自定义自己的本地集成开发环境IDE而不是让团队就一个基于云的 IDE 达成一致,那么就会让问题更加雪上加霜。
持续集成CI可以帮助开发人员更加频繁地有时甚至每天将代码更改合并到共享分支或"主干"中。一旦开发人员对应用所做的更改被合并系统就会通过自动构建应用并运行不同级别的自动化测试通常是单元测试和集成测试来验证这些更改确保这些更改没有对应用造成破坏。这意味着测试内容涵盖了从类和函数到构成整个应用的不同模块。如果自动化测试发现新代码和现有代码之间存在冲突CI 可以更加轻松地快速修复这些错误。
> 现有的CI工具则有
> - gitee (码云)
> - GitHub
> - gitlab (企业内部仓库)
> - gitea (轻量化代码仓库)
## CD 持续部署Continuous Deployment
对于一个成熟的 CI/CD 管道来说,最后的阶段是持续部署。作为持续交付——自动将生产就绪型构建版本发布到代码存储库——的延伸,持续部署可以自动将应用发布到生产环境。由于在生产之前的管道阶段没有手动门控,因此持续部署在很大程度上都得依赖精心设计的测试自动化。
实际上,持续部署意味着开发人员对应用的更改在编写后的几分钟内就能生效(假设它通过了自动化测试)。这更加便于持续接收和整合用户反馈。总而言之,所有这些 CI/CD 的关联步骤都有助于降低应用的部署风险,因此更便于以小件的方式(而非一次性)发布对应用的更改。不过,由于还需要编写自动化测试以适应 CI/CD 管道中的各种测试和发布阶段,因此前期投资还是会很大。
> 现有的CD工具
> - jekenis (主流)
> - drone (小众轻量化)
> - gitlab (自带cd环境,需要配置一台外部的ranner执行构建任务)
## 集群部署环境k8s
Kubernetes是Google 2014年创建管理的是Google 10多年大规模容器管理技术Borg的开源版本。它是容器集群管理系统是一个开源的平台可以实现容器集群的自动化部署、自动扩缩容、维护等功能。
在开发过程中大多时候开发人员或运维人员并不会使用Kubernetes client 命令行工具更多的是使用Kubernetes的可视化管理界面。
> - kuboard
> - Lens
> - KubeSphere
> - Wayne
> - Kubernetes Dashboard
> - Rancher
Kubernetes在应对分布式,集群管理的情况下可谓是的心应手。
## 完整的CI/CD组合
完整的ci/cd组合,即ci工具+cd工具联通,实现持续集成与持续部署的功能
- gitee + jekenis + k8s
- gitlab + jekenis + k8s
- gitea + jekenis + k8s
- gitea + drone + k8s
## 系统ci/cd
本系统由于资源紧张则选用轻量化的组合,gitea+drone+k8s(rancher)
下面会介绍每个组件的相关安装以及如何运用于本系统。
另外如需要参考ci/cd运用于其他的单体项目则可以参考
[Gitea+Drone+Rancher CI/CD持续集成解决方案](https://blog.odliken.cn/2022/08/07/giteadronerancher-ci-cd%e6%8c%81%e7%bb%ad%e9%9b%86%e6%88%90%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88/)

View File

@ -0,0 +1,90 @@
# Drone
## 关于Drone
Dron是一个现代化的持续集成平台它使用强大的云原生pipeline引擎自动化构建、测试和发布工作流。Drone 与多个源代码管理系统无缝集成,包括 GitHub、GitHubEnterprise、Bitbucket、GitLab和Gitea**它的每个构建都在一个隔离的 Docker 容器中运行**;另外它也支持插件,可以使用你熟知的语言轻松的扩展它们。
## 安装
### 依赖安装
需要安装docker和docker-compose,参照上方安装方式即可
### 安装Drone
安装参考: [Gitea | Drone](https://docs.drone.io/server/provider/gitea/ "Gitea | Drone")
此处同样采用docker-compose.yml的方式安装
```sh
version: '3'
services:
drone-server:
restart: always
image: drone/drone:2
ports:
- "映射宿主机端口:80"
volumes:
- 宿主机挂载目录:/var/lib/drone/
- 宿主机挂载目录:/data/
environment:
- DRONE_GITEA_SERVER=http://gitea服务器地址 # 支持http, https
- DRONE_GITEA_CLIENT_ID=gitea生成的OAuth2客户端ID
- DRONE_GITEA_CLIENT_SECRET=gitea生成的OAuth2客户端密钥
- DRONE_SERVER_HOST=drone服务器地址
- DRONE_SERVER_PROTO=http # 支持http, https
- DRONE_RPC_SECRET=自定义的Drone与runner通信密钥
- DRONE_GIT_ALWAYS_AUTH=true
- DRONE_GIT_USERNAME=部署账户的用户名
- DRONE_GIT_PASSWORD=部署账户的密码
- DRONE_USER_CREATE=username:你的管理员账户名,admin:true # 开启管理员账户
drone-runner-docker:
restart: always
image: drone/drone-runner-docker:1
ports:
- "3000:3000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_RPC_PROTO=http # 支持http, https
- DRONE_RPC_HOST=drone-server
- DRONE_RPC_SECRET=自定义的Drone与runner通信密钥
- DRONE_RUNNER_NAME=drone-runner-docker
- DRONE_RUNNER_CAPACITY=2
```
其中需要将gitea的授权信息填写到上方yml文件中
Gitea个人中心的应用设置创建Gitea OAuth application
![Snipaste_2022-08-07_14-26-05.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e8bd24a1a7b64ba69cd3ef0c17e7b94b~tplv-k3u1fbpfcp-zoom-1.image)
点击创建后将秘钥妥善保管并替换到上面的docker-compose.yml
```
- DRONE_GITEA_CLIENT_ID=gitea生成的OAuth2客户端ID
- DRONE_GITEA_CLIENT_SECRET=gitea生成的OAuth2客户端密钥
- DRONE_GIT_USERNAME=令牌名称
- DRONE_GIT_PASSWORD=令牌秘钥
```
生成Drone与runner通信密钥并替换上面docker-compose.yml对应的字段
```
openssl rand -hex 16
93b722f581830b9abf11345536b9ecfb
```
启动drone
```
docker-compose up -d
```
### 访问drone
访问:[http://drone-server-domain](http://server-ip:80/ "http://drone-server-domain")
![Snipaste_2022-08-07_14-40-12.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/73d3ce553c35476d918423a338ba6b16~tplv-k3u1fbpfcp-zoom-1.image)
授权
![Snipaste_2022-08-07_15-46-05.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/938964948d1c41ce8a0bb8773c1d5625~tplv-k3u1fbpfcp-zoom-1.image)
填写登录信息
![7e22dd46559947ada73cb5605487610e.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6f0e14a98fe8497c873cedc3e51b325f~tplv-k3u1fbpfcp-zoom-1.image)
登录之后就可以看到刚刚我们gitea中的项目
![Snipaste_2022-08-07_15-46-05.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/de472caa4831442ca8a62599eeee2260~tplv-k3u1fbpfcp-zoom-1.image)
在设置中激活
![1659858792624.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ae20cae45d054faea8b2669d825c4b6d~tplv-k3u1fbpfcp-zoom-1.image)
激活保存
![1659858832731.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aa502a9023644e9e9f82475b0481a077~tplv-k3u1fbpfcp-zoom-1.image)

122
docs/ci-cd/gitea/README.md Normal file
View File

@ -0,0 +1,122 @@
## 关于Gitea
Gitea 是一个自己托管的Git服务程序。他和GitHub, Bitbucket or Gitlab等比较类似。他是从 [Gogs](http://gogs.io/) 发展而来Gitea 是一个开源社区驱动的轻量级代码托管解决方案,采用 MIT 许可证。极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构除了x86amd64还包括 ARM 和 PowerPC。
## 系统要求
- 最低的系统硬件要求为一个廉价的树莓派
- 如果用于团队项目,建议使用 2 核 CPU 及 1GB 内存
## [功能特性](https://docs.gitea.io/zh-cn/#%E5%8A%9F%E8%83%BD%E7%89%B9%E6%80%A7)
- 支持活动时间线
- 支持 SSH 以及 HTTP/HTTPS 协议
- 支持 SMTP、LDAP 和反向代理的用户认证
- 支持反向代理子路径
- 支持用户、组织和仓库管理系统
- 支持添加和删除仓库协作者
- 支持仓库和组织级别 Web 钩子(包括 Slack 集成)
- 支持仓库 Git 钩子和部署密钥
- 支持仓库工单Issue、合并请求Pull Request以及 Wiki
- 支持迁移和镜像仓库以及它的 Wiki
- 支持在线编辑仓库文件和 Wiki
- 支持自定义源的 Gravatar 和 Federated Avatar
- 支持邮件服务
- 支持后台管理面板
- 支持 MySQL、PostgreSQL、SQLite3、MSSQL 和 TiDB(MySQL) 数据库
- 支持多语言本地化21 种语言)
- 支持软件包注册中心Composer/Conan/Container/Generic/Helm/Maven/NPM/Nuget/PyPI/RubyGems
## 安装
### 安装环境依赖
gitea 依赖于docker和docker-compose
#### 安装docker
安装所需的安装包yum-utils
```sh
yum install -y yum-utils
```
添加yum源
```sh
yum -y update
#设置镜像仓库地址
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新yum软件包索引
yum makecache fase
```
查看可用版本
```sh
yum list docker-ce --showduplicates | sort -r
```
安装docker社区版和社区办对应的cli工具已经依赖
```sh
yum install -y docker-ce docker-ce-cli containerd.io
```
启动 Docker 并设置开机自启
```sh
systemctl start docker
systemctl enable docker
```
添加镜像源地址
```
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://uyah70su.mirror.aliyuncs.com"]
}
EOF
```
重新启动 Docker 服务
```
systemctl daemon-reload && sudo systemctl restart docker
```
验证配置是否生效
```
docker info | grep Mirrors -A1
```
#### 安装docker-compose
安装epel源
```
yum install -y epel-release
```
安装docker-compose
```
yum install -y docker-compose
```
### 安装gitea
安装参考链接:[使用 Docker 安装 - Docs](https://docs.gitea.io/zh-cn/install-with-docker/ "使用 Docker 安装 - Docs")
最简单的设置只是创建一个卷和一个网络,然后将 `gitea/gitea:latest` 镜像作为服务启动。由于没有可用的数据库,因此可以使用 SQLite3 初始化数据库。创建一个类似 `gitea` 的目录,并将以下内容粘贴到名为 `docker-compose.yml` 的文件中。
```
version: "3"
networks:
gitea:
external: false
services:
server:
image: gitea/gitea:1.16.7
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
networks:
- gitea
volumes:
- /home/data:/data # /home/data可以替换成你想要的挂载目录
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3030:3000" # 3030可以替换成你想要的端口
- "322:22" # 322可以替换成22
```
在后台启动
```
docker-compose up -d
```
### 配置gitea
访问:[http://server-ip:3030](http://server-ip:3030/ "http://server-ip:3030")
设置域名访问地址等信息
![Snipaste_2022-08-07_13-45-57.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9d7fd177f43c4dd7b4841a4621755b72~tplv-k3u1fbpfcp-zoom-1.image)
设置管理员账号密码
![Snipaste_2022-08-07_13-49-05.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e3ef5d88604c4eec8e890cc316f2307d~tplv-k3u1fbpfcp-zoom-1.image)
点击安装后,系统安装完毕会自动登录

165
docs/ci-cd/harbor/README.md Normal file
View File

@ -0,0 +1,165 @@
# Harbor
Harbor 是由 VMware 开源的一款云原生制品仓库Harbor 的核心功能是存储和管理 Artifact。Harbor 允许用户用命令行工具对容器镜像及其他 Artifact 进行推送和拉取,并提供了图形管理界面帮助用户查看和管理这些 Artifact。在 Harbor 2.0 版本中除容器镜像外Harbor 对符合 OCI 规范的 Helm Chart、CNAB、OPA Bundle 等都提供了更多的支持。
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3b77b4831446430f8545af9961979903~tplv-k3u1fbpfcp-zoom-1.image)
## 安装准备
1.需要安装docker和docker-compose并运行docker安装可以参考
[Gitea+Drone+Rancher CI/CD持续集成解决方案](https://blog.odliken.cn/2022/08/07/giteadronerancher-ci-cd%e6%8c%81%e7%bb%ad%e9%9b%86%e6%88%90%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88/)中有详细解决方案
## 安装
下载地址:[https://github.com/goharbor/harbor/releases](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fgoharbor%2Fharbor%2Freleases)
直接选择编译好的包
![18118090-5cb195f1965a6e92.webp](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1a1652fc32cf4d53ba9250a089808841~tplv-k3u1fbpfcp-watermark.image?)
这里有两个包Harbor offline installer 和 Harbor online installer两者的区别的是 Harbor offline installer 里就包含的 Harbor 需要使用的镜像文件
下载成功,并解压
```
tar zxf harbor-offline-installer-v1.10.1.tgz -C /data/
```
进入解压的目录,并 ls
```
[root@master ~]# cd /data/harbor/
[root@master harbor]# ls
common.sh harbor.v1.10.1.tar.gz harbor.yml install.sh LICENSE prepare
```
## 编辑配置文件
编辑 harbor.yml 配置文件hostname 是 harbor 对外暴露的访问地址HTTP 服务对外暴露 80 端口。这里可暂时先不配置HTTPS可将HTTPS 相关内容注释。
![8_FK_`PA`MN@AL@8H1SP_W4.jpg](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a14ddb5f77b4415b8d3431d957a8a993~tplv-k3u1fbpfcp-zoom-1.image)
修改完成后运行`./prepare `命令
# 部署
```
./install.sh
```
## 登录页面
浏览器输入 http://192.168.101.105 访问 Harbor 页面,用户名和密码为 harbor.yml 配置文件中默认设置的 adminHarbor12345。
![1665994860817.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2821dec1f0e143c199f8cda739bcced7~tplv-k3u1fbpfcp-zoom-1.image)
编辑 /etc/docker/daemon.json设置允许访问的 HTTP 仓库地址。
```
{
"insecure-registries":["11.8.36.21:8888"]
}
```
## HTTPS 配置(可选)
在生产环境中建议配置 HTTPS可以使用由受信任的第三方 CA 签名的证书,也可以使用自签名证书。如果想要启用 Content Trust with Notary 来正确签名所有图像,则必须使用 HTTPS。
### 生成 CA 证书
本次实验中我们使用自签名证书。生产环境中应使用受信任的第三方 CA 签名的证书。
### 生成 CA 证书私钥
```
openssl genrsa -out ca.key 4096
```
### 生成 CA 证书
-subj 表示证书的组织。CN 后面的值改成 harbor 的 IP 地址或者域名。
```
openssl req -x509 -new -nodes -sha512 -days 3650 \ -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=11.8.36.21" \ -key ca.key \ -out ca.crt
```
### 生成 Server 证书
生成 Harbor 使用的证书和私钥。
### 生成 Server 私钥
```
openssl genrsa -out server.key 4096
```
### 生成 Server 证书签名请求CSR
生成 Harbor 的证书签名请求,使用上面生成的 CA 证书来给 Server 签发证书。
```
openssl req -sha512 -new \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=11.8.36.21" \
-key server.key \
-out server.csr
```
### 生成 x509 v3 扩展文件
通过 docker 或者 ctr 等工具拉取 HTTPS 的镜像时,要求 HTTPS 的证书包含 SAN 扩展。
SANSubject Alternative Name 是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 [SSL 证书](https://cloud.tencent.com/product/symantecssl?from=10680),可以扩展此证书支持的域名,使得一个证书可以支持多个不同域名的解析。例如下图中 Google 的这张证书的主题备用名称SAN中列了一大串的域名因此这张证书能够被多个域名所使用。对于 Google 这种域名数量较多的公司来说,使用这种类型的证书能够极大的简化网站证书的管理。
使用以下命令生成 x509 v3 扩展文件:
```
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = IP:11.8.36.21
EOF
```
如果是域名访问通过下面方式生成 x509 v3 扩展文件:
```
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1=yourdomain.harbor.com
EO
```
### 使用 CA 证书签发 Server 证书
```
openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in server.csr \
-out server.crt
```
## 为 Harbor 和 Docker 配置证书
### 将 server 证书和密钥复制到 Harbor 主机上的 /data/cert 目录中
### 转换 server.crt 为 server.cert
Docker 守护程序会认为 .crt 文件是 CA 证书,因此需要将 server 证书转换为 server.cert 文件。其实改下后缀就可以了,证书里面的内容是一样的。
```
openssl x509 -inform PEM -in server.crt -out server.cert
```
### 重启 Docker Engine
```
systemctl restart docker
```
### 重新部署 Harbor
修改 harbor.yml 配置文件,添加 HTTPS 相关配置,指定 HTTPS 的端口号和证书路径:
### 使用 prepare 脚本生成 HTTPS 配置
使用 prepare 脚本为反向代理 Nginx 容器生成 HTTPS 配置。
```
./prepare
```
### 删除原有 Harbor 容器
Harbor 原有的数据文件默认是挂载在宿主机的 /data 目录下,因此删除 Harbor 容器并不会丢失数据。
```
docker-compose down -v
```
### 重新启动 Harbor
```
docker-compose up -d
```

View File

@ -0,0 +1,299 @@
# 集成
ebts-cloud快速开发系统采用前后端分离试开发后端为Spring Cloud 体系架构前端现有React后期会继续更新Vue3.0版本前端页面
## gitea + drone 集成
在安装drone的时候可知drone需要获取到gitea的oauth2的授权这样drone就可以通过携带秘钥信息去请求到gitea当前用户下的所有仓库了
当gitea中的仓库有request的时候gitea会发送一个Web沟子请求到drone
![webhook.png](./webhook.png)
请求内容中就会包括到当前提交的相关信息drone就可以拿到这些信息获取到gitea仓库中的最新代码
## drone + k8s(rancher)
drone触发k8s是非常简单的需要准备一个带有kubectl命令行工具的docker镜像当drone的steps运行到了这一步了之后只需要使用命令行工具运行:
```shell
kubectl apply -f deployment.yml -n dev --kubeconfig=/app/config/kubectl_conf.yml
```
其中 kubectl_conf.yml 则是k8s的连接配置文件deployment.yml文件则是需要构建内容的配置文件
当命令成功运行后即可在k8s中看到新构建的内容但是现在看来drone只是触发了k8s的构建但是k8s构建所需要的docker镜像现在还未知在docker中有一种叫做docker镜像仓库的存在我们制作好的docker镜像就可以推送到镜像仓库中并将仓库中对应的docker pull路径放到deployment.yml文件中可以由k8s pull下来。
## Harbor
Harbor是一个docker的镜像仓库他可以独立部署在drone和k8s中当做粘合剂当drone中构建好了对应docker镜像后将docker镜像推送到harbor然后将pull 的路径又放到k8s的deployment.yml文件中这样全链路就打通了。
为了方便区分每一次drone提交的docker镜像都是不同的并且在k8s的机制中如果你的pull 地址完全相同k8s认为你没有对镜像进行更新所以需要一个随机的变量那么在gitea中存在一个值叫做commit id这个值是每一次提交的唯一标识符所以也可以作为区分镜像版本的变量。
## 前端
在前端项目中,有这
```
.drone.yml -- drone ci/cd管道配置命令
deployment.yml -- k8s部署文件
default.conf -- Nginx的映射配置文件
Dockerfile -- 将前端的打包内容构建docker镜像的文件
docker.sh -- 进行docker打包并且按照约定格式推送到Harbor仓库
.dockerignore -- docker的ignore文件
```
### .drone.yml文件内容详情
```yaml
kind: pipeline # drone配置文件类型 pipeline管道
type: docker # 使用对应steps对应的类型drone是基于docker容器进行每一个步骤的
name: security-react # 本次构建任务的名称
steps:
- name: build-package-react # 当前steps的名称
image: node:16.18.0 # 需要使用到的镜像与react项目中packjson中配置的node版本一致
volumes: # 将容器内容部的地址映射到宿主机上
- name: cache # node构建是的缓存防止多次下载提高build速度
path: /drone/src/node_modules
- name: build # 内容挂在将打包的好产物放到当前目录下方便后续steps的时候
path: /app/build
commands: # 容器中需要执行的命令
- export CI=false
- rm -rf /app/build/react/* # 初始化需要使用的目录
- cp deployment.yml /app/build/react/ # 将k8s构建文件cp到产物挂在目录
- cp Dockerfile /app/build/react/ #
- cp .dockerignore /app/build/react/
- cp default.conf /app/build/react/
- cp docker.sh /app/build/react/
- cp nginx.conf /app/build/react/
- mkdir -p ./node_modules # 创建node依赖目录
- export NODE_MODULES_PATH=`pwd`/node_modules # 构建与缓存目录之间的关联
# - npm config set registry https://registry.npm.taobao.org # 可以开启淘宝npm的镜像加速
# - set NODE_OPTIONS=--openssl-legacy-provider
- npm install # 下载依赖虽然已经进行了依赖的缓存但是一旦有新的依赖加入缓存中没有则无法构建所以还需要install一下
- npm run build # 开始构建产物
- mkdir -p /app/build/react # 创建存放产物的映射目录
- cp -r build /app/build/react # 将打包好之后的内容放入的对应的目录中
- name: build-docker # 制作docker镜像
image: docker # 使用官方docker镜像
volumes: # 将容器内目录挂载到宿主机
- name: build
path: /app/build
- name: docker # 挂载宿主机的docker
path: /var/run/docker.sock
- name: config
path: /config
environment: # 获取到密文的docker用户名和密码
DOCKER_USERNAME:
from_secret: docker_username
DOCKER_PASSWORD:
from_secret: docker_password
REGISTRY:
from_secret: registry
REGISTRY_NAMESPACE:
from_secret: registry_namespace
commands: # 定义在Docker容器中执行的shell命令
- cd /app/build/react/
- cat Dockerfile
# 将一下文件中的密文信息替换成对应的内容
- sed -i 's/$REGISTRY/'"$REGISTRY"'/' deployment.yml
- sed -i 's/$REGISTRY_NAMESPACE/'"$REGISTRY_NAMESPACE"'/' deployment.yml
- sed -i 's/$DRONE_REPO_NAME/'"$DRONE_REPO_NAME"'/' deployment.yml
- sed -i 's/$DRONE_COMMIT/'"$DRONE_COMMIT"'/' deployment.yml
# docker登录不能在脚本中登录并且不能使用docker login -u -p
- echo $DOCKER_PASSWORD | docker login $REGISTRY --username $DOCKER_USERNAME --password-stdin
- chmod +x docker.sh
- sh docker.sh # 运行docker打包脚本
# 执行完脚本删除本次制作的docker镜像避免多次后当前runner空间不足
- docker rmi -f $(docker images | grep $DRONE_REPO_NAME | awk '{print $3}')
- name: drone-rancher # rancher运行
image: registry.cn-hangzhou.aliyuncs.com/claywang/kubectl #阿里云的kubectl镜像里面包含kubectl命令行工具
volumes: # 将容器内目录挂载到宿主机
- name: build
path: /app/build # 将应用打包好的Jar和执行脚本挂载出来
- name: config
path: /app/config # 将kubectl 配置文件挂载出来
commands: # 定义在Docker容器中执行的shell命令
- cd /app/build/react/
# 将deployment中定义的变量替换为drone中的内置变量
- cat deployment.yml
# 通过kubectl指令运行deployment.yml并指定授权文件kubectl_conf.yml
- kubectl apply -f deployment.yml -n dev --kubeconfig=/app/config/kubectl_conf.yml
volumes:
- name: build
host:
path: /home/build
- name: cache
host:
path: /var/lib/npm/cache
- name: config # k8s对接的配置文件
host:
path: /.kube/config
- name: maven-cache # maven的缓存文件
host:
path: /home/data/maven/cache
- name: docker # 宿主机中的docker
host:
path: /var/run/docker.sock
```
## 后端
后端采用的为maven聚合工程情况要比前端负责一些下面是后端聚合工程的模块划分:
```lua
security-cloud
├── auth -- 授权服务模块
├── gateway -- 网关服务模块
└── common -- 系统公共模块
├── common-core -- 公共工具类核心包
├── common-mybatis -- mybatis 扩展封装
├── common-security -- 安全工具类
├── common-swagger -- 接口文档
├── common-feign -- feign 扩展封装
└── common-log -- 系统日志记录
└── upms -- 通用用户权限管理模块
└── upms-api -- 通用用户权限管理系统公共api模块
└── upms-biz -- 通用用户权限管理系统业务处理模块[4000]
└── visual -- 图形化管理模块
└── monitor -- 服务监控
└── codegen -- 图形化代码生成
```
现阶段需要进行ci/cd构建的模块有 auth(授权服务模块) umps-biz(通用用户权限管理系统业务处理模块) gateway(网关服务模块);在这样的前提下,后端就不能同前端一样,一个.drone.yml文件只是服务于单独的一个镜像构建打包了在后端的情况下则需要通过其他方式来区分每一个模块并对每一个模块进行从打包构建到发布的全部流程;所以ci/cd配置难度将加大。
在整个ci/cd活动中唯一能够区分他们并且能够伴随到整个ci/cd流程的只有分支名称所以通过分支名称作为他们的发布名称比如auth(授权服务模块)的发布名称就叫做auth同时项目的jar包名称以及后续的docker镜像名称还有k8s的发布名称都需要统一
在drone中用于储存分支名称的变量为$DRONE_COMMIT_BRANCH 需要了解其他drone变量则可以前往 [Drone内置变量](https://blog.odliken.cn/2022/08/06/drone%e5%86%85%e7%bd%ae%e5%8f%98%e9%87%8f/)
在编写ci/cd的过程中则使用该变量贯穿整个ci/cd的流程配合commit id实现区分不同的版本。
并且在获取分支的时候直接cd $DRONE_COMMIT_BRANCH即可进入到对应模块下然后找到target下$DRONE_COMMIT_BRANCH.jar就可以将这个jar包放到构建的缓存路径下进行下一步的操作了。
## 模块下的模块构建方式
上方的结构图中出现了umps-biz模块这个模块是在umps下方他的分支名应该是什么呢
当前模块的分支名当然是umps-biz但是cd $DRONE_COMMIT_BRANCH的时候真正的运行命令则是 cd umps-biz在项目路径中没有当前的路径所以这是我们需要使用到drone的when 关键词区分分支名称分支为umps-biz的时候我们需要将cd $DRONE_COMMIT_BRANCH 改为cd umps/当前模块的分支名当然是umps-biz但是cd $DRONE_COMMIT_BRANCH的时候真正的运行命令则是 cd umps-biz在项目路径中没有当前的路径所以这是我们需要使用到drone的when 关键词区分分支名称分支为umps-biz的时候我们需要将cd $DRONE_COMMIT_BRANCH 改为$DRONE_COMMIT_BRANCH这样就可以继续完成下面的steps了
## .drone.yml文件详细
```yaml
kind: pipeline
type: docker
name: security-cloud
steps:
- name: build-jar # 流水线名称
image: maven:3.8.5-openjdk-8 # 定义创建容器的Docker镜像maven:3.8.5-openjdk-8用于对java进行打包使用
volumes: # 将容器内目录挂载到宿主机仓库需要开启Trusted设置
- name: maven-cache
path: /root/.m2 # 将maven下载依赖的目录挂载出来防止重复下载
- name: maven-build
path: /app/build # 将应用打包好的Jar和执行脚本挂载出来
commands: # 定义在Docker容器中执行的shell命令
- rm -rf /app/build/*
- mvn clean package -DskipTests=true # 应用打包命
- cp start.sh /app/build/ # java包的启动脚本
- cp Dockerfile /app/build/ # docker镜像打包时的文件
- cp deployment.yml /app/build/ # k8s部署文件
- cp .dockerignore /app/build/ # docker镜像打包时过滤文件
- cp docker.sh /app/build/ # docker 镜像打包脚本
- cd $DRONE_COMMIT_BRANCH
- cp target/$DRONE_COMMIT_BRANCH.jar /app/build/$DRONE_COMMIT_BRANCH.jar # 将打包后的内容复制到挂载目录下
when:
branch:
- gateway
- auth
- name: build-jar-umps-biz # 流水线名称
image: maven:3.8.5-openjdk-8 # 定义创建容器的Docker镜像maven:3.8.5-openjdk-8用于对java进行打包使用
volumes: # 将容器内目录挂载到宿主机仓库需要开启Trusted设置
- name: maven-cache
path: /root/.m2 # 将maven下载依赖的目录挂载出来防止重复下载
- name: maven-build
path: /app/build # 将应用打包好的Jar和执行脚本挂载出来
commands: # 定义在Docker容器中执行的shell命令
- rm -rf /app/build/*
- mvn clean package -DskipTests=true # 应用打包命
- cp start.sh /app/build/ # java包的启动脚本
- cp Dockerfile /app/build/ # docker镜像打包时的文件
- cp deployment.yml /app/build/ # k8s部署文件
- cp .dockerignore /app/build/ # docker镜像打包时过滤文件
- cp docker.sh /app/build/ # docker 镜像打包脚本
- cd umps/$DRONE_COMMIT_BRANCH
- cp target/$DRONE_COMMIT_BRANCH.jar /app/build/$DRONE_COMMIT_BRANCH.jar # 将打包后的内容复制到挂载目录下
when:
branch:
- umps-biz
- name: build-docker # 制作docker镜像
image: docker # 使用官方docker镜像
volumes: # 将容器内目录挂载到宿主机
- name: maven-build
path: /app/build # 将应用打包好的Jar和执行脚本挂载出来
- name: docker
path: /var/run/docker.sock # 挂载宿主机的docker
environment: # 获取到密文的docker用户名和密码
DOCKER_USERNAME:
from_secret: docker_username
DOCKER_PASSWORD:
from_secret: docker_password
REGISTRY:
from_secret: registry
REGISTRY_NAMESPACE:
from_secret: registry_namespace
commands: # 定义在Docker容器中执行的shell命令
- cd /app/build
- sed -i 's/$REGISTRY/'"$REGISTRY"'/' deployment.yml
- sed -i 's/$REGISTRY_NAMESPACE/'"$REGISTRY_NAMESPACE"'/' deployment.yml
- sed -i 's/$DRONE_COMMIT_BRANCH/'"$DRONE_COMMIT_BRANCH"'/' start.sh
- sed -i 's/$DRONE_COMMIT_BRANCH/'"$DRONE_COMMIT_BRANCH"'/' Dockerfile
- sed -i 's/$DRONE_COMMIT_BRANCH/'"$DRONE_COMMIT_BRANCH"'/' .dockerignore
- sed -i 's/$DRONE_COMMIT_BRANCH/'"$DRONE_COMMIT_BRANCH"'/' deployment.yml
- sed -i 's/$DRONE_COMMIT/'"$DRONE_COMMIT"'/' deployment.yml
# docker登录不能在脚本中登录并且不能使用docker login -u -p
- cat Dockerfile
- echo $DOCKER_PASSWORD | docker login $REGISTRY --username $DOCKER_USERNAME --password-stdin
- chmod +x docker.sh
- sh docker.sh
# 执行完脚本删除本次制作的docker镜像避免多次后当前runner空间不足
- docker rmi -f $(docker images | grep $DRONE_COMMIT_BRANCH | awk '{print $3}')
- name: drone-rancher # rancher运行
image: registry.cn-hangzhou.aliyuncs.com/claywang/kubectl #阿里云的kubectl镜像里面包含kubectl命令行工具
volumes: # 将容器内目录挂载到宿主机
- name: maven-build
path: /app/build # 将应用打包好的Jar和执行脚本挂载出来
- name: config
path: /app/config # 将kubectl 配置文件挂载出来
commands: # 定义在Docker容器中执行的shell命令
- cd /app/build
# 通过kubectl指令运行deployment.yml并指定授权文件kubectl_conf.yml
# - kubectl apply -f deployment.yml -n $DRONE_COMMIT_BRANCH --kubeconfig=/app/config/kubectl_conf.yml
- kubectl apply -f deployment.yml -n dev --kubeconfig=/app/config/kubectl_conf.yml
volumes: # 定义流水线挂载目录,用于共享数据
- name: maven-build # maven打包后的文件
host:
path: /home/data/maven/build # 从宿主机中挂载的目录
- name: config # k8s对接的配置文件
host:
path: /.kube/config
- name: maven-cache # maven的缓存文件
host:
path: /home/data/maven/cache
- name: docker # 宿主机中的docker
host:
path: /var/run/docker.sock
# 定义触发条件
trigger:
branch:
- gateway
- auth
- umps-biz
event:
- push
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -0,0 +1,50 @@
# Rancher
Rancher 是供采用容器的团队使用的完整软件堆栈。它解决了管理多个Kubernetes集群的运营和安全挑战并为DevOps团队提供用于运行容器化工作负载的集成工具。简单来说是一个k8s的管理软件!
## 安装
rancher的latest版本是2.6以上,本次安装v2.4.15
```
docker run -d --privileged --restart=unless-stopped -p 80:80 -p 443:443 --privileged rancher/rancher:v2.4.15
```
访问(注意是https)
https://ip-server
输入admin 的密码
![1659861472908.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fb2b9226948d4a1c8f418c637d843bde~tplv-k3u1fbpfcp-zoom-1.image)
点击下一步,设置rancher的访问url,如果有域名则填写域名
![1659861565669.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a152c8f679ea4133a35ebc7d4fa2d792~tplv-k3u1fbpfcp-zoom-1.image)
进入管理页面
![1659861619139.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b59e72f4933a49ca886f143d91d8c425~tplv-k3u1fbpfcp-zoom-1.image)
## 添加集群
点击右上角的添加集群
![1659861716608.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f11c3112091e4dcf8a796bc3d7f1e1b3~tplv-k3u1fbpfcp-zoom-1.image)
选择自定义
![1659861756287.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1f85561e78cd4da2b6faff2ac22d030f~tplv-k3u1fbpfcp-zoom-1.image)
配置集训信息
![1659861839152.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/63ec1b53ebd341f1b8d935669f711116~tplv-k3u1fbpfcp-zoom-1.image)
点击下一步进入添加节点页面,由于当前集群还没有节点,所以主机选项中的每一个角色都需要选择
![1659861949108.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/042325d209af4830840285ef8550b6ce~tplv-k3u1fbpfcp-zoom-1.image)
复制下方的命令到装有docker的主机中运行即可,注意rancher安装的主机和其他节点主机的**ip都必须为静态ip**,不然主机重启后集群就失效了,原因为主机重启后ip变更,k8s不能够通过ip找到对应的节点
![1659862145815.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9ea0b40680144096aa7bab7b7c747c4a~tplv-k3u1fbpfcp-zoom-1.image)
集群正在添加节点(等待时间很漫长)
![1659862165132.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1cc87a62468f46d88bc9f6d97ee7f803~tplv-k3u1fbpfcp-zoom-1.image)
添加完成
![1659862423973.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/35e4e436b4b9498d9c9fed01a26b5d56~tplv-k3u1fbpfcp-zoom-1.image)
![1659862458725.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/023794f8136646fe904989fb381d0795~tplv-k3u1fbpfcp-zoom-1.image)

View File

@ -1,4 +1,125 @@
# 首先
# config.js配置教程
## 其次
固定侧边栏,不折叠显示: collapsable: false,
## 设置站点根路径
- 如果访问的时候是ip+端口,那么这里就是**/**如果访问的是ip+端口+工程名,那么这里就是 **/工程名/**
- 这是部署到github相关的配置
```
module.exports = {
base:'/',
}
```
## 设置编译后的输出目录
- **./ROOT**代表在工程的根目录下生成一个ROOT文件里面是编译好的文件可以拿ROOT直接部署。
```
module.exports = {
dest:'./ROOT',
}
```
## 本地调试的端口号默认是8080
```
module.exports = {
port:8086,
}
```
## 代码块显示行号
```
module.exports = {
markdown: {
lineNumbers: true // 代码块显示行号
}
}
```
## 页面路由地址对应写法
| 文件的相对路径 | 页面路由地址 |
| :------------ | :------------ |
| /README.md | / |
| /guide/README.md | /guide/ |
| /config.md | /config.html |
## 网页标签的图标
- 这里的 '/' 指向 docs/.vuepress/public 文件目录 ,即 docs/.vuepress/public/logo.png
```
themeConfig: {
head: [
['link', {rel: 'icon', href: '/logo.png'}],
],
}
```
## 导航栏Logo
```
themeConfig: {
logo:'/logo.png',
}
```
![](/navLogo.png)
## nav配置【右上角的导航条】
```
themeConfig: {
nav:
[
{text: "首页", link: "/"},
{text: "指南", link: "/wiki/introduce/"},
{text: "博客", link: "https://blog.isww.cn/"}
],
}
```
## 侧边栏配置
### 设置左侧导航显示的层级
- sidebarDepth: 2
- 一般是以单个md文件中的 # ## ### #### 这几个标题文字为锚点自动生成导航
- 0读取1级标题
- 1读取1级和2级标题
- 2读取1级、2级、3级标题
### 设置侧边栏内容
- 根据自己的需求来订对应自己在docs下的文件夹名默认首页是README.md 【/wiki/introduce/ 相当于 /wiki/introduce/README.md】效果如下图
- 【注】其中侧边栏除了config.js下的title外的导航栏目是根据该目录(例如:/wiki/introduce/)下的一级、二级、三级和四级标题所自动生成的导航栏目,所以**侧边栏只需要在config.js配置页面路由地址及title即可**
```
themeConfig: {
sidebar: [
{
title: '文档',
collapsable: false,
children: [
'/wiki/introduce/',
'/wiki/back-build/',
{
title: "侧边栏组合",
collapsable: false,
children: [
"/second/child/"
]
}
]
},
]
}
```
## 底部设置最后更新时间
```
themeConfig: {
//最后更新时间
lastUpdated: 'Last Updated',
}
```

View File

@ -1,25 +0,0 @@
# 第一个侧边栏
firstside
firstside
## 二级第一个侧边栏
二级第一个侧边栏
二级第一个侧边栏
## 二级第二个侧边栏
二级第二个侧边栏
二级第二个侧边栏
### 三级第一个侧边栏
三级第一个侧边栏
三级第一个侧边栏
三级第一个侧边栏
## 二级第三个侧边栏
二级第三个侧边栏
二级第三个侧边栏
二级第三个侧边栏

33
docs/module/README.md Normal file
View File

@ -0,0 +1,33 @@
# 模块信息
> 以下是security-cloud所以模块,本章节将对其中的每一个模块进行详细的介绍。
```lua
security-cloud
├── auth -- 授权服务提供
└── common -- 系统公共模块
├── common-core -- 公共工具类核心包
├── common-dubbo -- dubbo rpc服务
├── common-email -- 邮件发送服务
├── common-file -- 分布式文件存储
├── common-mybatis -- mybatis 扩展封装
├── common-redis -- redis序列化封装
├── common-security -- 安全工具类
├── common-swagger -- swagger接口文档
├── common-log -- 系统日志记录
└── common-websocket -- netty集群实现的websocket服务
└── notice -- 通用消息公告模块
├── notice-api -- 通用消息公告模块公共api模块
└── notice-biz -- 通用消息公告模块业务处理模块[5000]
└── upms -- 通用用户权限管理模块
├── upms-api -- 通用用户权限管理系统公共api模块
└── upms-biz -- 通用用户权限管理系统业务处理模块[4000]
└── visual -- 图形化管理模块
├── code-gen -- 代码生成模块
├── custom-query -- 自定义查询模块
├── flowable -- flowable实现的workflow模块
├── monitor -- 服务监控
├── sentinel-dashboard -- sentinel 官方版
├── sentinel-dashboard-pro -- sentinel 线上版,集成nacos
└── xxl-job-admin -- 定时任务管理器
```

View File

@ -0,0 +1,10 @@
# 授权服务模块
## 服务简介
授权登录服务是集群权限授权的入口,集群中的所有授权请求读应该在当前服务进行实现.
## 提供服务
- 验证码获取
- 账号密码登录
- 微信小程序授权登录(规划中)
- 用户登录后用户权限标识和用户信息获取

View File

@ -0,0 +1,3 @@
# 代码生成
## 简介
代码生成模块适配MySql,Oracle等多种关系型数据库,可快速导入数据库表格元数据生成对应的单表crud前后端代码

View File

@ -0,0 +1,385 @@
# 系统公共模块
系统公共模块主要对集群中的基础公共工具进行封装,提供更加高效的开发效率
## common-core
### 简介
对系统中的基础服务实体进行定义,基础的工具类进行定义.例如:list转Tree工具类,反射方式获取到用户信息等
### TreeUtil
自定义树形结构实体转换,可以将A对象结构具有树形关系的list转换成B对象的树形结构, 可以自定义A B两个对象之间的映射关系例如:
将Dept映射到OptionTree对象:
```javascript
//Dept 类
public class Dept extends BaseEntity {
private Long deptId;
private Long parentId;
private String ancestors;
@NotBlank(message = "部门名称不能为空!")
private String deptName;
@NotBlank(message = "显示顺序不能为空!")
private String orderNum;
@NotBlank(message = "负责人不能为空!")
private String leader;
@NotNull(message = "负责人id不能为空!")
private Long leaderId;
}
//OptionTree 目标对象
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OptionTree implements Serializable {
/**
* 节点ID
*/
private Object value;
/**
* 节点名称
*/
private String label;
/**
* 子节点
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<OptionTree> children;
}
//转换代码
List<OptionTree> optionTreeList = TreeUtil.build(deptList,OptionTree.class,(config)->{
config.setIdField("deptId");
config.setOption("deptId","deptName");
});
```
并且TreeUtil可以通过config进行自定义配置,配置项如下:
- 是否启用BeanUtils.copyProperties方法进行字段的copy(默认为ture)
- 父级关系字段名称定义
- id字段定义
- tree子级字段定义
- mapper其余字段关系映射
- exclude排除字段
## common-dubbo
### 简介
对dubbo的基础依赖进行引入,后期进行全局的dubbo功能封装
## common-log
### 简介
自定义操作日志模块,完成使用自定义注解`@Log`实现操作日志的记录
`@Log`注解参数说明
| 参数 | 类型 | 默认 | 描述|
| :-- | :-- | :-- | :-- |
| title | String | 空 | 日志记录名称 |
| businessType | BusinessType | OTHER | 功能,具体操作有 OTHER,INSERT,UPDATE,DELETE,GRANT,EXPORT,IMPORT,FORCE,GENCODE,CLEAN,BIND |
| operatorType | OperateType | MANAGE | 操作人类别 |
| isSaveRequestData | boole | 空 | 是否保存请求的参数 |
### 使用
```javascript
@ApiOperation("新增部门")
@PostMapping
@PreAuthorize("@ss.hasPermission('admin:dept:add')")
@Log(title = "新增部门",businessType = BusinessType.INSERT)
public Result<Void> add(@RequestBody @Validated Dept dept){
if (UserConstants.DEPT_DISABLE.equals(deptService.checkDeptNameUnique(dept))){
return Result.error("新增部门: "+ dept.getDeptName() +"'失败,部门名称以存在!");
}
deptService.saveDept(dept);
return Result.ok();
}
```
通过LogAspect实现当前注解的apo切面,切面中将操作的日志封装成一个操作日志对象,然后使用spring的事件发布机制发布这个日志操作对象,再使用OperationLogListener异步监听到发布的事件,再通过rpc远程调用到umps中的日志存储接口,将当前对象落地到数据库
## common-mybatis
### 简介
对mybatis的分页插件进行封装,使用注解+aop+mybatis拦截器实现自动注入用户信息或者时间
### 分页操作
只需要在执行SQL的Mapper之前调用`PageUtils.startPage()`方法,然后调用SQL执行方法,再使用获取到的数组调用PageUtils.getDataTable(list)方法获取到封装好的返回结果对象即。
- 代码演示
```java
@Override
public TableDataInfo<DemoVo> searchDemoList(DemoQuery query) {
PageUtils.startPage();
List<Demo> list = demoMapper.selectDemoList(query);
Long total = PageUtils.getTotal(list);
List<DemoVo> convertList = list.stream().map(DemoVo::toDemoVo).collect(Collectors.toList());
return PageUtils.convertDataTable(convertList, total);
}
```
> 注意,上方代码为需要将Demo 转换为 DemoVo 如果无需转换,则可直接调用`PageUtils.getDataTable(list)`方法
### 自动注入能力
自动注入使用场景为,当实体累中在特定的时间或者业务之下,需要设置一些固定的参数时,可以使用到此功能,列如当实体类中存在createBy,createTime,updateBy,updateTime等固定字段,在创建和更新的时候都需要固定的设置参数时,可以使用到此功能
- `@EnableAutoField` 开启mybatis的自动注入能力
- `@GenerateId` 自动生成id并注入
- `@AutoUser` 自动注入一些用户信息
- `@AutoTime` 自动注入时间
#### `@GenerateId`注解参数说明
|参数 | 类型 | 默认 | 描述|
| :-- | :-- | :-- | :-- |
| idType | GenIdEnum | UUID | 需要生成的id类型 |
`@GenerateId`为实现需要指定id时候使用,可以自动生成指定类型的id,并注入其中,支持UUID的生成
#### `@AutoUser`注解参数说明
|参数 | 类型 | 默认 | 描述|
| :-- | :-- | :-- | :-- |
| value | AutoUserEnum | USER_NAME | 需要注入的用户信息 |
| method | MethodEnum | 空 | 指定SQL执行方法下进行自动注入 |
`@AutoUser`可以根据用户需要设置那种用户信息和具体SQL执行的那种类型的方法情况下自动注入需要的信息
#### `@AutoTime`注解参数说明
|参数 | 类型 | 默认 | 描述|
| :-- | :-- | :-- | :-- |
| method | MethodEnum | 空 | 指定SQL执行方法下进行自动注入 |
`@AutoTime`可以根据SQL执行的方法类型进行匹配,自动创建时间对象并注入
## common-file
### 简介
在集群环境下文件不能够单独放置在某一个单一节点执行需要集中存储起来我们提供了阿里云的oss自建服务的minio以及轻量化的ftp三种模式
### 使用
1. 将依赖引入到对应的pom.xml中
```xml
<!--文件组件-->
<dependency>
<groupId>cn.odliken</groupId>
<artifactId>common-file</artifactId>
</dependency>
```
2. 在yml文件中配置好信息
```yml
file:
store:
minio:
endpoint: endpoint
bucket: bucket
access-key: access-key
secret-key: secret-key@2023
aliyun:
endpoint: endpoint
#AccessId 和 AccessKey
access-key-id: access-key-id
secret-access-key: secret-access-key
#创建的Bucket
bucket: bucket
ftp:
address: address
port: port
username: username
password: password
encoding: UTF-8
# 静态资源路径
asset: asset
# 公共文件资源
pubfiles: pubfiles
# 需要保密的文件资源
prifiles: prifiles
```
3. 注入`FileStoreService`接口,需要指定使用那种类型的文件储存,也可以直接注入具体的实现类
```java
/**
* 文件存储服务接口类
*
* @author Clay
* @date 2023-02-16
*/
public interface FileStoreService {
/**
* 创建文件桶
*
* @param bucketName 桶名
* @return 创建结果
*/
Boolean createBucket(String bucketName);
/**
* 删除文件桶
*
* @param bucketName 桶名
* @return 删除结果
*/
Boolean deleteBucket(String bucketName);
/**
* 上传文件
*
* @param file 文件对象
* @return FileInfo对象
*/
FileInfo upload(MultipartFile file);
/**
* 上传文件
*
* @param bucket 文件桶名
* @param file 文件对象
* @return FileInfo对象
*/
FileInfo upload(String bucket, MultipartFile file);
/**
* 下载文件
*
* @param fileUri 文件的资源定位符
* @return 文件流
*/
InputStream download(String fileUri);
/**
* 下载文件
*
* @param bucket 文件桶名
* @param fileUri 文件的资源定位符
* @return 文件流
*/
InputStream download(String bucket, String fileUri);
/**
* 删除文件
*
* @param fileUri 文件的资源定位符
* @return 删除状态
*/
Boolean delete(String fileUri);
/**
* 删除文件
*
* @param bucket 文件桶名
* @param fileUri 文件的资源定位符
* @return 删除状态
*/
Boolean delete(String bucket, String fileUri) throws IOException;
}
```
4. `FileStoreCombinationService`类可以直线多种对象存储混合使用,只需要在方法上添加上需要指定的储存类型枚举即可
## common-redis
### 简介
对redis中`RedisTemplate`进行了fastjson序列化的封装,也保留了原本的Java序列化方式
对fastjson序列化封装的`RedisTemplate`进行了进一步的封装实现了`RedisService`,让开发者更方便的使用
## common-security
### 简介
集群中最核心的部分,spring security 安全校验封装,自定义PermissionService实现spring security自定校验方法,实现自定义校验逻辑,使用Inner注解实现集群内rpc远程调用接口的区分
## common-swagger
### 简介
swagger接口文档配置,通过SwaggerConfig类从nacos中获取到当前服务对应的swagger配置信息,生成当前服务的swagger接口文档数据,配合gateway swagger聚合生成集群的swagger聚合文档
解决swagger聚合文档请求/v3/doc-api接口时,swaggerui无法发起请求的bug
### 使用
1. 引入配置
```xml
<!--swagger文档-->
<dependency>
<groupId>cn.odliken</groupId>
<artifactId>common-swagger</artifactId>
</dependency>
```
2. 在yml中填写好配置信息
```yaml
swagger:
title: 演示api文档
description: 演示api文档
```
## common-email
### 简介
为系统提供最基础的邮件发送功能,其中实现同步邮件发送和异步邮件发送两种功能实现
### 使用
1. 引入依赖
```xml
<!--邮件发送组件-->
<dependency>
<groupId>cn.odliken</groupId>
<artifactId>common-email</artifactId>
</dependency>
```
2. 在yml中填写好配置信息
```yaml
email:
sender: 发送人邮箱
personal: 发送人名称
email-smtp-host: 邮件服务器
email-smtp-port: 邮件服务器端口
username: 发送人用户名
password: 发送人密码
encryption: 加密协议
```
3. 使用
注入`EmailService`后,使用`EmailService`中的同步发送邮件或者异步发送邮件即可进行邮件发送
## common-lock
### 简介
为系统提供分布式锁的能力,采用的是redisson实现,其中使用注解+aop+反射实现防重复提交和接口的分布式锁访问两大功能,并对提供封装好的分布式锁服务类
### 防重复提交
防重复提交是指在进行数据提交的过程中,防止用户重复提交相同的数据或者重复执行同一操作的一种技术手段。这种技术手段的主要目的是避免数据的重复录入或者重复操作所带来的不必要的麻烦和风险,同时也可以提高应用程序的稳定性和可靠性。系统使用后端校验+分布式锁的方式实现
### 锁的唯一性
锁的唯一性保证是通过用户登录后的token(匿名用户则使用客户端ip)+加上uri+方法请求类型+需要使用的请求参数组成的key保证锁的唯一性
### 使用
1. 引入依赖
```xml
<dependency>
<groupId>cn.odliken</groupId>
<artifactId>common-lock</artifactId>
</dependency>
```
2. 在接口上添加注解
```java
@PostMapping
@ResubmitLock
public Result<String> login(@Validated @RequestBody LoginBody login) {
return Result.ok("操作成功");
}
```
3. 拦截效果
![img.png](./img.png)
### 通用分布式锁
通用分布式锁主要通过
### 分布式锁
分布式锁的实现与防重复提交实现原理相似,也是采用注解+aop+反射实现
## common-websocket
### 简介
该模块使用Netty搭建websocket服务,并将websocket服务注册到nacos实现Netty集群,之后可以使用Gateway实现代理和负载均衡
### 使用
1. 引入依赖
```xml
<dependency>
<groupId>cn.odliken</groupId>
<artifactId>common-websocket</artifactId>
</dependency>
```
2. 配置yml文件
```yaml
websocket:
application-name: netty-application-name
port: 8080
path: /websocket
```

BIN
docs/module/common/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1 @@
# 自定义查询

View File

@ -0,0 +1,90 @@
# 网关服务模块
在集群环境中gateway将会是集群网络的唯一出入口是系统安全的重要节点同时gateway承担Sentinel限流服务分发负载均衡和提供swagger文档等工作。
## 文件结构
```lua
gateway
└── java
├── config -- 配置包
├── controller -- swagger聚合需要使用的到的接口
├── filter -- 全局过滤器
├── handler -- 异常处理
├── util -- 工具
└── GatewayApplication.java -- 启动类
└── resources
├── bootstrap.yml -- 配置文件
└── logback-spring.xml -- 日志记录文件
```
## 配置文件
```yaml
# Tomcat
server:
port: 5000
# Spring
spring:
application:
# 应用名称
name: monitor
profiles:
# 环境配置
active: local
security:
user:
name: root
password: password
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 192.168.101.108:8848
username: nacos
password: nacos
namespace: ${spring.profiles.active}
metadata:
management:
context-path: /actuator
config:
# 配置中心地址
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: ${spring.profiles.active}
shared-configs:
- ${spring.application.name}-${spring.profiles.active}.yml
```
配置文件相当简洁,主要为设置运行端口,active的环境以及注册到nacos,并从nacos读取到gateway自身的配置文件
属于gateway的配置文件:
```yaml
spring:
cloud:
gateway:
discovery:
locator:
# gateway 能够进行服务发现
enabled: true
routes:
# 认证中心
- id: auth
uri: lb://auth
predicates:
- Path=/auth/**
```
## 路由分发
路由分发是gateway的一个重要功能,当gateway启动后会向nacos发起注册,并从nacos cconfig中心获取到gateway的那一份配置文件,gateway再将文件加载到自己的路由中,当又接口请求到后,gateway则可以根据路由表对请求进行分发。

View File

@ -0,0 +1,86 @@
# 网关服务模块
在集群环境中gateway将会是集群网络的唯一出入口是系统安全的重要节点同时gateway承担Sentinel限流服务分发负载均衡和提供swagger文档等工作。
## 文件结构
```lua
gateway
└── java
├── config -- 配置包
├── controller -- swagger聚合需要使用的到的接口
├── filter -- 全局过滤器
├── handler -- 异常处理
├── util -- 工具
└── GatewayApplication.java -- 启动类
└── resources
├── bootstrap.yml -- 配置文件
└── logback-spring.xml -- 日志记录文件
```
## 配置文件
```yaml
# Tomcat
server:
port: 5000
# Spring
spring:
application:
# 应用名称
name: monitor
profiles:
# 环境配置
active: local
security:
user:
name: root
password: password
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 192.168.101.108:8848
username: nacos
password: nacos
namespace: ${spring.profiles.active}
metadata:
management:
context-path: /actuator
config:
# 配置中心地址
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: ${spring.profiles.active}
shared-configs:
- ${spring.application.name}-${spring.profiles.active}.yml
```
配置文件相当简洁,主要为设置运行端口,active的环境以及注册到nacos,并从nacos读取到gateway自身的配置文件
属于gateway的配置文件:
```yaml
spring:
cloud:
gateway:
discovery:
locator:
# gateway 能够进行服务发现
enabled: true
routes:
# 认证中心
- id: auth
uri: lb://auth
predicates:
- Path=/auth/**
```
## 路由分发
路由分发是gateway的一个重要功能,当gateway启动后会向nacos发起注册,并从nacos cconfig中心获取到gateway的那一份配置文件,gateway再将文件加载到自己的路由中,当又接口请求到后,gateway则可以根据路由表对请求进行分发。
gateway中配置了全局路由器,对

View File

@ -0,0 +1,32 @@
# 通用消息公告模块
## 简介
痛用消息模块使用netty实现的websocket,引入common-websocket模块进行实现,基于netty集群+rabbitmq实现集群模式下的消息精准推送功能。
通用消息模块可为系统任意模块提供消息发布和websocket消息推送功能,并对外提供rpc消息发送功能。
消息推送时可以指定发送到指定用户,发送到指定角色,发送到指定部门或者全部发送四大模式。
在用户侧websocket不作为用户与service进行消息发送的桥梁,websocket只会进行消息的推送和授权,消息的发送则是使用消息发送接口进行。
## 消息推送时序图
![img.png](./img.png)
## 消息发送确认机制
![img_1.png](./img_1.png)
- 当用户发送消息后,消息首选会数据库进行持久化,持久化成功推送至mq,若消息推送失败则发生数据库回滚。
- mq接受到消息之后,向netty的监听服务发起事件,netty进行消费,消费成功手动ack确认,若3次消费失败,则认为当前服务消费失败,手动ack确认消息消费失败,并删除mq中的消息。
## websocket连接与授权
连接: websocket请求url为http://gateway-service/notice-ws/notice。
授权: 授权需要获取到用户登录时获取到的token,并按照规定数据格式在连接成功websocket之后发送授权信息,如果连接websocket 3s内未发送授权验证信息,连接将被自动断开。
```json
{
"token": "用户令牌",
"cluster": "消息群组"
}
```
## notice服务实现模块分离
在notice服务中,消息体或者websocket连接用户授权是都需要指定到消息群组(cluster),notice服务则通过cluster区分消息群组,并对其用户的websocket连接进行隔离。

BIN
docs/module/notice/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,15 @@
# 通用用户权限管理模块
## 服务简介
通用用户权限模块为集群中的核心,集群中的系统基础服务的在此实现
## 提供服务
- 用户管理
- 角色管理
- 菜单管理
- 部门管理
- 岗位管理
- 字典管理
- 字典类型配置
- 在线用户管理
- fegin rpc远程调用api服务

View File

@ -0,0 +1,95 @@
# 图形化管理模块
主要实现集群中的一些扩展功能:
- code-gen -- 分布式可视化代码生成
- custom-query -- 自定义查询
- flowable -- workflow工作流模块
- monitor -- 服务监控
- sentinel-dashboard -- sentinel监控面板
- sentinel-dashboard-pro -- sentinel监控面板,配置规则同步到nacos管理
## code-gen(正在开发)
为提高集群编码效率,可以快速生成crud后端代码和配套的前端页面代码,以数据库元数据作为数据基础是.
在集群模式下每一个服务所在的数据库地址不同,数据库不同,甚至数据库类型不同,所以提供数据库数据源的配置,支持mysql,MariaDB,以及oracle三种数据库
支持可视化的代码生成配置,并且根据数据源不同生成对应数据库的标准curd代码
## custom-query(正在规划)
将ebts中的自定义查询和er可视化查询集群化,ebts网站:https://demo.ebts.top/
## flowable
### 简介
flowable模块为系统提供工作流的服务支撑前端采用开源的防钉钉bpmn编辑器并对前端编辑器进行升级和自定义功能的开发
### 实现功能
- 流程发布
- 自定义表单
- 表单节点权限控制
- 流程流转
- 全新的日志记录
- 发起流程时全新的全局流程
- 流程流转是邮件提醒
- 自定义监听器
- 触发器http请求js可编程影响流程流转结果
- 流程自定义任意节点回滚
- 表单编辑器可自定义组件开发
### 1. 流程发布
流程发布为workflow第一个步骤需要用户自定义流程配置审批表单并且可以对表单权限与节点权限进行控制
#### 审批流程
审批流程共实现如下节点
- 审批人:审批节点,可以选择指定用户对本次流程进行审批
- 抄送人:将当前流程抄送给设置的用户进行查看
- 条件分支:可以设置对条件影响流程的执行,其中可使用表单中的参数
- 并行分支:可以同时执行两条或多条审批路线
- 延时等待:可以让流程在指定时间或者指定等待时间执行
- 触发器可以发起http请求或者邮件
#### 审批人
审批人实现多种方式指定审批人,配置下图所示:
![img.png](./img.png)
当用户选择了对应的审批对象后,系统则会根据对应的审批对象去获取对应的审批人,加入到审批流程中,并且还对其审批人为和审批期限进行辅助
#### 抄送人
抄送人节点只需要选择对应的抄送人即可,后续可扩展和审批人相同的选择审批对象
#### 条件分支
条件分支节点下可以设置多种条件,条件可以进行多种自定义组合,实现用户指定的流程流转方向
#### 触发器
触发器可以发起http请求或者email邮件发起http请求的时候可以编写自定义脚本来处理http的响应结果并可以影响到整个流程的流程
#### 流程简单demo
![img_1.png](./img_1.png)
### 自定义表单
自定义表单实现为拖拽的方式进行表单的自定义设计,这样用户就可以制作任意业务需求的表单满足所以的业务场景
![img_2.png](./img_2.png)
### 发起流程
流程发起提供左右两个区域,左侧区域为表单输入位置,右侧为流程的预览,此处可以看到流程执行情况以及当前流程对应的审批人
![img_3.png](./img_3.png)
### 查看流程
到我的处理页面即可查看到需要当前登录用户处理的流,点击之后就可以看到流程的信息,此处定制开发流程的日志信息
![img_4.png](./img_4.png)
### 我发起的流程
登录用户查看我发起的,当前页面可以查看到流程当前的节点,当前的审批人,流程状态等,点击流程就可以查看到流程的详细情况,详细情况和查看流程完全一样,并且新增全局的流程信息
![img_5.png](./img_5.png)
![img_6.png](./img_6.png)
流程全局预览和日志记录可以记录每个操作的情况,列如那些用户没有审批,那些节点处于审批状态,那个节点被拒绝,并且拒绝的用户是谁等都可以记录下来,方便后续精准的定位人员
## sentinel-dashboard
sentinel的控制面板
## sentinel-dashboard-pro
实现了sentinel配置规则落地到nacos中

BIN
docs/module/visual/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -1,50 +0,0 @@
### 1001 害死人不偿命的(3n+1)猜想 (15分)
**卡拉兹(Callatz)猜想**
对任何一个自然数n如果它是偶数那么把它砍掉一半如果它是奇数那么把(3n+1)砍掉一半。这样一直反复砍下去最后一定在某一步得到n=1。卡拉兹在1950年的世界数学家大会上公布了这个猜想传说当时耶鲁大学师生齐动员拼命想证明这个貌似很傻很天真的命题结果闹得学生们无心学业一心只证(3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……
我们今天的题目不是证明卡拉兹猜想而是对给定的任一不超过1000的正整数n简单地数一下需要多少步(砍几下)才能得到n=1
**输入格式**
每个测试输入包含1个测试用例即给出自然数n的值。
**输出格式**
输出从 n 计算到1需要的步数。
**输入样例**:
~~~ bash
3
~~~
**输出样例**:
~~~ bash
5
~~~
代码实现:
~~~ java
//java代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner =new Scanner(System.in);
int N = scanner.nextInt();
int steps =0;
while (N !=1) {
if (N %2 ==0) {
N = N /2;
} else {
N = (3 * N +1) / 2;
}
steps++;
}
System.out.println(steps);
}
}
~~~

View File

@ -0,0 +1,36 @@
# sentinel dashboard 限流模块
> sentinel dashboard可以通过页面图形化的方式监控机器以及服务的运行情况和配置复杂的各种流控、降级等规则以保证线上服务的稳定运行本篇文章主要是介绍控制台参数意义和使用规则达到快速使用的目的
## 具体实现
ebts-cloud快速开发系统有两个sentinel dashboard模块,一个是官方给的完整版,另外一个为集成了nacos持久化,适合生产环境使用
### 官方提供
- xml
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
```
- 添加yaml配置文件到client服务中
```yaml
spring:
cloud:
sentinel:
transport:
# sentinel dashboard服务地址
dashboard: localhost:5000
```
### nacos升级
- 配置数据持久化到nacos
- client注册到sentinel dashboard时,sentinel dashboard将nacos上对应的配置文件初始化给client
- 支持配置设置针对单一client设置配置文件还是集群内全部服务设置配置
> 配置与上方相同,只需要添加nacos的配置中心信息即可
![](./sentinel.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -0,0 +1,113 @@
# 监控模块使用
监控模块使用 Spring Boot Admin,配合客户端引入spring-boot-starter-actuator依赖就可以在监控模块中看到对应服务的情况,但是Spring Boot Admin没有权限拦截,所以需要二次权限认证。
## 实现原理
- 引入 spring security
```xml
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
```
- 配置 spring security
```java
/**
* 配置安全认证,以便其他服务注册
*
* @author Clay
* @date 2022/11/10
*/
@Configuration
public class SecuritySecureConfig {
/**
* 应用上下文路径
*/
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
http.authorizeRequests()
//1.配置所有静态资源和登录也可以公开访问
.antMatchers(adminContextPath + "/assets/**")
.permitAll()
.antMatchers(adminContextPath + "/login")
.permitAll()
//2. 其他请求,必须经过认证
.antMatchers("/actuator/**","/instances").permitAll()
.anyRequest().authenticated()
.and()
//3. 配置登录和登出路径
.formLogin().loginPage(adminContextPath + "/login")
.successHandler(successHandler)
.and()
.logout().logoutUrl(adminContextPath + "/logout");
return http.build();
}
@Bean
public HttpHeadersProvider customHttpHeadersProvider() {
return (instance) -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(SecurityConstants.ACTUATOR_FROM, SecurityConstants.ACTUATOR_FROM_IN);
return httpHeaders;
};
}
}
```
- 在对应的monitor-运行环境.yml 配置用户
```yaml
spring:
security:
user:
name: root
password: password
```
## 客户端配置
- 在对应的application-运行环境.yml 配置actuator暴露信息
```yaml
management:
endpoints:
web:
# 设置是否暴露端点 默认只有health和info可见
exposure:
# include: env # 方式1: 暴露端点env配置多个以,隔开
include: "*" # 方式2: 包括所有端点,注意需要添加引号
# 排除端点
exclude: shutdown
server:
port: 9595 # 开监控端口,不和应用用同一个端口, 服务端口,在使用k8s的情况下,每一个服务都是在单独的一个docker中,所以他们的端口是不会发生冲突的
endpoint:
health:
show-details: always # 显示db、redis、rabbti连接情况等
shutdown:
enabled: true #默认情况下除shutdown以外的所有端点均已启用。手动开启
```
## 效果图
![](./login.png)
![](./application.png)
![](./wallboard.png)
![](./instances.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

184
docs/util/excel/README.md Normal file
View File

@ -0,0 +1,184 @@
# Excel快速导出
## 功能介绍
- 在对应实现类上加上自定义注解`@Excel`后,在编写web接口是调用ExcelUtil.exportExcel即可实现对应实体Excel的快速导出
## 实现原理
- 主要使用到Java反射机制,获取到目标实体的Class对象后通过java发射获取到每个字段,并且获取到对应字段上的@Excel注解,将注解中的数据记录下来作为Excel中的表头。再通过java反射获取到对应的数据并做好与标表头的映射关系最终使用ease-excel实现Excel的渲染
## 代码展示
```java
/**
* @author Clay
* @date 2022/12/19
*/
public class ExcelUtil {
public static List<ExcelAssist> assistList = new ArrayList<>();
public static Map<String,Map<String,DictData>> dictDataMap;
private static DictDataService getBean() {
return SpringContextHolder.getBean(DictDataService.class);
}
/**
* 获取到数据列表
*
* @param list
* @return
*/
private static List<List<Object>> getDataList(List<?> list) {
return list.stream().map(object ->
assistList.stream().map(assist -> {
Field field = assist.getField();
Excel excel = assist.getExcel();
Object value = null;
if (StringUtils.isEmpty(assist.getObjectFieldName())) {
value = getData(object, excel, field);
} else {
Object sunValue = null;
try {
sunValue = ReflectUtils.invokeGetter(object, assist.getObjectFieldName());
} catch (Exception e) {
return null;
}
if (null != sunValue) {
value = getData(object, excel, field);
}
}
return value;
}).collect(Collectors.toList())
).collect(Collectors.toList());
}
/**
* 获取到对象中的数据
*
* @param object
* @param excel
* @param field
* @return
*/
private static Object getData(Object object, Excel excel, Field field) {
try {
Object objectValue = ReflectUtils.invokeGetter(object, field.getName());
if (objectValue instanceof Date) {
objectValue = DateUtils.parseDateToStr(excel.dateFormat(), (Date) objectValue);
}
String dictType = excel.dictType();
if (StringUtils.isNotEmpty(dictType)){
Map<String,DictData> dictMap = dictDataMap.get(dictType);
if (null != dictMap){
DictData dictData = dictMap.get(objectValue.toString());
if (null!= dictData){
objectValue = dictData.getDictLabel();
}
}
}
return objectValue;
} catch (Exception e) {
return null;
}
}
/**
* 初始化header数据
*
* @param clazz
* @param assist
*/
private static void initHeader(Class<?> clazz, ExcelAssist assist) {
for (Field field : clazz.getDeclaredFields()) {
Excel excel = field.getAnnotation(Excel.class);
if (null != excel) {
assistList.add(new ExcelAssist(field, excel, assist));
} else {
Excels excels = field.getAnnotation(Excels.class);
if (excels == null) {
continue;
}
Class<?> objectValue = field.getType();
if (clazz == objectValue) {
throw new CustomException("不允许嵌套对象导出Excel");
}
ExcelAssist excelAssist = new ExcelAssist(field, excels);
initHeader(objectValue, excelAssist);
}
}
}
public static void exportExcel(List<?> list, Class<?> clazz) {
exportExcel(list, clazz, null);
}
/**
* 导出数据Excel
*
* @param list
* @param clazz
* @param sheetName
*/
public static void exportExcel(List<?> list, Class<?> clazz, String sheetName) {
Set<String> dictList = new HashSet<>();
initHeader(clazz, null);
List<List<String>> headerList = new ArrayList<>(assistList.size());
assistList = assistList.stream().sorted(Comparator.comparing(ExcelAssist::getOrder))
.peek(assist -> headerList.add(Collections.singletonList(assist.getExcel().value())))
.peek(assist -> {
String dictType = assist.getExcel().dictType();
if (StringUtils.isNotEmpty(dictType)) {
dictList.add(dictType);
}
})
.collect(Collectors.toList());
if (dictList.size() > 0) {
getDictData(new ArrayList<>(dictList));
}
List<List<Object>> dataList = getDataList(list);
try {
sheetName = StringUtils.isEmpty(sheetName) ? "sheet" : sheetName;
HttpServletResponse response = getResponse(sheetName);
EasyExcel.write(response.getOutputStream())
.head(headerList)
.excelType(ExcelTypeEnum.XLSX)
.sheet(StringUtils.isEmpty(sheetName) ? "sheet" : sheetName)
.doWrite(dataList);
} catch (IOException e) {
throw new CustomException("Excel导出失败!");
}
}
private static HttpServletResponse getResponse(String sheetName){
HttpServletResponse response = SecurityUtils.getResponse();
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition" ,
"attachment;fileName=" + sheetName + UUID.randomUUID() + ".xlsx");
return response;
}
private static void getDictData(List<String> dictList) {
DictDataService dictDataService = getBean();
Result<Map<String, Map<String,DictData>>> result = dictDataService.searchDictDataCacheKeys(dictList, SecurityConstants.FROM_IN);
System.out.println(result);
if (result.getCode() == ResultConstant.SUCCESS_CODE){
dictDataMap = result.getData();
}
}
}
```
## 使用demo
```java
@ApiOperation("导出excel数据")
@GetMapping("/export")
@PreAuthorize("@ss.hasPermission('code:goods:export')")
public void export(DemoGoodsQuery query){
List<DemoGoodsVo> list = demoGoodsService.exportDemoGoodsList(query);
ExcelUtil.exportExcel(list,DemoGoodsVo.class);
}
```

View File

@ -0,0 +1,148 @@
# 树形结构转换工具类
## 功能介绍
- 将 A类的List数组快速转换为 B类型 List 的树形结构列表
## 实现原理
- 主要使用到Java反射机制,将A类中的字段拷贝到B类中,并且根据A类中id 与 pid之间的关系快速构建树形结构
- 设置配置类,更方便的实现A类与B类之前转换的需要,配置类包含有id字段与pid字段之间自定义设置,A类中需要转换到B类中的字段,以及是需要Spring 中 BeanUtils直接copy,以及如果使用了BeanUtil后需要排除的字段
## 代码展示
```java
/**
* @author Clay
* @date 2022/11/16
*/
public class TreeUtil {
private static TreeConfig config;
private static Class<?> targetClass;
/**
* 构建tree结构
*
* @param list
* @param target
* @param node
* @param <T>
* @return
*/
public static <T> List<T> build(List<?> list, Class<T> target, Node node) {
//初始化config
config = new TreeConfig();
//将目标class对象设置为全局对象
TreeUtil.targetClass = target;
//提供给实现类对config进行修改
node.build(config);
//获取到最小的
Object min = list.stream().min(Comparator.comparing(object -> getParentId(object).toString())).get();
//获取到最小的父级id
Object minPid = getParentId(min);
//将数据通过他们的各自的父id进行分组
Map<Object, List<Object>> listMap = list.stream().collect(Collectors.groupingBy(object -> getParentId(object)));
//最终开始进行tree的构建
return getChildren(listMap, minPid);
}
/**
* 获取到子节点
*
* @param listMap
* @param parentId
* @param <T>
* @return
*/
private static <T> List<T> getChildren(Map<Object, List<Object>> listMap, Object parentId) {
//获取到缓存中的list
List<?> objects = listMap.get(parentId);
if (chickList(objects)) {
return null;
}
listMap.remove(parentId);
//遍历数组,并将对象一一的转换
List<Object> collect = objects.stream().map(object ->
conversion(object, listMap)).collect(Collectors.toList());
return (List<T>) collect;
}
/**
* 对象直接的字段进行转换
*
* @param object
* @param listMap
* @param <T>
* @return
*/
private static <T> T conversion(Object object, Map<Object, List<Object>> listMap) {
try {
Object targetObject = targetClass.newInstance();
//相同字段名称直接赋值
if (config.isCopy()){
BeanUtils.copyProperties(object, targetObject);
}
//不同字段名进行赋值
for (Map.Entry<String, String> entry : config.getMapper().entrySet()) {
String targetKey = entry.getKey();
String sourceKey = entry.getValue();
Object value = ReflectUtils.invokeGetter(object, sourceKey);
Object[] args = new Object[]{value};
ReflectUtils.invokeSetter(targetObject, targetKey, args);
}
//设置子节点
Object id = ReflectUtils.invokeGetter(object, config.getIdField());
List<Object> children = getChildren(listMap, id);
if (!chickList(children)) {
ReflectUtils.invokeSetter(targetObject, config.getChildrenField(), new Object[]{children});
}
//设置完毕后,将需要排除的字段进行置空
for (String key : config.getExclude()) {
ReflectUtils.invokeSetNull(targetObject, key);
}
//返回结果
return (T) targetObject;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 检查list是否为空
*
* @param objects
* @return
*/
private static boolean chickList(List<?> objects) {
return null == objects || objects.isEmpty();
}
/**
* 获取到父级id
*
* @param object
* @return
*/
private static Object getParentId(Object object) {
try {
return ReflectUtils.invokeGetter(object, config.getParentField());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
```
## 使用demo
```java
@Override
public List<DeptVo> selectDeptTree(String deptName, Integer state) {
List<Dept> deptList = deptMapper.selectDeptList(deptName, state);
return TreeUtil.build(deptList,DeptVo.class,(config)->{
config.setIdField("deptId");
config.setMapper("key","deptId");
config.setExclude("phone");
});
}
```

View File

@ -1,5 +1,5 @@
# 后端部署
## 需要部署的内容
- auth
- gateway
- umps
- auth 权限认证模块
- gateway 网关服务模块
- umps 系统用户权限管理模块

View File

@ -1,50 +1,36 @@
# 介绍
## 它是如何工作的?
**卡拉兹(Callatz)猜想**
对任何一个自然数n如果它是偶数那么把它砍掉一半如果它是奇数那么把(3n+1)砍掉一半。这样一直反复砍下去最后一定在某一步得到n=1。卡拉兹在1950年的世界数学家大会上公布了这个猜想传说当时耶鲁大学师生齐动员拼命想证明这个貌似很傻很天真的命题结果闹得学生们无心学业一心只证(3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……
我们今天的题目不是证明卡拉兹猜想而是对给定的任一不超过1000的正整数n简单地数一下需要多少步(砍几下)才能得到n=1
# 项目简介
**输入格式**
## 项目背景
互联网对高并发集群的需求愈发的变大,spring boot 的单体应用已经不满足于现在复杂的业务需求,spring cloud逐渐成为高并发集群的标杆,学习spring cloud也刻不容缓,
该项目是在学习了spring cloud中各种组件之后,为锻炼自己的集群能力,并且自己也想做一套集群的基础权限管理系统。
每个测试输入包含1个测试用例即给出自然数n的值。
该集群为一套基础的权限管理系统主导权限控制权限管理等核心功能并且配合配合visual图形化管理模块对集群的资源进行更方便的关系提高软件开发的效率
**输出格式**
## 系统说明
- 基于 Spring Cloud 2021 、Spring Boot 2.7、 Spring Security 的权限管理系统
- 采用前后端分离的模式,前端(基于 Security-React, Security-Vue)
- 注册中心,配置中心使用Nacos,
- 权限认证使用Spring Security + Redis
- 流量控制使用Sentinel
- gitea+drone+harbor+rancher全套部署流程
输出从 n 计算到1需要的步数。
## 核心依赖
**输入样例**:
| 依赖 | 版本 |
|----------------------|------------|
| Spring Boot | 2.7.5 |
| Spring Cloud | 2021.0.5 |
| Spring Cloud Alibaba | 2021.0.4.0 |
| Mybatis | 3.5.2 |
| Vue | 3.1.3 |
| React | 3.1.3 |
~~~ bash
3
~~~
## 软件相关架构
![](./jiagou1.png)
**输出样例**:
- 集群通过gateway作为集群的唯一入口,然后访问到授权中心等其他服务,服务之间授权则使用`@inner`注解加上aop标识
~~~ bash
5
~~~
## CI/CD
![](./cicd.png)
代码实现:
~~~ java
//java代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner =new Scanner(System.in);
int N = scanner.nextInt();
int steps =0;
while (N !=1) {
if (N %2 ==0) {
N = N /2;
} else {
N = (3 * N +1) / 2;
}
steps++;
}
System.out.println(steps);
}
}
~~~

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB