init
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
|||||||
|
######################################################################
|
||||||
|
# Build Tools
|
||||||
|
|
||||||
|
.gradle
|
||||||
|
/build/
|
||||||
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|
||||||
|
.flattened-pom.xml
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# IDE
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
nbproject/private/
|
||||||
|
build/*
|
||||||
|
nbbuild/
|
||||||
|
dist/
|
||||||
|
nbdist/
|
||||||
|
.nb-gradle/
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Others
|
||||||
|
*.log
|
||||||
|
*.xml.versionsBackup
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
!*/build/*.java
|
||||||
|
!*/build/*.html
|
||||||
|
!*/build/*.xml
|
||||||
|
|
||||||
|
### JRebel ###
|
||||||
|
rebel.xml
|
||||||
|
|
||||||
|
application-my.yaml
|
||||||
|
|
||||||
|
/yudao-ui-app/unpackage/
|
||||||
|
**/.DS_Store
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2021 ruoyi-vue-pro
|
||||||
|
|
||||||
|
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.
|
||||||
@@ -0,0 +1,391 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img src="https://img.shields.io/badge/Spring%20Boot-2.7.18-blue.svg" alt="Downloads">
|
||||||
|
<img src="https://img.shields.io/badge/Vue-3.2-blue.svg" alt="Downloads">
|
||||||
|
<img src="https://img.shields.io/github/license/YunaiV/ruoyi-vue-pro"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!!**
|
||||||
|
|
||||||
|
**「我喜欢写代码,乐此不疲」**
|
||||||
|
**「我喜欢做开源,以此为乐」**
|
||||||
|
|
||||||
|
我 🐶 在上海艰苦奋斗,早中晚在 top3 大厂认真搬砖,夜里为开源做贡献。
|
||||||
|
|
||||||
|
如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。
|
||||||
|
|
||||||
|
## 🐶 新手必读
|
||||||
|
|
||||||
|
* 演示地址【Vue3 + element-plus】:<http://dashboard-vue3.yudao.iocoder.cn>
|
||||||
|
* 演示地址【Vue3 + vben(ant-design-vue)】:<http://dashboard-vben.yudao.iocoder.cn>
|
||||||
|
* 演示地址【Vue2 + element-ui】:<http://dashboard.yudao.iocoder.cn>
|
||||||
|
* 启动文档:<https://doc.iocoder.cn/quick-start/>
|
||||||
|
* 视频教程:<https://doc.iocoder.cn/video/>
|
||||||
|
|
||||||
|
## 🐰 版本说明
|
||||||
|
|
||||||
|
| 版本 | JDK 8 + Spring Boot 2.7 | JDK 17/21 + Spring Boot 3.2 |
|
||||||
|
|---------------------------------------------------------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------|
|
||||||
|
| 【完整版】[ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [`master`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master-jdk17/) 分支 |
|
||||||
|
| 【精简版】[yudao-boot-mini](https://gitee.com/yudaocode/yudao-boot-mini) | [`master`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master-jdk17/) 分支 |
|
||||||
|
|
||||||
|
* 【完整版】:包括系统功能、基础设施、会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP 等功能
|
||||||
|
* 【精简版】:只包括系统功能、基础设施功能,不包括会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP 等功能
|
||||||
|
|
||||||
|
可参考 [《迁移文档》](https://doc.iocoder.cn/migrate-module/) ,只需要 5-10 分钟,即可将【完整版】按需迁移到【精简版】
|
||||||
|
|
||||||
|
## 🐯 平台简介
|
||||||
|
|
||||||
|
**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。
|
||||||
|
|
||||||
|
> 有任何问题,或者想要的功能,可以在 _Issues_ 中提给艿艿。
|
||||||
|
>
|
||||||
|
> 😜 给项目点点 Star 吧,这对我们真的很重要!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
* Java 后端:`master` 分支为 JDK 8 + Spring Boot 2.7,`master-jdk17` 分支为 JDK 17/21 + Spring Boot 3.2
|
||||||
|
* 管理后台的电脑端:Vue3 提供 `element-plus`、`vben(ant-design-vue)` 两个版本,Vue2 提供 `element-ui` 版本
|
||||||
|
* 管理后台的移动端:采用 `uni-app` 方案,一份代码多终端适配,同时支持 APP、小程序、H5!
|
||||||
|
* 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson
|
||||||
|
* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等
|
||||||
|
* 消息队列可使用 Event、Redis、RabbitMQ、Kafka、RocketMQ 等
|
||||||
|
* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录
|
||||||
|
* 支持加载动态权限菜单,按钮级别权限控制,Redis 缓存提升性能
|
||||||
|
* 支持 SaaS 多租户,可自定义每个租户的权限,提供透明化的多租户底层封装
|
||||||
|
* 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式
|
||||||
|
* 高效率开发,使用代码生成器可以一键生成 Java、Vue 前后端代码、SQL 脚本、接口文档,支持单表、树表、主子表
|
||||||
|
* 实时通信,采用 Spring WebSocket 实现,内置 Token 身份校验,支持 WebSocket 集群
|
||||||
|
* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款
|
||||||
|
* 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务
|
||||||
|
* 集成报表设计器、大屏设计器,通过拖拽即可生成酷炫的报表与大屏
|
||||||
|
|
||||||
|
## 🐳 项目关系
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
三个项目的功能对比,可见社区共同整理的 [国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn) 表格。
|
||||||
|
|
||||||
|
### 后端项目
|
||||||
|
|
||||||
|
| 项目 | Star | 简介 |
|
||||||
|
|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|
|
||||||
|
| [ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [](https://gitee.com/zhijiantianya/ruoyi-vue-pro) [](https://github.com/YunaiV/ruoyi-vue-pro) | 基于 Spring Boot 多模块架构 |
|
||||||
|
| [yudao-cloud](https://gitee.com/zhijiantianya/yudao-cloud) | [](https://gitee.com/zhijiantianya/yudao-cloud) [](https://github.com/YunaiV/yudao-cloud) | 基于 Spring Cloud 微服务架构 |
|
||||||
|
| [Spring-Boot-Labs](https://gitee.com/yudaocode/SpringBoot-Labs) | [](https://gitee.com/zhijiantianya/yudao-cloud) [](https://github.com/yudaocode/SpringBoot-Labs) | 系统学习 Spring Boot & Cloud 专栏 |
|
||||||
|
|
||||||
|
### 前端项目
|
||||||
|
|
||||||
|
| 项目 | Star | 简介 |
|
||||||
|
|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------|
|
||||||
|
| [yudao-ui-admin-vue3](https://gitee.com/yudaocode/yudao-ui-admin-vue3) | [](https://gitee.com/yudaocode/yudao-ui-admin-vue3) [](https://github.com/yudaocode/yudao-ui-admin-vue3) | 基于 Vue3 + element-plus 实现的管理后台 |
|
||||||
|
| [yudao-ui-admin-vben](https://gitee.com/yudaocode/yudao-ui-admin-vben) | [](https://gitee.com/yudaocode/yudao-ui-admin-vben) [](https://github.com/yudaocode/yudao-ui-admin-vben) | 基于 Vue3 + vben(ant-design-vue) 实现的管理后台 |
|
||||||
|
| [yudao-mall-uniapp](https://gitee.com/yudaocode/yudao-mall-uniapp) | [](https://gitee.com/yudaocode/yudao-mall-uniapp) [](https://github.com/yudaocode/yudao-mall-uniapp) | 基于 uni-app 实现的商城小程序 |
|
||||||
|
| [yudao-ui-admin-vue2](https://gitee.com/yudaocode/yudao-ui-admin-vue2) | [](https://gitee.com/yudaocode/yudao-ui-admin-vue2) [](https://github.com/yudaocode/yudao-ui-admin-vue2) | 基于 Vue2 + element-ui 实现的管理后台 |
|
||||||
|
| [yudao-ui-admin-uniapp](https://gitee.com/yudaocode/yudao-ui-admin-uniapp) | [](https://gitee.com/yudaocode/yudao-ui-admin-uniapp) [](https://github.com/yudaocode/yudao-ui-admin-uniapp) | 基于 Vue2 + element-ui 实现的管理后台 |
|
||||||
|
| [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [](https://gitee.com/yudaocode/yudao-ui-go-view) [](https://github.com/yudaocode/yudao-ui-go-view) | 基于 Vue3 + naive-ui 实现的大屏报表 |
|
||||||
|
|
||||||
|
## 😎 开源协议
|
||||||
|
|
||||||
|
**为什么推荐使用本项目?**
|
||||||
|
|
||||||
|
① 本项目采用比 Apache 2.0 更宽松的 [MIT License](https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE) 开源协议,个人与企业可 100% 免费使用,不用保留类作者、Copyright 信息。
|
||||||
|
|
||||||
|
② 代码全部开源,不会像其他项目一样,只开源部分代码,让你无法了解整个项目的架构设计。[国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
③ 代码整洁、架构整洁,遵循《阿里巴巴 Java 开发手册》规范,代码注释详细,113770 行 Java 代码,42462 行代码注释。
|
||||||
|
|
||||||
|
## 🤝 项目外包
|
||||||
|
|
||||||
|
我们也是接外包滴,如果你有项目想要外包,可以微信联系【**Aix9975**】。
|
||||||
|
|
||||||
|
团队包含专业的项目经理、架构师、前端工程师、后端工程师、测试工程师、运维工程师,可以提供全流程的外包服务。
|
||||||
|
|
||||||
|
项目可以是商城、SCRM 系统、OA 系统、物流系统、ERP 系统、CMS 系统、HIS 系统、支付系统、IM 聊天、微信公众号、微信小程序等等。
|
||||||
|
|
||||||
|
## 🐼 内置功能
|
||||||
|
|
||||||
|
系统内置多种多种业务功能,可以用于快速你的业务系统:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
* 通用模块(必选):系统功能、基础设施
|
||||||
|
* 通用模块(可选):工作流程、支付系统、数据报表、会员中心
|
||||||
|
* 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号、AI 大模型
|
||||||
|
|
||||||
|
> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。
|
||||||
|
>
|
||||||
|
> * 额外新增的功能,我们使用 🚀 标记。
|
||||||
|
> * 重新实现的功能,我们使用 ⭐️ 标记。
|
||||||
|
|
||||||
|
🙂 所有功能,都通过 **单元测试** 保证高质量。
|
||||||
|
|
||||||
|
### 系统功能
|
||||||
|
|
||||||
|
| | 功能 | 描述 |
|
||||||
|
|-----|-------|---------------------------------|
|
||||||
|
| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |
|
||||||
|
| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |
|
||||||
|
| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |
|
||||||
|
| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |
|
||||||
|
| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
|
||||||
|
| | 岗位管理 | 配置系统用户所属担任职务 |
|
||||||
|
| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |
|
||||||
|
| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |
|
||||||
|
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
|
||||||
|
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |
|
||||||
|
| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 |
|
||||||
|
| 🚀 | 站内信 | 系统内的消息通知,提供站内信模版、站内信消息 |
|
||||||
|
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
|
||||||
|
| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |
|
||||||
|
| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |
|
||||||
|
| | 通知公告 | 系统通知公告信息发布维护 |
|
||||||
|
| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |
|
||||||
|
| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |
|
||||||
|
| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 工作流程
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
基于 Flowable 构建,可支持信创(国产)数据库,满足中国特色流程操作:
|
||||||
|
|
||||||
|
| BPMN 设计器 | 钉钉/飞书设计器 |
|
||||||
|
|------------------------------|--------------------------------|
|
||||||
|
|  |  |
|
||||||
|
|
||||||
|
> 历经头部企业生产验证,工作流引擎须标配仿钉钉/飞书 + BPMN 双设计器!!!
|
||||||
|
>
|
||||||
|
> 前者支持轻量配置简单流程,后者实现复杂场景深度编排
|
||||||
|
|
||||||
|
| 功能列表 | 功能描述 | 是否完成 |
|
||||||
|
|------------|-------------------------------------------------------------------------------------|------|
|
||||||
|
| SIMPLE 设计器 | 仿钉钉/飞书设计器,支持拖拽搭建表单流程,10 分钟快速完成审批流程配置 | ✅ |
|
||||||
|
| BPMN 设计器 | 基于 BPMN 标准开发,适配复杂业务场景,满足多层级审批及流程自动化需求 | ✅ |
|
||||||
|
| 会签 | 同一个审批节点设置多个人(如 A、B、C 三人,三人会同时收到待办任务),需全部同意之后,审批才可到下一审批节点 | ✅ |
|
||||||
|
| 或签 | 同一个审批节点设置多个人,任意一个人处理后,就能进入下一个节点 | ✅ |
|
||||||
|
| 依次审批 | (顺序会签)同一个审批节点设置多个人(如 A、B、C 三人),三人按顺序依次收到待办,即 A 先审批,A 提交后 B 才能审批,需全部同意之后,审批才可到下一审批节点 | ✅ |
|
||||||
|
| 抄送 | 将审批结果通知给抄送人,同一个审批默认排重,不重复抄送给同一人 | ✅ |
|
||||||
|
| 驳回 | (退回)将审批重置发送给某节点,重新审批。可驳回至发起人、上一节点、任意节点 | ✅ |
|
||||||
|
| 转办 | A 转给其 B 审批,B 审批后,进入下一节点 | ✅ |
|
||||||
|
| 委派 | A 转给其 B 审批,B 审批后,转给 A,A 继续审批后进入下一节点 | ✅ |
|
||||||
|
| 加签 | 允许当前审批人根据需要,自行增加当前节点的审批人,支持向前、向后加签 | ✅ |
|
||||||
|
| 减签 | (取消加签)在当前审批人操作之前,减少审批人 | ✅ |
|
||||||
|
| 撤销 | (取消流程)流程发起人,可以对流程进行撤销处理 | ✅ |
|
||||||
|
| 终止 | 系统管理员,在任意节点终止流程实例 | ✅ |
|
||||||
|
| 表单权限 | 支持拖拉拽配置表单,每个审批节点可配置只读、编辑、隐藏权限 | ✅ |
|
||||||
|
| 超时审批 | 配置超时审批时间,超时后自动触发审批通过、不通过、驳回等操作 | ✅ |
|
||||||
|
| 自动提醒 | 配置提醒时间,到达时间后自动触发短信、邮箱、站内信等通知提醒,支持自定义重复提醒频次 | ✅ |
|
||||||
|
| 父子流程 | 主流程设置子流程节点,子流程节点会自动触发子流程。子流程结束后,主流程才会执行(继续往下下执行),支持同步子流程、异步子流程 | ✅ |
|
||||||
|
| 条件分支 | (排它分支)用于在流程中实现决策,即根据条件选择一个分支执行 | ✅ |
|
||||||
|
| 并行分支 | 允许将流程分成多条分支,不进行条件判断,所有分支都会执行 | ✅ |
|
||||||
|
| 包容分支 | (条件分支 + 并行分支的结合体)允许基于条件选择多条分支执行,但如果没有任何一个分支满足条件,则可以选择默认分支 | ✅ |
|
||||||
|
| 路由分支 | 根据条件选择一个分支执行(重定向到指定配置节点),也可以选择默认分支执行(继续往下执行) | ✅ |
|
||||||
|
| 触发节点 | 执行到该节点,触发 HTTP 请求、HTTP 回调、更新数据、删除数据等 | ✅ |
|
||||||
|
| 延迟节点 | 执行到该节点,审批等待一段时间再执行,支持固定时长、固定日期等 | ✅ |
|
||||||
|
| 拓展设置 | 流程前置/后置通知,节点(任务)前置、后置通知,流程报表,自动审批去重,自定流程编号、标题、摘要,流程报表等 | ✅ |
|
||||||
|
|
||||||
|
### 支付系统
|
||||||
|
|
||||||
|
| | 功能 | 描述 |
|
||||||
|
|-----|------|---------------------------|
|
||||||
|
| 🚀 | 应用信息 | 配置商户的应用信息,对接支付宝、微信等多个支付渠道 |
|
||||||
|
| 🚀 | 支付订单 | 查看用户发起的支付宝、微信等的【支付】订单 |
|
||||||
|
| 🚀 | 退款订单 | 查看用户发起的支付宝、微信等的【退款】订单 |
|
||||||
|
| 🚀 | 回调通知 | 查看支付回调业务的【支付】【退款】的通知结果 |
|
||||||
|
| 🚀 | 接入示例 | 提供接入支付系统的【支付】【退款】的功能实战 |
|
||||||
|
|
||||||
|
### 基础设施
|
||||||
|
|
||||||
|
| | 功能 | 描述 |
|
||||||
|
|-----|-----------|----------------------------------------------|
|
||||||
|
| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |
|
||||||
|
| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |
|
||||||
|
| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |
|
||||||
|
| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |
|
||||||
|
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
|
||||||
|
| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
|
||||||
|
| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 |
|
||||||
|
| 🚀 | WebSocket | 提供 WebSocket 接入示例,支持一对一、一对多发送方式 |
|
||||||
|
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
|
||||||
|
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
|
||||||
|
| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
|
||||||
|
| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 |
|
||||||
|
| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |
|
||||||
|
| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |
|
||||||
|
| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |
|
||||||
|
| 🚀 | 服务保障 | 基于 Redis 实现分布式锁、幂等、限流功能,满足高并发场景 |
|
||||||
|
| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |
|
||||||
|
| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 数据报表
|
||||||
|
|
||||||
|
| | 功能 | 描述 |
|
||||||
|
|-----|-------|--------------------|
|
||||||
|
| 🚀 | 报表设计器 | 支持数据报表、图形报表、打印设计等 |
|
||||||
|
| 🚀 | 大屏设计器 | 拖拽生成数据大屏,内置几十种图表组件 |
|
||||||
|
|
||||||
|
### 微信公众号
|
||||||
|
|
||||||
|
| | 功能 | 描述 |
|
||||||
|
|-----|--------|-------------------------------|
|
||||||
|
| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 |
|
||||||
|
| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 |
|
||||||
|
| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 |
|
||||||
|
| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 |
|
||||||
|
| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 |
|
||||||
|
| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 |
|
||||||
|
| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 |
|
||||||
|
| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 |
|
||||||
|
| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 |
|
||||||
|
| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 |
|
||||||
|
|
||||||
|
### 商城系统
|
||||||
|
|
||||||
|
演示地址:<https://doc.iocoder.cn/mall-preview/>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 会员中心
|
||||||
|
|
||||||
|
| | 功能 | 描述 |
|
||||||
|
|-----|------|----------------------------------|
|
||||||
|
| 🚀 | 会员管理 | 会员是 C 端的消费者,该功能用于会员的搜索与管理 |
|
||||||
|
| 🚀 | 会员标签 | 对会员的标签进行创建、查询、修改、删除等操作 |
|
||||||
|
| 🚀 | 会员等级 | 对会员的等级、成长值进行管理,可用于订单折扣等会员权益 |
|
||||||
|
| 🚀 | 会员分组 | 对会员进行分组,用于用户画像、内容推送等运营手段 |
|
||||||
|
| 🚀 | 积分签到 | 回馈给签到、消费等行为的积分,会员可订单抵现、积分兑换等途径消耗 |
|
||||||
|
|
||||||
|
### ERP 系统
|
||||||
|
|
||||||
|
演示地址:<https://doc.iocoder.cn/erp-preview/>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### CRM 系统
|
||||||
|
|
||||||
|
演示地址:<https://doc.iocoder.cn/crm-preview/>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### AI 大模型
|
||||||
|
|
||||||
|
演示地址:<https://doc.iocoder.cn/ai-preview/>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 🐨 技术栈
|
||||||
|
|
||||||
|
### 模块
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|-----------------------|--------------------|
|
||||||
|
| `yudao-dependencies` | Maven 依赖版本管理 |
|
||||||
|
| `yudao-framework` | Java 框架拓展 |
|
||||||
|
| `yudao-server` | 管理后台 + 用户 APP 的服务端 |
|
||||||
|
| `yudao-module-system` | 系统功能的 Module 模块 |
|
||||||
|
| `yudao-module-member` | 会员中心的 Module 模块 |
|
||||||
|
| `yudao-module-infra` | 基础设施的 Module 模块 |
|
||||||
|
| `yudao-module-bpm` | 工作流程的 Module 模块 |
|
||||||
|
| `yudao-module-pay` | 支付系统的 Module 模块 |
|
||||||
|
| `yudao-module-mall` | 商城系统的 Module 模块 |
|
||||||
|
| `yudao-module-erp` | ERP 系统的 Module 模块 |
|
||||||
|
| `yudao-module-crm` | CRM 系统的 Module 模块 |
|
||||||
|
| `yudao-module-ai` | AI 大模型的 Module 模块 |
|
||||||
|
| `yudao-module-mp` | 微信公众号的 Module 模块 |
|
||||||
|
| `yudao-module-report` | 大屏报表 Module 模块 |
|
||||||
|
|
||||||
|
### 框架
|
||||||
|
|
||||||
|
| 框架 | 说明 | 版本 | 学习指南 |
|
||||||
|
|---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|
|
||||||
|
| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.18 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
|
||||||
|
| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |
|
||||||
|
| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.23 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||||
|
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.7 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
|
||||||
|
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.1 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||||
|
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 /7.0 | |
|
||||||
|
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.32.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
|
||||||
|
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
|
||||||
|
| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.11 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
|
||||||
|
| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
|
||||||
|
| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.8.0 | [文档](https://doc.iocoder.cn/bpm/) |
|
||||||
|
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
|
||||||
|
| [Springdoc](https://springdoc.org/) | Swagger 文档 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
|
||||||
|
| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
|
||||||
|
| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.10 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
|
||||||
|
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.5 | |
|
||||||
|
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.6.3 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
|
||||||
|
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.34 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
|
||||||
|
| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |
|
||||||
|
| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - |
|
||||||
|
|
||||||
|
## 🐷 演示图
|
||||||
|
|
||||||
|
### 系统功能
|
||||||
|
|
||||||
|
| 模块 | biu | biu | biu |
|
||||||
|
|----------|-----------------------------|---------------------------|--------------------------|
|
||||||
|
| 登录 & 首页 |  |  |  |
|
||||||
|
| 用户 & 应用 |  |  |  |
|
||||||
|
| 租户 & 套餐 |  |  | - |
|
||||||
|
| 部门 & 岗位 |  |  | - |
|
||||||
|
| 菜单 & 角色 |  |  | - |
|
||||||
|
| 审计日志 |  |  | - |
|
||||||
|
| 短信 |  |  |  |
|
||||||
|
| 字典 & 敏感词 |  |  |  |
|
||||||
|
| 错误码 & 通知 |  |  | - |
|
||||||
|
|
||||||
|
### 工作流程
|
||||||
|
|
||||||
|
| 模块 | biu | biu | biu |
|
||||||
|
|---------|---------------------------------|---------------------------------|---------------------------------|
|
||||||
|
| 流程模型 |  |  |  |
|
||||||
|
| 表单 & 分组 |  |  | - |
|
||||||
|
| 我的流程 |  |  |  |
|
||||||
|
| 待办 & 已办 |  |  |  |
|
||||||
|
| OA 请假 |  |  |  |
|
||||||
|
|
||||||
|
### 基础设施
|
||||||
|
|
||||||
|
| 模块 | biu | biu | biu |
|
||||||
|
|---------------|-------------------------------|-----------------------------|---------------------------|
|
||||||
|
| 代码生成 |  |  | - |
|
||||||
|
| 文档 |  |  | - |
|
||||||
|
| 文件 & 配置 |  |  |  |
|
||||||
|
| 定时任务 |  |  | - |
|
||||||
|
| API 日志 |  |  | - |
|
||||||
|
| MySQL & Redis |  |  | - |
|
||||||
|
| 监控平台 |  |  |  |
|
||||||
|
|
||||||
|
### 支付系统
|
||||||
|
|
||||||
|
| 模块 | biu | biu | biu |
|
||||||
|
|---------|---------------------------|---------------------------------|---------------------------------|
|
||||||
|
| 商家 & 应用 |  |  |  |
|
||||||
|
| 支付 & 退款 |  |  | --- |
|
||||||
|
### 数据报表
|
||||||
|
|
||||||
|
| 模块 | biu | biu | biu |
|
||||||
|
|-------|---------------------------------|---------------------------------|---------------------------------------|
|
||||||
|
| 报表设计器 |  |  |  |
|
||||||
|
| 大屏设计器 |  |  |  |
|
||||||
|
|
||||||
|
### 移动端(管理后台)
|
||||||
|
|
||||||
|
| biu | biu | biu |
|
||||||
|
|----------------------------------|----------------------------------|----------------------------------|
|
||||||
|
|  |  |  |
|
||||||
|
|  |  |  |
|
||||||
|
|  |  |  |
|
||||||
|
|
||||||
|
目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
config.stopBubbling = true
|
||||||
|
lombok.tostring.callsuper=CALL
|
||||||
|
lombok.equalsandhashcode.callsuper=CALL
|
||||||
|
lombok.accessors.chain=true
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<modules>
|
||||||
|
<module>yudao-dependencies</module>
|
||||||
|
<module>yudao-framework</module>
|
||||||
|
<!-- Server 主项目 -->
|
||||||
|
<module>yudao-server</module>
|
||||||
|
<!-- 各种 module 拓展 -->
|
||||||
|
<module>yudao-module-system</module>
|
||||||
|
<module>yudao-module-infra</module>
|
||||||
|
<module>yudao-module-member</module>
|
||||||
|
<!-- <module>yudao-module-bpm</module>-->
|
||||||
|
<!-- <module>yudao-module-report</module>-->
|
||||||
|
<!-- <module>yudao-module-mp</module>-->
|
||||||
|
<module>yudao-module-pay</module>
|
||||||
|
<module>yudao-module-mall</module>
|
||||||
|
<module>yudao-module-digital</module>
|
||||||
|
<!-- <module>yudao-module-crm</module>-->
|
||||||
|
<!-- <module>yudao-module-erp</module>-->
|
||||||
|
<!-- <module>yudao-module-iot</module>-->
|
||||||
|
<!-- AI 大模型的开启,请参考 https://doc.iocoder.cn/ai/build/ 文档,对 JDK 版本要要求! -->
|
||||||
|
<!-- <module>yudao-module-ai</module>-->
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<name>${project.artifactId}</name>
|
||||||
|
<description>芋道项目基础脚手架</description>
|
||||||
|
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<revision>2025.09-jdk8-SNAPSHOT</revision>
|
||||||
|
<!-- Maven 相关 -->
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||||
|
<maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
|
||||||
|
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
|
||||||
|
<flatten-maven-plugin.version>1.7.2</flatten-maven-plugin.version>
|
||||||
|
<!-- maven-surefire-plugin 暂时无法通过 bom 的依赖读取(兼容老版本 IDEA 2024 及以前版本) -->
|
||||||
|
<lombok.version>1.18.38</lombok.version>
|
||||||
|
<spring.boot.version>2.7.18</spring.boot.version>
|
||||||
|
<mapstruct.version>1.6.3</mapstruct.version>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-dependencies</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<!-- maven-surefire-plugin 插件,用于运行单元测试。 -->
|
||||||
|
<!-- 注意,需要使用 3.0.X+,因为要支持 Junit 5 版本 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<!-- maven-compiler-plugin 插件,解决 spring-boot-configuration-processor + Lombok + MapStruct 组合 -->
|
||||||
|
<!-- https://stackoverflow.com/questions/33483697/re-run-spring-boot-configuration-annotation-processor-to-update-generated-metada -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>${maven-compiler-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<!-- 确保 Lombok 生成的 getter/setter 方法能被 MapStruct 正确识别,
|
||||||
|
避免出现 No property named “xxx" exists 的编译错误 -->
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||||
|
<version>0.2.0</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>flatten-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<!-- 统一 revision 版本 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>flatten-maven-plugin</artifactId>
|
||||||
|
<version>${flatten-maven-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<flattenMode>oss</flattenMode>
|
||||||
|
<updatePomFile>true</updatePomFile>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>flatten</goal>
|
||||||
|
</goals>
|
||||||
|
<id>flatten</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>clean</goal>
|
||||||
|
</goals>
|
||||||
|
<id>flatten.clean</id>
|
||||||
|
<phase>clean</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<!-- 使用 huawei / aliyun 的 Maven 源,提升下载速度 -->
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>huaweicloud</id>
|
||||||
|
<name>huawei</name>
|
||||||
|
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>aliyunmaven</id>
|
||||||
|
<name>aliyun</name>
|
||||||
|
<url>https://maven.aliyun.com/repository/public</url>
|
||||||
|
</repository>
|
||||||
|
|
||||||
|
<repository>
|
||||||
|
<id>spring-milestones</id>
|
||||||
|
<name>Spring Milestones</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>spring-snapshots</id>
|
||||||
|
<name>Spring Snapshots</name>
|
||||||
|
<url>https://repo.spring.io/snapshot</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Docker Build & Up
|
||||||
|
|
||||||
|
目标: 快速部署体验系统,帮助了解系统之间的依赖关系。
|
||||||
|
依赖:docker compose v2,删除`name: yudao-system`,降低`version`版本为`3.3`以下,支持`docker-compose`。
|
||||||
|
|
||||||
|
## 功能文件列表
|
||||||
|
|
||||||
|
```text
|
||||||
|
.
|
||||||
|
├── Docker-HOWTO.md
|
||||||
|
├── docker-compose.yml
|
||||||
|
├── docker.env <-- 提供docker-compose环境变量配置
|
||||||
|
├── yudao-server
|
||||||
|
│ └── Dockerfile
|
||||||
|
└── yudao-ui-admin
|
||||||
|
├── .dockerignore
|
||||||
|
├── Dockerfile
|
||||||
|
└── nginx.conf <-- 提供基础配置,gzip压缩、api转发
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建 jar 包
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 创建maven缓存volume
|
||||||
|
docker volume create --name yudao-maven-repo
|
||||||
|
|
||||||
|
docker run -it --rm --name yudao-maven \
|
||||||
|
-v yudao-maven-repo:/root/.m2 \
|
||||||
|
-v $PWD:/usr/src/mymaven \
|
||||||
|
-w /usr/src/mymaven \
|
||||||
|
maven mvn clean install package '-Dmaven.test.skip=true'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建启动服务
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker compose --env-file docker.env up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
首次运行会自动构建容器。可以通过`docker compose build [service]`来手动构建所有或某个docker镜像
|
||||||
|
|
||||||
|
`--env-file docker.env`为可选参数,只是展示了通过`.env`文件配置容器启动的环境变量,`docker-compose.yml`本身已经提供足够的默认参数来正常运行系统。
|
||||||
|
|
||||||
|
## 服务器的宿主机端口映射
|
||||||
|
|
||||||
|
- admin ui: http://localhost:8080
|
||||||
|
- api server: http://localhost:48080
|
||||||
|
- mysql: root/123456, port: 3306
|
||||||
|
- redis: port: 6379
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
version: "3.4"
|
||||||
|
|
||||||
|
name: yudao-system
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
container_name: yudao-mysql
|
||||||
|
image: mysql:8
|
||||||
|
restart: unless-stopped
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
environment:
|
||||||
|
MYSQL_DATABASE: ${MYSQL_DATABASE:-ruoyi-vue-pro}
|
||||||
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456}
|
||||||
|
volumes:
|
||||||
|
- mysql:/var/lib/mysql/
|
||||||
|
- ../../sql/mysql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/ruoyi-vue-pro.sql:ro
|
||||||
|
|
||||||
|
redis:
|
||||||
|
container_name: yudao-redis
|
||||||
|
image: redis:6-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis:/data
|
||||||
|
|
||||||
|
server:
|
||||||
|
container_name: yudao-server
|
||||||
|
build:
|
||||||
|
context: ./yudao-server/
|
||||||
|
image: yudao-server
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "48080:48080"
|
||||||
|
environment:
|
||||||
|
# https://github.com/polovyivan/docker-pass-configs-to-container
|
||||||
|
SPRING_PROFILES_ACTIVE: local
|
||||||
|
JAVA_OPTS:
|
||||||
|
${JAVA_OPTS:-
|
||||||
|
-Xms512m
|
||||||
|
-Xmx512m
|
||||||
|
-Djava.security.egd=file:/dev/./urandom
|
||||||
|
}
|
||||||
|
ARGS:
|
||||||
|
--spring.datasource.dynamic.datasource.master.url=${MASTER_DATASOURCE_URL:-jdbc:mysql://yudao-mysql:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true}
|
||||||
|
--spring.datasource.dynamic.datasource.master.username=${MASTER_DATASOURCE_USERNAME:-root}
|
||||||
|
--spring.datasource.dynamic.datasource.master.password=${MASTER_DATASOURCE_PASSWORD:-123456}
|
||||||
|
--spring.datasource.dynamic.datasource.slave.url=${SLAVE_DATASOURCE_URL:-jdbc:mysql://yudao-mysql:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true}
|
||||||
|
--spring.datasource.dynamic.datasource.slave.username=${SLAVE_DATASOURCE_USERNAME:-root}
|
||||||
|
--spring.datasource.dynamic.datasource.slave.password=${SLAVE_DATASOURCE_PASSWORD:-123456}
|
||||||
|
--spring.redis.host=${REDIS_HOST:-yudao-redis}
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
- redis
|
||||||
|
|
||||||
|
admin:
|
||||||
|
container_name: yudao-admin
|
||||||
|
build:
|
||||||
|
context: ./yudao-ui-admin
|
||||||
|
args:
|
||||||
|
NODE_ENV:
|
||||||
|
ENV=${NODE_ENV:-production}
|
||||||
|
PUBLIC_PATH=${PUBLIC_PATH:-/}
|
||||||
|
VUE_APP_TITLE=${VUE_APP_TITLE:-芋道管理系统}
|
||||||
|
VUE_APP_BASE_API=${VUE_APP_BASE_API:-/prod-api}
|
||||||
|
VUE_APP_APP_NAME=${VUE_APP_APP_NAME:-/}
|
||||||
|
VUE_APP_TENANT_ENABLE=${VUE_APP_TENANT_ENABLE:-true}
|
||||||
|
VUE_APP_CAPTCHA_ENABLE=${VUE_APP_CAPTCHA_ENABLE:-true}
|
||||||
|
VUE_APP_DOC_ENABLE=${VUE_APP_DOC_ENABLE:-true}
|
||||||
|
VUE_APP_BAIDU_CODE=${VUE_APP_BAIDU_CODE:-fadc1bd5db1a1d6f581df60a1807f8ab}
|
||||||
|
image: yudao-admin
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
depends_on:
|
||||||
|
- server
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql:
|
||||||
|
driver: local
|
||||||
|
redis:
|
||||||
|
driver: local
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
## mysql
|
||||||
|
MYSQL_DATABASE=ruoyi-vue-pro
|
||||||
|
MYSQL_ROOT_PASSWORD=123456
|
||||||
|
|
||||||
|
## server
|
||||||
|
JAVA_OPTS=-Xms512m -Xmx512m -Djava.security.egd=file:/dev/./urandom
|
||||||
|
|
||||||
|
MASTER_DATASOURCE_URL=jdbc:mysql://yudao-mysql:3306/${MYSQL_DATABASE}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
|
MASTER_DATASOURCE_USERNAME=root
|
||||||
|
MASTER_DATASOURCE_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||||
|
SLAVE_DATASOURCE_URL=${MASTER_DATASOURCE_URL}
|
||||||
|
SLAVE_DATASOURCE_USERNAME=${MASTER_DATASOURCE_USERNAME}
|
||||||
|
SLAVE_DATASOURCE_PASSWORD=${MASTER_DATASOURCE_PASSWORD}
|
||||||
|
REDIS_HOST=yudao-redis
|
||||||
|
|
||||||
|
## admin
|
||||||
|
NODE_ENV=production
|
||||||
|
PUBLIC_PATH=/
|
||||||
|
VUE_APP_TITLE=芋道管理系统
|
||||||
|
VUE_APP_BASE_API=/prod-api
|
||||||
|
VUE_APP_APP_NAME=/
|
||||||
|
VUE_APP_TENANT_ENABLE=true
|
||||||
|
VUE_APP_CAPTCHA_ENABLE=true
|
||||||
|
VUE_APP_DOC_ENABLE=true
|
||||||
|
VUE_APP_BAIDU_CODE=fadc1bd5db1a1d6f581df60a1807f8ab
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"local": {
|
||||||
|
"baseUrl": "http://127.0.0.1:48080/admin-api",
|
||||||
|
"token": "test1",
|
||||||
|
"adminTenantId": "1",
|
||||||
|
|
||||||
|
"appApi": "http://127.0.0.1:48080/app-api",
|
||||||
|
"appToken": "test247",
|
||||||
|
"appTenantId": "1"
|
||||||
|
},
|
||||||
|
"gateway": {
|
||||||
|
"baseUrl": "http://127.0.0.1:8888/admin-api",
|
||||||
|
"token": "test1",
|
||||||
|
"adminTenantId": "1",
|
||||||
|
|
||||||
|
"appApi": "http://127.0.0.1:8888/app-api",
|
||||||
|
"appToken": "test1",
|
||||||
|
"appTenantId": "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+60
@@ -0,0 +1,60 @@
|
|||||||
|
#!groovy
|
||||||
|
pipeline {
|
||||||
|
|
||||||
|
agent any
|
||||||
|
|
||||||
|
parameters {
|
||||||
|
string(name: 'TAG_NAME', defaultValue: '', description: '')
|
||||||
|
}
|
||||||
|
|
||||||
|
environment {
|
||||||
|
// DockerHub 凭证 ID(登录您的 DockerHub)
|
||||||
|
DOCKER_CREDENTIAL_ID = 'dockerhub-id'
|
||||||
|
// GitHub 凭证 ID (推送 tag 到 GitHub 仓库)
|
||||||
|
GITHUB_CREDENTIAL_ID = 'github-id'
|
||||||
|
// kubeconfig 凭证 ID (访问接入正在运行的 Kubernetes 集群)
|
||||||
|
KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
|
||||||
|
// 镜像的推送
|
||||||
|
REGISTRY = 'docker.io'
|
||||||
|
// DockerHub 账号名
|
||||||
|
DOCKERHUB_NAMESPACE = 'docker_username'
|
||||||
|
// GitHub 账号名
|
||||||
|
GITHUB_ACCOUNT = 'https://gitee.com/zhijiantianya/ruoyi-vue-pro'
|
||||||
|
// 应用名称
|
||||||
|
APP_NAME = 'yudao-server'
|
||||||
|
// 应用部署路径
|
||||||
|
APP_DEPLOY_BASE_DIR = '/media/pi/KINGTON/data/work/projects/'
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('检出') {
|
||||||
|
steps {
|
||||||
|
git url: "https://gitee.com/will-we/ruoyi-vue-pro.git",
|
||||||
|
branch: "devops"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('构建') {
|
||||||
|
steps {
|
||||||
|
// TODO 解决多环境链接、密码不同配置临时方案
|
||||||
|
sh 'if [ ! -d "' + "${env.HOME}" + '/resources" ];then\n' +
|
||||||
|
' echo "配置文件不存在无需修改"\n' +
|
||||||
|
'else\n' +
|
||||||
|
' cp -rf ' + "${env.HOME}" + '/resources/*.yaml ' + "${env.APP_NAME}" + '/src/main/resources\n' +
|
||||||
|
' echo "配置文件替换"\n' +
|
||||||
|
'fi'
|
||||||
|
sh 'mvn clean package -Dmaven.test.skip=true'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('部署') {
|
||||||
|
steps {
|
||||||
|
sh 'cp -f ' + ' bin/deploy.sh ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}"
|
||||||
|
sh 'cp -f ' + "${env.APP_NAME}" + '/target/*.jar ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" +'/build/'
|
||||||
|
archiveArtifacts "${env.APP_NAME}" + '/target/*.jar'
|
||||||
|
sh 'chmod +x ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" + '/deploy.sh'
|
||||||
|
sh 'bash ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" + '/deploy.sh'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
DATE=$(date +%Y%m%d%H%M)
|
||||||
|
# 基础路径
|
||||||
|
BASE_PATH=/work/projects/yudao-server
|
||||||
|
# 编译后 jar 的地址。部署时,Jenkins 会上传 jar 包到该目录下
|
||||||
|
SOURCE_PATH=$BASE_PATH/build
|
||||||
|
# 服务名称。同时约定部署服务的 jar 包名字也为它。
|
||||||
|
SERVER_NAME=yudao-server
|
||||||
|
# 环境
|
||||||
|
PROFILES_ACTIVE=development
|
||||||
|
# 健康检查 URL
|
||||||
|
HEALTH_CHECK_URL=http://127.0.0.1:48080/actuator/health/
|
||||||
|
|
||||||
|
# heapError 存放路径
|
||||||
|
HEAP_ERROR_PATH=$BASE_PATH/heapError
|
||||||
|
# JVM 参数
|
||||||
|
JAVA_OPS="-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$HEAP_ERROR_PATH"
|
||||||
|
|
||||||
|
# SkyWalking Agent 配置
|
||||||
|
#export SW_AGENT_NAME=$SERVER_NAME
|
||||||
|
#export SW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.0.84:11800
|
||||||
|
#export SW_GRPC_LOG_SERVER_HOST=192.168.0.84
|
||||||
|
#export SW_AGENT_TRACE_IGNORE_PATH="Redisson/PING,/actuator/**,/admin/**"
|
||||||
|
#export JAVA_AGENT=-javaagent:/work/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar
|
||||||
|
|
||||||
|
# 备份
|
||||||
|
function backup() {
|
||||||
|
# 如果不存在,则无需备份
|
||||||
|
if [ ! -f "$BASE_PATH/$SERVER_NAME.jar" ]; then
|
||||||
|
echo "[backup] $BASE_PATH/$SERVER_NAME.jar 不存在,跳过备份"
|
||||||
|
# 如果存在,则备份到 backup 目录下,使用时间作为后缀
|
||||||
|
else
|
||||||
|
echo "[backup] 开始备份 $SERVER_NAME ..."
|
||||||
|
cp $BASE_PATH/$SERVER_NAME.jar $BASE_PATH/backup/$SERVER_NAME-$DATE.jar
|
||||||
|
echo "[backup] 备份 $SERVER_NAME 完成"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 最新构建代码 移动到项目环境
|
||||||
|
function transfer() {
|
||||||
|
echo "[transfer] 开始转移 $SERVER_NAME.jar"
|
||||||
|
|
||||||
|
# 删除原 jar 包
|
||||||
|
if [ ! -f "$BASE_PATH/$SERVER_NAME.jar" ]; then
|
||||||
|
echo "[transfer] $BASE_PATH/$SERVER_NAME.jar 不存在,跳过删除"
|
||||||
|
else
|
||||||
|
echo "[transfer] 移除 $BASE_PATH/$SERVER_NAME.jar 完成"
|
||||||
|
rm $BASE_PATH/$SERVER_NAME.jar
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 复制新 jar 包
|
||||||
|
echo "[transfer] 从 $SOURCE_PATH 中获取 $SERVER_NAME.jar 并迁移至 $BASE_PATH ...."
|
||||||
|
cp $SOURCE_PATH/$SERVER_NAME.jar $BASE_PATH
|
||||||
|
|
||||||
|
echo "[transfer] 转移 $SERVER_NAME.jar 完成"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 停止:优雅关闭之前已经启动的服务
|
||||||
|
function stop() {
|
||||||
|
echo "[stop] 开始停止 $BASE_PATH/$SERVER_NAME"
|
||||||
|
PID=$(ps -ef | grep $BASE_PATH/$SERVER_NAME | grep -v "grep" | awk '{print $2}')
|
||||||
|
# 如果 Java 服务启动中,则进行关闭
|
||||||
|
if [ -n "$PID" ]; then
|
||||||
|
# 正常关闭
|
||||||
|
echo "[stop] $BASE_PATH/$SERVER_NAME 运行中,开始 kill [$PID]"
|
||||||
|
kill -15 $PID
|
||||||
|
# 等待最大 120 秒,直到关闭完成。
|
||||||
|
for ((i = 0; i < 120; i++))
|
||||||
|
do
|
||||||
|
sleep 1
|
||||||
|
PID=$(ps -ef | grep $BASE_PATH/$SERVER_NAME | grep -v "grep" | awk '{print $2}')
|
||||||
|
if [ -n "$PID" ]; then
|
||||||
|
echo -e ".\c"
|
||||||
|
else
|
||||||
|
echo "[stop] 停止 $BASE_PATH/$SERVER_NAME 成功"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 如果正常关闭失败,那么进行强制 kill -9 进行关闭
|
||||||
|
if [ -n "$PID" ]; then
|
||||||
|
echo "[stop] $BASE_PATH/$SERVER_NAME 失败,强制 kill -9 $PID"
|
||||||
|
kill -9 $PID
|
||||||
|
fi
|
||||||
|
# 如果 Java 服务未启动,则无需关闭
|
||||||
|
else
|
||||||
|
echo "[stop] $BASE_PATH/$SERVER_NAME 未启动,无需停止"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 启动:启动后端项目
|
||||||
|
function start() {
|
||||||
|
# 开启启动前,打印启动参数
|
||||||
|
echo "[start] 开始启动 $BASE_PATH/$SERVER_NAME"
|
||||||
|
echo "[start] JAVA_OPS: $JAVA_OPS"
|
||||||
|
echo "[start] JAVA_AGENT: $JAVA_AGENT"
|
||||||
|
echo "[start] PROFILES: $PROFILES_ACTIVE"
|
||||||
|
|
||||||
|
# 开始启动
|
||||||
|
BUILD_ID=dontKillMe nohup java -server $JAVA_OPS $JAVA_AGENT -jar $BASE_PATH/$SERVER_NAME.jar --spring.profiles.active=$PROFILES_ACTIVE &
|
||||||
|
echo "[start] 启动 $BASE_PATH/$SERVER_NAME 完成"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 健康检查:自动判断后端项目是否正常启动
|
||||||
|
function healthCheck() {
|
||||||
|
# 如果配置健康检查,则进行健康检查
|
||||||
|
if [ -n "$HEALTH_CHECK_URL" ]; then
|
||||||
|
# 健康检查最大 120 秒,直到健康检查通过
|
||||||
|
echo "[healthCheck] 开始通过 $HEALTH_CHECK_URL 地址,进行健康检查";
|
||||||
|
for ((i = 0; i < 120; i++))
|
||||||
|
do
|
||||||
|
# 请求健康检查地址,只获取状态码。
|
||||||
|
result=`curl -I -m 10 -o /dev/null -s -w %{http_code} $HEALTH_CHECK_URL || echo "000"`
|
||||||
|
# 如果状态码为 200,则说明健康检查通过
|
||||||
|
if [ "$result" == "200" ]; then
|
||||||
|
echo "[healthCheck] 健康检查通过";
|
||||||
|
break
|
||||||
|
# 如果状态码非 200,则说明未通过。sleep 1 秒后,继续重试
|
||||||
|
else
|
||||||
|
echo -e ".\c"
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 健康检查未通过,则异常退出 shell 脚本,不继续部署。
|
||||||
|
if [ ! "$result" == "200" ]; then
|
||||||
|
echo "[healthCheck] 健康检查不通过,可能部署失败。查看日志,自行判断是否启动成功";
|
||||||
|
tail -n 10 nohup.out
|
||||||
|
exit 1;
|
||||||
|
# 健康检查通过,打印最后 10 行日志,可能部署的人想看下日志。
|
||||||
|
else
|
||||||
|
tail -n 10 nohup.out
|
||||||
|
fi
|
||||||
|
# 如果未配置健康检查,则 sleep 120 秒,人工看日志是否部署成功。
|
||||||
|
else
|
||||||
|
echo "[healthCheck] HEALTH_CHECK_URL 未配置,开始 sleep 120 秒";
|
||||||
|
sleep 120
|
||||||
|
echo "[healthCheck] sleep 120 秒完成,查看日志,自行判断是否启动成功";
|
||||||
|
tail -n 50 nohup.out
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 部署
|
||||||
|
function deploy() {
|
||||||
|
cd $BASE_PATH
|
||||||
|
# 备份原 jar
|
||||||
|
backup
|
||||||
|
# 停止 Java 服务
|
||||||
|
stop
|
||||||
|
# 部署新 jar
|
||||||
|
transfer
|
||||||
|
# 启动 Java 服务
|
||||||
|
start
|
||||||
|
# 健康检查
|
||||||
|
healthCheck
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
暂未适配 IBM DB2 数据库,如果你有需要,可以微信联系 wangwenbin-server 一起建设。
|
||||||
|
|
||||||
|
你需要把表结构与数据导入到 DM 数据库,我来测试与适配代码。
|
||||||
@@ -0,0 +1,598 @@
|
|||||||
|
package liquibase.database.core;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import liquibase.CatalogAndSchema;
|
||||||
|
import liquibase.Scope;
|
||||||
|
import liquibase.database.AbstractJdbcDatabase;
|
||||||
|
import liquibase.database.DatabaseConnection;
|
||||||
|
import liquibase.database.OfflineConnection;
|
||||||
|
import liquibase.database.jvm.JdbcConnection;
|
||||||
|
import liquibase.exception.DatabaseException;
|
||||||
|
import liquibase.exception.UnexpectedLiquibaseException;
|
||||||
|
import liquibase.exception.ValidationErrors;
|
||||||
|
import liquibase.executor.ExecutorService;
|
||||||
|
import liquibase.statement.DatabaseFunction;
|
||||||
|
import liquibase.statement.SequenceCurrentValueFunction;
|
||||||
|
import liquibase.statement.SequenceNextValueFunction;
|
||||||
|
import liquibase.statement.core.RawCallStatement;
|
||||||
|
import liquibase.statement.core.RawSqlStatement;
|
||||||
|
import liquibase.structure.DatabaseObject;
|
||||||
|
import liquibase.structure.core.Catalog;
|
||||||
|
import liquibase.structure.core.Index;
|
||||||
|
import liquibase.structure.core.PrimaryKey;
|
||||||
|
import liquibase.structure.core.Schema;
|
||||||
|
import liquibase.util.JdbcUtils;
|
||||||
|
import liquibase.util.StringUtil;
|
||||||
|
|
||||||
|
public class DmDatabase extends AbstractJdbcDatabase {
|
||||||
|
private static final String PRODUCT_NAME = "DM DBMS";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultDatabaseProductName() {
|
||||||
|
return PRODUCT_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this AbstractDatabase subclass the correct one to use for the given connection.
|
||||||
|
*
|
||||||
|
* @param conn
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
|
||||||
|
return PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this database understands the given url, return the default driver class name. Otherwise return null.
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDefaultDriver(String url) {
|
||||||
|
if(url.startsWith("jdbc:dm")) {
|
||||||
|
return "dm.jdbc.driver.DmDriver";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an all-lower-case short name of the product. Used for end-user selecting of database type
|
||||||
|
* such as the DBMS precondition.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getShortName() {
|
||||||
|
return "dm";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getDefaultPort() {
|
||||||
|
return 5236;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this database support initially deferrable columns.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supportsInitiallyDeferrableColumns() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsTablespaces() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return PRIORITY_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Pattern PROXY_USER = Pattern.compile(".*(?:thin|oci)\\:(.+)/@.*");
|
||||||
|
|
||||||
|
protected final int SHORT_IDENTIFIERS_LENGTH = 30;
|
||||||
|
protected final int LONG_IDENTIFIERS_LEGNTH = 128;
|
||||||
|
public static final int ORACLE_12C_MAJOR_VERSION = 12;
|
||||||
|
|
||||||
|
private Set<String> reservedWords = new HashSet<>();
|
||||||
|
private Set<String> userDefinedTypes;
|
||||||
|
private Map<String, String> savedSessionNlsSettings;
|
||||||
|
|
||||||
|
private Boolean canAccessDbaRecycleBin;
|
||||||
|
private Integer databaseMajorVersion;
|
||||||
|
private Integer databaseMinorVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor for an object that represents the Oracle Database DBMS.
|
||||||
|
*/
|
||||||
|
public DmDatabase() {
|
||||||
|
super.unquotedObjectsAreUppercased = true;
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
super.setCurrentDateTimeFunction("SYSTIMESTAMP");
|
||||||
|
// Setting list of Oracle's native functions
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
dateFunctions.add(new DatabaseFunction("SYSDATE"));
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
dateFunctions.add(new DatabaseFunction("SYSTIMESTAMP"));
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
dateFunctions.add(new DatabaseFunction("CURRENT_TIMESTAMP"));
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
super.sequenceNextValueFunction = "%s.nextval";
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
super.sequenceCurrentValueFunction = "%s.currval";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryProxySession(final String url, final Connection con) {
|
||||||
|
Matcher m = PROXY_USER.matcher(url);
|
||||||
|
if (m.matches()) {
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("PROXY_USER_NAME", m.group(1));
|
||||||
|
try {
|
||||||
|
Method method = con.getClass().getMethod("openProxySession", int.class, Properties.class);
|
||||||
|
method.setAccessible(true);
|
||||||
|
method.invoke(con, 1, props);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Scope.getCurrentScope().getLog(getClass()).info("Could not open proxy session on OracleDatabase: " + e.getCause().getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDatabaseMajorVersion() throws DatabaseException {
|
||||||
|
if (databaseMajorVersion == null) {
|
||||||
|
return super.getDatabaseMajorVersion();
|
||||||
|
} else {
|
||||||
|
return databaseMajorVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDatabaseMinorVersion() throws DatabaseException {
|
||||||
|
if (databaseMinorVersion == null) {
|
||||||
|
return super.getDatabaseMinorVersion();
|
||||||
|
} else {
|
||||||
|
return databaseMinorVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getJdbcCatalogName(CatalogAndSchema schema) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getJdbcSchemaName(CatalogAndSchema schema) {
|
||||||
|
return correctObjectName((schema.getCatalogName() == null) ? schema.getSchemaName() : schema.getCatalogName(), Schema.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getAutoIncrementClause(final String generationType, final Boolean defaultOnNull) {
|
||||||
|
if (StringUtil.isEmpty(generationType)) {
|
||||||
|
return super.getAutoIncrementClause();
|
||||||
|
}
|
||||||
|
|
||||||
|
String autoIncrementClause = "GENERATED %s AS IDENTITY"; // %s -- [ ALWAYS | BY DEFAULT [ ON NULL ] ]
|
||||||
|
String generationStrategy = generationType;
|
||||||
|
if (Boolean.TRUE.equals(defaultOnNull) && generationType.toUpperCase().equals("BY DEFAULT")) {
|
||||||
|
generationStrategy += " ON NULL";
|
||||||
|
}
|
||||||
|
return String.format(autoIncrementClause, generationStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generatePrimaryKeyName(String tableName) {
|
||||||
|
if (tableName.length() > 27) {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
return "PK_" + tableName.toUpperCase(Locale.US).substring(0, 27);
|
||||||
|
} else {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
return "PK_" + tableName.toUpperCase(Locale.US);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReservedWord(String objectName) {
|
||||||
|
return reservedWords.contains(objectName.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsSequences() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Oracle supports catalogs in liquibase terms
|
||||||
|
*
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supportsSchemas() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getConnectionCatalogName() throws DatabaseException {
|
||||||
|
if (getConnection() instanceof OfflineConnection) {
|
||||||
|
return getConnection().getCatalog();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
return Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForObject(new RawCallStatement("select sys_context( 'userenv', 'current_schema' ) from dual"), String.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
Scope.getCurrentScope().getLog(getClass()).info("Error getting default schema", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDefaultCatalogName() {//NOPMD
|
||||||
|
return (super.getDefaultCatalogName() == null) ? null : super.getDefaultCatalogName().toUpperCase(Locale.US);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns an Oracle date literal with the same value as a string formatted using ISO 8601.</p>
|
||||||
|
*
|
||||||
|
* <p>Convert an ISO8601 date string to one of the following results:
|
||||||
|
* to_date('1995-05-23', 'YYYY-MM-DD')
|
||||||
|
* to_date('1995-05-23 09:23:59', 'YYYY-MM-DD HH24:MI:SS')</p>
|
||||||
|
* <p>
|
||||||
|
* Implementation restriction:<br>
|
||||||
|
* Currently, only the following subsets of ISO8601 are supported:<br>
|
||||||
|
* <ul>
|
||||||
|
* <li>YYYY-MM-DD</li>
|
||||||
|
* <li>YYYY-MM-DDThh:mm:ss</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDateLiteral(String isoDate) {
|
||||||
|
String normalLiteral = super.getDateLiteral(isoDate);
|
||||||
|
|
||||||
|
if (isDateOnly(isoDate)) {
|
||||||
|
return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD')";
|
||||||
|
} else if (isTimeOnly(isoDate)) {
|
||||||
|
return "TO_DATE(" + normalLiteral + ", 'HH24:MI:SS')";
|
||||||
|
} else if (isTimestamp(isoDate)) {
|
||||||
|
return "TO_TIMESTAMP(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS.FF')";
|
||||||
|
} else if (isDateTime(isoDate)) {
|
||||||
|
int seppos = normalLiteral.lastIndexOf('.');
|
||||||
|
if (seppos != -1) {
|
||||||
|
normalLiteral = normalLiteral.substring(0, seppos) + "'";
|
||||||
|
}
|
||||||
|
return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS')";
|
||||||
|
}
|
||||||
|
return "UNSUPPORTED:" + isoDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSystemObject(DatabaseObject example) {
|
||||||
|
if (example == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isLiquibaseObject(example)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (example instanceof Schema) {
|
||||||
|
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
|
||||||
|
if ("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
|
||||||
|
if ("SYSTEM".equals(example.getSchema().getCatalogName()) || "SYS".equals(example.getSchema().getCatalogName()) || "CTXSYS".equals(example.getSchema().getCatalogName()) || "XDB".equals(example.getSchema().getCatalogName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (isSystemObject(example.getSchema())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (example instanceof Catalog) {
|
||||||
|
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
|
||||||
|
if (("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName()))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (example.getName() != null) {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("BIN$")) { //oracle deleted table
|
||||||
|
boolean filteredInOriginalQuery = this.canAccessDbaRecycleBin();
|
||||||
|
if (!filteredInOriginalQuery) {
|
||||||
|
filteredInOriginalQuery = StringUtil.trimToEmpty(example.getSchema().getName()).equalsIgnoreCase(this.getConnection().getConnectionUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filteredInOriginalQuery) {
|
||||||
|
return !((example instanceof PrimaryKey) || (example instanceof Index) || (example instanceof
|
||||||
|
liquibase.statement.UniqueConstraint));
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("AQ$")) { //oracle AQ tables
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("DR$")) { //oracle index tables
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("SYS_IOT_OVER")) { //oracle system table
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral,HardCodedStringLiteral
|
||||||
|
if ((example.getName().startsWith("MDRT_") || example.getName().startsWith("MDRS_")) && example.getName().endsWith("$")) {
|
||||||
|
// CORE-1768 - Oracle creates these for spatial indices and will remove them when the index is removed.
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("MLOG$_")) { //Created by materliaized view logs for every table that is part of a materialized view. Not available for DDL operations.
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("RUPD$_")) { //Created by materialized view log tables using primary keys. Not available for DDL operations.
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("WM$_")) { //Workspace Manager backup tables.
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if ("CREATE$JAVA$LOB$TABLE".equals(example.getName())) { //This table contains the name of the Java object, the date it was loaded, and has a BLOB column to store the Java object.
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if ("JAVA$CLASS$MD5$TABLE".equals(example.getName())) { //This is a hash table that tracks the loading of Java objects into a schema.
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("ISEQ$$_")) { //System-generated sequence
|
||||||
|
return true;
|
||||||
|
} else //noinspection HardCodedStringLiteral
|
||||||
|
if (example.getName().startsWith("USLOG$")) { //for update materialized view
|
||||||
|
return true;
|
||||||
|
} else if (example.getName().startsWith("SYS_FBA")) { //for Flashback tables
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.isSystemObject(example);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAutoIncrement() {
|
||||||
|
// Oracle supports Identity beginning with version 12c
|
||||||
|
boolean isAutoIncrementSupported = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (getDatabaseMajorVersion() >= 12) {
|
||||||
|
isAutoIncrementSupported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returning true will generate create table command with 'IDENTITY' clause, example:
|
||||||
|
// CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) GENERATED BY DEFAULT AS IDENTITY NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey));
|
||||||
|
|
||||||
|
// While returning false will continue to generate create table command without 'IDENTITY' clause, example:
|
||||||
|
// CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey));
|
||||||
|
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
isAutoIncrementSupported = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isAutoIncrementSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public Set<UniqueConstraint> findUniqueConstraints(String schema) throws DatabaseException {
|
||||||
|
// Set<UniqueConstraint> returnSet = new HashSet<UniqueConstraint>();
|
||||||
|
//
|
||||||
|
// List<Map> maps = new Executor(this).queryForList(new RawSqlStatement("SELECT UC.CONSTRAINT_NAME, UCC.TABLE_NAME, UCC.COLUMN_NAME FROM USER_CONSTRAINTS UC, USER_CONS_COLUMNS UCC WHERE UC.CONSTRAINT_NAME=UCC.CONSTRAINT_NAME AND CONSTRAINT_TYPE='U' ORDER BY UC.CONSTRAINT_NAME"));
|
||||||
|
//
|
||||||
|
// UniqueConstraint constraint = null;
|
||||||
|
// for (Map map : maps) {
|
||||||
|
// if (constraint == null || !constraint.getName().equals(constraint.getName())) {
|
||||||
|
// returnSet.add(constraint);
|
||||||
|
// Table table = new Table((String) map.get("TABLE_NAME"));
|
||||||
|
// constraint = new UniqueConstraint(map.get("CONSTRAINT_NAME").toString(), table);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (constraint != null) {
|
||||||
|
// returnSet.add(constraint);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return returnSet;
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRestrictForeignKeys() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDataTypeMaxParameters(String dataTypeName) {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
if ("BINARY_FLOAT".equals(dataTypeName.toUpperCase())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
if ("BINARY_DOUBLE".equals(dataTypeName.toUpperCase())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return super.getDataTypeMaxParameters(dataTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSystemTableWhereClause(String tableNameColumn) {
|
||||||
|
List<String> clauses = new ArrayList<String>(Arrays.asList("BIN$",
|
||||||
|
"AQ$",
|
||||||
|
"DR$",
|
||||||
|
"SYS_IOT_OVER",
|
||||||
|
"MLOG$_",
|
||||||
|
"RUPD$_",
|
||||||
|
"WM$_",
|
||||||
|
"ISEQ$$_",
|
||||||
|
"USLOG$",
|
||||||
|
"SYS_FBA"));
|
||||||
|
|
||||||
|
for (int i = 0;i<clauses.size(); i++) {
|
||||||
|
clauses.set(i, tableNameColumn+" NOT LIKE '"+clauses.get(i)+"%'");
|
||||||
|
}
|
||||||
|
return "("+ StringUtil.join(clauses, " AND ") + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean jdbcCallsCatalogsSchemas() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getUserDefinedTypes() {
|
||||||
|
if (userDefinedTypes == null) {
|
||||||
|
userDefinedTypes = new HashSet<>();
|
||||||
|
if ((getConnection() != null) && !(getConnection() instanceof OfflineConnection)) {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
userDefinedTypes.addAll(Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForList(new RawSqlStatement("SELECT DISTINCT TYPE_NAME FROM ALL_TYPES"), String.class));
|
||||||
|
} catch (DatabaseException e) { //fall back to USER_TYPES if the user cannot see ALL_TYPES
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
userDefinedTypes.addAll(Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForList(new RawSqlStatement("SELECT TYPE_NAME FROM USER_TYPES"), String.class));
|
||||||
|
}
|
||||||
|
} catch (DatabaseException e) {
|
||||||
|
//ignore error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return userDefinedTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateDatabaseFunctionValue(DatabaseFunction databaseFunction) {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
if ((databaseFunction != null) && "current_timestamp".equalsIgnoreCase(databaseFunction.toString())) {
|
||||||
|
return databaseFunction.toString();
|
||||||
|
}
|
||||||
|
if ((databaseFunction instanceof SequenceNextValueFunction) || (databaseFunction instanceof
|
||||||
|
SequenceCurrentValueFunction)) {
|
||||||
|
String quotedSeq = super.generateDatabaseFunctionValue(databaseFunction);
|
||||||
|
// replace "myschema.my_seq".nextval with "myschema"."my_seq".nextval
|
||||||
|
return quotedSeq.replaceFirst("\"([^\\.\"]+)\\.([^\\.\"]+)\"", "\"$1\".\"$2\"");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.generateDatabaseFunctionValue(databaseFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValidationErrors validate() {
|
||||||
|
ValidationErrors errors = super.validate();
|
||||||
|
DatabaseConnection connection = getConnection();
|
||||||
|
if ((connection == null) || (connection instanceof OfflineConnection)) {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
Scope.getCurrentScope().getLog(getClass()).info("Cannot validate offline database");
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canAccessDbaRecycleBin()) {
|
||||||
|
errors.addWarning(getDbaRecycleBinWarning());
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDbaRecycleBinWarning() {
|
||||||
|
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
|
||||||
|
// HardCodedStringLiteral
|
||||||
|
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
|
||||||
|
return "Liquibase needs to access the DBA_RECYCLEBIN table so we can automatically handle the case where " +
|
||||||
|
"constraints are deleted and restored. Since Oracle doesn't properly restore the original table names " +
|
||||||
|
"referenced in the constraint, we use the information from the DBA_RECYCLEBIN to automatically correct this" +
|
||||||
|
" issue.\n" +
|
||||||
|
"\n" +
|
||||||
|
"The user you used to connect to the database (" + getConnection().getConnectionUserName() +
|
||||||
|
") needs to have \"SELECT ON SYS.DBA_RECYCLEBIN\" permissions set before we can perform this operation. " +
|
||||||
|
"Please run the following SQL to set the appropriate permissions, and try running the command again.\n" +
|
||||||
|
"\n" +
|
||||||
|
" GRANT SELECT ON SYS.DBA_RECYCLEBIN TO " + getConnection().getConnectionUserName() + ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canAccessDbaRecycleBin() {
|
||||||
|
if (canAccessDbaRecycleBin == null) {
|
||||||
|
DatabaseConnection connection = getConnection();
|
||||||
|
if ((connection == null) || (connection instanceof OfflineConnection)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement statement = null;
|
||||||
|
try {
|
||||||
|
statement = ((JdbcConnection) connection).createStatement();
|
||||||
|
@SuppressWarnings("HardCodedStringLiteral") ResultSet resultSet = statement.executeQuery("select 1 from dba_recyclebin where 0=1");
|
||||||
|
resultSet.close(); //don't need to do anything with the result set, just make sure statement ran.
|
||||||
|
this.canAccessDbaRecycleBin = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
if ((e instanceof SQLException) && e.getMessage().startsWith("ORA-00942")) { //ORA-00942: table or view does not exist
|
||||||
|
this.canAccessDbaRecycleBin = false;
|
||||||
|
} else {
|
||||||
|
//noinspection HardCodedStringLiteral
|
||||||
|
Scope.getCurrentScope().getLog(getClass()).warning("Cannot check dba_recyclebin access", e);
|
||||||
|
this.canAccessDbaRecycleBin = false;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
JdbcUtils.close(null, statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canAccessDbaRecycleBin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsNotNullConstraintNames() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if the given String would be a valid identifier in Oracle DBMS. In Oracle, a valid identifier has
|
||||||
|
* the following form (case-insensitive comparison):
|
||||||
|
* 1st character: A-Z
|
||||||
|
* 2..n characters: A-Z0-9$_#
|
||||||
|
* The maximum length of an identifier differs by Oracle version and object type.
|
||||||
|
*/
|
||||||
|
public boolean isValidOracleIdentifier(String identifier, Class<? extends DatabaseObject> type) {
|
||||||
|
if ((identifier == null) || (identifier.length() < 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!identifier.matches("^(i?)[A-Z][A-Z0-9\\$\\_\\#]*$"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @todo It seems we currently do not have a class for tablespace identifiers, and all other classes
|
||||||
|
* we do know seem to be supported as 12cR2 long identifiers, so:
|
||||||
|
*/
|
||||||
|
return (identifier.length() <= LONG_IDENTIFIERS_LEGNTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of bytes (NOT: characters) for an identifier. For Oracle <=12c Release 20, this
|
||||||
|
* is 30 bytes, and starting from 12cR2, up to 128 (except for tablespaces, PDB names and some other rather rare
|
||||||
|
* object types).
|
||||||
|
*
|
||||||
|
* @return the maximum length of an object identifier, in bytes
|
||||||
|
*/
|
||||||
|
public int getIdentifierMaximumLength() {
|
||||||
|
try {
|
||||||
|
if (getDatabaseMajorVersion() < ORACLE_12C_MAJOR_VERSION) {
|
||||||
|
return SHORT_IDENTIFIERS_LENGTH;
|
||||||
|
} else if ((getDatabaseMajorVersion() == ORACLE_12C_MAJOR_VERSION) && (getDatabaseMinorVersion() <= 1)) {
|
||||||
|
return SHORT_IDENTIFIERS_LENGTH;
|
||||||
|
} else {
|
||||||
|
return LONG_IDENTIFIERS_LEGNTH;
|
||||||
|
}
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
throw new UnexpectedLiquibaseException("Cannot determine the Oracle database version number", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
package liquibase.datatype.core;
|
||||||
|
|
||||||
|
import liquibase.change.core.LoadDataChange;
|
||||||
|
import liquibase.database.Database;
|
||||||
|
import liquibase.database.core.*;
|
||||||
|
import liquibase.datatype.DataTypeInfo;
|
||||||
|
import liquibase.datatype.DatabaseDataType;
|
||||||
|
import liquibase.datatype.LiquibaseDataType;
|
||||||
|
import liquibase.exception.UnexpectedLiquibaseException;
|
||||||
|
import liquibase.statement.DatabaseFunction;
|
||||||
|
import liquibase.util.StringUtil;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@DataTypeInfo(name = "boolean", aliases = {"java.sql.Types.BOOLEAN", "java.lang.Boolean", "bit", "bool"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT)
|
||||||
|
public class BooleanType extends LiquibaseDataType {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatabaseDataType toDatabaseDataType(Database database) {
|
||||||
|
String originalDefinition = StringUtil.trimToEmpty(getRawDefinition());
|
||||||
|
if ((database instanceof Firebird3Database)) {
|
||||||
|
return new DatabaseDataType("BOOLEAN");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((database instanceof Db2zDatabase) || (database instanceof FirebirdDatabase)) {
|
||||||
|
return new DatabaseDataType("SMALLINT");
|
||||||
|
} else if (database instanceof MSSQLDatabase) {
|
||||||
|
return new DatabaseDataType(database.escapeDataTypeName("bit"));
|
||||||
|
} else if (database instanceof MySQLDatabase) {
|
||||||
|
if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) {
|
||||||
|
return new DatabaseDataType("BIT", getParameters());
|
||||||
|
}
|
||||||
|
return new DatabaseDataType("BIT", 1);
|
||||||
|
} else if (database instanceof OracleDatabase) {
|
||||||
|
return new DatabaseDataType("NUMBER", 1);
|
||||||
|
} else if ((database instanceof SybaseASADatabase) || (database instanceof SybaseDatabase)) {
|
||||||
|
return new DatabaseDataType("BIT");
|
||||||
|
} else if (database instanceof DerbyDatabase) {
|
||||||
|
if (((DerbyDatabase) database).supportsBooleanDataType()) {
|
||||||
|
return new DatabaseDataType("BOOLEAN");
|
||||||
|
} else {
|
||||||
|
return new DatabaseDataType("SMALLINT");
|
||||||
|
}
|
||||||
|
} else if (database instanceof DB2Database) {
|
||||||
|
if (((DB2Database) database).supportsBooleanDataType())
|
||||||
|
return new DatabaseDataType("BOOLEAN");
|
||||||
|
else
|
||||||
|
return new DatabaseDataType("SMALLINT");
|
||||||
|
} else if (database instanceof HsqlDatabase) {
|
||||||
|
return new DatabaseDataType("BOOLEAN");
|
||||||
|
} else if (database instanceof PostgresDatabase) {
|
||||||
|
if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) {
|
||||||
|
return new DatabaseDataType("BIT", getParameters());
|
||||||
|
}
|
||||||
|
} else if (database instanceof DmDatabase) { // dhb52: DM Support
|
||||||
|
return new DatabaseDataType("bit");
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.toDatabaseDataType(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String objectToSql(Object value, Database database) {
|
||||||
|
if ((value == null) || "null".equals(value.toString().toLowerCase(Locale.US))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String returnValue;
|
||||||
|
if (value instanceof String) {
|
||||||
|
value = ((String) value).replaceAll("'", "");
|
||||||
|
if ("true".equals(((String) value).toLowerCase(Locale.US)) || "1".equals(value) || "b'1'".equals(((String) value).toLowerCase(Locale.US)) || "t".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getTrueBooleanValue(database).toLowerCase(Locale.US))) {
|
||||||
|
returnValue = this.getTrueBooleanValue(database);
|
||||||
|
} else if ("false".equals(((String) value).toLowerCase(Locale.US)) || "0".equals(value) || "b'0'".equals(
|
||||||
|
((String) value).toLowerCase(Locale.US)) || "f".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getFalseBooleanValue(database).toLowerCase(Locale.US))) {
|
||||||
|
returnValue = this.getFalseBooleanValue(database);
|
||||||
|
} else if (database instanceof PostgresDatabase && Pattern.matches("b?([01])\\1*(::bit|::\"bit\")?", (String) value)) {
|
||||||
|
returnValue = "b'"
|
||||||
|
+ value.toString()
|
||||||
|
.replace("b", "")
|
||||||
|
.replace("\"", "")
|
||||||
|
.replace("::it", "")
|
||||||
|
+ "'::\"bit\"";
|
||||||
|
} else {
|
||||||
|
throw new UnexpectedLiquibaseException("Unknown boolean value: " + value);
|
||||||
|
}
|
||||||
|
} else if (value instanceof Long) {
|
||||||
|
if (Long.valueOf(1).equals(value)) {
|
||||||
|
returnValue = this.getTrueBooleanValue(database);
|
||||||
|
} else {
|
||||||
|
returnValue = this.getFalseBooleanValue(database);
|
||||||
|
}
|
||||||
|
} else if (value instanceof Number) {
|
||||||
|
if (value.equals(1) || "1".equals(value.toString()) || "1.0".equals(value.toString())) {
|
||||||
|
returnValue = this.getTrueBooleanValue(database);
|
||||||
|
} else {
|
||||||
|
returnValue = this.getFalseBooleanValue(database);
|
||||||
|
}
|
||||||
|
} else if (value instanceof DatabaseFunction) {
|
||||||
|
return value.toString();
|
||||||
|
} else if (value instanceof Boolean) {
|
||||||
|
if (((Boolean) value)) {
|
||||||
|
returnValue = this.getTrueBooleanValue(database);
|
||||||
|
} else {
|
||||||
|
returnValue = this.getFalseBooleanValue(database);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new UnexpectedLiquibaseException("Cannot convert type " + value.getClass() + " to a boolean value");
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isNumericBoolean(Database database) {
|
||||||
|
if (database instanceof Firebird3Database) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (database instanceof DerbyDatabase) {
|
||||||
|
return !((DerbyDatabase) database).supportsBooleanDataType();
|
||||||
|
} else if (database instanceof DB2Database) {
|
||||||
|
return !((DB2Database) database).supportsBooleanDataType();
|
||||||
|
}
|
||||||
|
return (database instanceof Db2zDatabase)
|
||||||
|
|| (database instanceof FirebirdDatabase)
|
||||||
|
|| (database instanceof MSSQLDatabase)
|
||||||
|
|| (database instanceof MySQLDatabase)
|
||||||
|
|| (database instanceof OracleDatabase)
|
||||||
|
|| (database instanceof SQLiteDatabase)
|
||||||
|
|| (database instanceof SybaseASADatabase)
|
||||||
|
|| (database instanceof SybaseDatabase)
|
||||||
|
|| (database instanceof DmDatabase); // dhb52: DM Support
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The database-specific value to use for "false" "boolean" columns.
|
||||||
|
*/
|
||||||
|
public String getFalseBooleanValue(Database database) {
|
||||||
|
if (isNumericBoolean(database)) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
if (database instanceof InformixDatabase) {
|
||||||
|
return "'f'";
|
||||||
|
}
|
||||||
|
return "FALSE";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The database-specific value to use for "true" "boolean" columns.
|
||||||
|
*/
|
||||||
|
public String getTrueBooleanValue(Database database) {
|
||||||
|
if (isNumericBoolean(database)) {
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
if (database instanceof InformixDatabase) {
|
||||||
|
return "'t'";
|
||||||
|
}
|
||||||
|
return "TRUE";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoadDataChange.LOAD_DATA_TYPE getLoadTypeName() {
|
||||||
|
return LoadDataChange.LOAD_DATA_TYPE.BOOLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+2068
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
|||||||
|
防止IDEA将`.`和`/`混为一谈
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
liquibase.database.core.CockroachDatabase
|
||||||
|
liquibase.database.core.DB2Database
|
||||||
|
liquibase.database.core.Db2zDatabase
|
||||||
|
liquibase.database.core.DerbyDatabase
|
||||||
|
liquibase.database.core.Firebird3Database
|
||||||
|
liquibase.database.core.FirebirdDatabase
|
||||||
|
liquibase.database.core.H2Database
|
||||||
|
liquibase.database.core.HsqlDatabase
|
||||||
|
liquibase.database.core.InformixDatabase
|
||||||
|
liquibase.database.core.Ingres9Database
|
||||||
|
liquibase.database.core.MSSQLDatabase
|
||||||
|
liquibase.database.core.MariaDBDatabase
|
||||||
|
liquibase.database.core.MockDatabase
|
||||||
|
liquibase.database.core.MySQLDatabase
|
||||||
|
liquibase.database.core.OracleDatabase
|
||||||
|
liquibase.database.core.PostgresDatabase
|
||||||
|
liquibase.database.core.SQLiteDatabase
|
||||||
|
liquibase.database.core.SybaseASADatabase
|
||||||
|
liquibase.database.core.SybaseDatabase
|
||||||
|
liquibase.database.core.DmDatabase
|
||||||
|
liquibase.database.core.UnsupportedDatabase
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
--
|
||||||
|
-- A hint submitted by a user: Oracle DB MUST be created as "shared" and the
|
||||||
|
-- job_queue_processes parameter must be greater than 2
|
||||||
|
-- However, these settings are pretty much standard after any
|
||||||
|
-- Oracle install, so most users need not worry about this.
|
||||||
|
--
|
||||||
|
-- Many other users (including the primary author of Quartz) have had success
|
||||||
|
-- running in dedicated mode, so only consider the above as a hint ;-)
|
||||||
|
--
|
||||||
|
|
||||||
|
drop table if exists qrtz_calendars;
|
||||||
|
drop table if exists qrtz_fired_triggers;
|
||||||
|
drop table if exists qrtz_blob_triggers;
|
||||||
|
drop table if exists qrtz_cron_triggers;
|
||||||
|
drop table if exists qrtz_simple_triggers;
|
||||||
|
drop table if exists qrtz_simprop_triggers;
|
||||||
|
drop table if exists qrtz_triggers;
|
||||||
|
drop table if exists qrtz_job_details;
|
||||||
|
drop table if exists qrtz_paused_trigger_grps;
|
||||||
|
drop table if exists qrtz_locks;
|
||||||
|
drop table if exists qrtz_scheduler_state;
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_job_details
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
JOB_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
DESCRIPTION VARCHAR2(250) NULL,
|
||||||
|
JOB_CLASS_NAME VARCHAR2(250) NOT NULL,
|
||||||
|
IS_DURABLE VARCHAR2(1) NOT NULL,
|
||||||
|
IS_NONCONCURRENT VARCHAR2(1) NOT NULL,
|
||||||
|
IS_UPDATE_DATA VARCHAR2(1) NOT NULL,
|
||||||
|
REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,
|
||||||
|
JOB_DATA BLOB NULL,
|
||||||
|
CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_triggers
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
JOB_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
DESCRIPTION VARCHAR2(250) NULL,
|
||||||
|
NEXT_FIRE_TIME NUMBER(19) NULL,
|
||||||
|
PREV_FIRE_TIME NUMBER(19) NULL,
|
||||||
|
PRIORITY NUMBER(13) NULL,
|
||||||
|
TRIGGER_STATE VARCHAR2(16) NOT NULL,
|
||||||
|
TRIGGER_TYPE VARCHAR2(8) NOT NULL,
|
||||||
|
START_TIME NUMBER(19) NOT NULL,
|
||||||
|
END_TIME NUMBER(19) NULL,
|
||||||
|
CALENDAR_NAME VARCHAR2(200) NULL,
|
||||||
|
MISFIRE_INSTR NUMBER(2) NULL,
|
||||||
|
JOB_DATA BLOB NULL,
|
||||||
|
CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||||
|
CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
|
||||||
|
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_simple_triggers
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
REPEAT_COUNT NUMBER(7) NOT NULL,
|
||||||
|
REPEAT_INTERVAL NUMBER(12) NOT NULL,
|
||||||
|
TIMES_TRIGGERED NUMBER(10) NOT NULL,
|
||||||
|
CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||||
|
CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_cron_triggers
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
CRON_EXPRESSION VARCHAR2(120) NOT NULL,
|
||||||
|
TIME_ZONE_ID VARCHAR2(80),
|
||||||
|
CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||||
|
CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_simprop_triggers
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
STR_PROP_1 VARCHAR2(512) NULL,
|
||||||
|
STR_PROP_2 VARCHAR2(512) NULL,
|
||||||
|
STR_PROP_3 VARCHAR2(512) NULL,
|
||||||
|
INT_PROP_1 NUMBER(10) NULL,
|
||||||
|
INT_PROP_2 NUMBER(10) NULL,
|
||||||
|
LONG_PROP_1 NUMBER(19) NULL,
|
||||||
|
LONG_PROP_2 NUMBER(19) NULL,
|
||||||
|
DEC_PROP_1 NUMERIC(13,4) NULL,
|
||||||
|
DEC_PROP_2 NUMERIC(13,4) NULL,
|
||||||
|
BOOL_PROP_1 VARCHAR2(1) NULL,
|
||||||
|
BOOL_PROP_2 VARCHAR2(1) NULL,
|
||||||
|
TIME_ZONE_ID VARCHAR2(80) NULL,
|
||||||
|
CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||||
|
CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_blob_triggers
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
BLOB_DATA BLOB NULL,
|
||||||
|
CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||||
|
CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_calendars
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
CALENDAR_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
CALENDAR BLOB NOT NULL,
|
||||||
|
CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_paused_trigger_grps
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_fired_triggers
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
ENTRY_ID VARCHAR2(140) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
|
||||||
|
INSTANCE_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
FIRED_TIME NUMBER(19) NOT NULL,
|
||||||
|
SCHED_TIME NUMBER(19) NOT NULL,
|
||||||
|
PRIORITY NUMBER(13) NOT NULL,
|
||||||
|
STATE VARCHAR2(16) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR2(200) NULL,
|
||||||
|
JOB_GROUP VARCHAR2(200) NULL,
|
||||||
|
IS_NONCONCURRENT VARCHAR2(1) NULL,
|
||||||
|
REQUESTS_RECOVERY VARCHAR2(1) NULL,
|
||||||
|
CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_scheduler_state
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
INSTANCE_NAME VARCHAR2(200) NOT NULL,
|
||||||
|
LAST_CHECKIN_TIME NUMBER(19) NOT NULL,
|
||||||
|
CHECKIN_INTERVAL NUMBER(13) NOT NULL,
|
||||||
|
CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
|
||||||
|
);
|
||||||
|
CREATE TABLE qrtz_locks
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR2(120) NOT NULL,
|
||||||
|
LOCK_NAME VARCHAR2(40) NOT NULL,
|
||||||
|
CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME)
|
||||||
|
);
|
||||||
|
|
||||||
|
create index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);
|
||||||
|
create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP);
|
||||||
|
|
||||||
|
create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);
|
||||||
|
create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);
|
||||||
|
create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);
|
||||||
|
create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);
|
||||||
|
create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);
|
||||||
|
create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
|
||||||
|
create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
|
||||||
|
create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);
|
||||||
|
create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
|
||||||
|
create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
|
||||||
|
create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
|
||||||
|
create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
|
||||||
|
|
||||||
|
create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);
|
||||||
|
create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
|
||||||
|
create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);
|
||||||
|
create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);
|
||||||
|
create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
|
||||||
|
create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
|||||||
|
set client_min_messages = WARNING;
|
||||||
|
DROP TABLE IF EXISTS qrtz_fired_triggers;
|
||||||
|
DROP TABLE IF EXISTS qrtz_paused_trigger_grps;
|
||||||
|
DROP TABLE IF EXISTS qrtz_scheduler_state;
|
||||||
|
DROP TABLE IF EXISTS qrtz_locks;
|
||||||
|
DROP TABLE IF EXISTS qrtz_simprop_triggers;
|
||||||
|
DROP TABLE IF EXISTS qrtz_simple_triggers;
|
||||||
|
DROP TABLE IF EXISTS qrtz_cron_triggers;
|
||||||
|
DROP TABLE IF EXISTS qrtz_blob_triggers;
|
||||||
|
DROP TABLE IF EXISTS qrtz_triggers;
|
||||||
|
DROP TABLE IF EXISTS qrtz_job_details;
|
||||||
|
DROP TABLE IF EXISTS qrtz_calendars;
|
||||||
|
set client_min_messages = NOTICE;
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_job_details
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
job_name TEXT NOT NULL,
|
||||||
|
job_group TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
job_class_name TEXT NOT NULL,
|
||||||
|
is_durable BOOL NOT NULL,
|
||||||
|
is_nonconcurrent BOOL NOT NULL,
|
||||||
|
is_update_data BOOL NOT NULL,
|
||||||
|
requests_recovery BOOL NOT NULL,
|
||||||
|
job_data BYTEA NULL,
|
||||||
|
PRIMARY KEY (sched_name,job_name,job_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_triggers
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
trigger_name TEXT NOT NULL,
|
||||||
|
trigger_group TEXT NOT NULL,
|
||||||
|
job_name TEXT NOT NULL,
|
||||||
|
job_group TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
next_fire_time BIGINT NULL,
|
||||||
|
prev_fire_time BIGINT NULL,
|
||||||
|
priority INTEGER NULL,
|
||||||
|
trigger_state TEXT NOT NULL,
|
||||||
|
trigger_type TEXT NOT NULL,
|
||||||
|
start_time BIGINT NOT NULL,
|
||||||
|
end_time BIGINT NULL,
|
||||||
|
calendar_name TEXT NULL,
|
||||||
|
misfire_instr SMALLINT NULL,
|
||||||
|
job_data BYTEA NULL,
|
||||||
|
PRIMARY KEY (sched_name,trigger_name,trigger_group),
|
||||||
|
FOREIGN KEY (sched_name,job_name,job_group)
|
||||||
|
REFERENCES qrtz_job_details(sched_name,job_name,job_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_simple_triggers
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
trigger_name TEXT NOT NULL,
|
||||||
|
trigger_group TEXT NOT NULL,
|
||||||
|
repeat_count BIGINT NOT NULL,
|
||||||
|
repeat_interval BIGINT NOT NULL,
|
||||||
|
times_triggered BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name,trigger_name,trigger_group),
|
||||||
|
FOREIGN KEY (sched_name,trigger_name,trigger_group)
|
||||||
|
REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
trigger_name TEXT NOT NULL ,
|
||||||
|
trigger_group TEXT NOT NULL ,
|
||||||
|
str_prop_1 TEXT NULL,
|
||||||
|
str_prop_2 TEXT NULL,
|
||||||
|
str_prop_3 TEXT NULL,
|
||||||
|
int_prop_1 INTEGER NULL,
|
||||||
|
int_prop_2 INTEGER NULL,
|
||||||
|
long_prop_1 BIGINT NULL,
|
||||||
|
long_prop_2 BIGINT NULL,
|
||||||
|
dec_prop_1 NUMERIC NULL,
|
||||||
|
dec_prop_2 NUMERIC NULL,
|
||||||
|
bool_prop_1 BOOL NULL,
|
||||||
|
bool_prop_2 BOOL NULL,
|
||||||
|
time_zone_id TEXT NULL,
|
||||||
|
PRIMARY KEY (sched_name,trigger_name,trigger_group),
|
||||||
|
FOREIGN KEY (sched_name,trigger_name,trigger_group)
|
||||||
|
REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_cron_triggers
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
trigger_name TEXT NOT NULL,
|
||||||
|
trigger_group TEXT NOT NULL,
|
||||||
|
cron_expression TEXT NOT NULL,
|
||||||
|
time_zone_id TEXT,
|
||||||
|
PRIMARY KEY (sched_name,trigger_name,trigger_group),
|
||||||
|
FOREIGN KEY (sched_name,trigger_name,trigger_group)
|
||||||
|
REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_blob_triggers
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
trigger_name TEXT NOT NULL,
|
||||||
|
trigger_group TEXT NOT NULL,
|
||||||
|
blob_data BYTEA NULL,
|
||||||
|
PRIMARY KEY (sched_name,trigger_name,trigger_group),
|
||||||
|
FOREIGN KEY (sched_name,trigger_name,trigger_group)
|
||||||
|
REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_calendars
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
calendar_name TEXT NOT NULL,
|
||||||
|
calendar BYTEA NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name,calendar_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_paused_trigger_grps
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
trigger_group TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name,trigger_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_fired_triggers
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
entry_id TEXT NOT NULL,
|
||||||
|
trigger_name TEXT NOT NULL,
|
||||||
|
trigger_group TEXT NOT NULL,
|
||||||
|
instance_name TEXT NOT NULL,
|
||||||
|
fired_time BIGINT NOT NULL,
|
||||||
|
sched_time BIGINT NOT NULL,
|
||||||
|
priority INTEGER NOT NULL,
|
||||||
|
state TEXT NOT NULL,
|
||||||
|
job_name TEXT NULL,
|
||||||
|
job_group TEXT NULL,
|
||||||
|
is_nonconcurrent BOOL NOT NULL,
|
||||||
|
requests_recovery BOOL NULL,
|
||||||
|
PRIMARY KEY (sched_name,entry_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_scheduler_state
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
instance_name TEXT NOT NULL,
|
||||||
|
last_checkin_time BIGINT NOT NULL,
|
||||||
|
checkin_interval BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name,instance_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE qrtz_locks
|
||||||
|
(
|
||||||
|
sched_name TEXT NOT NULL,
|
||||||
|
lock_name TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name,lock_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
create index idx_qrtz_j_req_recovery on qrtz_job_details(requests_recovery);
|
||||||
|
create index idx_qrtz_t_next_fire_time on qrtz_triggers(next_fire_time);
|
||||||
|
create index idx_qrtz_t_state on qrtz_triggers(trigger_state);
|
||||||
|
create index idx_qrtz_t_nft_st on qrtz_triggers(next_fire_time,trigger_state);
|
||||||
|
create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(trigger_name);
|
||||||
|
create index idx_qrtz_ft_trig_group on qrtz_fired_triggers(trigger_group);
|
||||||
|
create index idx_qrtz_ft_trig_nm_gp on qrtz_fired_triggers(sched_name,trigger_name,trigger_group);
|
||||||
|
create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(instance_name);
|
||||||
|
create index idx_qrtz_ft_job_name on qrtz_fired_triggers(job_name);
|
||||||
|
create index idx_qrtz_ft_job_group on qrtz_fired_triggers(job_group);
|
||||||
|
create index idx_qrtz_ft_job_req_recovery on qrtz_fired_triggers(requests_recovery);
|
||||||
File diff suppressed because it is too large
Load Diff
+10602
File diff suppressed because one or more lines are too long
@@ -0,0 +1,253 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_blob_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_blob_triggers
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
trigger_name varchar(190) NOT NULL,
|
||||||
|
trigger_group varchar(190) NOT NULL,
|
||||||
|
blob_data bytea NULL,
|
||||||
|
PRIMARY KEY (sched_name, trigger_name, trigger_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_qrtz_blob_triggers_sched_name ON qrtz_blob_triggers (sched_name, trigger_name, trigger_group);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_calendars
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_calendars
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
calendar_name varchar(190) NOT NULL,
|
||||||
|
calendar bytea NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name, calendar_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_cron_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_cron_triggers
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
trigger_name varchar(190) NOT NULL,
|
||||||
|
trigger_group varchar(190) NOT NULL,
|
||||||
|
cron_expression varchar(120) NOT NULL,
|
||||||
|
time_zone_id varchar(80) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (sched_name, trigger_name, trigger_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- @formatter:off
|
||||||
|
BEGIN;
|
||||||
|
COMMIT;
|
||||||
|
-- @formatter:on
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_fired_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_fired_triggers
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
entry_id varchar(95) NOT NULL,
|
||||||
|
trigger_name varchar(190) NOT NULL,
|
||||||
|
trigger_group varchar(190) NOT NULL,
|
||||||
|
instance_name varchar(190) NOT NULL,
|
||||||
|
fired_time int8 NOT NULL,
|
||||||
|
sched_time int8 NOT NULL,
|
||||||
|
priority int4 NOT NULL,
|
||||||
|
state varchar(16) NOT NULL,
|
||||||
|
job_name varchar(190) NULL DEFAULT NULL,
|
||||||
|
job_group varchar(190) NULL DEFAULT NULL,
|
||||||
|
is_nonconcurrent varchar(1) NULL DEFAULT NULL,
|
||||||
|
requests_recovery varchar(1) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (sched_name, entry_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_qrtz_ft_trig_inst_name ON qrtz_fired_triggers (sched_name, instance_name);
|
||||||
|
CREATE INDEX idx_qrtz_ft_inst_job_req_rcvry ON qrtz_fired_triggers (sched_name, instance_name, requests_recovery);
|
||||||
|
CREATE INDEX idx_qrtz_ft_j_g ON qrtz_fired_triggers (sched_name, job_name, job_group);
|
||||||
|
CREATE INDEX idx_qrtz_ft_jg ON qrtz_fired_triggers (sched_name, job_group);
|
||||||
|
CREATE INDEX idx_qrtz_ft_t_g ON qrtz_fired_triggers (sched_name, trigger_name, trigger_group);
|
||||||
|
CREATE INDEX idx_qrtz_ft_tg ON qrtz_fired_triggers (sched_name, trigger_group);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_job_details
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_job_details
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
job_name varchar(190) NOT NULL,
|
||||||
|
job_group varchar(190) NOT NULL,
|
||||||
|
description varchar(250) NULL DEFAULT NULL,
|
||||||
|
job_class_name varchar(250) NOT NULL,
|
||||||
|
is_durable varchar(1) NOT NULL,
|
||||||
|
is_nonconcurrent varchar(1) NOT NULL,
|
||||||
|
is_update_data varchar(1) NOT NULL,
|
||||||
|
requests_recovery varchar(1) NOT NULL,
|
||||||
|
job_data bytea NULL,
|
||||||
|
PRIMARY KEY (sched_name, job_name, job_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_qrtz_j_req_recovery ON qrtz_job_details (sched_name, requests_recovery);
|
||||||
|
CREATE INDEX idx_qrtz_j_grp ON qrtz_job_details (sched_name, job_group);
|
||||||
|
|
||||||
|
-- @formatter:off
|
||||||
|
BEGIN;
|
||||||
|
COMMIT;
|
||||||
|
-- @formatter:on
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_locks
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_locks
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
lock_name varchar(40) NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name, lock_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- @formatter:off
|
||||||
|
BEGIN;
|
||||||
|
COMMIT;
|
||||||
|
-- @formatter:on
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_paused_trigger_grps
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_paused_trigger_grps
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
trigger_group varchar(190) NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name, trigger_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_scheduler_state
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_scheduler_state
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
instance_name varchar(190) NOT NULL,
|
||||||
|
last_checkin_time int8 NOT NULL,
|
||||||
|
checkin_interval int8 NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name, instance_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- @formatter:off
|
||||||
|
BEGIN;
|
||||||
|
COMMIT;
|
||||||
|
-- @formatter:on
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_simple_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_simple_triggers
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
trigger_name varchar(190) NOT NULL,
|
||||||
|
trigger_group varchar(190) NOT NULL,
|
||||||
|
repeat_count int8 NOT NULL,
|
||||||
|
repeat_interval int8 NOT NULL,
|
||||||
|
times_triggered int8 NOT NULL,
|
||||||
|
PRIMARY KEY (sched_name, trigger_name, trigger_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_simprop_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_simprop_triggers
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
trigger_name varchar(190) NOT NULL,
|
||||||
|
trigger_group varchar(190) NOT NULL,
|
||||||
|
str_prop_1 varchar(512) NULL DEFAULT NULL,
|
||||||
|
str_prop_2 varchar(512) NULL DEFAULT NULL,
|
||||||
|
str_prop_3 varchar(512) NULL DEFAULT NULL,
|
||||||
|
int_prop_1 int4 NULL DEFAULT NULL,
|
||||||
|
int_prop_2 int4 NULL DEFAULT NULL,
|
||||||
|
long_prop_1 int8 NULL DEFAULT NULL,
|
||||||
|
long_prop_2 int8 NULL DEFAULT NULL,
|
||||||
|
dec_prop_1 numeric(13, 4) NULL DEFAULT NULL,
|
||||||
|
dec_prop_2 numeric(13, 4) NULL DEFAULT NULL,
|
||||||
|
bool_prop_1 varchar(1) NULL DEFAULT NULL,
|
||||||
|
bool_prop_2 varchar(1) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (sched_name, trigger_name, trigger_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- qrtz_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE qrtz_triggers
|
||||||
|
(
|
||||||
|
sched_name varchar(120) NOT NULL,
|
||||||
|
trigger_name varchar(190) NOT NULL,
|
||||||
|
trigger_group varchar(190) NOT NULL,
|
||||||
|
job_name varchar(190) NOT NULL,
|
||||||
|
job_group varchar(190) NOT NULL,
|
||||||
|
description varchar(250) NULL DEFAULT NULL,
|
||||||
|
next_fire_time int8 NULL DEFAULT NULL,
|
||||||
|
prev_fire_time int8 NULL DEFAULT NULL,
|
||||||
|
priority int4 NULL DEFAULT NULL,
|
||||||
|
trigger_state varchar(16) NOT NULL,
|
||||||
|
trigger_type varchar(8) NOT NULL,
|
||||||
|
start_time int8 NOT NULL,
|
||||||
|
end_time int8 NULL DEFAULT NULL,
|
||||||
|
calendar_name varchar(190) NULL DEFAULT NULL,
|
||||||
|
misfire_instr int2 NULL DEFAULT NULL,
|
||||||
|
job_data bytea NULL,
|
||||||
|
PRIMARY KEY (sched_name, trigger_name, trigger_group)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_qrtz_t_j ON qrtz_triggers (sched_name, job_name, job_group);
|
||||||
|
CREATE INDEX idx_qrtz_t_jg ON qrtz_triggers (sched_name, job_group);
|
||||||
|
CREATE INDEX idx_qrtz_t_c ON qrtz_triggers (sched_name, calendar_name);
|
||||||
|
CREATE INDEX idx_qrtz_t_g ON qrtz_triggers (sched_name, trigger_group);
|
||||||
|
CREATE INDEX idx_qrtz_t_state ON qrtz_triggers (sched_name, trigger_state);
|
||||||
|
CREATE INDEX idx_qrtz_t_n_state ON qrtz_triggers (sched_name, trigger_name, trigger_group, trigger_state);
|
||||||
|
CREATE INDEX idx_qrtz_t_n_g_state ON qrtz_triggers (sched_name, trigger_group, trigger_state);
|
||||||
|
CREATE INDEX idx_qrtz_t_next_fire_time ON qrtz_triggers (sched_name, next_fire_time);
|
||||||
|
CREATE INDEX idx_qrtz_t_nft_st ON qrtz_triggers (sched_name, trigger_state, next_fire_time);
|
||||||
|
CREATE INDEX idx_qrtz_t_nft_misfire ON qrtz_triggers (sched_name, misfire_instr, next_fire_time);
|
||||||
|
CREATE INDEX idx_qrtz_t_nft_st_misfire ON qrtz_triggers (sched_name, misfire_instr, next_fire_time, trigger_state);
|
||||||
|
CREATE INDEX idx_qrtz_t_nft_st_misfire_grp ON qrtz_triggers (sched_name, misfire_instr, next_fire_time, trigger_group,
|
||||||
|
trigger_state);
|
||||||
|
|
||||||
|
-- @formatter:off
|
||||||
|
BEGIN;
|
||||||
|
COMMIT;
|
||||||
|
-- @formatter:on
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- FK: qrtz_blob_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE qrtz_blob_triggers
|
||||||
|
ADD CONSTRAINT qrtz_blob_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name,
|
||||||
|
trigger_name,
|
||||||
|
trigger_group);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- FK: qrtz_cron_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE qrtz_cron_triggers
|
||||||
|
ADD CONSTRAINT qrtz_cron_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name, trigger_name, trigger_group);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- FK: qrtz_simple_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE qrtz_simple_triggers
|
||||||
|
ADD CONSTRAINT qrtz_simple_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name,
|
||||||
|
trigger_name,
|
||||||
|
trigger_group);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- FK: qrtz_simprop_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE qrtz_simprop_triggers
|
||||||
|
ADD CONSTRAINT qrtz_simprop_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name, trigger_name, trigger_group);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- FK: qrtz_triggers
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE qrtz_triggers
|
||||||
|
ADD CONSTRAINT qrtz_triggers_ibfk_1 FOREIGN KEY (sched_name, job_name, job_group) REFERENCES qrtz_job_details (sched_name, job_name, job_group);
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,845 @@
|
|||||||
|
/*
|
||||||
|
注意:仅仅需要 Quartz 定时任务的场景,可选!!!
|
||||||
|
|
||||||
|
Date: 15/06/2022 08:20:08
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_BLOB_TRIGGERS";
|
||||||
|
CREATE TABLE "QRTZ_BLOB_TRIGGERS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"BLOB_DATA" BLOB
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_CALENDARS";
|
||||||
|
CREATE TABLE "QRTZ_CALENDARS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"CALENDAR_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"CALENDAR" BLOB NOT NULL
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_CRON_TRIGGERS";
|
||||||
|
CREATE TABLE "QRTZ_CRON_TRIGGERS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"CRON_EXPRESSION" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"TIME_ZONE_ID" VARCHAR2(80 BYTE)
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_FIRED_TRIGGERS";
|
||||||
|
CREATE TABLE "QRTZ_FIRED_TRIGGERS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"ENTRY_ID" VARCHAR2(95 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"INSTANCE_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"FIRED_TIME" NUMBER(13,0) NOT NULL,
|
||||||
|
"SCHED_TIME" NUMBER(13,0) NOT NULL,
|
||||||
|
"PRIORITY" NUMBER(13,0) NOT NULL,
|
||||||
|
"STATE" VARCHAR2(16 BYTE) NOT NULL,
|
||||||
|
"JOB_NAME" VARCHAR2(200 BYTE),
|
||||||
|
"JOB_GROUP" VARCHAR2(200 BYTE),
|
||||||
|
"IS_NONCONCURRENT" VARCHAR2(1 BYTE),
|
||||||
|
"REQUESTS_RECOVERY" VARCHAR2(1 BYTE)
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_JOB_DETAILS";
|
||||||
|
CREATE TABLE "QRTZ_JOB_DETAILS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"JOB_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"JOB_GROUP" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"DESCRIPTION" VARCHAR2(250 BYTE),
|
||||||
|
"JOB_CLASS_NAME" VARCHAR2(250 BYTE) NOT NULL,
|
||||||
|
"IS_DURABLE" VARCHAR2(1 BYTE) NOT NULL,
|
||||||
|
"IS_NONCONCURRENT" VARCHAR2(1 BYTE) NOT NULL,
|
||||||
|
"IS_UPDATE_DATA" VARCHAR2(1 BYTE) NOT NULL,
|
||||||
|
"REQUESTS_RECOVERY" VARCHAR2(1 BYTE) NOT NULL,
|
||||||
|
"JOB_DATA" BLOB
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_LOCKS";
|
||||||
|
CREATE TABLE "QRTZ_LOCKS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"LOCK_NAME" VARCHAR2(40 BYTE) NOT NULL
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_PAUSED_TRIGGER_GRPS";
|
||||||
|
CREATE TABLE "QRTZ_PAUSED_TRIGGER_GRPS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_SCHEDULER_STATE";
|
||||||
|
CREATE TABLE "QRTZ_SCHEDULER_STATE" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"INSTANCE_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"LAST_CHECKIN_TIME" NUMBER(13,0) NOT NULL,
|
||||||
|
"CHECKIN_INTERVAL" NUMBER(13,0) NOT NULL
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_SIMPLE_TRIGGERS";
|
||||||
|
CREATE TABLE "QRTZ_SIMPLE_TRIGGERS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"REPEAT_COUNT" NUMBER(7,0) NOT NULL,
|
||||||
|
"REPEAT_INTERVAL" NUMBER(12,0) NOT NULL,
|
||||||
|
"TIMES_TRIGGERED" NUMBER(10,0) NOT NULL
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_SIMPROP_TRIGGERS";
|
||||||
|
CREATE TABLE "QRTZ_SIMPROP_TRIGGERS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"STR_PROP_1" VARCHAR2(512 BYTE),
|
||||||
|
"STR_PROP_2" VARCHAR2(512 BYTE),
|
||||||
|
"STR_PROP_3" VARCHAR2(512 BYTE),
|
||||||
|
"INT_PROP_1" NUMBER(10,0),
|
||||||
|
"INT_PROP_2" NUMBER(10,0),
|
||||||
|
"LONG_PROP_1" NUMBER(13,0),
|
||||||
|
"LONG_PROP_2" NUMBER(13,0),
|
||||||
|
"DEC_PROP_1" NUMBER(13,4),
|
||||||
|
"DEC_PROP_2" NUMBER(13,4),
|
||||||
|
"BOOL_PROP_1" VARCHAR2(1 BYTE),
|
||||||
|
"BOOL_PROP_2" VARCHAR2(1 BYTE)
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE "QRTZ_TRIGGERS";
|
||||||
|
CREATE TABLE "QRTZ_TRIGGERS" (
|
||||||
|
"SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"JOB_NAME" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"JOB_GROUP" VARCHAR2(200 BYTE) NOT NULL,
|
||||||
|
"DESCRIPTION" VARCHAR2(250 BYTE),
|
||||||
|
"NEXT_FIRE_TIME" NUMBER(13,0),
|
||||||
|
"PREV_FIRE_TIME" NUMBER(13,0),
|
||||||
|
"PRIORITY" NUMBER(13,0),
|
||||||
|
"TRIGGER_STATE" VARCHAR2(16 BYTE) NOT NULL,
|
||||||
|
"TRIGGER_TYPE" VARCHAR2(8 BYTE) NOT NULL,
|
||||||
|
"START_TIME" NUMBER(13,0) NOT NULL,
|
||||||
|
"END_TIME" NUMBER(13,0),
|
||||||
|
"CALENDAR_NAME" VARCHAR2(200 BYTE),
|
||||||
|
"MISFIRE_INSTR" NUMBER(2,0),
|
||||||
|
"JOB_DATA" BLOB
|
||||||
|
)
|
||||||
|
LOGGING
|
||||||
|
NOCOMPRESS
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 1
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
)
|
||||||
|
PARALLEL 1
|
||||||
|
NOCACHE
|
||||||
|
DISABLE ROW MOVEMENT
|
||||||
|
;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
COMMIT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "QRTZ_BLOB_TRIG_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008266" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008267" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008268" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008653" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008654" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008655" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "QRTZ_CALENDARS_PK" PRIMARY KEY ("SCHED_NAME", "CALENDAR_NAME");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008271" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008272" CHECK ("CALENDAR_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008273" CHECK ("CALENDAR" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008656" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008657" CHECK ("CALENDAR_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008658" CHECK ("CALENDAR" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "QRTZ_CRON_TRIG_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008255" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008256" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008257" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008258" CHECK ("CRON_EXPRESSION" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008659" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008660" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008661" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008662" CHECK ("CRON_EXPRESSION" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "QRTZ_FIRED_TRIGGER_PK" PRIMARY KEY ("SCHED_NAME", "ENTRY_ID");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008278" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008279" CHECK ("ENTRY_ID" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008280" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008281" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008282" CHECK ("INSTANCE_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008283" CHECK ("FIRED_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008284" CHECK ("SCHED_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008285" CHECK ("PRIORITY" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008286" CHECK ("STATE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008663" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008664" CHECK ("ENTRY_ID" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008665" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008666" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008667" CHECK ("INSTANCE_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008668" CHECK ("FIRED_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008669" CHECK ("SCHED_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008670" CHECK ("PRIORITY" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008671" CHECK ("STATE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Indexes structure for table QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE INDEX "IDX_QRTZ_FT_INST_JOB_REQ_RCVRY"
|
||||||
|
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "INSTANCE_NAME" ASC, "REQUESTS_RECOVERY" ASC)
|
||||||
|
LOGGING
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_FT_JG"
|
||||||
|
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC)
|
||||||
|
LOGGING
|
||||||
|
ONLINE
|
||||||
|
NOSORT
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_FT_J_G"
|
||||||
|
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "JOB_NAME" ASC, "JOB_GROUP" ASC)
|
||||||
|
LOGGING
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_FT_TG"
|
||||||
|
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "TRIGGER_GROUP" ASC) LOCAL
|
||||||
|
LOGGING
|
||||||
|
NOSORT
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "QRTZ_JOB_DETAILS_PK" PRIMARY KEY ("SCHED_NAME", "JOB_NAME", "JOB_GROUP");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008228" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008229" CHECK ("JOB_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008230" CHECK ("JOB_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008231" CHECK ("JOB_CLASS_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008232" CHECK ("IS_DURABLE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008233" CHECK ("IS_NONCONCURRENT" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008234" CHECK ("IS_UPDATE_DATA" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008235" CHECK ("REQUESTS_RECOVERY" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Indexes structure for table QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE INDEX "IDX_QRTZ_J_GRP"
|
||||||
|
ON "QRTZ_JOB_DETAILS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC)
|
||||||
|
LOGGING
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_J_REQ_RECOVERY"
|
||||||
|
ON "QRTZ_JOB_DETAILS" ("SCHED_NAME" ASC, "REQUESTS_RECOVERY" ASC) LOCAL
|
||||||
|
LOGGING
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "QRTZ_LOCKS_PK" PRIMARY KEY ("SCHED_NAME", "LOCK_NAME");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "SYS_C008293" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "SYS_C008294" CHECK ("LOCK_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "SYS_C008672" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "SYS_C008673" CHECK ("LOCK_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "QRTZ_PAUSED_TRIG_GRPS_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_GROUP");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "SYS_C008275" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "SYS_C008276" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "SYS_C008674" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "SYS_C008675" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "QRTZ_SCHEDULER_STATE_PK" PRIMARY KEY ("SCHED_NAME", "INSTANCE_NAME");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008288" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008289" CHECK ("INSTANCE_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008290" CHECK ("LAST_CHECKIN_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008291" CHECK ("CHECKIN_INTERVAL" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008676" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008677" CHECK ("INSTANCE_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008678" CHECK ("LAST_CHECKIN_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008679" CHECK ("CHECKIN_INTERVAL" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPLE_TRIG_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008247" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008248" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008249" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008250" CHECK ("REPEAT_COUNT" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008251" CHECK ("REPEAT_INTERVAL" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008252" CHECK ("TIMES_TRIGGERED" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008680" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008681" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008682" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008683" CHECK ("REPEAT_COUNT" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008684" CHECK ("REPEAT_INTERVAL" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008685" CHECK ("TIMES_TRIGGERED" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPROP_TRIG_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008261" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008262" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008263" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008686" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008687" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008688" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "QRTZ_TRIGGERS_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP");
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Checks structure for table QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008237" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008238" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008239" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008240" CHECK ("JOB_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008241" CHECK ("JOB_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008242" CHECK ("TRIGGER_STATE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008243" CHECK ("TRIGGER_TYPE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008244" CHECK ("START_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008689" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008690" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008691" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008692" CHECK ("JOB_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008693" CHECK ("JOB_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008694" CHECK ("TRIGGER_STATE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008695" CHECK ("TRIGGER_TYPE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008696" CHECK ("START_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Indexes structure for table QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE INDEX "IDX_QRTZ_T_C"
|
||||||
|
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "CALENDAR_NAME" ASC) LOCAL
|
||||||
|
LOGGING
|
||||||
|
ONLINE
|
||||||
|
NOSORT
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_T_J"
|
||||||
|
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "JOB_NAME" ASC, "JOB_GROUP" ASC)
|
||||||
|
LOGGING
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_T_JG"
|
||||||
|
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC) LOCAL
|
||||||
|
LOGGING
|
||||||
|
ONLINE
|
||||||
|
NOSORT
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_T_NEXT_FIRE_TIME"
|
||||||
|
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "NEXT_FIRE_TIME" ASC)
|
||||||
|
LOGGING
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_T_NFT_ST"
|
||||||
|
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "TRIGGER_STATE" ASC, "NEXT_FIRE_TIME" ASC) LOCAL
|
||||||
|
LOGGING
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_T_NFT_ST_MISFIRE"
|
||||||
|
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "MISFIRE_INSTR" ASC, "NEXT_FIRE_TIME" ASC, "TRIGGER_STATE" ASC) LOCAL
|
||||||
|
LOGGING
|
||||||
|
ONLINE
|
||||||
|
NOSORT
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
CREATE INDEX "IDX_QRTZ_T_STATE"
|
||||||
|
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "TRIGGER_STATE" ASC)
|
||||||
|
LOGGING
|
||||||
|
VISIBLE
|
||||||
|
PCTFREE 10
|
||||||
|
INITRANS 2
|
||||||
|
STORAGE (
|
||||||
|
INITIAL 65536
|
||||||
|
NEXT 1048576
|
||||||
|
MINEXTENTS 1
|
||||||
|
MAXEXTENTS 2147483645
|
||||||
|
FREELISTS 1
|
||||||
|
FREELIST GROUPS 1
|
||||||
|
BUFFER_POOL DEFAULT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "QRTZ_BLOB_TRIG_TO_TRIG_FK" FOREIGN KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS" ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "QRTZ_CRON_TRIG_TO_TRIG_FK" FOREIGN KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS" ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPLE_TRIG_TO_TRIG_FK" FOREIGN KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS" ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPROP_TRIG_TO_TRIG_FK" FOREIGN KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS" ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,208 @@
|
|||||||
|
-- https://github.com/quartz-scheduler/quartz/blob/main/quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_postgres.sql
|
||||||
|
-- Thanks to Patrick Lightbody for submitting this...
|
||||||
|
--
|
||||||
|
-- In your Quartz properties file, you'll need to set
|
||||||
|
-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_LOCKS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_CALENDARS;
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_JOB_DETAILS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR(200) NOT NULL,
|
||||||
|
JOB_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
DESCRIPTION VARCHAR(250) NULL,
|
||||||
|
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
|
||||||
|
IS_DURABLE BOOL NOT NULL,
|
||||||
|
IS_NONCONCURRENT BOOL NOT NULL,
|
||||||
|
IS_UPDATE_DATA BOOL NOT NULL,
|
||||||
|
REQUESTS_RECOVERY BOOL NOT NULL,
|
||||||
|
JOB_DATA BYTEA NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR(200) NOT NULL,
|
||||||
|
JOB_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
DESCRIPTION VARCHAR(250) NULL,
|
||||||
|
NEXT_FIRE_TIME BIGINT NULL,
|
||||||
|
PREV_FIRE_TIME BIGINT NULL,
|
||||||
|
PRIORITY INTEGER NULL,
|
||||||
|
TRIGGER_STATE VARCHAR(16) NOT NULL,
|
||||||
|
TRIGGER_TYPE VARCHAR(8) NOT NULL,
|
||||||
|
START_TIME BIGINT NOT NULL,
|
||||||
|
END_TIME BIGINT NULL,
|
||||||
|
CALENDAR_NAME VARCHAR(200) NULL,
|
||||||
|
MISFIRE_INSTR SMALLINT NULL,
|
||||||
|
JOB_DATA BYTEA NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||||
|
REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
REPEAT_COUNT BIGINT NOT NULL,
|
||||||
|
REPEAT_INTERVAL BIGINT NOT NULL,
|
||||||
|
TIMES_TRIGGERED BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_CRON_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
CRON_EXPRESSION VARCHAR(120) NOT NULL,
|
||||||
|
TIME_ZONE_ID VARCHAR(80),
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
STR_PROP_1 VARCHAR(512) NULL,
|
||||||
|
STR_PROP_2 VARCHAR(512) NULL,
|
||||||
|
STR_PROP_3 VARCHAR(512) NULL,
|
||||||
|
INT_PROP_1 INT NULL,
|
||||||
|
INT_PROP_2 INT NULL,
|
||||||
|
LONG_PROP_1 BIGINT NULL,
|
||||||
|
LONG_PROP_2 BIGINT NULL,
|
||||||
|
DEC_PROP_1 NUMERIC(13, 4) NULL,
|
||||||
|
DEC_PROP_2 NUMERIC(13, 4) NULL,
|
||||||
|
BOOL_PROP_1 BOOL NULL,
|
||||||
|
BOOL_PROP_2 BOOL NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_BLOB_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
BLOB_DATA BYTEA NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_CALENDARS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
CALENDAR_NAME VARCHAR(200) NOT NULL,
|
||||||
|
CALENDAR BYTEA NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_FIRED_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
ENTRY_ID VARCHAR(95) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
INSTANCE_NAME VARCHAR(200) NOT NULL,
|
||||||
|
FIRED_TIME BIGINT NOT NULL,
|
||||||
|
SCHED_TIME BIGINT NOT NULL,
|
||||||
|
PRIORITY INTEGER NOT NULL,
|
||||||
|
STATE VARCHAR(16) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR(200) NULL,
|
||||||
|
JOB_GROUP VARCHAR(200) NULL,
|
||||||
|
IS_NONCONCURRENT BOOL NULL,
|
||||||
|
REQUESTS_RECOVERY BOOL NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, ENTRY_ID)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SCHEDULER_STATE
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
INSTANCE_NAME VARCHAR(200) NOT NULL,
|
||||||
|
LAST_CHECKIN_TIME BIGINT NOT NULL,
|
||||||
|
CHECKIN_INTERVAL BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_LOCKS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
LOCK_NAME VARCHAR(40) NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, LOCK_NAME)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY
|
||||||
|
ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
|
||||||
|
CREATE INDEX IDX_QRTZ_J_GRP
|
||||||
|
ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
|
||||||
|
|
||||||
|
CREATE INDEX IDX_QRTZ_T_J
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_JG
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_C
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_G
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_STATE
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_N_STATE
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_N_G_STATE
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NFT_ST
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP
|
||||||
|
ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||||
|
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME
|
||||||
|
ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY
|
||||||
|
ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_J_G
|
||||||
|
ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_JG
|
||||||
|
ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_T_G
|
||||||
|
ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_TG
|
||||||
|
ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
|
||||||
|
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,533 @@
|
|||||||
|
/*
|
||||||
|
注意:仅仅需要 Quartz 定时任务的场景,可选!!!
|
||||||
|
|
||||||
|
Date: 30/04/2024 09:54:18
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[BLOB_DATA] varbinary(max) NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_BLOB_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_CALENDARS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_CALENDARS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[CALENDAR_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[CALENDAR] varbinary(max) NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_CALENDARS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_CRON_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[CRON_EXPRESSION] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TIME_ZONE_ID] varchar(80) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[ENTRY_ID] varchar(95) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[INSTANCE_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[FIRED_TIME] bigint NOT NULL,
|
||||||
|
[SCHED_TIME] bigint NOT NULL,
|
||||||
|
[PRIORITY] int NOT NULL,
|
||||||
|
[STATE] varchar(16) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[JOB_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[IS_NONCONCURRENT] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[REQUESTS_RECOVERY] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_JOB_DETAILS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_JOB_DETAILS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[DESCRIPTION] varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[JOB_CLASS_NAME] varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[IS_DURABLE] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[IS_NONCONCURRENT] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[IS_UPDATE_DATA] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[REQUESTS_RECOVERY] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_DATA] varbinary(max) NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_LOCKS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_LOCKS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[LOCK_NAME] varchar(40) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_LOCKS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_SCHEDULER_STATE]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[INSTANCE_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[LAST_CHECKIN_TIME] bigint NOT NULL,
|
||||||
|
[CHECKIN_INTERVAL] bigint NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[REPEAT_COUNT] bigint NOT NULL,
|
||||||
|
[REPEAT_INTERVAL] bigint NOT NULL,
|
||||||
|
[TIMES_TRIGGERED] bigint NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[STR_PROP_1] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[STR_PROP_2] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[STR_PROP_3] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[INT_PROP_1] int NULL,
|
||||||
|
[INT_PROP_2] int NULL,
|
||||||
|
[LONG_PROP_1] bigint NULL,
|
||||||
|
[LONG_PROP_2] bigint NULL,
|
||||||
|
[DEC_PROP_1] numeric(13,4) NULL,
|
||||||
|
[DEC_PROP_2] numeric(13,4) NULL,
|
||||||
|
[BOOL_PROP_1] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[BOOL_PROP_2] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[DESCRIPTION] varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[NEXT_FIRE_TIME] bigint NULL,
|
||||||
|
[PREV_FIRE_TIME] bigint NULL,
|
||||||
|
[PRIORITY] int NULL,
|
||||||
|
[TRIGGER_STATE] varchar(16) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_TYPE] varchar(8) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[START_TIME] bigint NOT NULL,
|
||||||
|
[END_TIME] bigint NULL,
|
||||||
|
[CALENDAR_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[MISFIRE_INSTR] smallint NULL,
|
||||||
|
[JOB_DATA] varbinary(max) NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_CALENDARS] ADD CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [CALENDAR_NAME])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Indexes structure for table QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS]
|
||||||
|
ON [dbo].[QRTZ_CRON_TRIGGERS] (
|
||||||
|
[SCHED_NAME] ASC,
|
||||||
|
[TRIGGER_NAME] ASC,
|
||||||
|
[TRIGGER_GROUP] ASC
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [ENTRY_ID])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] ADD CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [JOB_NAME], [JOB_GROUP])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_LOCKS] ADD CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [LOCK_NAME])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] ADD CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_GROUP])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] ADD CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY CLUSTERED ([SCHED_NAME], [INSTANCE_NAME])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Indexes structure for table QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS]
|
||||||
|
ON [dbo].[QRTZ_SIMPLE_TRIGGERS] (
|
||||||
|
[SCHED_NAME] ASC,
|
||||||
|
[TRIGGER_NAME] ASC,
|
||||||
|
[TRIGGER_GROUP] ASC
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Indexes structure for table QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS]
|
||||||
|
ON [dbo].[QRTZ_SIMPROP_TRIGGERS] (
|
||||||
|
[SCHED_NAME] ASC,
|
||||||
|
[TRIGGER_NAME] ASC,
|
||||||
|
[TRIGGER_GROUP] ASC
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Indexes structure for table QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS]
|
||||||
|
ON [dbo].[QRTZ_TRIGGERS] (
|
||||||
|
[SCHED_NAME] ASC,
|
||||||
|
[TRIGGER_NAME] ASC,
|
||||||
|
[TRIGGER_GROUP] ASC
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
|
||||||
|
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_BLOB_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_BLOB_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) REFERENCES [dbo].[QRTZ_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) REFERENCES [dbo].[QRTZ_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) REFERENCES [dbo].[QRTZ_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) REFERENCES [dbo].[QRTZ_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Foreign Keys structure for table QRTZ_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] FOREIGN KEY ([SCHED_NAME], [JOB_NAME], [JOB_GROUP]) REFERENCES [dbo].[QRTZ_JOB_DETAILS] ([SCHED_NAME], [JOB_NAME], [JOB_GROUP]) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||||
|
GO
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
|||||||
|
# 忽略python虚拟环境
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
## 0. 友情提示
|
||||||
|
|
||||||
|
在 `sql/tools` 目录下,我们提供一些数据库相关的工具,包括测试数据库的快速启动、MySQL 转换其它数据库等等。
|
||||||
|
|
||||||
|
注意!所有的操作,必须在 `sql/tools` 目录下执行。
|
||||||
|
|
||||||
|
## 1. 测试数据库的快速启动
|
||||||
|
|
||||||
|
基于 Docker Compose,快速启动 MySQL、Oracle、PostgreSQL、SQL Server 等数据库。
|
||||||
|
|
||||||
|
注意!使用 Docker Compose 启动完测试数据后,因为会自动导入项目的 SQL 脚本,所以可能需要等待 1-2 分钟。
|
||||||
|
|
||||||
|
### 1.1 MySQL
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker compose up -d mysql
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 Oracle
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
## x86 版本
|
||||||
|
docker compose up -d oracle
|
||||||
|
|
||||||
|
## MacBook Apple Silicon
|
||||||
|
docker compose up -d oracle_m1
|
||||||
|
```
|
||||||
|
|
||||||
|
> 注意:如果使用 MacBook Apple Silicon 版本,它的 ORACLE_SID 不是 XE,而是 FREE!!!
|
||||||
|
|
||||||
|
### 1.3 PostgreSQL
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker compose up -d postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.4 SQL Server
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker compose up -d sqlserver
|
||||||
|
# 注意:启动完 sqlserver 后,需要手动再执行如下命令,因为 SQL Server 不支持初始化脚本
|
||||||
|
docker compose exec sqlserver bash /tmp/create_schema.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.5 DM 达梦
|
||||||
|
|
||||||
|
① 下载达梦 Docker 镜像:<https://eco.dameng.com/download/> 地址,点击“Docker 镜像”选项,进行下载。
|
||||||
|
|
||||||
|
② 加载镜像文件,在镜像 tar 文件所在目录运行:
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker load -i dm8_20240715_x86_rh6_rq_single.tar
|
||||||
|
```
|
||||||
|
|
||||||
|
③ 在项目 `sql/tools` 目录下运行:
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker compose up -d dm8
|
||||||
|
# 注意:启动完 dm 后,需要手动再执行如下命令,因为 dm 不支持初始化脚本
|
||||||
|
docker compose exec dm8 bash -c '/opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql'
|
||||||
|
exit
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.6 KingbaseES 人大金仓
|
||||||
|
|
||||||
|
① 下载人大金仓 Docker 镜像:
|
||||||
|
|
||||||
|
* [x86_64 版本](https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar) 【Windows 选择这个】
|
||||||
|
* [aarch64 版本](https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/aarch64/kdb_aarch64_V009R001C001B0025.tar) 【MacBook Apple Silicon 选择这个】
|
||||||
|
|
||||||
|
② 加载镜像文件,在镜像 tar 文件所在目录运行:
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker load -i kdb_x86_64_V009R001C001B0025.tar
|
||||||
|
```
|
||||||
|
|
||||||
|
③ 在项目 `sql/tools` 目录下运行:
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker compose up -d kingbase
|
||||||
|
# 注意:启动完 kingbase 后,需要手动再执行如下命令
|
||||||
|
docker compose exec kingbase bash -c 'ksql -U $DB_USER -d test -f /tmp/schema.sql'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.7 华为 OpenGauss
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker compose up -d opengauss
|
||||||
|
# 注意:启动完 opengauss 后,需要手动再执行如下命令
|
||||||
|
docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1.X 容器的销毁重建
|
||||||
|
|
||||||
|
开发测试过程中,有时候需要创建全新干净的数据库。由于测试数据 Docker 容器采用数据卷 Volume 挂载数据库实例的数据目录,因此销毁数据需要停止容器后,删除数据卷,然后再重新创建容器。
|
||||||
|
|
||||||
|
以 postgres 为例,操作如下:
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
docker compose down postgres
|
||||||
|
docker volume rm ruoyi-vue-pro_postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. MySQL 转换其它数据库
|
||||||
|
|
||||||
|
项目提供了 `sql/tools/convertor.py` 脚本,支持将 MySQL 转换为 Oracle、PostgreSQL、SQL Server、达梦、人大金仓、OpenGauss 等数据库的脚本。
|
||||||
|
|
||||||
|
### 2.1 实现原理
|
||||||
|
|
||||||
|
通过读取 MySQL 的 `sql/mysql/ruoyi-vue-pro.sql` 数据库文件,转换成对应的数据库脚本。
|
||||||
|
|
||||||
|
### 2.2 使用方法
|
||||||
|
|
||||||
|
① 安装依赖库 `simple-ddl-parser`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install simple-ddl-parser
|
||||||
|
# pip3 install simple-ddl-parser
|
||||||
|
```
|
||||||
|
|
||||||
|
② 在 `sql/tools/` 目录下,执行如下命令打印生成 postgres 的脚本内容,其他可选参数有:`oracle`、`sqlserver`、`dm8`、`kingbase`、`opengauss`:
|
||||||
|
|
||||||
|
```Bash
|
||||||
|
python3 convertor.py postgres
|
||||||
|
# python3 convertor.py postgres > tmp.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
程序将 SQL 脚本打印到终端,可以重定向到临时文件 `tmp.sql`。
|
||||||
|
|
||||||
|
确认无误后,可以利用 IDEA 进行格式化。当然,也可以直接导入到数据库中。
|
||||||
@@ -0,0 +1,945 @@
|
|||||||
|
# encoding=utf8
|
||||||
|
"""芋道系统数据库迁移工具
|
||||||
|
|
||||||
|
Author: dhb52 (https://gitee.com/dhb52)
|
||||||
|
|
||||||
|
pip install simple-ddl-parser
|
||||||
|
|
||||||
|
or with uv
|
||||||
|
uv run --with simple-ddl-parser convertor.py postgres > ../postgresql/ruoyi-vue-pro.sql 239ms 四 5/22 21:03:16 2025
|
||||||
|
uv run --with simple-ddl-parser convertor.py sqlserver > ../sqlserver/ruoyi-vue-pro.sql
|
||||||
|
uv run --with simple-ddl-parser convertor.py kingbase > ../kingbase/ruoyi-vue-pro.sql
|
||||||
|
uv run --with simple-ddl-parser convertor.py opengauss > ../opengauss/ruoyi-vue-pro.sql
|
||||||
|
uv run --with simple-ddl-parser convertor.py oracle > ../oracle/ruoyi-vue-pro.sql
|
||||||
|
uv run --with simple-ddl-parser convertor.py dm8 > ../dm/ruoyi-vue-pro-dm8.sql
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import pathlib
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import Dict, Generator, Optional, Tuple, Union
|
||||||
|
|
||||||
|
from simple_ddl_parser import DDLParser
|
||||||
|
|
||||||
|
PREAMBLE = """/*
|
||||||
|
Yudao Database Transfer Tool
|
||||||
|
|
||||||
|
Source Server Type : MySQL
|
||||||
|
|
||||||
|
Target Server Type : {db_type}
|
||||||
|
|
||||||
|
Date: {date}
|
||||||
|
*/
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def load_and_clean(sql_file: str) -> str:
|
||||||
|
"""加载源 SQL 文件,并清理内容方便下一步 ddl 解析
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sql_file (str): sql文件路径
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 清理后的sql文件内容
|
||||||
|
"""
|
||||||
|
REPLACE_PAIR_LIST = (
|
||||||
|
(")\nVALUES ", ") VALUES "),
|
||||||
|
(" CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ", " "),
|
||||||
|
(" KEY `", " INDEX `"),
|
||||||
|
("UNIQUE INDEX", "UNIQUE KEY"),
|
||||||
|
("b'0'", "'0'"),
|
||||||
|
("b'1'", "'1'"),
|
||||||
|
)
|
||||||
|
|
||||||
|
content = open(sql_file, encoding="utf-8").read()
|
||||||
|
for replace_pair in REPLACE_PAIR_LIST:
|
||||||
|
content = content.replace(*replace_pair)
|
||||||
|
content = re.sub(r"ENGINE.*COMMENT", "COMMENT", content)
|
||||||
|
content = re.sub(r"ENGINE.*;", ";", content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
class Convertor(ABC):
|
||||||
|
def __init__(self, src: str, db_type) -> None:
|
||||||
|
self.src = src
|
||||||
|
self.db_type = db_type
|
||||||
|
self.content = load_and_clean(self.src)
|
||||||
|
self.table_script_list = re.findall(r"CREATE TABLE [^;]*;", self.content)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]) -> str:
|
||||||
|
"""字段类型转换
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type (str): 字段类型
|
||||||
|
size (Optional[Union[int, Tuple[int]]]): 字段长度描述, 如varchar(255), decimal(10,2)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 类型定义
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def gen_create(self, table_ddl: Dict) -> str:
|
||||||
|
"""生成 create 脚本
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_ddl (Dict): 表DDL
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 生成脚本
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def gen_pk(self, table_name: str) -> str:
|
||||||
|
"""生成主键定义
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_name (str): 表名
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 生成脚本
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def gen_index(self, ddl: Dict) -> str:
|
||||||
|
"""生成索引定义
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_ddl (Dict): 表DDL
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 生成脚本
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def gen_comment(self, table_ddl: Dict) -> str:
|
||||||
|
"""生成字段/表注释
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_ddl (Dict): 表DDL
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 生成脚本
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def gen_uk(self, table_ddl: Dict) -> str:
|
||||||
|
"""生成
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_ddl (Dict): 表DDL
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 生成脚本
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def gen_insert(self, table_name: str) -> str:
|
||||||
|
"""生成 insert 语句块
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_name (str): 表名
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 生成脚本
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def gen_dual(self) -> str:
|
||||||
|
"""生成虚拟 dual 表
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 生成脚本, 默认返回空脚本, 表示当前数据库无需手工创建
|
||||||
|
"""
|
||||||
|
return ""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def inserts(table_name: str, script_content: str) -> Generator:
|
||||||
|
PREFIX = f"INSERT INTO `{table_name}`"
|
||||||
|
|
||||||
|
# 收集 `table_name` 对应的 insert 语句
|
||||||
|
for line in script_content.split("\n"):
|
||||||
|
if line.startswith(PREFIX):
|
||||||
|
head, tail = line.replace(PREFIX, "").split(" VALUES ", maxsplit=1)
|
||||||
|
head = head.strip().replace("`", "").lower()
|
||||||
|
tail = tail.strip().replace(r"\"", '"')
|
||||||
|
# tail = tail.replace("b'0'", "'0'").replace("b'1'", "'1'")
|
||||||
|
yield f"INSERT INTO {table_name.lower()} {head} VALUES {tail}"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def index(ddl: Dict) -> Generator:
|
||||||
|
"""生成索引定义
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ddl (Dict): 表DDL
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Generator[str]: create index 语句
|
||||||
|
"""
|
||||||
|
|
||||||
|
def generate_columns(columns):
|
||||||
|
keys = [
|
||||||
|
f"{col['name'].lower()}{' ' + col['order'].lower() if col['order'] != 'ASC' else ''}"
|
||||||
|
for col in columns[0]
|
||||||
|
]
|
||||||
|
return ", ".join(keys)
|
||||||
|
|
||||||
|
for no, index in enumerate(ddl["index"], 1):
|
||||||
|
columns = generate_columns(index["columns"])
|
||||||
|
table_name = ddl["table_name"].lower()
|
||||||
|
yield f"CREATE INDEX idx_{table_name}_{no:02d} ON {table_name} ({columns})"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unique_index(ddl: Dict) -> Generator:
|
||||||
|
if "constraints" in ddl and "uniques" in ddl["constraints"]:
|
||||||
|
uk_list = ddl["constraints"]["uniques"]
|
||||||
|
for uk in uk_list:
|
||||||
|
table_name = ddl["table_name"]
|
||||||
|
uk_name = uk["constraint_name"]
|
||||||
|
uk_columns = uk["columns"]
|
||||||
|
yield table_name, uk_name, uk_columns
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def filed_comments(table_sql: str) -> Generator:
|
||||||
|
for line in table_sql.split("\n"):
|
||||||
|
match = re.match(r"^`([^`]+)`.* COMMENT '([^']+)'", line.strip())
|
||||||
|
if match:
|
||||||
|
field = match.group(1)
|
||||||
|
comment_string = match.group(2).replace("\\n", "\n")
|
||||||
|
yield field, comment_string
|
||||||
|
|
||||||
|
def table_comment(self, table_sql: str) -> str:
|
||||||
|
match = re.search(r"COMMENT \='([^']+)';", table_sql)
|
||||||
|
return match.group(1) if match else None
|
||||||
|
|
||||||
|
def print(self):
|
||||||
|
"""打印转换后的sql脚本到终端"""
|
||||||
|
print(
|
||||||
|
PREAMBLE.format(
|
||||||
|
db_type=self.db_type,
|
||||||
|
date=time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
dual = self.gen_dual()
|
||||||
|
if dual:
|
||||||
|
print(
|
||||||
|
f"""-- ----------------------------
|
||||||
|
-- Table structure for dual
|
||||||
|
-- ----------------------------
|
||||||
|
{dual}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
error_scripts = []
|
||||||
|
for table_sql in self.table_script_list:
|
||||||
|
ddl = DDLParser(table_sql.replace("`", "")).run()
|
||||||
|
|
||||||
|
# 如果parse失败, 需要跟进
|
||||||
|
if len(ddl) == 0:
|
||||||
|
error_scripts.append(table_sql)
|
||||||
|
continue
|
||||||
|
|
||||||
|
table_ddl = ddl[0]
|
||||||
|
table_name = table_ddl["table_name"]
|
||||||
|
|
||||||
|
# 忽略 quartz 的内容
|
||||||
|
if table_name.lower().startswith("qrtz"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 解析注释
|
||||||
|
for column in table_ddl["columns"]:
|
||||||
|
column["comment"] = bytes(column["comment"], "utf-8").decode(
|
||||||
|
"unicode_escape"
|
||||||
|
)[1:-1]
|
||||||
|
table_ddl["comment"] = bytes(table_ddl["comment"], "utf-8").decode(
|
||||||
|
"unicode_escape"
|
||||||
|
)[1:-1]
|
||||||
|
|
||||||
|
# 为每个表生成个6个基本部分
|
||||||
|
create = self.gen_create(table_ddl)
|
||||||
|
pk = self.gen_pk(table_name)
|
||||||
|
uk = self.gen_uk(table_ddl)
|
||||||
|
index = self.gen_index(table_ddl)
|
||||||
|
comment = self.gen_comment(table_ddl)
|
||||||
|
inserts = self.gen_insert(table_name)
|
||||||
|
|
||||||
|
# 组合当前表的DDL脚本
|
||||||
|
script = f"""{create}
|
||||||
|
|
||||||
|
{pk}
|
||||||
|
|
||||||
|
{uk}
|
||||||
|
|
||||||
|
{index}
|
||||||
|
|
||||||
|
{comment}
|
||||||
|
|
||||||
|
{inserts}
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 清理
|
||||||
|
script = re.sub("\n{3,}", "\n\n", script).strip() + "\n"
|
||||||
|
|
||||||
|
print(script)
|
||||||
|
|
||||||
|
# 将parse失败的脚本打印出来
|
||||||
|
if error_scripts:
|
||||||
|
print("!!! 以下内容无法正常解析", file=sys.stderr)
|
||||||
|
for script in error_scripts:
|
||||||
|
# print to stderr
|
||||||
|
print(script, file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
class PostgreSQLConvertor(Convertor):
|
||||||
|
def __init__(self, src):
|
||||||
|
super().__init__(src, "PostgreSQL")
|
||||||
|
|
||||||
|
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]):
|
||||||
|
"""类型转换"""
|
||||||
|
|
||||||
|
type = type.lower()
|
||||||
|
|
||||||
|
if type == "varchar":
|
||||||
|
return f"varchar({size})"
|
||||||
|
if type in ("int", "int unsigned"):
|
||||||
|
return "int4"
|
||||||
|
if type in ("bigint", "bigint unsigned"):
|
||||||
|
return "int8"
|
||||||
|
if type == "datetime":
|
||||||
|
return "timestamp"
|
||||||
|
if type == "timestamp":
|
||||||
|
return f"timestamp({size})"
|
||||||
|
if type == "bit":
|
||||||
|
return "bool"
|
||||||
|
if type in ("tinyint", "smallint"):
|
||||||
|
return "int2"
|
||||||
|
if type in ("text", "longtext"):
|
||||||
|
return "text"
|
||||||
|
if type in ("blob", "mediumblob"):
|
||||||
|
return "bytea"
|
||||||
|
if type == "decimal":
|
||||||
|
return (
|
||||||
|
f"numeric({','.join(str(s) for s in size)})" if len(size) else "numeric"
|
||||||
|
)
|
||||||
|
|
||||||
|
def gen_create(self, ddl: Dict) -> str:
|
||||||
|
"""生成 create"""
|
||||||
|
|
||||||
|
def _generate_column(col):
|
||||||
|
name = col["name"].lower()
|
||||||
|
if name == "deleted":
|
||||||
|
return "deleted int2 NOT NULL DEFAULT 0"
|
||||||
|
|
||||||
|
type = col["type"].lower()
|
||||||
|
full_type = self.translate_type(type, col["size"])
|
||||||
|
nullable = "NULL" if col["nullable"] else "NOT NULL"
|
||||||
|
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
|
||||||
|
return f"{name} {full_type} {nullable} {default}"
|
||||||
|
|
||||||
|
table_name = ddl["table_name"].lower()
|
||||||
|
columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]]
|
||||||
|
filed_def_list = ",\n ".join(columns)
|
||||||
|
script = f"""-- ----------------------------
|
||||||
|
-- Table structure for {table_name}
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS {table_name};
|
||||||
|
CREATE TABLE {table_name} (
|
||||||
|
{filed_def_list}
|
||||||
|
);"""
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_index(self, ddl: Dict) -> str:
|
||||||
|
return "\n".join(f"{script};" for script in self.index(ddl))
|
||||||
|
|
||||||
|
def gen_comment(self, table_ddl: Dict) -> str:
|
||||||
|
"""生成字段及表的注释"""
|
||||||
|
|
||||||
|
script = ""
|
||||||
|
for column in table_ddl["columns"]:
|
||||||
|
table_comment = column["comment"]
|
||||||
|
script += (
|
||||||
|
f"COMMENT ON COLUMN {table_ddl['table_name']}.{column['name']} IS '{table_comment}';"
|
||||||
|
+ "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
table_comment = table_ddl["comment"]
|
||||||
|
if table_comment:
|
||||||
|
script += (
|
||||||
|
f"COMMENT ON TABLE {table_ddl['table_name']} IS '{table_comment}';\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_pk(self, table_name) -> str:
|
||||||
|
"""生成主键定义"""
|
||||||
|
return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n"
|
||||||
|
|
||||||
|
def gen_uk(self, table_ddl: Dict) -> str:
|
||||||
|
script = ""
|
||||||
|
uk_list = list(Convertor.unique_index(table_ddl))
|
||||||
|
for idx, (table_name, _, uk_columns) in enumerate(uk_list, 1):
|
||||||
|
uk_name = f"uk_{table_name}_{idx:02d}"
|
||||||
|
script += f"CREATE UNIQUE INDEX {uk_name} ON {table_name} ({', '.join(uk_columns)});\n"
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_insert(self, table_name: str) -> str:
|
||||||
|
"""生成 insert 语句,以及根据最后的 insert id+1 生成 Sequence"""
|
||||||
|
|
||||||
|
inserts = list(Convertor.inserts(table_name, self.content))
|
||||||
|
## 生成 insert 脚本
|
||||||
|
script = ""
|
||||||
|
last_id = 0
|
||||||
|
if inserts:
|
||||||
|
inserts_lines = "\n".join(inserts)
|
||||||
|
script += f"""\n\n-- ----------------------------
|
||||||
|
-- Records of {table_name.lower()}
|
||||||
|
-- ----------------------------
|
||||||
|
-- @formatter:off
|
||||||
|
BEGIN;
|
||||||
|
{inserts_lines}
|
||||||
|
COMMIT;
|
||||||
|
-- @formatter:on"""
|
||||||
|
match = re.search(r"VALUES \((\d+),", inserts[-1])
|
||||||
|
if match:
|
||||||
|
last_id = int(match.group(1))
|
||||||
|
|
||||||
|
# 生成 Sequence
|
||||||
|
script += (
|
||||||
|
"\n\n"
|
||||||
|
+ f"""DROP SEQUENCE IF EXISTS {table_name}_seq;
|
||||||
|
CREATE SEQUENCE {table_name}_seq
|
||||||
|
START {last_id + 1};"""
|
||||||
|
)
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_dual(self) -> str:
|
||||||
|
return """DROP TABLE IF EXISTS dual;
|
||||||
|
CREATE TABLE dual
|
||||||
|
(
|
||||||
|
id int2
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dual IS '数据库连接的表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of dual
|
||||||
|
-- ----------------------------
|
||||||
|
-- @formatter:off
|
||||||
|
INSERT INTO dual VALUES (1);
|
||||||
|
-- @formatter:on"""
|
||||||
|
|
||||||
|
|
||||||
|
class OracleConvertor(Convertor):
|
||||||
|
def __init__(self, src):
|
||||||
|
super().__init__(src, "Oracle")
|
||||||
|
|
||||||
|
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]):
|
||||||
|
"""类型转换"""
|
||||||
|
type = type.lower()
|
||||||
|
|
||||||
|
if type == "varchar":
|
||||||
|
return f"varchar2({size if size < 4000 else 4000})"
|
||||||
|
if type in ("int", "int unsigned"):
|
||||||
|
return "number"
|
||||||
|
if type == "bigint" or type == "bigint unsigned":
|
||||||
|
return "number"
|
||||||
|
if type == "datetime":
|
||||||
|
return "date"
|
||||||
|
if type == "timestamp":
|
||||||
|
return f"timestamp({size})"
|
||||||
|
if type == "bit":
|
||||||
|
return "number(1,0)"
|
||||||
|
if type in ("tinyint", "smallint"):
|
||||||
|
return "smallint"
|
||||||
|
if type in ("text", "longtext"):
|
||||||
|
return "clob"
|
||||||
|
if type in ("blob", "mediumblob"):
|
||||||
|
return "blob"
|
||||||
|
if type == "decimal":
|
||||||
|
return (
|
||||||
|
f"number({','.join(str(s) for s in size)})" if len(size) else "number"
|
||||||
|
)
|
||||||
|
|
||||||
|
def gen_create(self, ddl) -> str:
|
||||||
|
"""生成 CREATE 语句"""
|
||||||
|
|
||||||
|
def generate_column(col):
|
||||||
|
name = col["name"].lower()
|
||||||
|
if name == "deleted":
|
||||||
|
return "deleted number(1,0) DEFAULT 0 NOT NULL"
|
||||||
|
|
||||||
|
type = col["type"].lower()
|
||||||
|
full_type = self.translate_type(type, col["size"])
|
||||||
|
nullable = "NULL" if col["nullable"] else "NOT NULL"
|
||||||
|
# Oracle的 INSERT '' 不能通过NOT NULL校验,因此对文字类型字段覆写为 NULL
|
||||||
|
nullable = "NULL" if type in ("varchar", "text", "longtext") else nullable
|
||||||
|
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
|
||||||
|
# Oracle 中 size 不能作为字段名
|
||||||
|
field_name = '"size"' if name == "size" else name
|
||||||
|
# Oracle DEFAULT 定义在 NULLABLE 之前
|
||||||
|
return f"{field_name} {full_type} {default} {nullable}"
|
||||||
|
|
||||||
|
table_name = ddl["table_name"].lower()
|
||||||
|
columns = [f"{generate_column(col).strip()}" for col in ddl["columns"]]
|
||||||
|
field_def_list = ",\n ".join(columns)
|
||||||
|
script = f"""-- ----------------------------
|
||||||
|
-- Table structure for {table_name}
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE {table_name} (
|
||||||
|
{field_def_list}
|
||||||
|
);"""
|
||||||
|
|
||||||
|
# oracle INSERT '' 不能通过 NOT NULL 校验
|
||||||
|
script = script.replace("DEFAULT '' NOT NULL", "DEFAULT '' NULL")
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_index(self, ddl: Dict) -> str:
|
||||||
|
return "\n".join(f"{script};" for script in self.index(ddl))
|
||||||
|
|
||||||
|
def gen_comment(self, table_ddl: Dict) -> str:
|
||||||
|
script = ""
|
||||||
|
for column in table_ddl["columns"]:
|
||||||
|
table_comment = column["comment"]
|
||||||
|
script += (
|
||||||
|
f"COMMENT ON COLUMN {table_ddl['table_name']}.{column['name']} IS '{table_comment}';"
|
||||||
|
+ "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
table_comment = table_ddl["comment"]
|
||||||
|
if table_comment:
|
||||||
|
script += (
|
||||||
|
f"COMMENT ON TABLE {table_ddl['table_name']} IS '{table_comment}';\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_pk(self, table_name: str) -> str:
|
||||||
|
"""生成主键定义"""
|
||||||
|
return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n"
|
||||||
|
|
||||||
|
def gen_uk(self, table_ddl: Dict) -> str:
|
||||||
|
script = ""
|
||||||
|
uk_list = list(Convertor.unique_index(table_ddl))
|
||||||
|
for idx, (table_name, _, uk_columns) in enumerate(uk_list, 1):
|
||||||
|
uk_name = f"uk_{table_name}_{idx:02d}"
|
||||||
|
script += f"CREATE UNIQUE INDEX {uk_name} ON {table_name} ({', '.join(uk_columns)});\n"
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_index(self, ddl: Dict) -> str:
|
||||||
|
return "\n".join(f"{script};" for script in self.index(ddl))
|
||||||
|
|
||||||
|
def gen_insert(self, table_name: str) -> str:
|
||||||
|
"""拷贝 INSERT 语句"""
|
||||||
|
inserts = []
|
||||||
|
for insert_script in Convertor.inserts(table_name, self.content):
|
||||||
|
# 对日期数据添加 TO_DATE 转换
|
||||||
|
insert_script = re.sub(
|
||||||
|
r"('\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}')",
|
||||||
|
r"to_date(\g<1>, 'SYYYY-MM-DD HH24:MI:SS')",
|
||||||
|
insert_script,
|
||||||
|
)
|
||||||
|
inserts.append(insert_script)
|
||||||
|
|
||||||
|
## 生成 insert 脚本
|
||||||
|
script = ""
|
||||||
|
last_id = 0
|
||||||
|
if inserts:
|
||||||
|
inserts_lines = "\n".join(inserts)
|
||||||
|
script += f"""\n\n-- ----------------------------
|
||||||
|
-- Records of {table_name.lower()}
|
||||||
|
-- ----------------------------
|
||||||
|
-- @formatter:off
|
||||||
|
{inserts_lines}
|
||||||
|
COMMIT;
|
||||||
|
-- @formatter:on"""
|
||||||
|
match = re.search(r"VALUES \((\d+),", inserts[-1])
|
||||||
|
if match:
|
||||||
|
last_id = int(match.group(1))
|
||||||
|
|
||||||
|
# 生成 Sequence
|
||||||
|
script += f"""
|
||||||
|
|
||||||
|
CREATE SEQUENCE {table_name}_seq
|
||||||
|
START WITH {last_id + 1};"""
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
|
||||||
|
class SQLServerConvertor(Convertor):
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
Convertor (_type_): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, src):
|
||||||
|
super().__init__(src, "Microsoft SQL Server")
|
||||||
|
|
||||||
|
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]):
|
||||||
|
"""类型转换"""
|
||||||
|
|
||||||
|
type = type.lower()
|
||||||
|
|
||||||
|
if type == "varchar":
|
||||||
|
return f"nvarchar({size if size < 4000 else 4000})"
|
||||||
|
if type in ("int", "int unsigned"):
|
||||||
|
return "int"
|
||||||
|
if type in ("bigint", "bigint unsigned"):
|
||||||
|
return "bigint"
|
||||||
|
if type in ("datetime", "timestamp"):
|
||||||
|
return "datetime2"
|
||||||
|
if type == "bit":
|
||||||
|
return "varchar(1)"
|
||||||
|
if type in ("tinyint", "smallint"):
|
||||||
|
return "tinyint"
|
||||||
|
if type in ("text", "longtext"):
|
||||||
|
return "nvarchar(max)"
|
||||||
|
if type in ("blob", "mediumblob"):
|
||||||
|
return "varbinary(max)"
|
||||||
|
if type == "decimal":
|
||||||
|
return (
|
||||||
|
f"numeric({','.join(str(s) for s in size)})" if len(size) else "numeric"
|
||||||
|
)
|
||||||
|
|
||||||
|
def gen_create(self, ddl: Dict) -> str:
|
||||||
|
"""生成 create"""
|
||||||
|
|
||||||
|
def _generate_column(col):
|
||||||
|
name = col["name"].lower()
|
||||||
|
if name == "id":
|
||||||
|
return "id bigint NOT NULL PRIMARY KEY IDENTITY"
|
||||||
|
if name == "deleted":
|
||||||
|
return "deleted bit DEFAULT 0 NOT NULL"
|
||||||
|
|
||||||
|
type = col["type"].lower()
|
||||||
|
full_type = self.translate_type(type, col["size"])
|
||||||
|
nullable = "NULL" if col["nullable"] else "NOT NULL"
|
||||||
|
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
|
||||||
|
return f"{name} {full_type} {default} {nullable}"
|
||||||
|
|
||||||
|
table_name = ddl["table_name"].lower()
|
||||||
|
columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]]
|
||||||
|
filed_def_list = ",\n ".join(columns)
|
||||||
|
script = f"""-- ----------------------------
|
||||||
|
-- Table structure for {table_name}
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS {table_name}
|
||||||
|
GO
|
||||||
|
CREATE TABLE {table_name} (
|
||||||
|
{filed_def_list}
|
||||||
|
)
|
||||||
|
GO"""
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_comment(self, table_ddl: Dict) -> str:
|
||||||
|
"""生成字段及表的注释"""
|
||||||
|
|
||||||
|
script = ""
|
||||||
|
table_name = table_ddl["table_name"]
|
||||||
|
|
||||||
|
for column in table_ddl["columns"]:
|
||||||
|
column_comment = column["comment"]
|
||||||
|
field = column["name"]
|
||||||
|
|
||||||
|
script += f"""EXEC sp_addextendedproperty
|
||||||
|
'MS_Description', N'{column_comment}',
|
||||||
|
'SCHEMA', N'dbo',
|
||||||
|
'TABLE', N'{table_name}',
|
||||||
|
'COLUMN', N'{field}'
|
||||||
|
GO
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
table_comment = table_ddl["comment"]
|
||||||
|
if table_comment:
|
||||||
|
script += f"""EXEC sp_addextendedproperty
|
||||||
|
'MS_Description', N'{table_comment}',
|
||||||
|
'SCHEMA', N'dbo',
|
||||||
|
'TABLE', N'{table_name}'
|
||||||
|
GO
|
||||||
|
|
||||||
|
"""
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_pk(self, table_name: str) -> str:
|
||||||
|
"""生成主键定义"""
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def gen_uk(self, table_ddl: Dict) -> str:
|
||||||
|
script = ""
|
||||||
|
uk_list = list(Convertor.unique_index(table_ddl))
|
||||||
|
for idx, (table_name, _, uk_columns) in enumerate(uk_list, 1):
|
||||||
|
uk_name = f"uk_{table_name}_{idx:02d}"
|
||||||
|
script += f"CREATE UNIQUE INDEX {uk_name} ON {table_name} ({', '.join(uk_columns)})\nGO"
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_index(self, ddl: Dict) -> str:
|
||||||
|
"""生成 index"""
|
||||||
|
return "\n".join(f"{script}\nGO" for script in self.index(ddl))
|
||||||
|
|
||||||
|
def gen_insert(self, table_name: str) -> str:
|
||||||
|
"""生成 insert 语句"""
|
||||||
|
|
||||||
|
# 收集 `table_name` 对应的 insert 语句
|
||||||
|
inserts = []
|
||||||
|
for insert_script in Convertor.inserts(table_name, self.content):
|
||||||
|
# SQLServer: 字符串前加N,hack,是否存在替换字符串内容的风险
|
||||||
|
insert_script = insert_script.replace(", '", ", N'").replace(
|
||||||
|
"VALUES ('", "VALUES (N')"
|
||||||
|
)
|
||||||
|
# 删除 insert 的结尾分号
|
||||||
|
insert_script = re.sub(";$", r"\nGO", insert_script)
|
||||||
|
inserts.append(insert_script)
|
||||||
|
|
||||||
|
## 生成 insert 脚本
|
||||||
|
script = ""
|
||||||
|
if inserts:
|
||||||
|
inserts_lines = "\n".join(inserts)
|
||||||
|
script += f"""\n\n-- ----------------------------
|
||||||
|
-- Records of {table_name.lower()}
|
||||||
|
-- ----------------------------
|
||||||
|
-- @formatter:off
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
SET IDENTITY_INSERT {table_name.lower()} ON
|
||||||
|
GO
|
||||||
|
{inserts_lines}
|
||||||
|
SET IDENTITY_INSERT {table_name.lower()} OFF
|
||||||
|
GO
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
-- @formatter:on"""
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_dual(self) -> str:
|
||||||
|
return """DROP TABLE IF EXISTS dual
|
||||||
|
GO
|
||||||
|
CREATE TABLE dual
|
||||||
|
(
|
||||||
|
id int
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
EXEC sp_addextendedproperty
|
||||||
|
'MS_Description', N'数据库连接的表',
|
||||||
|
'SCHEMA', N'dbo',
|
||||||
|
'TABLE', N'dual'
|
||||||
|
GO
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of dual
|
||||||
|
-- ----------------------------
|
||||||
|
-- @formatter:off
|
||||||
|
INSERT INTO dual VALUES (1)
|
||||||
|
GO
|
||||||
|
-- @formatter:on"""
|
||||||
|
|
||||||
|
|
||||||
|
class DM8Convertor(Convertor):
|
||||||
|
def __init__(self, src):
|
||||||
|
super().__init__(src, "DM8")
|
||||||
|
|
||||||
|
def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]):
|
||||||
|
"""类型转换"""
|
||||||
|
type = type.lower()
|
||||||
|
|
||||||
|
if type == "varchar":
|
||||||
|
return f"varchar({size})"
|
||||||
|
if type in ("int", "int unsigned"):
|
||||||
|
return "int"
|
||||||
|
if type in ("bigint", "bigint unsigned"):
|
||||||
|
return "bigint"
|
||||||
|
if type == "datetime":
|
||||||
|
return "datetime"
|
||||||
|
if type == "timestamp":
|
||||||
|
return f"timestamp({size})"
|
||||||
|
if type == "bit":
|
||||||
|
return "bit"
|
||||||
|
if type in ("tinyint", "smallint"):
|
||||||
|
return "smallint"
|
||||||
|
if type in ("text", "longtext"):
|
||||||
|
return "text"
|
||||||
|
if type in ("blob", "mediumblob"):
|
||||||
|
return "blob"
|
||||||
|
if type == "decimal":
|
||||||
|
return (
|
||||||
|
f"decimal({','.join(str(s) for s in size)})" if len(size) else "decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
def gen_create(self, ddl) -> str:
|
||||||
|
"""生成 CREATE 语句"""
|
||||||
|
|
||||||
|
def generate_column(col):
|
||||||
|
name = col["name"].lower()
|
||||||
|
if name == "id":
|
||||||
|
return "id bigint NOT NULL PRIMARY KEY IDENTITY"
|
||||||
|
|
||||||
|
type = col["type"].lower()
|
||||||
|
full_type = self.translate_type(type, col["size"])
|
||||||
|
nullable = "NULL" if col["nullable"] else "NOT NULL"
|
||||||
|
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
|
||||||
|
return f"{name} {full_type} {default} {nullable}"
|
||||||
|
|
||||||
|
table_name = ddl["table_name"].lower()
|
||||||
|
columns = [f"{generate_column(col).strip()}" for col in ddl["columns"]]
|
||||||
|
field_def_list = ",\n ".join(columns)
|
||||||
|
script = f"""-- ----------------------------
|
||||||
|
-- Table structure for {table_name}
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE {table_name} (
|
||||||
|
{field_def_list}
|
||||||
|
);"""
|
||||||
|
|
||||||
|
# oracle INSERT '' 不能通过 NOT NULL 校验
|
||||||
|
script = script.replace("DEFAULT '' NOT NULL", "DEFAULT '' NULL")
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_comment(self, table_ddl: Dict) -> str:
|
||||||
|
script = ""
|
||||||
|
for column in table_ddl["columns"]:
|
||||||
|
table_comment = column["comment"]
|
||||||
|
script += (
|
||||||
|
f"COMMENT ON COLUMN {table_ddl['table_name']}.{column['name']} IS '{table_comment}';"
|
||||||
|
+ "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
table_comment = table_ddl["comment"]
|
||||||
|
if table_comment:
|
||||||
|
script += (
|
||||||
|
f"COMMENT ON TABLE {table_ddl['table_name']} IS '{table_comment}';\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_pk(self, table_name: str) -> str:
|
||||||
|
"""生成主键定义"""
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def gen_uk(self, table_ddl: Dict) -> str:
|
||||||
|
script = ""
|
||||||
|
uk_list = list(Convertor.unique_index(table_ddl))
|
||||||
|
for idx, (table_name, _, uk_columns) in enumerate(uk_list, 1):
|
||||||
|
uk_name = f"uk_{table_name}_{idx:02d}"
|
||||||
|
script += f"CREATE UNIQUE INDEX {uk_name} ON {table_name} ({', '.join(uk_columns)});\n"
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
def gen_index(self, ddl: Dict) -> str:
|
||||||
|
return "\n".join(f"{script};" for script in self.index(ddl))
|
||||||
|
|
||||||
|
def gen_insert(self, table_name: str) -> str:
|
||||||
|
"""拷贝 INSERT 语句"""
|
||||||
|
inserts = list(Convertor.inserts(table_name, self.content))
|
||||||
|
|
||||||
|
## 生成 insert 脚本
|
||||||
|
script = ""
|
||||||
|
if inserts:
|
||||||
|
inserts_lines = "\n".join(inserts)
|
||||||
|
script += f"""\n\n-- ----------------------------
|
||||||
|
-- Records of {table_name.lower()}
|
||||||
|
-- ----------------------------
|
||||||
|
-- @formatter:off
|
||||||
|
SET IDENTITY_INSERT {table_name.lower()} ON;
|
||||||
|
{inserts_lines}
|
||||||
|
COMMIT;
|
||||||
|
SET IDENTITY_INSERT {table_name.lower()} OFF;
|
||||||
|
-- @formatter:on"""
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
|
||||||
|
class KingbaseConvertor(PostgreSQLConvertor):
|
||||||
|
def __init__(self, src):
|
||||||
|
super().__init__(src)
|
||||||
|
self.db_type = "Kingbase"
|
||||||
|
|
||||||
|
def gen_create(self, ddl: Dict) -> str:
|
||||||
|
"""生成 create"""
|
||||||
|
|
||||||
|
def _generate_column(col):
|
||||||
|
name = col["name"].lower()
|
||||||
|
if name == "deleted":
|
||||||
|
return "deleted int2 NOT NULL DEFAULT 0"
|
||||||
|
|
||||||
|
type = col["type"].lower()
|
||||||
|
full_type = self.translate_type(type, col["size"])
|
||||||
|
nullable = "NULL" if col["nullable"] else "NOT NULL"
|
||||||
|
if full_type == "text":
|
||||||
|
nullable = "NULL"
|
||||||
|
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
|
||||||
|
return f"{name} {full_type} {nullable} {default}"
|
||||||
|
|
||||||
|
table_name = ddl["table_name"].lower()
|
||||||
|
columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]]
|
||||||
|
filed_def_list = ",\n ".join(columns)
|
||||||
|
script = f"""-- ----------------------------
|
||||||
|
-- Table structure for {table_name}
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS {table_name};
|
||||||
|
CREATE TABLE {table_name} (
|
||||||
|
{filed_def_list}
|
||||||
|
);"""
|
||||||
|
|
||||||
|
# Kingbase INSERT '' 不能通过 NOT NULL 校验
|
||||||
|
script = script.replace("NOT NULL DEFAULT ''", "NULL DEFAULT ''")
|
||||||
|
|
||||||
|
return script
|
||||||
|
|
||||||
|
|
||||||
|
class OpengaussConvertor(KingbaseConvertor):
|
||||||
|
def __init__(self, src):
|
||||||
|
super().__init__(src)
|
||||||
|
self.db_type = "OpenGauss"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="芋道系统数据库转换工具")
|
||||||
|
parser.add_argument(
|
||||||
|
"type",
|
||||||
|
type=str,
|
||||||
|
help="目标数据库类型",
|
||||||
|
choices=["postgres", "oracle", "sqlserver", "dm8", "kingbase", "opengauss"],
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
sql_file = pathlib.Path("../mysql/ruoyi-vue-pro.sql").resolve().as_posix()
|
||||||
|
convertor = None
|
||||||
|
if args.type == "postgres":
|
||||||
|
convertor = PostgreSQLConvertor(sql_file)
|
||||||
|
elif args.type == "oracle":
|
||||||
|
convertor = OracleConvertor(sql_file)
|
||||||
|
elif args.type == "sqlserver":
|
||||||
|
convertor = SQLServerConvertor(sql_file)
|
||||||
|
elif args.type == "dm8":
|
||||||
|
convertor = DM8Convertor(sql_file)
|
||||||
|
elif args.type == "kingbase":
|
||||||
|
convertor = KingbaseConvertor(sql_file)
|
||||||
|
elif args.type == "opengauss":
|
||||||
|
convertor = OpengaussConvertor(sql_file)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"不支持目标数据库类型: {args.type}")
|
||||||
|
|
||||||
|
convertor.print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
name: ruoyi-vue-pro
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql: { }
|
||||||
|
postgres: { }
|
||||||
|
sqlserver: { }
|
||||||
|
dm8: { }
|
||||||
|
kingbase: { }
|
||||||
|
opengauss: { }
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0.33
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
MYSQL_ROOT_PASSWORD: 123456
|
||||||
|
MYSQL_DATABASE: ruoyi-vue-pro
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
volumes:
|
||||||
|
- mysql:/var/lib/mysql/
|
||||||
|
# 注入初始化脚本
|
||||||
|
- ./mysql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||||
|
command:
|
||||||
|
--default-authentication-plugin=mysql_native_password
|
||||||
|
--character-set-server=utf8mb4
|
||||||
|
--collation-server=utf8mb4_general_ci
|
||||||
|
--explicit_defaults_for_timestamp=true
|
||||||
|
--lower_case_table_names=1
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:14.2
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: root
|
||||||
|
POSTGRES_PASSWORD: 123456
|
||||||
|
POSTGRES_DB: ruoyi-vue-pro
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres:/var/lib/postgresql/data
|
||||||
|
# 注入初始化脚本
|
||||||
|
- ../postgresql/quartz.sql:/docker-entrypoint-initdb.d/quartz.sql:ro
|
||||||
|
- ../postgresql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/ruoyi-vue-pro.sql:ro
|
||||||
|
|
||||||
|
oracle:
|
||||||
|
image: gvenzl/oracle-xe:18-slim-faststart
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
## 登录信息 SID: XE user: system password: oracle
|
||||||
|
ORACLE_PASSWORD: oracle
|
||||||
|
ports:
|
||||||
|
- "1521:1521"
|
||||||
|
volumes:
|
||||||
|
- ../oracle/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
|
||||||
|
# 创建app用户: ROOT/123456@//localhost/XEPDB1
|
||||||
|
- ./oracle/1_create_user.sql:/docker-entrypoint-initdb.d/1_create_user.sql:ro
|
||||||
|
- ./oracle/2_create_schema.sh:/docker-entrypoint-initdb.d/2_create_schema.sh:ro
|
||||||
|
|
||||||
|
oracle_m1:
|
||||||
|
image: einslib/oracle-19c:19.3.0-ee-slim-faststart
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
## 登录信息 SID: FREE user: system password: oracle
|
||||||
|
ORACLE_PASSWORD: oracle
|
||||||
|
ports:
|
||||||
|
- "1521:1521"
|
||||||
|
volumes:
|
||||||
|
- ../oracle/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
|
||||||
|
# 创建app用户: ROOT/123456@//localhost/XEPDB1
|
||||||
|
- ./oracle/1_create_user.sql:/docker-entrypoint-initdb.d/1_create_user.sql:ro
|
||||||
|
- ./oracle/2_create_schema.sh:/docker-entrypoint-initdb.d/2_create_schema.sh:ro
|
||||||
|
|
||||||
|
sqlserver:
|
||||||
|
image: mcr.microsoft.com/mssql/server:2017-latest
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
ACCEPT_EULA: "Y"
|
||||||
|
SA_PASSWORD: "Yudao@2024"
|
||||||
|
ports:
|
||||||
|
- "1433:1433"
|
||||||
|
volumes:
|
||||||
|
- sqlserver:/var/opt/mssql
|
||||||
|
- ../sqlserver/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
|
||||||
|
# docker compose exec sqlserver bash /tmp/create_schema.sh
|
||||||
|
- ./sqlserver/create_schema.sh:/tmp/create_schema.sh:ro
|
||||||
|
|
||||||
|
dm8:
|
||||||
|
# docker load -i dm8_20240715_x86_rh6_rq_single.tar
|
||||||
|
image: dm8_single:dm8_20240715_rev232765_x86_rh6_64
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PAGE_SIZE: 16
|
||||||
|
LD_LIBRARY_PATH: /opt/dmdbms/bin
|
||||||
|
EXTENT_SIZE: 32
|
||||||
|
BLANK_PAD_MODE: 1
|
||||||
|
LOG_SIZE: 1024
|
||||||
|
UNICODE_FLAG: 1
|
||||||
|
LENGTH_IN_CHAR: 1
|
||||||
|
INSTANCE_NAME: dm8_test
|
||||||
|
ports:
|
||||||
|
- "5236:5236"
|
||||||
|
volumes:
|
||||||
|
- dm8:/opt/dmdbms/data
|
||||||
|
- ../dm/ruoyi-vue-pro-dm8.sql:/tmp/schema.sql:ro
|
||||||
|
|
||||||
|
kingbase:
|
||||||
|
image: kingbase_v009r001c001b0025_single_x86:v1
|
||||||
|
# image: kingbase_v009r001c001b0025_single_arm:v1
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
DB_USER: root
|
||||||
|
DB_PASSWORD: 123456
|
||||||
|
ports:
|
||||||
|
- "54321:54321"
|
||||||
|
volumes:
|
||||||
|
- kingbase:/home/kingbase/userdata
|
||||||
|
- ../kingbase/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
|
||||||
|
|
||||||
|
opengauss:
|
||||||
|
image: opengauss/opengauss:5.0.0
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
GS_USERNAME: root
|
||||||
|
GS_PASSWORD: Yudao@2024
|
||||||
|
LD_LIBRARY_PATH: /usr/local/opengauss/lib:/usr/lib
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- opengauss:/var/lib/opengauss
|
||||||
|
- ../opengauss/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
|
||||||
|
# docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql'
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER SESSION SET CONTAINER=XEPDB1;
|
||||||
|
CREATE USER ROOT IDENTIFIED BY 123456 QUOTA UNLIMITED ON USERS;
|
||||||
|
GRANT CONNECT, RESOURCE TO ROOT;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
sqlplus -s ROOT/123456@//localhost/XEPDB1 @/tmp/schema.sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P ${SA_PASSWORD} -Q "CREATE DATABASE [ruoyi-vue-pro];
|
||||||
|
GO"
|
||||||
|
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P ${SA_PASSWORD} -d 'ruoyi-vue-pro' -i /tmp/schema.sql
|
||||||
@@ -0,0 +1,720 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-dependencies</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<name>${project.artifactId}</name>
|
||||||
|
<description>基础 bom 文件,管理整个项目的依赖版本</description>
|
||||||
|
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<revision>2025.09-jdk8-SNAPSHOT</revision>
|
||||||
|
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
|
||||||
|
<!-- 统一依赖管理 -->
|
||||||
|
<spring.framework.version>5.3.39</spring.framework.version>
|
||||||
|
<spring.security.version>5.8.16</spring.security.version>
|
||||||
|
<spring.boot.version>2.7.18</spring.boot.version>
|
||||||
|
<!-- Web 相关 -->
|
||||||
|
<springdoc.version>1.8.0</springdoc.version>
|
||||||
|
<knife4j.version>4.5.0</knife4j.version>
|
||||||
|
<servlet.versoin>2.5</servlet.versoin>
|
||||||
|
<!-- DB 相关 -->
|
||||||
|
<druid.version>1.2.27</druid.version>
|
||||||
|
<mybatis.version>3.5.19</mybatis.version>
|
||||||
|
<mybatis-plus.version>3.5.12</mybatis-plus.version>
|
||||||
|
<mybatis-plus-join.version>1.5.4</mybatis-plus-join.version>
|
||||||
|
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
||||||
|
<easy-trans.version>3.0.6</easy-trans.version>
|
||||||
|
<redisson.version>3.51.0</redisson.version>
|
||||||
|
<dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
|
||||||
|
<kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
|
||||||
|
<opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
|
||||||
|
<taos.version>3.7.3</taos.version>
|
||||||
|
<!-- 消息队列 -->
|
||||||
|
<rocketmq-spring.version>2.3.4</rocketmq-spring.version>
|
||||||
|
<!-- 服务保障相关 -->
|
||||||
|
<lock4j.version>2.2.7</lock4j.version>
|
||||||
|
<!-- 监控相关 -->
|
||||||
|
<skywalking.version>8.12.0</skywalking.version>
|
||||||
|
<spring-boot-admin.version>2.7.15</spring-boot-admin.version>
|
||||||
|
<opentracing.version>0.33.0</opentracing.version>
|
||||||
|
<!-- Test 测试相关 -->
|
||||||
|
<podam.version>7.2.11.RELEASE</podam.version> <!-- Spring Boot 2.X 最多使用 7.2.11 版本 -->
|
||||||
|
<jedis-mock.version>1.1.11</jedis-mock.version>
|
||||||
|
<mockito-inline.version>4.11.0</mockito-inline.version>
|
||||||
|
<!-- Bpm 工作流相关 -->
|
||||||
|
<flowable.version>6.8.0</flowable.version>
|
||||||
|
<!-- 工具类相关 -->
|
||||||
|
<anji-plus-captcha.version>1.4.0</anji-plus-captcha.version>
|
||||||
|
<jsoup.version>1.21.2</jsoup.version>
|
||||||
|
<lombok.version>1.18.38</lombok.version>
|
||||||
|
<mapstruct.version>1.6.3</mapstruct.version>
|
||||||
|
<hutool-5.version>5.8.40</hutool-5.version>
|
||||||
|
<fastexcel.version>1.3.0</fastexcel.version>
|
||||||
|
<velocity.version>2.4</velocity.version> <!-- JDK8 不能从 2.4 升级到 2.4.1,会报包不存在!!!! -->
|
||||||
|
<fastjson.version>1.2.83</fastjson.version>
|
||||||
|
<guava.version>33.4.8-jre</guava.version>
|
||||||
|
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
|
||||||
|
<commons-net.version>3.11.1</commons-net.version>
|
||||||
|
<commons-lang3.version>3.18.0</commons-lang3.version>
|
||||||
|
<jsch.version>0.1.55</jsch.version>
|
||||||
|
<tika-core.version>2.9.3</tika-core.version> <!-- JDK8 不能从 2.9.3 升级到 3.X,会报 JDK8 不支持 -->
|
||||||
|
<ip2region.version>2.7.0</ip2region.version>
|
||||||
|
<bizlog-sdk.version>3.0.6</bizlog-sdk.version>
|
||||||
|
<netty.version>4.2.4.Final</netty.version>
|
||||||
|
<mqtt.version>1.2.5</mqtt.version>
|
||||||
|
<pf4j-spring.version>0.9.0</pf4j-spring.version>
|
||||||
|
<vertx.version>4.5.13</vertx.version>
|
||||||
|
<!-- 三方云服务相关 -->
|
||||||
|
<awssdk.version>2.30.14</awssdk.version>
|
||||||
|
<justauth.version>1.16.7</justauth.version>
|
||||||
|
<justauth-starter.version>1.4.0</justauth-starter.version>
|
||||||
|
<jimureport.version>2.1.1</jimureport.version>
|
||||||
|
<jimubi.version>2.1.0</jimubi.version>
|
||||||
|
<weixin-java.version>4.7.7-20250808.182223</weixin-java.version>
|
||||||
|
<!-- 专属于 JDK8 安全漏洞升级 -->
|
||||||
|
<logback.version>1.2.13</logback.version> <!-- 无法使用 1.3.X 版本,启动会报错 -->
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<!-- 统一依赖管理 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-bom</artifactId>
|
||||||
|
<version>${netty.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-framework-bom</artifactId> <!-- JDK8 版本独有:保证 Spring Framework 尽量高 -->
|
||||||
|
<version>${spring.framework.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-bom</artifactId> <!-- JDK8 版本独有:保证 Spring Security 尽量高 -->
|
||||||
|
<version>${spring.security.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-dependencies</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 业务组件 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.mouzt</groupId>
|
||||||
|
<artifactId>bizlog-sdk</artifactId>
|
||||||
|
<version>${bizlog-sdk.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion> <!-- 排除掉springboot依赖使用项目的 -->
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring 核心 -->
|
||||||
|
<dependency>
|
||||||
|
<!-- 用于生成自定义的 Spring @ConfigurationProperties 配置类的说明文件 -->
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Web 相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-web</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-security</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-websocket</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
|
||||||
|
<version>${knife4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-ui</artifactId>
|
||||||
|
<version>${springdoc.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- DB 相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
|
<version>${druid.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<!-- 注意:必须声明,避免 flowable 和 mybatis-plus 引入的 mybatis 版本不一致!!! -->
|
||||||
|
<groupId>org.mybatis</groupId>
|
||||||
|
<artifactId>mybatis</artifactId>
|
||||||
|
<version>${mybatis.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
|
||||||
|
<version>${dynamic-datasource.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.yulichang</groupId>
|
||||||
|
<artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
|
||||||
|
<version>${mybatis-plus-join.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fhs-opensource</groupId> <!-- VO 数据翻译 -->
|
||||||
|
<artifactId>easy-trans-spring-boot-starter</artifactId>
|
||||||
|
<version>${easy-trans.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-commons</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fhs-opensource</groupId>
|
||||||
|
<artifactId>easy-trans-mybatis-plus-extend</artifactId>
|
||||||
|
<version>${easy-trans.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fhs-opensource</groupId>
|
||||||
|
<artifactId>easy-trans-anno</artifactId>
|
||||||
|
<version>${easy-trans.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-redis</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||||
|
<version>${redisson.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<!-- 使用 redisson-spring-data-27 替代,解决 Tuple NoClassDefFoundError 报错 -->
|
||||||
|
<artifactId>redisson-spring-data-35</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson-spring-data-27</artifactId>
|
||||||
|
<version>${redisson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.dameng</groupId>
|
||||||
|
<artifactId>DmJdbcDriver18</artifactId>
|
||||||
|
<version>${dm8.jdbc.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.opengauss</groupId>
|
||||||
|
<artifactId>opengauss-jdbc</artifactId>
|
||||||
|
<version>${opengauss.jdbc.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.com.kingbase</groupId>
|
||||||
|
<artifactId>kingbase8</artifactId>
|
||||||
|
<version>${kingbase.jdbc.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.taosdata.jdbc</groupId>
|
||||||
|
<artifactId>taos-jdbcdriver</artifactId>
|
||||||
|
<version>${taos.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Job 定时任务相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-job</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 消息队列相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-mq</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.rocketmq</groupId>
|
||||||
|
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||||
|
<version>${rocketmq-spring.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 服务保障相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-protection</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
|
||||||
|
<version>${lock4j.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 监控相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.skywalking</groupId>
|
||||||
|
<artifactId>apm-toolkit-trace</artifactId>
|
||||||
|
<version>${skywalking.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.skywalking</groupId>
|
||||||
|
<artifactId>apm-toolkit-logback-1.x</artifactId>
|
||||||
|
<version>${skywalking.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.skywalking</groupId>
|
||||||
|
<artifactId>apm-toolkit-opentracing</artifactId>
|
||||||
|
<version>${skywalking.version}</version>
|
||||||
|
<!-- <exclusions>-->
|
||||||
|
<!-- <exclusion>-->
|
||||||
|
<!-- <artifactId>opentracing-api</artifactId>-->
|
||||||
|
<!-- <groupId>io.opentracing</groupId>-->
|
||||||
|
<!-- </exclusion>-->
|
||||||
|
<!-- <exclusion>-->
|
||||||
|
<!-- <artifactId>opentracing-util</artifactId>-->
|
||||||
|
<!-- <groupId>io.opentracing</groupId>-->
|
||||||
|
<!-- </exclusion>-->
|
||||||
|
<!-- </exclusions>-->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.opentracing</groupId>
|
||||||
|
<artifactId>opentracing-api</artifactId>
|
||||||
|
<version>${opentracing.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.opentracing</groupId>
|
||||||
|
<artifactId>opentracing-util</artifactId>
|
||||||
|
<version>${opentracing.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.opentracing</groupId>
|
||||||
|
<artifactId>opentracing-noop</artifactId>
|
||||||
|
<version>${opentracing.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.codecentric</groupId>
|
||||||
|
<artifactId>spring-boot-admin-starter-server</artifactId> <!-- 实现 Spring Boot Admin Server 服务端 -->
|
||||||
|
<version>${spring-boot-admin.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>de.codecentric</groupId>
|
||||||
|
<artifactId>spring-boot-admin-server-cloud</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.codecentric</groupId>
|
||||||
|
<artifactId>spring-boot-admin-starter-client</artifactId> <!-- 实现 Spring Boot Admin Server 服务端 -->
|
||||||
|
<version>${spring-boot-admin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Test 测试相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-inline</artifactId>
|
||||||
|
<version>${mockito-inline.version}</version> <!-- 支持 Mockito 的 final 类与 static 方法的 mock -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.fppt</groupId> <!-- 单元测试,我们采用内嵌的 Redis 数据库 -->
|
||||||
|
<artifactId>jedis-mock</artifactId>
|
||||||
|
<version>${jedis-mock.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>uk.co.jemos.podam</groupId> <!-- 单元测试,随机生成 POJO 类 -->
|
||||||
|
<artifactId>podam</artifactId>
|
||||||
|
<version>${podam.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 工作流相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.flowable</groupId>
|
||||||
|
<artifactId>flowable-spring-boot-starter-process</artifactId>
|
||||||
|
<version>${flowable.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.flowable</groupId>
|
||||||
|
<artifactId>flowable-spring-boot-starter-actuator</artifactId>
|
||||||
|
<version>${flowable.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 工作流相关结束 -->
|
||||||
|
|
||||||
|
<!-- 工具类相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-common</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-jdk8</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>${hutool-5.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.idev.excel</groupId>
|
||||||
|
<artifactId>fastexcel</artifactId>
|
||||||
|
<version>${fastexcel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tika</groupId>
|
||||||
|
<artifactId>tika-core</artifactId> <!-- 文件类型的识别 -->
|
||||||
|
<version>${tika-core.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.velocity</groupId>
|
||||||
|
<artifactId>velocity-engine-core</artifactId>
|
||||||
|
<version>${velocity.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>${fastjson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>${guava.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>transmittable-thread-local</artifactId> <!-- 解决 ThreadLocal 父子线程的传值问题 -->
|
||||||
|
<version>${transmittable-thread-local.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-net</groupId>
|
||||||
|
<artifactId>commons-net</artifactId> <!-- 解决 ftp 连接 -->
|
||||||
|
<version>${commons-net.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jcraft</groupId>
|
||||||
|
<artifactId>jsch</artifactId> <!-- 解决 sftp 连接 -->
|
||||||
|
<version>${jsch.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons-lang3.version}</version> <!-- 解决 CVE-2025-48924 漏洞 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.anji-plus</groupId>
|
||||||
|
<artifactId>captcha-spring-boot-starter</artifactId> <!-- 验证码,一般用于登录使用 -->
|
||||||
|
<version>${anji-plus-captcha.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.lionsoul</groupId>
|
||||||
|
<artifactId>ip2region</artifactId>
|
||||||
|
<version>${ip2region.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jsoup</groupId>
|
||||||
|
<artifactId>jsoup</artifactId>
|
||||||
|
<version>${jsoup.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 三方云服务相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>software.amazon.awssdk</groupId>
|
||||||
|
<artifactId>s3</artifactId>
|
||||||
|
<version>${awssdk.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.zhyd.oauth</groupId>
|
||||||
|
<artifactId>JustAuth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
|
||||||
|
<version>${justauth.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.xkcoding.justauth</groupId>
|
||||||
|
<artifactId>justauth-spring-boot-starter</artifactId>
|
||||||
|
<version>${justauth-starter.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<!-- 移除,避免和项目里的 hutool-all 冲突 -->
|
||||||
|
<exclusion>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-pay</artifactId>
|
||||||
|
<version>${weixin-java.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
|
||||||
|
<version>${weixin-java.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
|
||||||
|
<version>${weixin-java.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 积木报表-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jeecgframework.jimureport</groupId>
|
||||||
|
<artifactId>jimureport-spring-boot-starter</artifactId>
|
||||||
|
<version>${jimureport.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jeecgframework.jimureport</groupId>
|
||||||
|
<artifactId>jimubi-spring-boot-starter</artifactId>
|
||||||
|
<version>${jimubi.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.github.jsqlparser</groupId>
|
||||||
|
<artifactId>jsqlparser</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- PF4J -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.pf4j</groupId>
|
||||||
|
<artifactId>pf4j-spring</artifactId>
|
||||||
|
<version>${pf4j-spring.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Vert.x -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vertx</groupId>
|
||||||
|
<artifactId>vertx-core</artifactId>
|
||||||
|
<version>${vertx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vertx</groupId>
|
||||||
|
<artifactId>vertx-web</artifactId>
|
||||||
|
<version>${vertx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vertx</groupId>
|
||||||
|
<artifactId>vertx-mqtt</artifactId>
|
||||||
|
<version>${vertx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- MQTT -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.paho</groupId>
|
||||||
|
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||||
|
<version>${mqtt.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 专属于 JDK8 安全漏洞升级 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
<version>${logback.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>${logback.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- 统一 revision 版本 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>flatten-maven-plugin</artifactId>
|
||||||
|
<version>${flatten-maven-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<flattenMode>bom</flattenMode>
|
||||||
|
<updatePomFile>true</updatePomFile>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>flatten</goal>
|
||||||
|
</goals>
|
||||||
|
<id>flatten</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>clean</goal>
|
||||||
|
</goals>
|
||||||
|
<id>flatten.clean</id>
|
||||||
|
<phase>clean</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?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>
|
||||||
|
<artifactId>yudao</artifactId>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<modules>
|
||||||
|
<module>yudao-common</module>
|
||||||
|
<module>yudao-spring-boot-starter-mybatis</module>
|
||||||
|
<module>yudao-spring-boot-starter-redis</module>
|
||||||
|
<module>yudao-spring-boot-starter-web</module>
|
||||||
|
<module>yudao-spring-boot-starter-security</module>
|
||||||
|
<module>yudao-spring-boot-starter-websocket</module>
|
||||||
|
|
||||||
|
<module>yudao-spring-boot-starter-monitor</module>
|
||||||
|
<module>yudao-spring-boot-starter-protection</module>
|
||||||
|
<module>yudao-spring-boot-starter-job</module>
|
||||||
|
<module>yudao-spring-boot-starter-mq</module>
|
||||||
|
|
||||||
|
<module>yudao-spring-boot-starter-excel</module>
|
||||||
|
<module>yudao-spring-boot-starter-test</module>
|
||||||
|
|
||||||
|
<module>yudao-spring-boot-starter-biz-tenant</module>
|
||||||
|
<module>yudao-spring-boot-starter-biz-data-permission</module>
|
||||||
|
<module>yudao-spring-boot-starter-biz-ip</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<artifactId>yudao-framework</artifactId>
|
||||||
|
<description>
|
||||||
|
该包是技术组件,每个子包,代表一个组件。每个组件包括两部分:
|
||||||
|
1. core 包:是该组件的核心封装
|
||||||
|
2. config 包:是该组件基于 Spring 的配置
|
||||||
|
|
||||||
|
技术组件,也分成两类:
|
||||||
|
1. 框架组件:和我们熟悉的 MyBatis、Redis 等等的拓展
|
||||||
|
2. 业务组件:和业务相关的组件的封装,例如说数据字典、操作日志等等。
|
||||||
|
如果是业务组件,Maven 名字会包含 biz
|
||||||
|
</description>
|
||||||
|
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
<?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.boot</groupId>
|
||||||
|
<artifactId>yudao-framework</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>yudao-common</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>${project.artifactId}</name>
|
||||||
|
<description>定义基础 pojo 类、枚举、工具类等等</description>
|
||||||
|
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Spring 核心 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-core</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-expression</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-aop</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.aspectj</groupId>
|
||||||
|
<artifactId>aspectjweaver</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<!-- 用于生成自定义的 Spring @ConfigurationProperties 配置类的说明文件 -->
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Web 相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-web</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.servlet</groupId>
|
||||||
|
<artifactId>jakarta.servlet-api</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-ui</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,主要是 PageParam 使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 监控相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.skywalking</groupId>
|
||||||
|
<artifactId>apm-toolkit-trace</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 工具类相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-jdk8</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.validation</groupId>
|
||||||
|
<artifactId>jakarta.validation-api</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,主要是 PageParam 使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>transmittable-thread-local</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fhs-opensource</groupId> <!-- VO 数据翻译 -->
|
||||||
|
<artifactId>easy-trans-anno</artifactId> <!-- 默认引入的原因,方便 xxx-module-api 包使用 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Test 测试相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.infra.logger;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 访问日志的 API 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface ApiAccessLogCommonApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 API 访问日志
|
||||||
|
*
|
||||||
|
* @param createDTO 创建信息
|
||||||
|
*/
|
||||||
|
void createApiAccessLog(@Valid ApiAccessLogCreateReqDTO createDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【异步】创建 API 访问日志
|
||||||
|
*
|
||||||
|
* @param createDTO 访问日志 DTO
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
default void createApiAccessLogAsync(ApiAccessLogCreateReqDTO createDTO) {
|
||||||
|
createApiAccessLog(createDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.infra.logger;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 错误日志的 API 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface ApiErrorLogCommonApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 API 错误日志
|
||||||
|
*
|
||||||
|
* @param createDTO 创建信息
|
||||||
|
*/
|
||||||
|
void createApiErrorLog(@Valid ApiErrorLogCreateReqDTO createDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【异步】创建 API 异常日志
|
||||||
|
*
|
||||||
|
* @param createDTO 异常日志 DTO
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
default void createApiErrorLogAsync(ApiErrorLogCreateReqDTO createDTO) {
|
||||||
|
createApiErrorLog(createDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.infra.logger.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 访问日志
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ApiAccessLogCreateReqDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 链路追踪编号
|
||||||
|
*/
|
||||||
|
private String traceId;
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*/
|
||||||
|
@NotNull(message = "应用名不能为空")
|
||||||
|
private String applicationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求方法名
|
||||||
|
*/
|
||||||
|
@NotNull(message = "http 请求方法不能为空")
|
||||||
|
private String requestMethod;
|
||||||
|
/**
|
||||||
|
* 访问地址
|
||||||
|
*/
|
||||||
|
@NotNull(message = "访问地址不能为空")
|
||||||
|
private String requestUrl;
|
||||||
|
/**
|
||||||
|
* 请求参数
|
||||||
|
*/
|
||||||
|
private String requestParams;
|
||||||
|
/**
|
||||||
|
* 响应结果
|
||||||
|
*/
|
||||||
|
private String responseBody;
|
||||||
|
/**
|
||||||
|
* 用户 IP
|
||||||
|
*/
|
||||||
|
@NotNull(message = "ip 不能为空")
|
||||||
|
private String userIp;
|
||||||
|
/**
|
||||||
|
* 浏览器 UA
|
||||||
|
*/
|
||||||
|
@NotNull(message = "User-Agent 不能为空")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作模块
|
||||||
|
*/
|
||||||
|
private String operateModule;
|
||||||
|
/**
|
||||||
|
* 操作名
|
||||||
|
*/
|
||||||
|
private String operateName;
|
||||||
|
/**
|
||||||
|
* 操作分类
|
||||||
|
*
|
||||||
|
* 枚举,参见 OperateTypeEnum 类
|
||||||
|
*/
|
||||||
|
private Integer operateType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始请求时间
|
||||||
|
*/
|
||||||
|
@NotNull(message = "开始请求时间不能为空")
|
||||||
|
private LocalDateTime beginTime;
|
||||||
|
/**
|
||||||
|
* 结束请求时间
|
||||||
|
*/
|
||||||
|
@NotNull(message = "结束请求时间不能为空")
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
/**
|
||||||
|
* 执行时长,单位:毫秒
|
||||||
|
*/
|
||||||
|
@NotNull(message = "执行时长不能为空")
|
||||||
|
private Integer duration;
|
||||||
|
/**
|
||||||
|
* 结果码
|
||||||
|
*/
|
||||||
|
@NotNull(message = "错误码不能为空")
|
||||||
|
private Integer resultCode;
|
||||||
|
/**
|
||||||
|
* 结果提示
|
||||||
|
*/
|
||||||
|
private String resultMsg;
|
||||||
|
|
||||||
|
}
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.infra.logger.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 错误日志
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ApiErrorLogCreateReqDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 链路编号
|
||||||
|
*/
|
||||||
|
private String traceId;
|
||||||
|
/**
|
||||||
|
* 账号编号
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*/
|
||||||
|
@NotNull(message = "应用名不能为空")
|
||||||
|
private String applicationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求方法名
|
||||||
|
*/
|
||||||
|
@NotNull(message = "http 请求方法不能为空")
|
||||||
|
private String requestMethod;
|
||||||
|
/**
|
||||||
|
* 访问地址
|
||||||
|
*/
|
||||||
|
@NotNull(message = "访问地址不能为空")
|
||||||
|
private String requestUrl;
|
||||||
|
/**
|
||||||
|
* 请求参数
|
||||||
|
*/
|
||||||
|
@NotNull(message = "请求参数不能为空")
|
||||||
|
private String requestParams;
|
||||||
|
/**
|
||||||
|
* 用户 IP
|
||||||
|
*/
|
||||||
|
@NotNull(message = "ip 不能为空")
|
||||||
|
private String userIp;
|
||||||
|
/**
|
||||||
|
* 浏览器 UA
|
||||||
|
*/
|
||||||
|
@NotNull(message = "User-Agent 不能为空")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常时间
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常时间不能为空")
|
||||||
|
private LocalDateTime exceptionTime;
|
||||||
|
/**
|
||||||
|
* 异常名
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常名不能为空")
|
||||||
|
private String exceptionName;
|
||||||
|
/**
|
||||||
|
* 异常发生的类全名
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常发生的类全名不能为空")
|
||||||
|
private String exceptionClassName;
|
||||||
|
/**
|
||||||
|
* 异常发生的类文件
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常发生的类文件不能为空")
|
||||||
|
private String exceptionFileName;
|
||||||
|
/**
|
||||||
|
* 异常发生的方法名
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常发生的方法名不能为空")
|
||||||
|
private String exceptionMethodName;
|
||||||
|
/**
|
||||||
|
* 异常发生的方法所在行
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常发生的方法所在行不能为空")
|
||||||
|
private Integer exceptionLineNumber;
|
||||||
|
/**
|
||||||
|
* 异常的栈轨迹异常的栈轨迹
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常的栈轨迹不能为空")
|
||||||
|
private String exceptionStackTrace;
|
||||||
|
/**
|
||||||
|
* 异常导致的根消息
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常导致的根消息不能为空")
|
||||||
|
private String exceptionRootCauseMessage;
|
||||||
|
/**
|
||||||
|
* 异常导致的消息
|
||||||
|
*/
|
||||||
|
@NotNull(message = "异常导致的消息不能为空")
|
||||||
|
private String exceptionMessage;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* 针对 infra 模块的 api 包
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.framework.common.biz.infra;
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* 特殊:用于 framework 下,starter 需要调用 biz 业务模块的接口定义!
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.framework.common.biz;
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.dict;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.biz.system.dict.dto.DictDataRespDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典数据 API 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface DictDataCommonApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得指定字典类型的字典数据列表
|
||||||
|
*
|
||||||
|
* @param dictType 字典类型
|
||||||
|
* @return 字典数据列表
|
||||||
|
*/
|
||||||
|
List<DictDataRespDTO> getDictDataList(String dictType);
|
||||||
|
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.dict.dto;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典数据 Response DTO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DictDataRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典标签
|
||||||
|
*/
|
||||||
|
private String label;
|
||||||
|
/**
|
||||||
|
* 字典值
|
||||||
|
*/
|
||||||
|
private String value;
|
||||||
|
/**
|
||||||
|
* 字典类型
|
||||||
|
*/
|
||||||
|
private String dictType;
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*
|
||||||
|
* 枚举 {@link CommonStatusEnum}
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.logger;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.biz.system.logger.dto.OperateLogCreateReqDTO;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志 API 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface OperateLogCommonApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建操作日志
|
||||||
|
*
|
||||||
|
* @param createReqDTO 请求
|
||||||
|
*/
|
||||||
|
void createOperateLog(@Valid OperateLogCreateReqDTO createReqDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【异步】创建操作日志
|
||||||
|
*
|
||||||
|
* @param createReqDTO 请求
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
default void createOperateLogAsync(OperateLogCreateReqDTO createReqDTO) {
|
||||||
|
createOperateLog(createReqDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.logger.dto;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统操作日志 Create Request DTO
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OperateLogCreateReqDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 链路追踪编号
|
||||||
|
*
|
||||||
|
* 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。
|
||||||
|
*/
|
||||||
|
private String traceId;
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*
|
||||||
|
* 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户编号不能为空")
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*
|
||||||
|
* 关联 {@link UserTypeEnum}
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户类型不能为空")
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 操作模块类型
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "操作模块类型不能为空")
|
||||||
|
private String type;
|
||||||
|
/**
|
||||||
|
* 操作名
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "操作名不能为空")
|
||||||
|
private String subType;
|
||||||
|
/**
|
||||||
|
* 操作模块业务编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "操作模块业务编号不能为空")
|
||||||
|
private Long bizId;
|
||||||
|
/**
|
||||||
|
* 操作内容,记录整个操作的明细
|
||||||
|
* 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "操作内容不能为空")
|
||||||
|
private String action;
|
||||||
|
/**
|
||||||
|
* 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 )
|
||||||
|
* 例如说,记录订单编号,{ orderId: "1"}
|
||||||
|
*/
|
||||||
|
private String extra;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求方法名
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "请求方法名不能为空")
|
||||||
|
private String requestMethod;
|
||||||
|
/**
|
||||||
|
* 请求地址
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "请求地址不能为空")
|
||||||
|
private String requestUrl;
|
||||||
|
/**
|
||||||
|
* 用户 IP
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "用户 IP 不能为空")
|
||||||
|
private String userIp;
|
||||||
|
/**
|
||||||
|
* 浏览器 UA
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "浏览器 UA 不能为空")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.oauth2;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
|
||||||
|
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenRespDTO;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth2.0 Token API 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface OAuth2TokenCommonApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建访问令牌
|
||||||
|
*
|
||||||
|
* @param reqDTO 访问令牌的创建信息
|
||||||
|
* @return 访问令牌的信息
|
||||||
|
*/
|
||||||
|
OAuth2AccessTokenRespDTO createAccessToken(@Valid OAuth2AccessTokenCreateReqDTO reqDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验访问令牌
|
||||||
|
*
|
||||||
|
* @param accessToken 访问令牌
|
||||||
|
* @return 访问令牌的信息
|
||||||
|
*/
|
||||||
|
OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除访问令牌
|
||||||
|
*
|
||||||
|
* @param accessToken 访问令牌
|
||||||
|
* @return 访问令牌的信息
|
||||||
|
*/
|
||||||
|
OAuth2AccessTokenRespDTO removeAccessToken(String accessToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新访问令牌
|
||||||
|
*
|
||||||
|
* @param refreshToken 刷新令牌
|
||||||
|
* @param clientId 客户端编号
|
||||||
|
* @return 访问令牌的信息
|
||||||
|
*/
|
||||||
|
OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId);
|
||||||
|
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.oauth2.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth2.0 访问令牌的校验 Response DTO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OAuth2AccessTokenCheckRespDTO implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 用户信息
|
||||||
|
*/
|
||||||
|
private Map<String, String> userInfo;
|
||||||
|
/**
|
||||||
|
* 租户编号
|
||||||
|
*/
|
||||||
|
private Long tenantId;
|
||||||
|
/**
|
||||||
|
* 授权范围的数组
|
||||||
|
*/
|
||||||
|
private List<String> scopes;
|
||||||
|
/**
|
||||||
|
* 过期时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime expiresTime;
|
||||||
|
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.oauth2.dto;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
|
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth2.0 访问令牌创建 Request DTO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OAuth2AccessTokenCreateReqDTO implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户编号不能为空")
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户类型不能为空")
|
||||||
|
@InEnum(value = UserTypeEnum.class, message = "用户类型必须是 {value}")
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 客户端编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "客户端编号不能为空")
|
||||||
|
private String clientId;
|
||||||
|
/**
|
||||||
|
* 授权范围
|
||||||
|
*/
|
||||||
|
private List<String> scopes;
|
||||||
|
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.oauth2.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth2.0 访问令牌的信息 Response DTO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OAuth2AccessTokenRespDTO implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问令牌
|
||||||
|
*/
|
||||||
|
private String accessToken;
|
||||||
|
/**
|
||||||
|
* 刷新令牌
|
||||||
|
*/
|
||||||
|
private String refreshToken;
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 过期时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime expiresTime;
|
||||||
|
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* 针对 system 模块的 api 包
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.framework.common.biz.system;
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.permission;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限 API 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface PermissionCommonApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否有权限,任一一个即可
|
||||||
|
*
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @param permissions 权限
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
boolean hasAnyPermissions(Long userId, String... permissions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否有角色,任一一个即可
|
||||||
|
*
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @param roles 角色数组
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
boolean hasAnyRoles(Long userId, String... roles);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得登陆用户的部门数据权限
|
||||||
|
*
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @return 部门数据权限
|
||||||
|
*/
|
||||||
|
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
|
||||||
|
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.permission.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门的数据权限 Response DTO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DeptDataPermissionRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可查看全部数据
|
||||||
|
*/
|
||||||
|
private Boolean all;
|
||||||
|
/**
|
||||||
|
* 是否可查看自己的数据
|
||||||
|
*/
|
||||||
|
private Boolean self;
|
||||||
|
/**
|
||||||
|
* 可查看的部门编号数组
|
||||||
|
*/
|
||||||
|
private Set<Long> deptIds;
|
||||||
|
|
||||||
|
public DeptDataPermissionRespDTO() {
|
||||||
|
this.all = false;
|
||||||
|
this.self = false;
|
||||||
|
this.deptIds = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.biz.system.tenant;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户的 API 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface TenantCommonApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得所有租户
|
||||||
|
*
|
||||||
|
* @return 租户编号数组
|
||||||
|
*/
|
||||||
|
List<Long> getTenantIdList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验租户是否合法
|
||||||
|
*
|
||||||
|
* @param id 租户编号
|
||||||
|
*/
|
||||||
|
void validateTenant(Long id);
|
||||||
|
|
||||||
|
}
|
||||||
+398
@@ -0,0 +1,398 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 通用常量
|
||||||
|
* @author: smcp
|
||||||
|
*/
|
||||||
|
public interface CommonConstant {
|
||||||
|
|
||||||
|
public static final Integer CALLBACK_SUCCESS = 0;
|
||||||
|
|
||||||
|
public static final Integer CALLBACK_FAIL = -1;
|
||||||
|
|
||||||
|
public static final String TRY_ON_TYPE_ALGO_CLOTH = "cloth";
|
||||||
|
|
||||||
|
public static final String TRY_ON_TYPE_ALGO_HAIR = "hair";
|
||||||
|
|
||||||
|
public static final String TRY_ON_TYPE_SINGLE = "single";
|
||||||
|
|
||||||
|
public static final String TRY_ON_TYPE_BATCH = "batch";
|
||||||
|
|
||||||
|
public static final String ROLE_TYPE_SUPER_ADMIN = "admin";
|
||||||
|
|
||||||
|
public static final String COMMON_YES = "yes";
|
||||||
|
|
||||||
|
public static final String COMMON_NO = "no";
|
||||||
|
|
||||||
|
public static final String EXCLUDE_SUIT = "excludeSuit";
|
||||||
|
|
||||||
|
public static final String TYPE_TOP_CLOTH = "topCloth";
|
||||||
|
|
||||||
|
public static final String TYPE_BOTTOM_CLOTH = "bottomCloth";
|
||||||
|
|
||||||
|
public static final String TYPE_DRESS = "dress";
|
||||||
|
|
||||||
|
//发型
|
||||||
|
public static final String TYPE_HAIR = "hair";
|
||||||
|
|
||||||
|
//身材
|
||||||
|
public static final String TYPE_FIGURE = "figure";
|
||||||
|
|
||||||
|
//内衣
|
||||||
|
public static final String TYPE_UNDERWEAR = "underwear";
|
||||||
|
|
||||||
|
//试穿 生成中图片链接
|
||||||
|
public static final String TRY_ON_IN_PROCESS = "https://digit-person.oss-cn-beijing.aliyuncs.com/digital_cloth/1720084773937.png";
|
||||||
|
//试穿 生成失败图片链接
|
||||||
|
public static final String TRY_ON_FAIL = "https://digit-person.oss-cn-beijing.aliyuncs.com/digital_cloth/1720084729963.png";
|
||||||
|
/**
|
||||||
|
* 短信验证码redis-key的前缀
|
||||||
|
*/
|
||||||
|
String PHONE_REDIS_KEY_PRE = "phone_msg";
|
||||||
|
/**
|
||||||
|
* 衣服
|
||||||
|
*/
|
||||||
|
public static final String CLOTH_FILE_TYPE = "clothType";
|
||||||
|
/**
|
||||||
|
* 模特
|
||||||
|
*/
|
||||||
|
public static final String MODEL_FILE_TYPE = "modelType";
|
||||||
|
|
||||||
|
public static final String DEFAULT_MODEL_FILE_TYPE = "defaultModelType";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 头像
|
||||||
|
*/
|
||||||
|
public static final String FACE_FILE_TYPE = "faceType";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发型
|
||||||
|
*/
|
||||||
|
public static final String HAIR_FILE_TYPE = "hair";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超级管理员 tenantId 值
|
||||||
|
*/
|
||||||
|
String ADMIN_TENANT_ID = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数字人审核 成功! 1 合格 0不 合格
|
||||||
|
*/
|
||||||
|
public static final Integer CUSTOM_CHECK_SUCCESS = 1;
|
||||||
|
/**
|
||||||
|
* 视频是否合格 1 合格 0不 合格
|
||||||
|
*/
|
||||||
|
public static final Integer VIDEO_CHECK_FAIL = 0;
|
||||||
|
/**
|
||||||
|
* 竖版
|
||||||
|
*/
|
||||||
|
public static final String picture_align_type_VERTICAL = "VERTICAL";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* :横版
|
||||||
|
*/
|
||||||
|
public static final String picture_align_type_HORIZONTAL = "HORIZONTAL";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传视频管理 前缀
|
||||||
|
*/
|
||||||
|
public static final String FILE_VIRTUAL_HUMAN = "virtual_human";
|
||||||
|
|
||||||
|
public static final String DIGITAL_CLOTH = "digital_cloth";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件状态 禁用
|
||||||
|
*/
|
||||||
|
public static final String FILE_STATUS_DISABLE = "disable";
|
||||||
|
/**
|
||||||
|
* 文件状态 失败
|
||||||
|
*/
|
||||||
|
public static final String FILE_STATUS_FAIL = "fail";
|
||||||
|
/**
|
||||||
|
* 文件状态可用
|
||||||
|
*/
|
||||||
|
public static final String FILE_STATUS_ENABLE = "enable";
|
||||||
|
/**
|
||||||
|
* 来源 第三方
|
||||||
|
*/
|
||||||
|
public static final String FILE_TYPE_VIDEO = "video";
|
||||||
|
|
||||||
|
public static final String PUTON_SWAP = "cloth_swap";
|
||||||
|
|
||||||
|
public static final String HAIR_SWAP = "hair";
|
||||||
|
|
||||||
|
public static final String FILE_TYPE_AUDIO = "audio";
|
||||||
|
|
||||||
|
public static final String FILE_TYPE_PICTURE = "picture";
|
||||||
|
/**
|
||||||
|
* 来源 自研
|
||||||
|
*/
|
||||||
|
public static final String SOURCE_TYPE_SELF_DEVELOP = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 来源 第三方
|
||||||
|
*/
|
||||||
|
public static final String SOURCE_TYPE_THIRD = "1";
|
||||||
|
|
||||||
|
public static final String CUSTOMIZED_TYPE = "CUSTOMIZED";
|
||||||
|
|
||||||
|
public static final String FREE_TYPE = "FREE";
|
||||||
|
|
||||||
|
public static final Integer CUSTOMIZED_TYPE_VALUE = 1;
|
||||||
|
|
||||||
|
public static final Integer FREE_TYPE_VALUE = 2;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除标志
|
||||||
|
*/
|
||||||
|
public static final Integer DEL_FLAG_1 = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未删除
|
||||||
|
*/
|
||||||
|
public static final Integer DEL_FLAG_0 = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统日志类型: 登录
|
||||||
|
*/
|
||||||
|
public static final int LOG_TYPE_1 = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统日志类型: 操作
|
||||||
|
*/
|
||||||
|
public static final int LOG_TYPE_2 = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志类型: 查询
|
||||||
|
*/
|
||||||
|
public static final int OPERATE_TYPE_1 = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志类型: 添加
|
||||||
|
*/
|
||||||
|
public static final int OPERATE_TYPE_2 = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志类型: 更新
|
||||||
|
*/
|
||||||
|
public static final int OPERATE_TYPE_3 = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志类型: 删除
|
||||||
|
*/
|
||||||
|
public static final int OPERATE_TYPE_4 = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志类型: 倒入
|
||||||
|
*/
|
||||||
|
public static final int OPERATE_TYPE_5 = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志类型: 导出
|
||||||
|
*/
|
||||||
|
public static final int OPERATE_TYPE_6 = 6;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code 500 Server Error} (HTTP/1.0 - RFC 1945)
|
||||||
|
*/
|
||||||
|
public static final Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
|
||||||
|
/**
|
||||||
|
* {@code 200 OK} (HTTP/1.0 - RFC 1945)
|
||||||
|
*/
|
||||||
|
public static final Integer SC_OK_200 = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问权限认证未通过 510
|
||||||
|
*/
|
||||||
|
public static final Integer SC_JEECG_NO_AUTHZ = 510;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录用户Shiro权限缓存KEY前缀
|
||||||
|
*/
|
||||||
|
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
||||||
|
/**
|
||||||
|
* 登录用户Token令牌缓存KEY前缀
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_USER_TOKEN = "prefix_user_token_";
|
||||||
|
// /** Token缓存时间:3600秒即一小时 */
|
||||||
|
// public static final int TOKEN_EXPIRE_TIME = 3600;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0:一级菜单
|
||||||
|
*/
|
||||||
|
public static final Integer MENU_TYPE_0 = 0;
|
||||||
|
/**
|
||||||
|
* 1:子菜单
|
||||||
|
*/
|
||||||
|
public static final Integer MENU_TYPE_1 = 1;
|
||||||
|
/**
|
||||||
|
* 2:按钮权限
|
||||||
|
*/
|
||||||
|
public static final Integer MENU_TYPE_2 = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通告对象类型(USER:指定用户,ALL:全体用户)
|
||||||
|
*/
|
||||||
|
public static final String MSG_TYPE_UESR = "USER";
|
||||||
|
public static final String MSG_TYPE_ALL = "ALL";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布状态(0未发布,1已发布,2已撤销)
|
||||||
|
*/
|
||||||
|
public static final String NO_SEND = "0";
|
||||||
|
public static final String HAS_SEND = "1";
|
||||||
|
public static final String HAS_CANCLE = "2";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阅读状态(0未读,1已读)
|
||||||
|
*/
|
||||||
|
public static final String HAS_READ_FLAG = "1";
|
||||||
|
public static final String NO_READ_FLAG = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级(L低,M中,H高)
|
||||||
|
*/
|
||||||
|
public static final String PRIORITY_L = "L";
|
||||||
|
public static final String PRIORITY_M = "M";
|
||||||
|
public static final String PRIORITY_H = "H";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信模板方式 0 .登录模板、1.注册模板、2.忘记密码模板
|
||||||
|
*/
|
||||||
|
public static final String SMS_TPL_TYPE_0 = "0";
|
||||||
|
public static final String SMS_TPL_TYPE_1 = "1";
|
||||||
|
public static final String SMS_TPL_TYPE_2 = "2";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0无效1有效)
|
||||||
|
*/
|
||||||
|
public static final String STATUS_0 = "0";
|
||||||
|
public static final String STATUS_1 = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步工作流引擎1同步0不同步
|
||||||
|
*/
|
||||||
|
public static final Integer ACT_SYNC_1 = 1;
|
||||||
|
public static final Integer ACT_SYNC_0 = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息类型1:通知公告2:系统消息
|
||||||
|
*/
|
||||||
|
public static final String MSG_CATEGORY_1 = "1";
|
||||||
|
public static final String MSG_CATEGORY_2 = "2";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否配置菜单的数据权限 1是0否
|
||||||
|
*/
|
||||||
|
public static final Integer RULE_FLAG_0 = 0;
|
||||||
|
public static final Integer RULE_FLAG_1 = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否用户已被冻结 1正常(解冻) 2冻结
|
||||||
|
*/
|
||||||
|
public static final Integer USER_UNFREEZE = 1;
|
||||||
|
public static final Integer USER_FREEZE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典翻译文本后缀
|
||||||
|
*/
|
||||||
|
public static final String DICT_TEXT_SUFFIX = "_dictText";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传类型(本地:local,Minio:minio,阿里云:alioss)
|
||||||
|
*/
|
||||||
|
public static final String UPLOAD_TYPE_LOCAL = "local";
|
||||||
|
public static final String UPLOAD_TYPE_MINIO = "minio";
|
||||||
|
public static final String UPLOAD_TYPE_OSS = "alioss";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sys_quartz_job 表 job_class_name 唯一键索引
|
||||||
|
*/
|
||||||
|
public static final String SQL_INDEX_UNIQ_JOB_CLASS_NAME = "uniq_job_class_name";
|
||||||
|
/**
|
||||||
|
* sys_position 表 code 唯一键索引
|
||||||
|
*/
|
||||||
|
public static final String SQL_INDEX_UNIQ_CODE = "uniq_code";
|
||||||
|
/**
|
||||||
|
* sys_role 表 code 唯一键索引
|
||||||
|
*/
|
||||||
|
public static final String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code";
|
||||||
|
/**
|
||||||
|
* sys_depart 表 code 唯一键索引
|
||||||
|
*/
|
||||||
|
public static final String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code";
|
||||||
|
/**
|
||||||
|
* sys_category 表 code 唯一键索引
|
||||||
|
*/
|
||||||
|
public static final String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code";
|
||||||
|
|
||||||
|
|
||||||
|
public final static String X_ACCESS_TOKEN = "X-Access-Token";
|
||||||
|
public final static String X_SIGN = "X-Sign";
|
||||||
|
public final static String X_TIMESTAMP = "X-TIMESTAMP";
|
||||||
|
public final static String TOKEN_IS_INVALID_MSG = "Token失效,请重新登录!";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户 请求头
|
||||||
|
*/
|
||||||
|
public final static String TENANT_ID = "tenant-id";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微服务读取配置文件属性 服务地址
|
||||||
|
*/
|
||||||
|
public final static String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登录 验证密码/创建用户 都需要设置一个操作码 防止被恶意调用
|
||||||
|
*/
|
||||||
|
public final static String THIRD_LOGIN_CODE = "third_login_code";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ONLINE 报表权限用 从request中获取地址栏后的参数
|
||||||
|
*/
|
||||||
|
String ONL_REP_URL_PARAM_STR = "onlRepUrlParamStr";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST请求
|
||||||
|
*/
|
||||||
|
String HTTP_POST = "POST";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PUT请求
|
||||||
|
*/
|
||||||
|
String HTTP_PUT = "PUT";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PATCH请求
|
||||||
|
*/
|
||||||
|
String HTTP_PATCH = "PATCH";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未知的
|
||||||
|
*/
|
||||||
|
String UNKNOWN = "unknown";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串http
|
||||||
|
*/
|
||||||
|
String STR_HTTP = "http";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String 类型的空值
|
||||||
|
*/
|
||||||
|
String STRING_NULL = "null";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* .do
|
||||||
|
*/
|
||||||
|
String SPOT_DO = ".do";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.constants;
|
||||||
|
|
||||||
|
public interface Face3dSeverHTTPConstant {
|
||||||
|
|
||||||
|
public static final String SWAP_UNDERWEAR = "http://192.168.11.219:8009/cloth/swapInner";
|
||||||
|
|
||||||
|
public static final String FIGURE_UPLOAD = "http://service.aicloud.fit:6068/bodyManager";
|
||||||
|
|
||||||
|
public static final String HAIR_UPLOAD = "http://service.aicloud.fit:7393/api/uploadHair/v1";
|
||||||
|
|
||||||
|
public static final String SWAP_HAIR_v1 = "http://service.aicloud.fit:7393/api/swapHair/v1";
|
||||||
|
|
||||||
|
public static final String SWAP_HAIR_v2 = "http://service.aicloud.fit:7393/api/swapHair/v2";
|
||||||
|
|
||||||
|
public static final String CLOTH_UPLOAD = "http://192.168.11.219:8009/cloth/upload";
|
||||||
|
|
||||||
|
public static final String SWAP_CLOTH = "http://192.168.11.219:8009/cloth/swap";
|
||||||
|
|
||||||
|
public static final String SWAP_CLOTH_MALE = "http://192.168.11.219:8009/cloth/swapMan";
|
||||||
|
|
||||||
|
public static final String CRAWLER_VIP = "http://192.168.11.138:9100/api/crawler_vip/v1";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DRAFT:草稿 IN_PROGRESS:制作中 IN_PROGRESS_FAIL:制作中 SUCCESS:制作成功 FAIL:制作失败
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static final String CREATE_STATUS_CANCEL = "CANCEL";
|
||||||
|
|
||||||
|
public static final String CREATE_STATUS_DRAFT = "DRAFT";
|
||||||
|
|
||||||
|
public static final String CREATE_STATUS_IN_PROGRESS = "IN_PROGRESS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DRAFT:草稿 IN_PROGRESS:制作中 IN_PROGRESS_FAIL:制作中 SUCCESS:制作成功 FAIL:制作失败
|
||||||
|
*/
|
||||||
|
public static final String CREATE_STATUS_SUCCESS = "SUCCESS";
|
||||||
|
/**
|
||||||
|
* DRAFT:草稿 IN_PROGRESS:制作中 IN_PROGRESS_FAIL:制作中 SUCCESS:制作成功 FAIL:制作失败
|
||||||
|
*/
|
||||||
|
public static final String CREATE_STATUS_FAIL = "FAIL";
|
||||||
|
|
||||||
|
public static final String result_success = "success";
|
||||||
|
|
||||||
|
public static final String result_fail = "FAIL";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 共享盘 存 衣服
|
||||||
|
*/
|
||||||
|
public static final String UPLOADED_FOLDER_CLOTH = "/cloth/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 共享盘 存 模特
|
||||||
|
*/
|
||||||
|
public static final String UPLOADED_FOLDER_MODEL = "/model/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 共享盘 存 平铺图
|
||||||
|
*/
|
||||||
|
public static final String UPLOADED_FOLDER_TILE = "/tile/";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Copyright (c) 2019-2020, 冷冷 (wangiegie@gmail.com).
|
||||||
|
* * <p>
|
||||||
|
* * Licensed under the GNU Lesser General Public License 3.0 (the "License");
|
||||||
|
* * you may not use this file except in compliance with the License.
|
||||||
|
* * You may obtain a copy of the License at
|
||||||
|
* * <p>
|
||||||
|
* * https://www.gnu.org/licenses/lgpl.html
|
||||||
|
* * <p>
|
||||||
|
* * Unless required by applicable law or agreed to in writing, software
|
||||||
|
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* * See the License for the specific language governing permissions and
|
||||||
|
* * limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cn.iocoder.yudao.framework.common.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author scott
|
||||||
|
* @date 2019年05月18日
|
||||||
|
* 服务名称
|
||||||
|
*/
|
||||||
|
public interface ServiceNameConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微服务名:系统管理模块
|
||||||
|
*/
|
||||||
|
String SERVICE_SYSTEM = "jeecg-system";
|
||||||
|
/**
|
||||||
|
* 微服务名:Demo模块
|
||||||
|
*/
|
||||||
|
String SERVICE_DEMO = "jeecg-demo";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gateway通过header传递根路径 basePath
|
||||||
|
*/
|
||||||
|
String X_GATEWAY_BASE_PATH = "X_GATEWAY_BASE_PATH";
|
||||||
|
|
||||||
|
}
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 符号和特殊符号常用类
|
||||||
|
* @author: wangshuai
|
||||||
|
* @date: 2022年03月30日 17:44
|
||||||
|
*/
|
||||||
|
public class SymbolConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:点
|
||||||
|
*/
|
||||||
|
public static final String SPOT = ".";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:双斜杠
|
||||||
|
*/
|
||||||
|
public static final String DOUBLE_BACKSLASH = "\\";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:冒号
|
||||||
|
*/
|
||||||
|
public static final String COLON = ":";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:逗号
|
||||||
|
*/
|
||||||
|
public static final String COMMA = ",";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:左花括号 }
|
||||||
|
*/
|
||||||
|
public static final String LEFT_CURLY_BRACKET = "{";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:右花括号 }
|
||||||
|
*/
|
||||||
|
public static final String RIGHT_CURLY_BRACKET = "}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:井号 #
|
||||||
|
*/
|
||||||
|
public static final String WELL_NUMBER = "#";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:单斜杠
|
||||||
|
*/
|
||||||
|
public static final String SINGLE_SLASH = "/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:双斜杠
|
||||||
|
*/
|
||||||
|
public static final String DOUBLE_SLASH = "//";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:感叹号
|
||||||
|
*/
|
||||||
|
public static final String EXCLAMATORY_MARK = "!";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:下划线
|
||||||
|
*/
|
||||||
|
public static final String UNDERLINE = "_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:单引号
|
||||||
|
*/
|
||||||
|
public static final String SINGLE_QUOTATION_MARK = "'";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:星号
|
||||||
|
*/
|
||||||
|
public static final String ASTERISK = "*";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:百分号
|
||||||
|
*/
|
||||||
|
public static final String PERCENT_SIGN = "%";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:美元 $
|
||||||
|
*/
|
||||||
|
public static final String DOLLAR = "$";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:和 &
|
||||||
|
*/
|
||||||
|
public static final String AND = "&";
|
||||||
|
}
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.constants;
|
||||||
|
|
||||||
|
public interface ZitaCommonConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别男
|
||||||
|
*/
|
||||||
|
public static final String sex_male = "male";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别女
|
||||||
|
*/
|
||||||
|
public static final String sex_female = "female";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别男 hairs
|
||||||
|
*/
|
||||||
|
public static final String sex_male_hairs = "[\"nan_tf_69\", \"nan_tf_92\", \"nan_tf_102\", \"nan_tf_142\", \"nan_tf_129\"]";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别女 hairs
|
||||||
|
*/
|
||||||
|
public static final String sex_female_hairs ="[\"nv_tf_128\", \"nv_tf_175\", \"nv_tf_132\", \"nv_tf_159\", \"nv_tf_161\"]";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正常状态
|
||||||
|
*/
|
||||||
|
public static final String STATUS_NORMAL = "200";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成图片和模型 1
|
||||||
|
*/
|
||||||
|
public static final String TASK_TYPE_PICTURE = "1";
|
||||||
|
/**
|
||||||
|
* 生成视频 2
|
||||||
|
*/
|
||||||
|
public static final String TASK_TYPE_VIDEO = "2";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新用户注册送5次试用机会
|
||||||
|
*/
|
||||||
|
public static final Integer New_register_member_try_times = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买卡类型-试用
|
||||||
|
*/
|
||||||
|
public static final String MEMBER_TYPE_TRY_CARD = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买卡类型-次卡
|
||||||
|
*/
|
||||||
|
public static final String MEMBER_TYPE_SUB_CARD = "2";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买卡类型-月卡
|
||||||
|
*/
|
||||||
|
public static final String MEMBER_TYPE_MONTH_CARD = "3";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买卡类型-年卡
|
||||||
|
*/
|
||||||
|
public static final String MEMBER_TYPE_YEAR_CARD = "4";
|
||||||
|
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可生成 T 数组的接口
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
public interface ArrayValuable<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 数组
|
||||||
|
*/
|
||||||
|
T[] array();
|
||||||
|
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.core;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Value 的键值对
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class KeyValue<K, V> implements Serializable {
|
||||||
|
|
||||||
|
private K key;
|
||||||
|
private V value;
|
||||||
|
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.enums;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用状态枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum CommonStatusEnum implements ArrayValuable<Integer> {
|
||||||
|
|
||||||
|
ENABLE(0, "开启"),
|
||||||
|
DISABLE(1, "关闭");
|
||||||
|
|
||||||
|
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CommonStatusEnum::getStatus).toArray(Integer[]::new);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态值
|
||||||
|
*/
|
||||||
|
private final Integer status;
|
||||||
|
/**
|
||||||
|
* 状态名
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer[] array() {
|
||||||
|
return ARRAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEnable(Integer status) {
|
||||||
|
return ObjUtil.equal(ENABLE.status, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDisable(Integer status) {
|
||||||
|
return ObjUtil.equal(DISABLE.status, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.enums;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间间隔的枚举
|
||||||
|
*
|
||||||
|
* @author dhb52
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum DateIntervalEnum implements ArrayValuable<Integer> {
|
||||||
|
|
||||||
|
HOUR(0, "小时"), // 特殊:字典里,暂时不会有这个枚举!!!因为大多数情况下,用不到这个间隔
|
||||||
|
DAY(1, "天"),
|
||||||
|
WEEK(2, "周"),
|
||||||
|
MONTH(3, "月"),
|
||||||
|
QUARTER(4, "季度"),
|
||||||
|
YEAR(5, "年")
|
||||||
|
;
|
||||||
|
|
||||||
|
public static final Integer[] ARRAYS = Arrays.stream(values()).map(DateIntervalEnum::getInterval).toArray(Integer[]::new);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final Integer interval;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer[] array() {
|
||||||
|
return ARRAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateIntervalEnum valueOf(Integer interval) {
|
||||||
|
return ArrayUtil.firstMatch(item -> item.getInterval().equals(interval), DateIntervalEnum.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文档地址
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum DocumentEnum {
|
||||||
|
|
||||||
|
REDIS_INSTALL("https://gitee.com/zhijiantianya/ruoyi-vue-pro/issues/I4VCSJ", "Redis 安装文档"),
|
||||||
|
TENANT("https://doc.iocoder.cn", "SaaS 多租户文档");
|
||||||
|
|
||||||
|
private final String url;
|
||||||
|
private final String memo;
|
||||||
|
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RPC 相关的枚举
|
||||||
|
*
|
||||||
|
* 虽然放在 yudao-spring-boot-starter-rpc 会相对合适,但是每个 API 模块需要使用到,所以暂时只好放在此处
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class RpcConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RPC API 的前缀
|
||||||
|
*/
|
||||||
|
public static final String RPC_API_PREFIX = "/rpc-api";
|
||||||
|
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.enums;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端的枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum TerminalEnum implements ArrayValuable<Integer> {
|
||||||
|
|
||||||
|
UNKNOWN(0, "未知"), // 目的:在无法解析到 terminal 时,使用它
|
||||||
|
WECHAT_MINI_PROGRAM(10, "微信小程序"),
|
||||||
|
WECHAT_WAP(11, "微信公众号"),
|
||||||
|
H5(20, "H5 网页"),
|
||||||
|
APP(31, "手机 App"),
|
||||||
|
;
|
||||||
|
|
||||||
|
public static final Integer[] ARRAYS = Arrays.stream(values()).map(TerminalEnum::getTerminal).toArray(Integer[]::new);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端
|
||||||
|
*/
|
||||||
|
private final Integer terminal;
|
||||||
|
/**
|
||||||
|
* 终端名
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer[] array() {
|
||||||
|
return ARRAYS;
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.enums;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局用户类型枚举
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum UserTypeEnum implements ArrayValuable<Integer> {
|
||||||
|
|
||||||
|
MEMBER(1, "会员"), // 面向 c 端,普通用户
|
||||||
|
ADMIN(2, "管理员"); // 面向 b 端,管理后台
|
||||||
|
|
||||||
|
public static final Integer[] ARRAYS = Arrays.stream(values()).map(UserTypeEnum::getValue).toArray(Integer[]::new);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final Integer value;
|
||||||
|
/**
|
||||||
|
* 类型名
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static UserTypeEnum valueOf(Integer value) {
|
||||||
|
return ArrayUtil.firstMatch(userType -> userType.getValue().equals(value), UserTypeEnum.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer[] array() {
|
||||||
|
return ARRAYS;
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期
|
||||||
|
*
|
||||||
|
* 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 enums 包下
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface WebFilterOrderEnum {
|
||||||
|
|
||||||
|
int CORS_FILTER = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
int TRACE_FILTER = CORS_FILTER + 1;
|
||||||
|
|
||||||
|
int REQUEST_BODY_CACHE_FILTER = Integer.MIN_VALUE + 500;
|
||||||
|
|
||||||
|
int API_ENCRYPT_FILTER = REQUEST_BODY_CACHE_FILTER + 1;
|
||||||
|
|
||||||
|
// OrderedRequestContextFilter 默认为 -105,用于国际化上下文等等
|
||||||
|
|
||||||
|
int TENANT_CONTEXT_FILTER = - 104; // 需要保证在 ApiAccessLogFilter 前面
|
||||||
|
|
||||||
|
int API_ACCESS_LOG_FILTER = -103; // 需要保证在 RequestBodyCacheFilter 后面
|
||||||
|
|
||||||
|
int XSS_FILTER = -102; // 需要保证在 RequestBodyCacheFilter 后面
|
||||||
|
|
||||||
|
// Spring Security Filter 默认为 -100,可见 org.springframework.boot.autoconfigure.security.SecurityProperties 配置属性类
|
||||||
|
|
||||||
|
int TENANT_SECURITY_FILTER = -99; // 需要保证在 Spring Security 过滤器后面
|
||||||
|
|
||||||
|
int FLOWABLE_FILTER = -98; // 需要保证在 Spring Security 过滤后面
|
||||||
|
|
||||||
|
int DEMO_FILTER = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.exception;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.ServiceErrorCodeRange;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码对象
|
||||||
|
*
|
||||||
|
* 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants}
|
||||||
|
* 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange}
|
||||||
|
*
|
||||||
|
* TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ErrorCode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*/
|
||||||
|
private final Integer code;
|
||||||
|
/**
|
||||||
|
* 错误提示
|
||||||
|
*/
|
||||||
|
private final String msg;
|
||||||
|
|
||||||
|
public ErrorCode(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.msg = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.exception;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器异常 Exception
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public final class ServerException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局错误码
|
||||||
|
*
|
||||||
|
* @see GlobalErrorCodeConstants
|
||||||
|
*/
|
||||||
|
private Integer code;
|
||||||
|
/**
|
||||||
|
* 错误提示
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空构造方法,避免反序列化问题
|
||||||
|
*/
|
||||||
|
public ServerException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerException(ErrorCode errorCode) {
|
||||||
|
this.code = errorCode.getCode();
|
||||||
|
this.message = errorCode.getMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerException(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerException setCode(Integer code) {
|
||||||
|
this.code = code;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerException setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.exception;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.ServiceErrorCodeRange;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务逻辑异常 Exception
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public final class ServiceException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务错误码
|
||||||
|
*
|
||||||
|
* @see ServiceErrorCodeRange
|
||||||
|
*/
|
||||||
|
private Integer code;
|
||||||
|
/**
|
||||||
|
* 错误提示
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空构造方法,避免反序列化问题
|
||||||
|
*/
|
||||||
|
public ServiceException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException(ErrorCode errorCode) {
|
||||||
|
this.code = errorCode.getCode();
|
||||||
|
this.message = errorCode.getMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException setCode(Integer code) {
|
||||||
|
this.code = code;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.exception.enums;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局错误码枚举
|
||||||
|
* 0-999 系统异常编码保留
|
||||||
|
*
|
||||||
|
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
|
||||||
|
* 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
|
||||||
|
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface GlobalErrorCodeConstants {
|
||||||
|
|
||||||
|
ErrorCode SUCCESS = new ErrorCode(0, "成功");
|
||||||
|
|
||||||
|
// ========== 客户端错误段 ==========
|
||||||
|
|
||||||
|
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
|
||||||
|
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
|
||||||
|
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
|
||||||
|
ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到");
|
||||||
|
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
|
||||||
|
ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
|
||||||
|
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
|
||||||
|
|
||||||
|
// ========== 服务端错误段 ==========
|
||||||
|
|
||||||
|
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
|
||||||
|
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
|
||||||
|
ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "错误的配置项");
|
||||||
|
|
||||||
|
// ========== 自定义错误段 ==========
|
||||||
|
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
|
||||||
|
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
|
||||||
|
|
||||||
|
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
||||||
|
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.exception.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务异常的错误码区间,解决:解决各模块错误码定义,避免重复,在此只声明不做实际使用
|
||||||
|
*
|
||||||
|
* 一共 10 位,分成四段
|
||||||
|
*
|
||||||
|
* 第一段,1 位,类型
|
||||||
|
* 1 - 业务级别异常
|
||||||
|
* x - 预留
|
||||||
|
* 第二段,3 位,系统类型
|
||||||
|
* 001 - 用户系统
|
||||||
|
* 002 - 商品系统
|
||||||
|
* 003 - 订单系统
|
||||||
|
* 004 - 支付系统
|
||||||
|
* 005 - 优惠劵系统
|
||||||
|
* ... - ...
|
||||||
|
* 第三段,3 位,模块
|
||||||
|
* 不限制规则。
|
||||||
|
* 一般建议,每个系统里面,可能有多个模块,可以再去做分段。以用户系统为例子:
|
||||||
|
* 001 - OAuth2 模块
|
||||||
|
* 002 - User 模块
|
||||||
|
* 003 - MobileCode 模块
|
||||||
|
* 第四段,3 位,错误码
|
||||||
|
* 不限制规则。
|
||||||
|
* 一般建议,每个模块自增。
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class ServiceErrorCodeRange {
|
||||||
|
|
||||||
|
// 模块 infra 错误码区间 [1-001-000-000 ~ 1-002-000-000)
|
||||||
|
// 模块 system 错误码区间 [1-002-000-000 ~ 1-003-000-000)
|
||||||
|
// 模块 report 错误码区间 [1-003-000-000 ~ 1-004-000-000)
|
||||||
|
// 模块 member 错误码区间 [1-004-000-000 ~ 1-005-000-000)
|
||||||
|
// 模块 mp 错误码区间 [1-006-000-000 ~ 1-007-000-000)
|
||||||
|
// 模块 pay 错误码区间 [1-007-000-000 ~ 1-008-000-000)
|
||||||
|
// 模块 bpm 错误码区间 [1-009-000-000 ~ 1-010-000-000)
|
||||||
|
|
||||||
|
// 模块 product 错误码区间 [1-008-000-000 ~ 1-009-000-000)
|
||||||
|
// 模块 trade 错误码区间 [1-011-000-000 ~ 1-012-000-000)
|
||||||
|
// 模块 promotion 错误码区间 [1-013-000-000 ~ 1-014-000-000)
|
||||||
|
|
||||||
|
// 模块 crm 错误码区间 [1-020-000-000 ~ 1-021-000-000)
|
||||||
|
|
||||||
|
// 模块 ai 错误码区间 [1-022-000-000 ~ 1-023-000-000)
|
||||||
|
|
||||||
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.exception.util;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ServiceException} 工具类
|
||||||
|
*
|
||||||
|
* 目的在于,格式化异常信息提示。
|
||||||
|
* 考虑到 String.format 在参数不正确时会报错,因此使用 {} 作为占位符,并使用 {@link #doFormat(int, String, Object...)} 方法来格式化
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class ServiceExceptionUtil {
|
||||||
|
|
||||||
|
// ========== 和 ServiceException 的集成 ==========
|
||||||
|
|
||||||
|
public static ServiceException exception(ErrorCode errorCode) {
|
||||||
|
return exception0(errorCode.getCode(), errorCode.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServiceException exception(ErrorCode errorCode, Object... params) {
|
||||||
|
return exception0(errorCode.getCode(), errorCode.getMsg(), params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServiceException exception0(Integer code, String messagePattern, Object... params) {
|
||||||
|
String message = doFormat(code, messagePattern, params);
|
||||||
|
return new ServiceException(code, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServiceException invalidParamException(String messagePattern, Object... params) {
|
||||||
|
return exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), messagePattern, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 格式化方法 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将错误编号对应的消息使用 params 进行格式化。
|
||||||
|
*
|
||||||
|
* @param code 错误编号
|
||||||
|
* @param messagePattern 消息模版
|
||||||
|
* @param params 参数
|
||||||
|
* @return 格式化后的提示
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public static String doFormat(int code, String messagePattern, Object... params) {
|
||||||
|
StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
|
||||||
|
int i = 0;
|
||||||
|
int j;
|
||||||
|
int l;
|
||||||
|
for (l = 0; l < params.length; l++) {
|
||||||
|
j = messagePattern.indexOf("{}", i);
|
||||||
|
if (j == -1) {
|
||||||
|
log.error("[doFormat][参数过多:错误码({})|错误内容({})|参数({})", code, messagePattern, params);
|
||||||
|
if (i == 0) {
|
||||||
|
return messagePattern;
|
||||||
|
} else {
|
||||||
|
sbuf.append(messagePattern.substring(i));
|
||||||
|
return sbuf.toString();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sbuf.append(messagePattern, i, j);
|
||||||
|
sbuf.append(params[l]);
|
||||||
|
i = j + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (messagePattern.indexOf("{}", i) != -1) {
|
||||||
|
log.error("[doFormat][参数过少:错误码({})|错误内容({})|参数({})", code, messagePattern, params);
|
||||||
|
}
|
||||||
|
sbuf.append(messagePattern.substring(i));
|
||||||
|
return sbuf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* 基础的通用类,和框架无关
|
||||||
|
*
|
||||||
|
* 例如说,CommonResult 为通用返回
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.framework.common;
|
||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.pojo;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用返回
|
||||||
|
*
|
||||||
|
* @param <T> 数据泛型
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CommonResult<T> implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*
|
||||||
|
* @see ErrorCode#getCode()
|
||||||
|
*/
|
||||||
|
private Integer code;
|
||||||
|
/**
|
||||||
|
* 错误提示,用户可阅读
|
||||||
|
*
|
||||||
|
* @see ErrorCode#getMsg() ()
|
||||||
|
*/
|
||||||
|
private String msg;
|
||||||
|
/**
|
||||||
|
* 返回数据
|
||||||
|
*/
|
||||||
|
private T data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将传入的 result 对象,转换成另外一个泛型结果的对象
|
||||||
|
*
|
||||||
|
* 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
|
||||||
|
*
|
||||||
|
* @param result 传入的 result 对象
|
||||||
|
* @param <T> 返回的泛型
|
||||||
|
* @return 新的 CommonResult 对象
|
||||||
|
*/
|
||||||
|
public static <T> CommonResult<T> error(CommonResult<?> result) {
|
||||||
|
return error(result.getCode(), result.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommonResult<T> error(Integer code, String message) {
|
||||||
|
Assert.notEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), code, "code 必须是错误的!");
|
||||||
|
CommonResult<T> result = new CommonResult<>();
|
||||||
|
result.code = code;
|
||||||
|
result.msg = message;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommonResult<T> error(ErrorCode errorCode, Object... params) {
|
||||||
|
Assert.notEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), errorCode.getCode(), "code 必须是错误的!");
|
||||||
|
CommonResult<T> result = new CommonResult<>();
|
||||||
|
result.code = errorCode.getCode();
|
||||||
|
result.msg = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMsg(), params);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommonResult<T> error(ErrorCode errorCode) {
|
||||||
|
return error(errorCode.getCode(), errorCode.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommonResult<T> success(T data) {
|
||||||
|
CommonResult<T> result = new CommonResult<>();
|
||||||
|
result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
|
||||||
|
result.data = data;
|
||||||
|
result.msg = "";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSuccess(Integer code) {
|
||||||
|
return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore // 避免 jackson 序列化
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return isSuccess(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore // 避免 jackson 序列化
|
||||||
|
public boolean isError() {
|
||||||
|
return !isSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========= 和 Exception 异常体系集成 =========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
|
||||||
|
*/
|
||||||
|
public void checkError() throws ServiceException {
|
||||||
|
if (isSuccess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 业务异常
|
||||||
|
throw new ServiceException(code, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
|
||||||
|
* 如果没有,则返回 {@link #data} 数据
|
||||||
|
*/
|
||||||
|
@JsonIgnore // 避免 jackson 序列化
|
||||||
|
public T getCheckedData() {
|
||||||
|
checkError();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CommonResult<T> error(ServiceException serviceException) {
|
||||||
|
return error(serviceException.getCode(), serviceException.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.pojo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.Max;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Schema(description="分页参数")
|
||||||
|
@Data
|
||||||
|
public class PageParam implements Serializable {
|
||||||
|
|
||||||
|
private static final Integer PAGE_NO = 1;
|
||||||
|
private static final Integer PAGE_SIZE = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每页条数 - 不分页
|
||||||
|
*
|
||||||
|
* 例如说,导出接口,可以设置 {@link #pageSize} 为 -1 不分页,查询所有数据。
|
||||||
|
*/
|
||||||
|
public static final Integer PAGE_SIZE_NONE = -1;
|
||||||
|
|
||||||
|
@Schema(description = "页码,从 1 开始", requiredMode = Schema.RequiredMode.REQUIRED,example = "1")
|
||||||
|
@NotNull(message = "页码不能为空")
|
||||||
|
@Min(value = 1, message = "页码最小值为 1")
|
||||||
|
private Integer pageNo = PAGE_NO;
|
||||||
|
|
||||||
|
@Schema(description = "每页条数,最大值为 100", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||||
|
@NotNull(message = "每页条数不能为空")
|
||||||
|
@Min(value = 1, message = "每页条数最小值为 1")
|
||||||
|
@Max(value = 100, message = "每页条数最大值为 100")
|
||||||
|
private Integer pageSize = PAGE_SIZE;
|
||||||
|
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.pojo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "分页结果")
|
||||||
|
@Data
|
||||||
|
public final class PageResult<T> implements Serializable {
|
||||||
|
|
||||||
|
@Schema(description = "总量", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Long total;
|
||||||
|
|
||||||
|
@Schema(description = "数据", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private List<T> list;
|
||||||
|
|
||||||
|
public PageResult() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageResult(List<T> list, Long total) {
|
||||||
|
this.list = list;
|
||||||
|
this.total = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageResult(Long total) {
|
||||||
|
this.list = new ArrayList<>();
|
||||||
|
this.total = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> PageResult<T> empty() {
|
||||||
|
return new PageResult<>(0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> PageResult<T> empty(Long total) {
|
||||||
|
return new PageResult<>(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.pojo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "可排序的分页参数")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class SortablePageParam extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "排序字段")
|
||||||
|
private List<SortingField> sortingFields;
|
||||||
|
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.pojo;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序字段 DTO
|
||||||
|
*
|
||||||
|
* 类名加了 ing 的原因是,避免和 ES SortField 重名。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SortingField implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顺序 - 升序
|
||||||
|
*/
|
||||||
|
public static final String ORDER_ASC = "asc";
|
||||||
|
/**
|
||||||
|
* 顺序 - 降序
|
||||||
|
*/
|
||||||
|
public static final String ORDER_DESC = "desc";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段
|
||||||
|
*/
|
||||||
|
private String field;
|
||||||
|
/**
|
||||||
|
* 顺序
|
||||||
|
*/
|
||||||
|
private String order;
|
||||||
|
|
||||||
|
}
|
||||||
+394
@@ -0,0 +1,394 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||||
|
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用 Restful 接口 Util
|
||||||
|
*
|
||||||
|
* @author sunjianlei
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RestUtil {
|
||||||
|
|
||||||
|
// 服务实例缓存,用于负载均衡
|
||||||
|
private static final Map<String, String[]> serviceInstances = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 负载均衡计数器
|
||||||
|
private static final Map<String, AtomicInteger> serviceCounters = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private static String domain = null;
|
||||||
|
|
||||||
|
public static String getDomain() {
|
||||||
|
if (domain == null) {
|
||||||
|
domain = SpringContextUtils.getDomain();
|
||||||
|
// issues/2959
|
||||||
|
// 微服务版集成企业微信单点登录
|
||||||
|
// 因为微服务版没有端口号,导致 SpringContextUtils.getDomain() 方法获取的域名的端口号变成了:-1所以出问题了,只需要把这个-1给去掉就可以了。
|
||||||
|
String port=":-1";
|
||||||
|
if (domain.endsWith(port)) {
|
||||||
|
domain = domain.substring(0, domain.length() - 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String path = null;
|
||||||
|
|
||||||
|
public static String getPath() {
|
||||||
|
if (path == null) {
|
||||||
|
path = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("server.servlet.context-path");
|
||||||
|
}
|
||||||
|
return oConvertUtils.getString(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getBaseUrl() {
|
||||||
|
String basepath = getDomain() + getPath();
|
||||||
|
log.info(" RestUtil.getBaseUrl: " + basepath);
|
||||||
|
return basepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加服务实例,用于负载均衡
|
||||||
|
* @param serviceName 服务名称
|
||||||
|
* @param instances 服务实例地址数组,如 ["localhost:8081", "localhost:8082"]
|
||||||
|
*/
|
||||||
|
public static void addServiceInstance(String serviceName, String... instances) {
|
||||||
|
serviceInstances.put(serviceName, instances);
|
||||||
|
serviceCounters.putIfAbsent(serviceName, new AtomicInteger(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除服务实例
|
||||||
|
* @param serviceName 服务名称
|
||||||
|
*/
|
||||||
|
public static void removeServiceInstance(String serviceName) {
|
||||||
|
serviceInstances.remove(serviceName);
|
||||||
|
serviceCounters.remove(serviceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RestAPI 调用器 (移除 @LoadBalanced 注解)
|
||||||
|
*/
|
||||||
|
private final static RestTemplate RT;
|
||||||
|
|
||||||
|
static {
|
||||||
|
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||||
|
requestFactory.setConnectTimeout(7200*1000);
|
||||||
|
requestFactory.setReadTimeout(7200*1000);
|
||||||
|
RT = new RestTemplate(requestFactory);
|
||||||
|
// 解决乱码问题
|
||||||
|
RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RestTemplate getRestTemplate() {
|
||||||
|
return RT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析URL并应用负载均衡
|
||||||
|
* 将 http://service-name/path 转换为 http://actual-host:port/path
|
||||||
|
* @param url 原始URL
|
||||||
|
* @return 解析后的URL
|
||||||
|
*/
|
||||||
|
private static String resolveUrlWithLoadBalance(String url) {
|
||||||
|
// 检查是否是服务名URL (例如: http://service-name/path)
|
||||||
|
if (url.startsWith("http://")) {
|
||||||
|
String withoutProtocol = url.substring(7);
|
||||||
|
int slashIndex = withoutProtocol.indexOf('/');
|
||||||
|
if (slashIndex > 0) {
|
||||||
|
String serviceName = withoutProtocol.substring(0, slashIndex);
|
||||||
|
// 检查是否有该服务的实例
|
||||||
|
if (serviceInstances.containsKey(serviceName)) {
|
||||||
|
// 使用轮询算法选择实例
|
||||||
|
String[] instances = serviceInstances.get(serviceName);
|
||||||
|
AtomicInteger counter = serviceCounters.get(serviceName);
|
||||||
|
int index = Math.abs(counter.getAndIncrement()) % instances.length;
|
||||||
|
String selectedInstance = instances[index];
|
||||||
|
// 替换服务名为实际地址
|
||||||
|
return "http://" + selectedInstance + withoutProtocol.substring(slashIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 get 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject get(String url) {
|
||||||
|
return getNative(url, null, null).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 get 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject get(String url, JSONObject variables) {
|
||||||
|
return getNative(url, variables, null).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 get 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject get(String url, JSONObject variables, JSONObject params) {
|
||||||
|
return getNative(url, variables, params).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 get 请求,返回原生 ResponseEntity 对象
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<JSONObject> getNative(String url, JSONObject variables, JSONObject params) {
|
||||||
|
return request(url, HttpMethod.GET, variables, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 Post 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject post(String url) {
|
||||||
|
return postNative(url, null, null).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 Post 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject post(String url, JSONObject params) {
|
||||||
|
return postNative(url, null, params).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 Post 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject post(String url, JSONObject variables, JSONObject params) {
|
||||||
|
return postNative(url, variables, params).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 POST 请求,返回原生 ResponseEntity 对象
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<JSONObject> postNative(String url, JSONObject variables, JSONObject params) {
|
||||||
|
return request(url, HttpMethod.POST, variables, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 put 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject put(String url) {
|
||||||
|
return putNative(url, null, null).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 put 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject put(String url, JSONObject params) {
|
||||||
|
return putNative(url, null, params).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 put 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject put(String url, JSONObject variables, JSONObject params) {
|
||||||
|
return putNative(url, variables, params).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 put 请求,返回原生 ResponseEntity 对象
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<JSONObject> putNative(String url, JSONObject variables, JSONObject params) {
|
||||||
|
return request(url, HttpMethod.PUT, variables, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 delete 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject delete(String url) {
|
||||||
|
return deleteNative(url, null, null).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 delete 请求
|
||||||
|
*/
|
||||||
|
public static JSONObject delete(String url, JSONObject variables, JSONObject params) {
|
||||||
|
return deleteNative(url, variables, params).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 delete 请求,返回原生 ResponseEntity 对象
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<JSONObject> deleteNative(String url, JSONObject variables, JSONObject params) {
|
||||||
|
return request(url, HttpMethod.DELETE, null, variables, params, JSONObject.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送请求
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<JSONObject> request(String url, HttpMethod method, JSONObject variables, JSONObject params) {
|
||||||
|
return request(url, method, getHeaderApplicationJson(), variables, params, JSONObject.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送请求
|
||||||
|
*
|
||||||
|
* @param url 请求地址
|
||||||
|
* @param method 请求方式
|
||||||
|
* @param headers 请求头 可空
|
||||||
|
* @param variables 请求url参数 可空
|
||||||
|
* @param params 请求body参数 可空
|
||||||
|
* @param responseType 返回类型
|
||||||
|
* @return ResponseEntity<responseType>
|
||||||
|
*/
|
||||||
|
public static <T> ResponseEntity<T> request(String url, HttpMethod method, HttpHeaders headers, JSONObject variables, Object params, Class<T> responseType) {
|
||||||
|
log.info(" RestUtil --- request --- url = "+ url);
|
||||||
|
if (StringUtils.isEmpty(url)) {
|
||||||
|
throw new RuntimeException("url 不能为空");
|
||||||
|
}
|
||||||
|
if (method == null) {
|
||||||
|
throw new RuntimeException("method 不能为空");
|
||||||
|
}
|
||||||
|
if (headers == null) {
|
||||||
|
headers = new HttpHeaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用负载均衡解析URL
|
||||||
|
String resolvedUrl = resolveUrlWithLoadBalance(url);
|
||||||
|
|
||||||
|
// 请求体
|
||||||
|
String body = "";
|
||||||
|
if (params != null) {
|
||||||
|
if (params instanceof JSONObject) {
|
||||||
|
body = ((JSONObject) params).toJSONString();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
body = params.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 拼接 url 参数
|
||||||
|
if (variables != null) {
|
||||||
|
resolvedUrl += ("?" + asUrlVariables(variables));
|
||||||
|
}
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<String> request = new HttpEntity<>(body, headers);
|
||||||
|
return RT.exchange(resolvedUrl, method, request, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResponseEntity<T> zitaRequest(String url, HttpMethod method,
|
||||||
|
HttpHeaders headers ,JSONObject variables,
|
||||||
|
Object params, Class<T> responseType) {
|
||||||
|
log.info(" RestUtil --- request --- url = "+ url);
|
||||||
|
if (StringUtils.isEmpty(url)) {
|
||||||
|
throw new RuntimeException("url 不能为空");
|
||||||
|
}
|
||||||
|
if (method == null) {
|
||||||
|
throw new RuntimeException("method 不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用负载均衡解析URL
|
||||||
|
String resolvedUrl = resolveUrlWithLoadBalance(url);
|
||||||
|
|
||||||
|
// 请求体
|
||||||
|
String body = "";
|
||||||
|
if (params != null) {
|
||||||
|
if (params instanceof JSONObject) {
|
||||||
|
body = ((JSONObject) params).toJSONString();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
body = params.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 拼接 url 参数
|
||||||
|
if (variables != null) {
|
||||||
|
resolvedUrl += ("?" + asUrlVariables(variables));
|
||||||
|
}
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<String> request = new HttpEntity<>(body, headers);
|
||||||
|
return RT.exchange(resolvedUrl, method, request, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> ResponseEntity<T> zitaRequest(String url, HttpMethod method ,JSONObject variables, Object params, Class<T> responseType) {
|
||||||
|
log.info(" RestUtil --- request --- url = "+ url);
|
||||||
|
if (StringUtils.isEmpty(url)) {
|
||||||
|
throw new RuntimeException("url 不能为空");
|
||||||
|
}
|
||||||
|
if (method == null) {
|
||||||
|
throw new RuntimeException("method 不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add("Content-Type","application/json;charset=UTF-8");
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
|
||||||
|
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
|
||||||
|
|
||||||
|
// 应用负载均衡解析URL
|
||||||
|
String resolvedUrl = resolveUrlWithLoadBalance(url);
|
||||||
|
|
||||||
|
// 请求体
|
||||||
|
String body = "";
|
||||||
|
if (params != null) {
|
||||||
|
if (params instanceof JSONObject) {
|
||||||
|
body = ((JSONObject) params).toJSONString();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
body = params.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 拼接 url 参数
|
||||||
|
if (variables != null) {
|
||||||
|
resolvedUrl += ("?" + asUrlVariables(variables));
|
||||||
|
}
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<String> request = new HttpEntity<>(body, headers);
|
||||||
|
return RT.exchange(resolvedUrl, method, request, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取JSON请求头
|
||||||
|
*/
|
||||||
|
public static HttpHeaders getHeaderApplicationJson() {
|
||||||
|
return getHeader(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求头
|
||||||
|
*/
|
||||||
|
public static HttpHeaders getHeader(String mediaType) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.parseMediaType(mediaType));
|
||||||
|
headers.add("Accept", mediaType);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 JSONObject 转为 a=1&b=2&c=3...&n=n 的形式
|
||||||
|
*/
|
||||||
|
public static String asUrlVariables(JSONObject variables) {
|
||||||
|
Map<String, Object> source = variables.getInnerMap();
|
||||||
|
Iterator<String> it = source.keySet().iterator();
|
||||||
|
StringBuilder urlVariables = new StringBuilder();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
String key = it.next();
|
||||||
|
String value = "";
|
||||||
|
Object object = source.get(key);
|
||||||
|
if (object != null) {
|
||||||
|
if (!StringUtils.isEmpty(object.toString())) {
|
||||||
|
value = object.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
urlVariables.append("&").append(key).append("=").append(value);
|
||||||
|
}
|
||||||
|
// 去掉第一个&
|
||||||
|
return urlVariables.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
package cn.iocoder.yudao.framework.common.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.
|
||||||
|
*
|
||||||
|
* @author zyf
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SpringContextHolder implements ApplicationContextAware {
|
||||||
|
private static ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||||
|
// NOSONAR
|
||||||
|
SpringContextHolder.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得存储在静态变量中的ApplicationContext.
|
||||||
|
*/
|
||||||
|
public static ApplicationContext getApplicationContext() {
|
||||||
|
checkApplicationContext();
|
||||||
|
return applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||||
|
*/
|
||||||
|
public static <T> T getBean(String name) {
|
||||||
|
checkApplicationContext();
|
||||||
|
return (T) applicationContext.getBean(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||||
|
*/
|
||||||
|
public static <T> T getHandler(String name, Class<T> cls) {
|
||||||
|
T t = null;
|
||||||
|
if (ObjectUtil.isNotEmpty(name)) {
|
||||||
|
checkApplicationContext();
|
||||||
|
try {
|
||||||
|
t = applicationContext.getBean(name, cls);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Customize redis listener handle [ " + name + " ], does not exist!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||||
|
*/
|
||||||
|
public static <T> T getBean(Class<T> clazz) {
|
||||||
|
checkApplicationContext();
|
||||||
|
return applicationContext.getBean(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除applicationContext静态变量.
|
||||||
|
*/
|
||||||
|
public static void cleanApplicationContext() {
|
||||||
|
applicationContext = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkApplicationContext() {
|
||||||
|
if (applicationContext == null) {
|
||||||
|
throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.constants.ServiceNameConstants;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: spring上下文工具类
|
||||||
|
* @author: smcp
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SpringContextUtils implements ApplicationContextAware {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上下文对象实例
|
||||||
|
*/
|
||||||
|
private static ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
SpringContextUtils.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取applicationContext
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static ApplicationContext getApplicationContext() {
|
||||||
|
return applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取HttpServletRequest
|
||||||
|
*/
|
||||||
|
public static HttpServletRequest getHttpServletRequest() {
|
||||||
|
if (RequestContextHolder.getRequestAttributes() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取HttpServletResponse
|
||||||
|
*/
|
||||||
|
public static HttpServletResponse getHttpServletResponse() {
|
||||||
|
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取项目根路径 basePath
|
||||||
|
*/
|
||||||
|
public static String getDomain(){
|
||||||
|
HttpServletRequest request = getHttpServletRequest();
|
||||||
|
StringBuffer url = request.getRequestURL();
|
||||||
|
//微服务情况下,获取gateway的basePath
|
||||||
|
String basePath = request.getHeader(ServiceNameConstants.X_GATEWAY_BASE_PATH);
|
||||||
|
if(oConvertUtils.isNotEmpty(basePath)){
|
||||||
|
return basePath;
|
||||||
|
}else{
|
||||||
|
return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getOrigin(){
|
||||||
|
HttpServletRequest request = getHttpServletRequest();
|
||||||
|
return request.getHeader("Origin");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过name获取 Bean.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Object getBean(String name) {
|
||||||
|
return getApplicationContext().getBean(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过class获取Bean.
|
||||||
|
*
|
||||||
|
* @param clazz
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> T getBean(Class<T> clazz) {
|
||||||
|
return getApplicationContext().getBean(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过name,以及Clazz返回指定的Bean
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param clazz
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> T getBean(String name, Class<T> clazz) {
|
||||||
|
return getApplicationContext().getBean(name, clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.cache;
|
||||||
|
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache 工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class CacheUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步刷新的 LoadingCache 最大缓存数量
|
||||||
|
*
|
||||||
|
* @see <a href="">本地缓存 CacheUtils 工具类建议</a>
|
||||||
|
*/
|
||||||
|
private static final Integer CACHE_MAX_SIZE = 10000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建异步刷新的 LoadingCache 对象
|
||||||
|
*
|
||||||
|
* 注意:如果你的缓存和 ThreadLocal 有关系,要么自己处理 ThreadLocal 的传递,要么使用 {@link #buildCache(Duration, CacheLoader)} 方法
|
||||||
|
*
|
||||||
|
* 或者简单理解:
|
||||||
|
* 1、和“人”相关的,使用 {@link #buildCache(Duration, CacheLoader)} 方法
|
||||||
|
* 2、和“全局”、“系统”相关的,使用当前缓存方法
|
||||||
|
*
|
||||||
|
* @param duration 过期时间
|
||||||
|
* @param loader CacheLoader 对象
|
||||||
|
* @return LoadingCache 对象
|
||||||
|
*/
|
||||||
|
public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(Duration duration, CacheLoader<K, V> loader) {
|
||||||
|
return CacheBuilder.newBuilder()
|
||||||
|
.maximumSize(CACHE_MAX_SIZE)
|
||||||
|
// 只阻塞当前数据加载线程,其他线程返回旧值
|
||||||
|
.refreshAfterWrite(duration)
|
||||||
|
// 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程
|
||||||
|
.build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿:可能要思考下,未来要不要做成可配置
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建同步刷新的 LoadingCache 对象
|
||||||
|
*
|
||||||
|
* @param duration 过期时间
|
||||||
|
* @param loader CacheLoader 对象
|
||||||
|
* @return LoadingCache 对象
|
||||||
|
*/
|
||||||
|
public static <K, V> LoadingCache<K, V> buildCache(Duration duration, CacheLoader<K, V> loader) {
|
||||||
|
return CacheBuilder.newBuilder()
|
||||||
|
.maximumSize(CACHE_MAX_SIZE)
|
||||||
|
// 只阻塞当前数据加载线程,其他线程返回旧值
|
||||||
|
.refreshAfterWrite(duration)
|
||||||
|
.build(loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.collection;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.collection.IterUtil;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array 工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class ArrayUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 object 和 newElements 合并成一个数组
|
||||||
|
*
|
||||||
|
* @param object 对象
|
||||||
|
* @param newElements 数组
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @return 结果数组
|
||||||
|
*/
|
||||||
|
@SafeVarargs
|
||||||
|
public static <T> Consumer<T>[] append(Consumer<T> object, Consumer<T>... newElements) {
|
||||||
|
if (object == null) {
|
||||||
|
return newElements;
|
||||||
|
}
|
||||||
|
Consumer<T>[] result = ArrayUtil.newArray(Consumer.class, 1 + newElements.length);
|
||||||
|
result[0] = object;
|
||||||
|
System.arraycopy(newElements, 0, result, 1, newElements.length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, V> V[] toArray(Collection<T> from, Function<T, V> mapper) {
|
||||||
|
return toArray(convertList(from, mapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> T[] toArray(Collection<T> from) {
|
||||||
|
if (CollectionUtil.isEmpty(from)) {
|
||||||
|
return (T[]) (new Object[0]);
|
||||||
|
}
|
||||||
|
return ArrayUtil.toArray(from, (Class<T>) IterUtil.getElementType(from.iterator()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T get(T[] array, int index) {
|
||||||
|
if (null == array || index >= array.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return array[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+352
@@ -0,0 +1,352 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.collection;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static cn.hutool.core.convert.Convert.toCollection;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection 工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class CollectionUtils {
|
||||||
|
|
||||||
|
public static boolean containsAny(Object source, Object... targets) {
|
||||||
|
return asList(targets).contains(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAnyEmpty(Collection<?>... collections) {
|
||||||
|
return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> boolean anyMatch(Collection<T> from, Predicate<T> predicate) {
|
||||||
|
return from.stream().anyMatch(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return from.stream().filter(predicate).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> List<T> distinct(Collection<T> from, Function<T, R> keyMapper) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return distinct(from, keyMapper, (t1, t2) -> t1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> List<T> distinct(Collection<T> from, Function<T, R> keyMapper, BinaryOperator<T> cover) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return new ArrayList<>(convertMap(from, keyMapper, Function.identity(), cover).values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> List<U> convertList(T[] from, Function<T, U> func) {
|
||||||
|
if (ArrayUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return convertList(Arrays.asList(from), func);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> List<U> convertList(Collection<T> from, Function<T, U> func) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> List<U> convertList(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> PageResult<U> convertPage(PageResult<T> from, Function<T, U> func) {
|
||||||
|
if (ArrayUtil.isEmpty(from)) {
|
||||||
|
return new PageResult<>(from.getTotal());
|
||||||
|
}
|
||||||
|
return new PageResult<>(convertList(from.getList(), func), from.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> List<U> convertListByFlatMap(Collection<T> from,
|
||||||
|
Function<T, ? extends Stream<? extends U>> func) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U, R> List<R> convertListByFlatMap(Collection<T> from,
|
||||||
|
Function<? super T, ? extends U> mapper,
|
||||||
|
Function<U, ? extends Stream<? extends R>> func) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> List<V> mergeValuesFromMap(Map<K, List<V>> map) {
|
||||||
|
return map.values()
|
||||||
|
.stream()
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Set<T> convertSet(Collection<T> from) {
|
||||||
|
return convertSet(from, v -> v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K> Map<K, T> convertMapByFilter(Collection<T> from, Predicate<T> filter, Function<T, K> keyFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return from.stream().filter(filter).collect(Collectors.toMap(keyFunc, v -> v));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> Set<U> convertSetByFlatMap(Collection<T> from,
|
||||||
|
Function<T, ? extends Stream<? extends U>> func) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U, R> Set<R> convertSetByFlatMap(Collection<T> from,
|
||||||
|
Function<? super T, ? extends U> mapper,
|
||||||
|
Function<U, ? extends Stream<? extends R>> func) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return convertMap(from, keyFunc, Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc, Supplier<? extends Map<K, T>> supplier) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
return convertMap(from, keyFunc, Function.identity(), supplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, BinaryOperator<V> mergeFunction) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return convertMap(from, keyFunc, valueFunc, mergeFunction, HashMap::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, Supplier<? extends Map<K, V>> supplier) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1, supplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, BinaryOperator<V> mergeFunction, Supplier<? extends Map<K, V>> supplier) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return from.stream().collect(Collectors.toMap(keyFunc, valueFunc, mergeFunction, supplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K> Map<K, List<T>> convertMultiMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(t -> t, Collectors.toList())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K, V> Map<K, List<V>> convertMultiMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return from.stream()
|
||||||
|
.collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toList())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂时没想好名字,先以 2 结尾噶
|
||||||
|
public static <T, K, V> Map<K, Set<V>> convertMultiMap2(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toSet())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, K> Map<K, T> convertImmutableMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
ImmutableMap.Builder<K, T> builder = ImmutableMap.builder();
|
||||||
|
from.forEach(item -> builder.put(keyFunc.apply(item), item));
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对比老、新两个列表,找出新增、修改、删除的数据
|
||||||
|
*
|
||||||
|
* @param oldList 老列表
|
||||||
|
* @param newList 新列表
|
||||||
|
* @param sameFunc 对比函数,返回 true 表示相同,返回 false 表示不同
|
||||||
|
* 注意,same 是通过每个元素的“标识”,判断它们是不是同一个数据
|
||||||
|
* @return [新增列表、修改列表、删除列表]
|
||||||
|
*/
|
||||||
|
public static <T> List<List<T>> diffList(Collection<T> oldList, Collection<T> newList,
|
||||||
|
BiFunction<T, T, Boolean> sameFunc) {
|
||||||
|
List<T> createList = new LinkedList<>(newList); // 默认都认为是新增的,后续会进行移除
|
||||||
|
List<T> updateList = new ArrayList<>();
|
||||||
|
List<T> deleteList = new ArrayList<>();
|
||||||
|
|
||||||
|
// 通过以 oldList 为主遍历,找出 updateList 和 deleteList
|
||||||
|
for (T oldObj : oldList) {
|
||||||
|
// 1. 寻找是否有匹配的
|
||||||
|
T foundObj = null;
|
||||||
|
for (Iterator<T> iterator = createList.iterator(); iterator.hasNext(); ) {
|
||||||
|
T newObj = iterator.next();
|
||||||
|
// 1.1 不匹配,则直接跳过
|
||||||
|
if (!sameFunc.apply(oldObj, newObj)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 1.2 匹配,则移除,并结束寻找
|
||||||
|
iterator.remove();
|
||||||
|
foundObj = newObj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 2. 匹配添加到 updateList;不匹配则添加到 deleteList 中
|
||||||
|
if (foundObj != null) {
|
||||||
|
updateList.add(foundObj);
|
||||||
|
} else {
|
||||||
|
deleteList.add(oldObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return asList(createList, updateList, deleteList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean containsAny(Collection<?> source, Collection<?> candidates) {
|
||||||
|
return org.springframework.util.CollectionUtils.containsAny(source, candidates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getFirst(List<T> from) {
|
||||||
|
return !CollectionUtil.isEmpty(from) ? from.get(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T findFirst(Collection<T> from, Predicate<T> predicate) {
|
||||||
|
return findFirst(from, predicate, Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> U findFirst(Collection<T> from, Predicate<T> predicate, Function<T, U> func) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return from.stream().filter(predicate).findFirst().map(func).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, V extends Comparable<? super V>> V getMaxValue(Collection<T> from, Function<T, V> valueFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
assert !from.isEmpty(); // 断言,避免告警
|
||||||
|
T t = from.stream().max(Comparator.comparing(valueFunc)).get();
|
||||||
|
return valueFunc.apply(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, V extends Comparable<? super V>> V getMinValue(List<T> from, Function<T, V> valueFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
assert from.size() > 0; // 断言,避免告警
|
||||||
|
T t = from.stream().min(Comparator.comparing(valueFunc)).get();
|
||||||
|
return valueFunc.apply(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, V extends Comparable<? super V>> T getMinObject(List<T> from, Function<T, V> valueFunc) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
assert from.size() > 0; // 断言,避免告警
|
||||||
|
return from.stream().min(Comparator.comparing(valueFunc)).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, V extends Comparable<? super V>> V getSumValue(Collection<T> from, Function<T, V> valueFunc,
|
||||||
|
BinaryOperator<V> accumulator) {
|
||||||
|
return getSumValue(from, valueFunc, accumulator, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, V extends Comparable<? super V>> V getSumValue(Collection<T> from, Function<T, V> valueFunc,
|
||||||
|
BinaryOperator<V> accumulator, V defaultValue) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
assert !from.isEmpty(); // 断言,避免告警
|
||||||
|
return from.stream().map(valueFunc).filter(Objects::nonNull).reduce(accumulator).orElse(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void addIfNotNull(Collection<T> coll, T item) {
|
||||||
|
if (item == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
coll.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Collection<T> singleton(T obj) {
|
||||||
|
return obj == null ? Collections.emptyList() : Collections.singleton(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> newArrayList(List<List<T>> list) {
|
||||||
|
return list.stream().filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为 LinkedHashSet
|
||||||
|
*
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @param elementType 集合中元素类型
|
||||||
|
* @param value 被转换的值
|
||||||
|
* @return {@link LinkedHashSet}
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> LinkedHashSet<T> toLinkedHashSet(Class<T> elementType, Object value) {
|
||||||
|
return (LinkedHashSet<T>) toCollection(LinkedHashSet.class, elementType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.collection;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map 工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class MapUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从哈希表表中,获得 keys 对应的所有 value 数组
|
||||||
|
*
|
||||||
|
* @param multimap 哈希表
|
||||||
|
* @param keys keys
|
||||||
|
* @return value 数组
|
||||||
|
*/
|
||||||
|
public static <K, V> List<V> getList(Multimap<K, V> multimap, Collection<K> keys) {
|
||||||
|
List<V> result = new ArrayList<>();
|
||||||
|
keys.forEach(k -> {
|
||||||
|
Collection<V> values = multimap.get(k);
|
||||||
|
if (CollectionUtil.isEmpty(values)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result.addAll(values);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从哈希表查找到 key 对应的 value,然后进一步处理
|
||||||
|
* key 为 null 时, 不处理
|
||||||
|
* 注意,如果查找到的 value 为 null 时,不进行处理
|
||||||
|
*
|
||||||
|
* @param map 哈希表
|
||||||
|
* @param key key
|
||||||
|
* @param consumer 进一步处理的逻辑
|
||||||
|
*/
|
||||||
|
public static <K, V> void findAndThen(Map<K, V> map, K key, Consumer<V> consumer) {
|
||||||
|
if (ObjUtil.isNull(key) || CollUtil.isEmpty(map)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
V value = map.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
consumer.accept(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> Map<K, V> convertMap(List<KeyValue<K, V>> keyValues) {
|
||||||
|
Map<K, V> map = Maps.newLinkedHashMapWithExpectedSize(keyValues.size());
|
||||||
|
keyValues.forEach(keyValue -> map.put(keyValue.getKey(), keyValue.getValue()));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.collection;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set 工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class SetUtils {
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <T> Set<T> asSet(T... objs) {
|
||||||
|
return CollUtil.newHashSet(objs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.date;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
|
||||||
|
import java.time.*;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class DateUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时区 - 默认
|
||||||
|
*/
|
||||||
|
public static final String TIME_ZONE_DEFAULT = "GMT+8";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 秒转换成毫秒
|
||||||
|
*/
|
||||||
|
public static final long SECOND_MILLIS = 1000;
|
||||||
|
|
||||||
|
public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";
|
||||||
|
|
||||||
|
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 LocalDateTime 转换成 Date
|
||||||
|
*
|
||||||
|
* @param date LocalDateTime
|
||||||
|
* @return LocalDateTime
|
||||||
|
*/
|
||||||
|
public static Date of(LocalDateTime date) {
|
||||||
|
if (date == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 将此日期时间与时区相结合以创建 ZonedDateTime
|
||||||
|
ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault());
|
||||||
|
// 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳
|
||||||
|
Instant instant = zonedDateTime.toInstant();
|
||||||
|
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||||
|
return Date.from(instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Date 转换成 LocalDateTime
|
||||||
|
*
|
||||||
|
* @param date Date
|
||||||
|
* @return LocalDateTime
|
||||||
|
*/
|
||||||
|
public static LocalDateTime of(Date date) {
|
||||||
|
if (date == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 转为时间戳
|
||||||
|
Instant instant = date.toInstant();
|
||||||
|
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||||
|
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Date addTime(Duration duration) {
|
||||||
|
return new Date(System.currentTimeMillis() + duration.toMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isExpired(LocalDateTime time) {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
return now.isAfter(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建指定时间
|
||||||
|
*
|
||||||
|
* @param year 年
|
||||||
|
* @param month 月
|
||||||
|
* @param day 日
|
||||||
|
* @return 指定时间
|
||||||
|
*/
|
||||||
|
public static Date buildTime(int year, int month, int day) {
|
||||||
|
return buildTime(year, month, day, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建指定时间
|
||||||
|
*
|
||||||
|
* @param year 年
|
||||||
|
* @param month 月
|
||||||
|
* @param day 日
|
||||||
|
* @param hour 小时
|
||||||
|
* @param minute 分钟
|
||||||
|
* @param second 秒
|
||||||
|
* @return 指定时间
|
||||||
|
*/
|
||||||
|
public static Date buildTime(int year, int month, int day,
|
||||||
|
int hour, int minute, int second) {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.set(Calendar.YEAR, year);
|
||||||
|
calendar.set(Calendar.MONTH, month - 1);
|
||||||
|
calendar.set(Calendar.DAY_OF_MONTH, day);
|
||||||
|
calendar.set(Calendar.HOUR_OF_DAY, hour);
|
||||||
|
calendar.set(Calendar.MINUTE, minute);
|
||||||
|
calendar.set(Calendar.SECOND, second);
|
||||||
|
calendar.set(Calendar.MILLISECOND, 0); // 一般情况下,都是 0 毫秒
|
||||||
|
return calendar.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Date max(Date a, Date b) {
|
||||||
|
if (a == null) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
if (b == null) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return a.compareTo(b) > 0 ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime max(LocalDateTime a, LocalDateTime b) {
|
||||||
|
if (a == null) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
if (b == null) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return a.isAfter(b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否今天
|
||||||
|
*
|
||||||
|
* @param date 日期
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
public static boolean isToday(LocalDateTime date) {
|
||||||
|
return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否昨天
|
||||||
|
*
|
||||||
|
* @param date 日期
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
public static boolean isYesterday(LocalDateTime date) {
|
||||||
|
return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now().minusDays(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Date localDateTimeToDate(LocalDateTime localDateTime) {
|
||||||
|
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime toLocalDateTime(Date date) {
|
||||||
|
return date == null ? null :
|
||||||
|
date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String localDateTimeToStr(LocalDateTime createTime) {
|
||||||
|
return createTime == null ? null :
|
||||||
|
LocalDateTimeUtil.format(createTime, FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
|
||||||
|
}
|
||||||
|
}
|
||||||
+350
@@ -0,0 +1,350 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.date;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.date.DatePattern;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.date.TemporalAccessorUtil;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.*;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.time.temporal.TemporalAdjusters;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.hutool.core.date.DatePattern.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间工具类,用于 {@link LocalDateTime}
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class LocalDateTimeUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空的 LocalDateTime 对象,主要用于 DB 唯一索引的默认值
|
||||||
|
*/
|
||||||
|
public static LocalDateTime EMPTY = buildTime(1970, 1, 1);
|
||||||
|
|
||||||
|
public static DateTimeFormatter UTC_MS_WITH_XXX_OFFSET_FORMATTER = createFormatter(UTC_MS_WITH_XXX_OFFSET_PATTERN);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析时间
|
||||||
|
*
|
||||||
|
* 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功
|
||||||
|
*
|
||||||
|
* @param time 时间
|
||||||
|
* @return 时间字符串
|
||||||
|
*/
|
||||||
|
public static LocalDateTime parse(String time) {
|
||||||
|
try {
|
||||||
|
return LocalDateTimeUtil.parse(time, DatePattern.NORM_DATE_PATTERN);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
return LocalDateTimeUtil.parse(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime addTime(Duration duration) {
|
||||||
|
return LocalDateTime.now().plus(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime minusTime(Duration duration) {
|
||||||
|
return LocalDateTime.now().minus(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean beforeNow(LocalDateTime date) {
|
||||||
|
return date.isBefore(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean afterNow(LocalDateTime date) {
|
||||||
|
return date.isAfter(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建指定时间
|
||||||
|
*
|
||||||
|
* @param year 年
|
||||||
|
* @param month 月
|
||||||
|
* @param day 日
|
||||||
|
* @return 指定时间
|
||||||
|
*/
|
||||||
|
public static LocalDateTime buildTime(int year, int month, int day) {
|
||||||
|
return LocalDateTime.of(year, month, day, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime[] buildBetweenTime(int year1, int month1, int day1,
|
||||||
|
int year2, int month2, int day2) {
|
||||||
|
return new LocalDateTime[]{buildTime(year1, month1, day1), buildTime(year2, month2, day2)};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判指定断时间,是否在该时间范围内
|
||||||
|
*
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @param time 指定时间
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime, Timestamp time) {
|
||||||
|
if (startTime == null || endTime == null || time == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return LocalDateTimeUtil.isIn(LocalDateTimeUtil.of(time), startTime, endTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判指定断时间,是否在该时间范围内
|
||||||
|
*
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @param time 指定时间
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime, String time) {
|
||||||
|
if (startTime == null || endTime == null || time == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return LocalDateTimeUtil.isIn(parse(time), startTime, endTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前时间是否在该时间范围内
|
||||||
|
*
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {
|
||||||
|
if (startTime == null || endTime == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前时间是否在该时间范围内
|
||||||
|
*
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
public static boolean isBetween(String startTime, String endTime) {
|
||||||
|
if (startTime == null || endTime == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LocalDate nowDate = LocalDate.now();
|
||||||
|
return LocalDateTimeUtil.isIn(LocalDateTime.now(),
|
||||||
|
LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
|
||||||
|
LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断时间段是否重叠
|
||||||
|
*
|
||||||
|
* @param startTime1 开始 time1
|
||||||
|
* @param endTime1 结束 time1
|
||||||
|
* @param startTime2 开始 time2
|
||||||
|
* @param endTime2 结束 time2
|
||||||
|
* @return 重叠:true 不重叠:false
|
||||||
|
*/
|
||||||
|
public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
|
||||||
|
LocalDate nowDate = LocalDate.now();
|
||||||
|
return LocalDateTimeUtil.isOverlap(LocalDateTime.of(nowDate, startTime1), LocalDateTime.of(nowDate, endTime1),
|
||||||
|
LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定日期所在的月份的开始时间
|
||||||
|
* 例如:2023-09-30 00:00:00,000
|
||||||
|
*
|
||||||
|
* @param date 日期
|
||||||
|
* @return 月份的开始时间
|
||||||
|
*/
|
||||||
|
public static LocalDateTime beginOfMonth(LocalDateTime date) {
|
||||||
|
return date.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定日期所在的月份的最后时间
|
||||||
|
* 例如:2023-09-30 23:59:59,999
|
||||||
|
*
|
||||||
|
* @param date 日期
|
||||||
|
* @return 月份的结束时间
|
||||||
|
*/
|
||||||
|
public static LocalDateTime endOfMonth(LocalDateTime date) {
|
||||||
|
return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得指定日期所在季度
|
||||||
|
*
|
||||||
|
* @param date 日期
|
||||||
|
* @return 所在季度
|
||||||
|
*/
|
||||||
|
public static int getQuarterOfYear(LocalDateTime date) {
|
||||||
|
return (date.getMonthValue() - 1) / 3 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定日期到现在过了几天,如果指定日期在当前日期之后,获取结果为负
|
||||||
|
*
|
||||||
|
* @param dateTime 日期
|
||||||
|
* @return 相差天数
|
||||||
|
*/
|
||||||
|
public static Long between(LocalDateTime dateTime) {
|
||||||
|
return LocalDateTimeUtil.between(dateTime, LocalDateTime.now(), ChronoUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取今天的开始时间
|
||||||
|
*
|
||||||
|
* @return 今天
|
||||||
|
*/
|
||||||
|
public static LocalDateTime getToday() {
|
||||||
|
return LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取昨天的开始时间
|
||||||
|
*
|
||||||
|
* @return 昨天
|
||||||
|
*/
|
||||||
|
public static LocalDateTime getYesterday() {
|
||||||
|
return LocalDateTimeUtil.beginOfDay(LocalDateTime.now().minusDays(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取本月的开始时间
|
||||||
|
*
|
||||||
|
* @return 本月
|
||||||
|
*/
|
||||||
|
public static LocalDateTime getMonth() {
|
||||||
|
return beginOfMonth(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取本年的开始时间
|
||||||
|
*
|
||||||
|
* @return 本年
|
||||||
|
*/
|
||||||
|
public static LocalDateTime getYear() {
|
||||||
|
return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<LocalDateTime[]> getDateRangeList(LocalDateTime startTime,
|
||||||
|
LocalDateTime endTime,
|
||||||
|
Integer interval) {
|
||||||
|
// 1.1 找到枚举
|
||||||
|
DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval);
|
||||||
|
Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval);
|
||||||
|
// 1.2 将时间对齐
|
||||||
|
startTime = LocalDateTimeUtil.beginOfDay(startTime);
|
||||||
|
endTime = LocalDateTimeUtil.endOfDay(endTime);
|
||||||
|
|
||||||
|
// 2. 循环,生成时间范围
|
||||||
|
List<LocalDateTime[]> timeRanges = new ArrayList<>();
|
||||||
|
switch (intervalEnum) {
|
||||||
|
case HOUR:
|
||||||
|
while (startTime.isBefore(endTime)) {
|
||||||
|
timeRanges.add(new LocalDateTime[]{startTime, startTime.plusHours(1).minusNanos(1)});
|
||||||
|
startTime = startTime.plusHours(1);
|
||||||
|
}
|
||||||
|
case DAY:
|
||||||
|
while (startTime.isBefore(endTime)) {
|
||||||
|
timeRanges.add(new LocalDateTime[]{startTime, startTime.plusDays(1).minusNanos(1)});
|
||||||
|
startTime = startTime.plusDays(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WEEK:
|
||||||
|
while (startTime.isBefore(endTime)) {
|
||||||
|
LocalDateTime endOfWeek = startTime.with(DayOfWeek.SUNDAY).plusDays(1).minusNanos(1);
|
||||||
|
timeRanges.add(new LocalDateTime[]{startTime, endOfWeek});
|
||||||
|
startTime = endOfWeek.plusNanos(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MONTH:
|
||||||
|
while (startTime.isBefore(endTime)) {
|
||||||
|
LocalDateTime endOfMonth = startTime.with(TemporalAdjusters.lastDayOfMonth()).plusDays(1).minusNanos(1);
|
||||||
|
timeRanges.add(new LocalDateTime[]{startTime, endOfMonth});
|
||||||
|
startTime = endOfMonth.plusNanos(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QUARTER:
|
||||||
|
while (startTime.isBefore(endTime)) {
|
||||||
|
int quarterOfYear = getQuarterOfYear(startTime);
|
||||||
|
LocalDateTime quarterEnd = quarterOfYear == 4
|
||||||
|
? startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1)
|
||||||
|
: startTime.withMonth(quarterOfYear * 3 + 1).withDayOfMonth(1).minusNanos(1);
|
||||||
|
timeRanges.add(new LocalDateTime[]{startTime, quarterEnd});
|
||||||
|
startTime = quarterEnd.plusNanos(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case YEAR:
|
||||||
|
while (startTime.isBefore(endTime)) {
|
||||||
|
LocalDateTime endOfYear = startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1);
|
||||||
|
timeRanges.add(new LocalDateTime[]{startTime, endOfYear});
|
||||||
|
startTime = endOfYear.plusNanos(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid interval: " + interval);
|
||||||
|
}
|
||||||
|
// 3. 兜底,最后一个时间,需要保持在 endTime 之前
|
||||||
|
LocalDateTime[] lastTimeRange = CollUtil.getLast(timeRanges);
|
||||||
|
if (lastTimeRange != null) {
|
||||||
|
lastTimeRange[1] = endTime;
|
||||||
|
}
|
||||||
|
return timeRanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间范围
|
||||||
|
*
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @param interval 时间间隔
|
||||||
|
* @return 时间范围
|
||||||
|
*/
|
||||||
|
public static String formatDateRange(LocalDateTime startTime, LocalDateTime endTime, Integer interval) {
|
||||||
|
// 1. 找到枚举
|
||||||
|
DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval);
|
||||||
|
Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval);
|
||||||
|
|
||||||
|
// 2. 循环,生成时间范围
|
||||||
|
switch (intervalEnum) {
|
||||||
|
case HOUR:
|
||||||
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATETIME_MINUTE_PATTERN);
|
||||||
|
case DAY:
|
||||||
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN);
|
||||||
|
case WEEK:
|
||||||
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN)
|
||||||
|
+ StrUtil.format("(第 {} 周)", LocalDateTimeUtil.weekOfYear(startTime));
|
||||||
|
case MONTH:
|
||||||
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_MONTH_PATTERN);
|
||||||
|
case QUARTER:
|
||||||
|
return StrUtil.format("{}-Q{}", startTime.getYear(), getQuarterOfYear(startTime));
|
||||||
|
case YEAR:
|
||||||
|
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_YEAR_PATTERN);
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid interval: " + interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将给定的 {@link LocalDateTime} 转换为自 Unix 纪元时间(1970-01-01T00:00:00Z)以来的秒数。
|
||||||
|
*
|
||||||
|
* @param sourceDateTime 需要转换的本地日期时间,不能为空
|
||||||
|
* @return 自 1970-01-01T00:00:00Z 起的秒数(epoch second)
|
||||||
|
* @throws NullPointerException 如果 {@code sourceDateTime} 为 {@code null}
|
||||||
|
* @throws DateTimeException 如果转换过程中发生时间超出范围或其他时间处理异常
|
||||||
|
*/
|
||||||
|
public static Long toEpochSecond(LocalDateTime sourceDateTime) {
|
||||||
|
return TemporalAccessorUtil.toInstant(sourceDateTime).getEpochSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+184
@@ -0,0 +1,184 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.http;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.core.map.TableMap;
|
||||||
|
import cn.hutool.core.net.url.UrlBuilder;
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.util.UriComponents;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP 工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class HttpUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编码 URL 参数
|
||||||
|
*
|
||||||
|
* @param value 参数
|
||||||
|
* @return 编码后的参数
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public static String encodeUtf8(String value) {
|
||||||
|
return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static String replaceUrlQuery(String url, String key, String value) {
|
||||||
|
UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
|
||||||
|
// 先移除
|
||||||
|
TableMap<CharSequence, CharSequence> query = (TableMap<CharSequence, CharSequence>)
|
||||||
|
ReflectUtil.getFieldValue(builder.getQuery(), "query");
|
||||||
|
query.remove(key);
|
||||||
|
// 后添加
|
||||||
|
builder.addQuery(key, value);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String removeUrlQuery(String url) {
|
||||||
|
if (!StrUtil.contains(url, '?')) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
|
||||||
|
// 移除 query、fragment
|
||||||
|
builder.setQuery(null);
|
||||||
|
builder.setFragment(null);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼接 URL
|
||||||
|
*
|
||||||
|
* copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 append 方法
|
||||||
|
*
|
||||||
|
* @param base 基础 URL
|
||||||
|
* @param query 查询参数
|
||||||
|
* @param keys query 的 key,对应的原本的 key 的映射。例如说 query 里有个 key 是 xx,实际它的 key 是 extra_xx,则通过 keys 里添加这个映射
|
||||||
|
* @param fragment URL 的 fragment,即拼接到 # 中
|
||||||
|
* @return 拼接后的 URL
|
||||||
|
*/
|
||||||
|
public static String append(String base, Map<String, ?> query, Map<String, String> keys, boolean fragment) {
|
||||||
|
UriComponentsBuilder template = UriComponentsBuilder.newInstance();
|
||||||
|
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(base);
|
||||||
|
URI redirectUri;
|
||||||
|
try {
|
||||||
|
// assume it's encoded to start with (if it came in over the wire)
|
||||||
|
redirectUri = builder.build(true).toUri();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ... but allow client registrations to contain hard-coded non-encoded values
|
||||||
|
redirectUri = builder.build().toUri();
|
||||||
|
builder = UriComponentsBuilder.fromUri(redirectUri);
|
||||||
|
}
|
||||||
|
template.scheme(redirectUri.getScheme()).port(redirectUri.getPort()).host(redirectUri.getHost())
|
||||||
|
.userInfo(redirectUri.getUserInfo()).path(redirectUri.getPath());
|
||||||
|
|
||||||
|
if (fragment) {
|
||||||
|
StringBuilder values = new StringBuilder();
|
||||||
|
if (redirectUri.getFragment() != null) {
|
||||||
|
String append = redirectUri.getFragment();
|
||||||
|
values.append(append);
|
||||||
|
}
|
||||||
|
for (String key : query.keySet()) {
|
||||||
|
if (values.length() > 0) {
|
||||||
|
values.append("&");
|
||||||
|
}
|
||||||
|
String name = key;
|
||||||
|
if (keys != null && keys.containsKey(key)) {
|
||||||
|
name = keys.get(key);
|
||||||
|
}
|
||||||
|
values.append(name).append("={").append(key).append("}");
|
||||||
|
}
|
||||||
|
if (values.length() > 0) {
|
||||||
|
template.fragment(values.toString());
|
||||||
|
}
|
||||||
|
UriComponents encoded = template.build().expand(query).encode();
|
||||||
|
builder.fragment(encoded.getFragment());
|
||||||
|
} else {
|
||||||
|
for (String key : query.keySet()) {
|
||||||
|
String name = key;
|
||||||
|
if (keys != null && keys.containsKey(key)) {
|
||||||
|
name = keys.get(key);
|
||||||
|
}
|
||||||
|
template.queryParam(name, "{" + key + "}");
|
||||||
|
}
|
||||||
|
template.fragment(redirectUri.getFragment());
|
||||||
|
UriComponents encoded = template.build().expand(query).encode();
|
||||||
|
builder.query(encoded.getQuery());
|
||||||
|
}
|
||||||
|
return builder.build().toUriString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] obtainBasicAuthorization(HttpServletRequest request) {
|
||||||
|
String clientId;
|
||||||
|
String clientSecret;
|
||||||
|
// 先从 Header 中获取
|
||||||
|
String authorization = request.getHeader("Authorization");
|
||||||
|
authorization = StrUtil.subAfter(authorization, "Basic ", true);
|
||||||
|
if (StringUtils.hasText(authorization)) {
|
||||||
|
authorization = Base64.decodeStr(authorization);
|
||||||
|
clientId = StrUtil.subBefore(authorization, ":", false);
|
||||||
|
clientSecret = StrUtil.subAfter(authorization, ":", false);
|
||||||
|
// 再从 Param 中获取
|
||||||
|
} else {
|
||||||
|
clientId = request.getParameter("client_id");
|
||||||
|
clientSecret = request.getParameter("client_secret");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果两者非空,则返回
|
||||||
|
if (StrUtil.isNotEmpty(clientId) && StrUtil.isNotEmpty(clientSecret)) {
|
||||||
|
return new String[]{clientId, clientSecret};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP post 请求,基于 {@link cn.hutool.http.HttpUtil} 实现
|
||||||
|
*
|
||||||
|
* 为什么要封装该方法,因为 HttpUtil 默认封装的方法,没有允许传递 headers 参数
|
||||||
|
*
|
||||||
|
* @param url URL
|
||||||
|
* @param headers 请求头
|
||||||
|
* @param requestBody 请求体
|
||||||
|
* @return 请求结果
|
||||||
|
*/
|
||||||
|
public static String post(String url, Map<String, String> headers, String requestBody) {
|
||||||
|
try (HttpResponse response = HttpRequest.post(url)
|
||||||
|
.addHeaders(headers)
|
||||||
|
.body(requestBody)
|
||||||
|
.execute()) {
|
||||||
|
return response.body();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP get 请求,基于 {@link cn.hutool.http.HttpUtil} 实现
|
||||||
|
*
|
||||||
|
* 为什么要封装该方法,因为 HttpUtil 默认封装的方法,没有允许传递 headers 参数
|
||||||
|
*
|
||||||
|
* @param url URL
|
||||||
|
* @param headers 请求头
|
||||||
|
* @return 请求结果
|
||||||
|
*/
|
||||||
|
public static String get(String url, Map<String, String> headers) {
|
||||||
|
try (HttpResponse response = HttpRequest.get(url)
|
||||||
|
.addHeaders(headers)
|
||||||
|
.execute()) {
|
||||||
|
return response.body();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.io;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class FileUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建临时文件
|
||||||
|
* 该文件会在 JVM 退出时,进行删除
|
||||||
|
*
|
||||||
|
* @param data 文件内容
|
||||||
|
* @return 文件
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public static File createTempFile(String data) {
|
||||||
|
File file = createTempFile();
|
||||||
|
// 写入内容
|
||||||
|
FileUtil.writeUtf8String(data, file);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建临时文件
|
||||||
|
* 该文件会在 JVM 退出时,进行删除
|
||||||
|
*
|
||||||
|
* @param data 文件内容
|
||||||
|
* @return 文件
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public static File createTempFile(byte[] data) {
|
||||||
|
File file = createTempFile();
|
||||||
|
// 写入内容
|
||||||
|
FileUtil.writeBytes(data, file);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建临时文件,无内容
|
||||||
|
* 该文件会在 JVM 退出时,进行删除
|
||||||
|
*
|
||||||
|
* @return 文件
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public static File createTempFile() {
|
||||||
|
// 创建文件,通过 UUID 保证唯一
|
||||||
|
File file = File.createTempFile(IdUtil.simpleUUID(), null);
|
||||||
|
// 标记 JVM 退出时,自动删除
|
||||||
|
file.deleteOnExit();
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.io;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IO 工具类,用于 {@link cn.hutool.core.io.IoUtil} 缺失的方法
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class IoUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从流中读取 UTF8 编码的内容
|
||||||
|
*
|
||||||
|
* @param in 输入流
|
||||||
|
* @param isClose 是否关闭
|
||||||
|
* @return 内容
|
||||||
|
* @throws IORuntimeException IO 异常
|
||||||
|
*/
|
||||||
|
public static String readUtf8(InputStream in, boolean isClose) throws IORuntimeException {
|
||||||
|
return StrUtil.utf8Str(IoUtil.read(in, isClose));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+232
@@ -0,0 +1,232 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.json;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON 工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class JsonUtils {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
static {
|
||||||
|
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||||
|
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值
|
||||||
|
// 解决 LocalDateTime 的序列化
|
||||||
|
SimpleModule simpleModule = new JavaTimeModule()
|
||||||
|
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
|
||||||
|
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
|
||||||
|
objectMapper.registerModules(simpleModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 objectMapper 属性
|
||||||
|
* <p>
|
||||||
|
* 通过这样的方式,使用 Spring 创建的 ObjectMapper Bean
|
||||||
|
*
|
||||||
|
* @param objectMapper ObjectMapper 对象
|
||||||
|
*/
|
||||||
|
public static void init(ObjectMapper objectMapper) {
|
||||||
|
JsonUtils.objectMapper = objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static String toJsonString(Object object) {
|
||||||
|
return objectMapper.writeValueAsString(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static byte[] toJsonByte(Object object) {
|
||||||
|
return objectMapper.writeValueAsBytes(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static String toJsonPrettyString(Object object) {
|
||||||
|
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(String text, Class<T> clazz) {
|
||||||
|
if (StrUtil.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(String text, String path, Class<T> clazz) {
|
||||||
|
if (StrUtil.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JsonNode treeNode = objectMapper.readTree(text);
|
||||||
|
JsonNode pathNode = treeNode.path(path);
|
||||||
|
return objectMapper.readValue(pathNode.toString(), clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(String text, Type type) {
|
||||||
|
if (StrUtil.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(byte[] text, Type type) {
|
||||||
|
if (ArrayUtil.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串解析成指定类型的对象
|
||||||
|
* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下,
|
||||||
|
* 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。
|
||||||
|
*
|
||||||
|
* @param text 字符串
|
||||||
|
* @param clazz 类型
|
||||||
|
* @return 对象
|
||||||
|
*/
|
||||||
|
public static <T> T parseObject2(String text, Class<T> clazz) {
|
||||||
|
if (StrUtil.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JSONUtil.toBean(text, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
|
||||||
|
if (ArrayUtil.isEmpty(bytes)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(bytes, clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", bytes, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(String text, TypeReference<T> typeReference) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, typeReference);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null
|
||||||
|
*
|
||||||
|
* @param text 字符串
|
||||||
|
* @param typeReference 类型引用
|
||||||
|
* @return 指定类型的对象
|
||||||
|
*/
|
||||||
|
public static <T> T parseObjectQuietly(String text, TypeReference<T> typeReference) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, typeReference);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> parseArray(String text, Class<T> clazz) {
|
||||||
|
if (StrUtil.isEmpty(text)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> parseArray(String text, String path, Class<T> clazz) {
|
||||||
|
if (StrUtil.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JsonNode treeNode = objectMapper.readTree(text);
|
||||||
|
JsonNode pathNode = treeNode.path(path);
|
||||||
|
return objectMapper.readValue(pathNode.toString(), objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonNode parseTree(String text) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readTree(text);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonNode parseTree(byte[] text) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readTree(text);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("json parse err,json:{}", text, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isJson(String text) {
|
||||||
|
return JSONUtil.isTypeJSON(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否为 JSON 类型的字符串
|
||||||
|
* @param str 字符串
|
||||||
|
*/
|
||||||
|
public static boolean isJsonObject(String str) {
|
||||||
|
return JSONUtil.isTypeJSONObject(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.json.databind;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Long 序列化规则
|
||||||
|
*
|
||||||
|
* 会将超长 long 值转换为 string,解决前端 JavaScript 最大安全整数是 2^53-1 的问题
|
||||||
|
*
|
||||||
|
* @author 星语
|
||||||
|
*/
|
||||||
|
@JacksonStdImpl
|
||||||
|
public class NumberSerializer extends com.fasterxml.jackson.databind.ser.std.NumberSerializer {
|
||||||
|
|
||||||
|
private static final long MAX_SAFE_INTEGER = 9007199254740991L;
|
||||||
|
private static final long MIN_SAFE_INTEGER = -9007199254740991L;
|
||||||
|
|
||||||
|
public static final NumberSerializer INSTANCE = new NumberSerializer(Number.class);
|
||||||
|
|
||||||
|
public NumberSerializer(Class<? extends Number> rawType) {
|
||||||
|
super(rawType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(Number value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||||
|
// 超出范围 序列化位字符串
|
||||||
|
if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
|
||||||
|
super.serialize(value, gen, serializers);
|
||||||
|
} else {
|
||||||
|
gen.writeString(value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.util.json.databind;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于时间戳的 LocalDateTime 反序列化器
|
||||||
|
*
|
||||||
|
* @author 老五
|
||||||
|
*/
|
||||||
|
public class TimestampLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
|
||||||
|
|
||||||
|
public static final TimestampLocalDateTimeDeserializer INSTANCE = new TimestampLocalDateTimeDeserializer();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||||
|
// 将 Long 时间戳,转换为 LocalDateTime 对象
|
||||||
|
return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user