Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/wechat-mp
# Conflicts: # pom.xml # sql/mysql/ruoyi-vue-pro.sql # yudao-dependencies/pom.xml # yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml # yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java # yudao-server/pom.xml # yudao-server/src/main/resources/admin-ui/static/js/4.js # yudao-server/src/main/resources/admin-ui/static/js/chunk-vendors.js # yudao-server/src/main/resources/application-local.yaml # yudao-ui-admin/yarn.lock
This commit is contained in:
commit
48520a456b
|
@ -45,3 +45,7 @@ nbdist/
|
|||
|
||||
### JRebel ###
|
||||
rebel.xml
|
||||
|
||||
application-my.yaml
|
||||
|
||||
/yudao-ui-app/unpackage/
|
||||
|
|
275
README.md
275
README.md
|
@ -1,6 +1,4 @@
|
|||
**严肃声明:现在、未来都不会有商业版本,所有功能全部开源!**
|
||||
|
||||
**拒绝虚假开源,售卖商业版,程序员不骗程序员!!**
|
||||
**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!**
|
||||
|
||||
**「我喜欢写代码,乐此不疲」**
|
||||
**「我喜欢做开源,以此为乐」**
|
||||
|
@ -9,6 +7,12 @@
|
|||
|
||||
如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。
|
||||
|
||||
## 🐶 新手必读
|
||||
|
||||
* 演示地址:<http://dashboard.yudao.iocoder.cn>
|
||||
* 启动文档:<https://doc.iocoder.cn/quick-start/>
|
||||
* 视频教程:<https://doc.iocoder.cn/video/>
|
||||
|
||||
## 🐯 平台简介
|
||||
|
||||
**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。
|
||||
|
@ -17,41 +21,53 @@
|
|||
>
|
||||
> 😜 给项目点点 Star 吧,这对我们真的很重要!
|
||||
|
||||
* 前端采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) ,正在支持 Vue 3 + ElementUI Plus 最新方案。
|
||||
* 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson。
|
||||

|
||||
|
||||
* 管理后台的 Vue3 版本采用 [vue-element-plus-admin](https://gitee.com/kailong110120130/vue-element-plus-admin) ,Vue2 版本采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||
* 管理后台的移动端采用 [uni-app](https://github.com/dcloudio/uni-app) 方案,一份代码多终端适配,同时支持 APP、小程序、H5!
|
||||
* 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson
|
||||
* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等
|
||||
* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统。
|
||||
* 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能。
|
||||
* 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装。
|
||||
* 工作流使用 Activiti + Flowable,支持动态表单、在线设计流程、多种任务分配方式。
|
||||
* 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验。
|
||||
* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款。
|
||||
* 集成阿里云、腾讯云、云片等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务。
|
||||
* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录
|
||||
* 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能
|
||||
* 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装
|
||||
* 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式
|
||||
* 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验
|
||||
* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款
|
||||
* 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务
|
||||
* 集成报表设计器,支持数据报表、图形报表、打印设计等
|
||||
|
||||
| 项目名 | 说明 | 传说门 |
|
||||
|--------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `ruoyi-vue-pro` | Spring Boot 多模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro)** [Github](https://github.com/YunaiV/ruoyi-vue-pro) |
|
||||
| `yudao-cloud` | Spring Cloud 微服务 | **[Gitee](https://gitee.com/zhijiantianya/yudao-cloud)** [Github](https://github.com/YunaiV/yudao-cloud) |
|
||||
| `Spring-Boot-Labs` | Spring Boot & Cloud 入门 | **[Gitee](https://gitee.com/zhijiantianya/SpringBoot-Labs)** [Github](https://github.com/YunaiV/SpringBoot-Labs) |
|
||||
| 项目名 | 说明 | 传送门 |
|
||||
|----------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `ruoyi-vue-pro` | Spring Boot 多模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro)** [Github](https://github.com/YunaiV/ruoyi-vue-pro) |
|
||||
| `yudao-cloud` | Spring Cloud 微服务 | **[Gitee](https://gitee.com/zhijiantianya/yudao-cloud)** [Github](https://github.com/YunaiV/yudao-cloud) |
|
||||
| `Spring-Boot-Labs` | Spring Boot & Cloud 入门 | **[Gitee](https://gitee.com/zhijiantianya/SpringBoot-Labs)** [Github](https://github.com/YunaiV/SpringBoot-Labs) |
|
||||
| `ruoyi-vue-pro-mini` | 精简版:移除工作流、支付等模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/mini)** |
|
||||
|
||||
## 🐶 在线体验
|
||||
## 😎 开源协议
|
||||
|
||||
演示地址:<http://dashboard.yudao.iocoder.cn>
|
||||
* 账号密码:admin/admin123
|
||||
**为什么推荐使用本项目?**
|
||||
|
||||
文档地址:<http://www.iocoder.cn/categories/Yudao/>
|
||||
* [《如何搭建环境》](http://www.iocoder.cn/categories/Yudao/?yudao)
|
||||
① 本项目采用比 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 开发手册》规范,代码注释详细,57000 行 Java 代码,22000 行代码注释。
|
||||
|
||||
## 🐼 内置功能
|
||||
|
||||
分成多种内置功能:
|
||||
系统内置多种多种业务功能,可以用于快速你的业务系统:
|
||||
|
||||

|
||||
|
||||
* 系统功能
|
||||
* 基础设施
|
||||
* 工作流程
|
||||
* 支付系统
|
||||
* 会员中心
|
||||
* 数据报表
|
||||
* 商城系统
|
||||
* 基础设施
|
||||
|
||||
> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。
|
||||
>
|
||||
|
@ -73,11 +89,14 @@
|
|||
| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |
|
||||
| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |
|
||||
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
|
||||
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、云片等主流短信平台 |
|
||||
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |
|
||||
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
|
||||
| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |
|
||||
| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |
|
||||
| | 通知公告 | 系统通知公告信息发布维护 |
|
||||
| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |
|
||||
| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |
|
||||
| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 |
|
||||
|
||||
### 工作流程
|
||||
|
||||
|
@ -102,17 +121,6 @@
|
|||
|
||||
ps:核心功能已经实现,正在对接微信小程序中...
|
||||
|
||||
### 商城系统
|
||||
|
||||
正在开发中,大体计划如下:
|
||||
* 2022 Q2 => 完成对 <https://github.com/YunaiV/onemall> 的迁移,作为 onemall 的 Spring Boot 单体版本。
|
||||
* 2022 Q4 => 完成对 <https://github.com/YunaiV/onemall>> 的重构,作为 onemall 的 Spring Cloud 微服务版本。
|
||||
|
||||
### 会员中心
|
||||
|
||||
正在开发中,大体计划如下:
|
||||
* 2021 Q1 =》完成对 <https://github.com/YunaiV/onemall> 的迁移
|
||||
|
||||
### 基础设施
|
||||
|
||||
| | 功能 | 描述 |
|
||||
|
@ -123,7 +131,7 @@ ps:核心功能已经实现,正在对接微信小程序中...
|
|||
| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |
|
||||
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
|
||||
| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
|
||||
| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 |
|
||||
| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 |
|
||||
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
|
||||
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
|
||||
| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
|
||||
|
@ -137,97 +145,154 @@ ps:核心功能已经实现,正在对接微信小程序中...
|
|||
| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |
|
||||
| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |
|
||||
|
||||
### 数据报表
|
||||
|
||||
| | 功能 | 描述 |
|
||||
|-----|----------|----------------------------------------------|
|
||||
| 🚀 | 报表设计器 | 支持数据报表、图形报表、打印设计等 |
|
||||
| 🚀 | 大屏设计器 | 建设中... 拖拽式实现可视化数据大屏 |
|
||||
|
||||
### 商城系统
|
||||
|
||||
建设中...
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 会员中心
|
||||
|
||||
和「商城系统」一起开发
|
||||
|
||||
## 🐨 技术栈
|
||||
|
||||
| 项目 | 说明 |
|
||||
|-----------------------|--------------------|
|
||||
| `yudao-dependencies` | Maven 依赖版本管理 |
|
||||
| `yudao-framework` | Java 框架拓展 |
|
||||
| `yudao-server` | 管理后台 + 用户 APP 的服务端 |
|
||||
| `yudao-admin-ui` | 管理后台的 UI 界面 |
|
||||
| `yudao-user-ui` | 用户 APP 的 UI 界面 |
|
||||
| `yudao-module-system` | 系统功能的 Module 模块 |
|
||||
| `yudao-module-member` | 会员中心的 Module 模块 |
|
||||
| `yudao-module-infra` | 基础设施的 Module 模块 |
|
||||
| `yudao-module-tool` | 研发工具的 Module 模块 |
|
||||
| `yudao-module-bpm` | 工作流程的 Module 模块 |
|
||||
| `yudao-module-pay` | 支付系统的 Module 模块 |
|
||||
| 项目 | 说明 |
|
||||
|------------------------------|--------------------|
|
||||
| `yudao-dependencies` | Maven 依赖版本管理 |
|
||||
| `yudao-framework` | Java 框架拓展 |
|
||||
| `yudao-server` | 管理后台 + 用户 APP 的服务端 |
|
||||
| `yudao-ui-admin` | 管理后台的 Vue2 前端项目 |
|
||||
| `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 |
|
||||
| `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 |
|
||||
| `yudao-ui-app` | 用户 APP 的 UI 界面 |
|
||||
| `yudao-module-system` | 系统功能的 Module 模块 |
|
||||
| `yudao-module-member` | 会员中心的 Module 模块 |
|
||||
| `yudao-module-infra` | 基础设施的 Module 模块 |
|
||||
| `yudao-module-bpm` | 工作流程的 Module 模块 |
|
||||
| `yudao-module-pay` | 支付系统的 Module 模块 |
|
||||
| `yudao-module-visualization` | 大屏报表 Module 模块 |
|
||||
|
||||
### 后端
|
||||
|
||||
| 框架 | 说明 | 版本 | 学习指南 |
|
||||
|---------------------------------------------------------------------------------------------|------------------|----------|----------------------------------------------------------------|
|
||||
| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.5.12 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
|
||||
| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 | |
|
||||
| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.8 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.1 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
|
||||
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 | |
|
||||
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.16.8 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
|
||||
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.16 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
|
||||
| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.5.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
|
||||
| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.2 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
|
||||
| [Activiti](https://github.com/Activiti/Activiti) | 工作流引擎 | 7.1.0.M6 | [文档](TODO) |
|
||||
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
|
||||
| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
|
||||
| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
|
||||
| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
|
||||
| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.4.2 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
|
||||
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.12.6 | |
|
||||
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
|
||||
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
|
||||
| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.7.2 | - |
|
||||
| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 3.9.0 | - |
|
||||
| 框架 | 说明 | 版本 | 学习指南 |
|
||||
|---------------------------------------------------------------------------------------------|------------------|-------------|----------------------------------------------------------------|
|
||||
| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.6 | [文档](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.15 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
|
||||
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
||||
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | |
|
||||
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.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.5 | [文档](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.7.2 | [文档](https://doc.iocoder.cn/bpm/) |
|
||||
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
|
||||
| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
|
||||
| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?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.9 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
|
||||
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |
|
||||
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
|
||||
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](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 | - |
|
||||
|
||||
### 前端
|
||||
### [管理后台 Vue2 前端](./yudao-ui-admin)
|
||||
|
||||
| 框架 | 说明 | 版本 |
|
||||
|------------------------------------------------------------------------------|---------------|--------|
|
||||
| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.6.12 |
|
||||
| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.7.14 |
|
||||
| [Vue Element Admin](https://panjiachen.github.io/vue-element-admin-site/zh/) | 后台前端解决方案 | - |
|
||||
|
||||
### [管理后台 Vue3 前端](./yudao-ui-admin-vue3)
|
||||
|
||||
| 框架 | 说明 | 版本 |
|
||||
|----------------------------------------------------------------------|:------------:|:------:|
|
||||
| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.45 |
|
||||
| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.3 |
|
||||
| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.27 |
|
||||
| [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.9.4 |
|
||||
| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.28 |
|
||||
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |
|
||||
| [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.3.7 |
|
||||
|
||||
### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp)
|
||||
|
||||
| 框架 | 说明 | 版本 |
|
||||
|-------------------------------------------------|--------------------|--------|
|
||||
| [uni-app](hhttps://github.com/dcloudio/uni-app) | 跨平台框架 | 2.0.0 |
|
||||
| [uni-ui](https://github.com/dcloudio/uni-ui) | 基于 uni-app 的 UI 框架 | 1.4.20 |
|
||||
|
||||
## 🐷 演示图
|
||||
|
||||
### 系统功能
|
||||
|
||||
| 模块 | biu | biu | biu |
|
||||
|----------|--------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|
|
||||
| 登录 & 首页 |  |  |  |
|
||||
| 用户 |  |  | - |
|
||||
| 租户 & 套餐 |  |  | - |
|
||||
| 部门 & 岗位 |  |  | - |
|
||||
| 菜单 & 角色 |  |  | - |
|
||||
| 审计日志 |  |  | - |
|
||||
| 短信 |  |  |  |
|
||||
| 字典 |  |  | - |
|
||||
| 错误码 & 通知 |  |  | - |
|
||||
|------------|--------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|
|
||||
| 登录 & 首页 |  |  |  |
|
||||
| 用户 & 应用 |  |  |  |
|
||||
| 租户 & 套餐 |  |  | - |
|
||||
| 部门 & 岗位 |  |  | - |
|
||||
| 菜单 & 角色 |  |  | - |
|
||||
| 审计日志 |  |  | - |
|
||||
| 短信 |  |  |  |
|
||||
| 字典 & 敏感词 |  |  |  |
|
||||
| 错误码 & 通知 |  |  | - |
|
||||
|
||||
### 工作流程
|
||||
|
||||
| 模块 | biu | biu | biu |
|
||||
|---------|------------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||
| 流程模型 |  |  |  |
|
||||
| 表单 & 分组 |  |  | - |
|
||||
| 我的流程 |  |  |  |
|
||||
| 待办 & 已办 |  |  |  |
|
||||
| OA 请假 |  |  |  |
|
||||
|
||||
### 支付系统
|
||||
|
||||
| 模块 | biu | biu | biu |
|
||||
|---------|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||
| 商家 & 应用 |  |  |  |
|
||||
| 支付 & 退款 |  |  | --- |
|
||||
| 流程模型 |  |  |  |
|
||||
| 表单 & 分组 |  |  | - |
|
||||
| 我的流程 |  |  |  |
|
||||
| 待办 & 已办 |  |  |  |
|
||||
| OA 请假 |  |  |  |
|
||||
|
||||
### 基础设施
|
||||
|
||||
| 模块 | biu | biu | biu |
|
||||
|---------------|----------------------------------------------------------------------|--------------------------------------------------------------------|------------------------------------------------------------------|
|
||||
| 代码生成 |  |  | - |
|
||||
| 文档 |  |  | - |
|
||||
| 文件 & 配置 |  |  |  |
|
||||
| 定时任务 |  |  | - |
|
||||
| API 日志 |  |  | - |
|
||||
| MySQL & Redis |  |  | - |
|
||||
| 监控平台 |  |  |  |
|
||||
| 代码生成 |  |  | - |
|
||||
| 文档 |  |  | - |
|
||||
| 文件 & 配置 |  |  |  |
|
||||
| 定时任务 |  |  | - |
|
||||
| API 日志 |  |  | - |
|
||||
| MySQL & Redis |  |  | - |
|
||||
| 监控平台 |  |  |  |
|
||||
|
||||
### 支付系统
|
||||
|
||||
| 模块 | biu | biu | biu |
|
||||
|---------|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||
| 商家 & 应用 |  |  |  |
|
||||
| 支付 & 退款 |  |  | --- |
|
||||
|
||||
### 数据报表
|
||||
|
||||
| 模块 | biu | biu | biu |
|
||||
|---------|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||
| 报表设计器 |  |  |  |
|
||||
|
||||
### 移动端(管理后台)
|
||||
|
||||
| biu | biu | biu |
|
||||
|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||
|  |  |  |
|
||||
|  |  |  |
|
||||
|  |  |  |
|
||||
|
||||
目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。
|
||||
|
|
|
@ -5,6 +5,15 @@
|
|||
"appTenantId": "1",
|
||||
|
||||
"appApi": "http://127.0.0.1:48080/app-api",
|
||||
"appToken": "test247",
|
||||
"appTenentId": "1"
|
||||
},
|
||||
"gateway": {
|
||||
"baseUrl": "http://127.0.0.1:8888/admin-api",
|
||||
"token": "test1",
|
||||
"adminTenentId": "1",
|
||||
|
||||
"appApi": "http://127.0.0.1:8888/app-api",
|
||||
"appToken": "test1",
|
||||
"appTenantId": "1"
|
||||
}
|
||||
|
|
14
pom.xml
14
pom.xml
|
@ -12,13 +12,17 @@
|
|||
<module>yudao-framework</module>
|
||||
<!-- Server 主项目 -->
|
||||
<module>yudao-server</module>
|
||||
<!-- 各种 module 拓展 -->
|
||||
<!-- 各种 module 拓展 -->
|
||||
<module>yudao-module-member</module>
|
||||
<module>yudao-module-bpm</module>
|
||||
<module>yudao-module-system</module>
|
||||
<module>yudao-module-infra</module>
|
||||
<module>yudao-module-pay</module>
|
||||
<!-- <module>yudao-module-bpm</module>-->
|
||||
<module>yudao-module-visualization</module>
|
||||
<module>yudao-module-mp</module>
|
||||
<!-- <module>yudao-module-mall</module>-->
|
||||
<!-- 示例项目 -->
|
||||
<module>yudao-example</module>
|
||||
</modules>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
|
@ -26,7 +30,7 @@
|
|||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<revision>1.6.2-snapshot</revision>
|
||||
<revision>1.6.5-snapshot</revision>
|
||||
<!-- Maven 相关 -->
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
|
@ -34,8 +38,8 @@
|
|||
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
|
||||
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||
<!-- 看看咋放到 bom 里 -->
|
||||
<lombok.version>1.18.20</lombok.version>
|
||||
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
||||
<lombok.version>1.18.24</lombok.version>
|
||||
<mapstruct.version>1.5.3.Final</mapstruct.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -0,0 +1,266 @@
|
|||
-- ----------------------------
|
||||
-- Table structure for system_menu
|
||||
-- icon 不兼容
|
||||
-- 注意!!!只有在使用 yudao-ui-admin-vue3 才进行导入!!!
|
||||
-- 注意!!!只有在使用 yudao-ui-admin-vue3 才进行导入!!!
|
||||
-- 注意!!!只有在使用 yudao-ui-admin-vue3 才进行导入!!!
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `system_menu`;
|
||||
CREATE TABLE `system_menu` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
|
||||
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '菜单名称',
|
||||
`permission` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '权限标识',
|
||||
`type` tinyint NOT NULL COMMENT '菜单类型',
|
||||
`sort` int NOT NULL DEFAULT 0 COMMENT '显示顺序',
|
||||
`parent_id` bigint NOT NULL DEFAULT 0 COMMENT '父菜单ID',
|
||||
`path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '路由地址',
|
||||
`icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '#' COMMENT '菜单图标',
|
||||
`component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '组件路径',
|
||||
`status` tinyint NOT NULL DEFAULT 0 COMMENT '菜单状态',
|
||||
`visible` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否可见',
|
||||
`keep_alive` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否缓存',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1268 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_menu
|
||||
-- ----------------------------
|
||||
INSERT INTO `system_menu` VALUES (1, '系统管理', '', 1, 10, 0, '/system', 'ep:tools', NULL, 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 13:10:54', b'0');
|
||||
INSERT INTO `system_menu` VALUES (2, '基础设施', '', 1, 20, 0, '/infra', 'ep:brush-filled', NULL, 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 13:11:55', b'0');
|
||||
INSERT INTO `system_menu` VALUES (5, 'OA 示例', '', 1, 40, 1185, 'oa', 'ep:guide', NULL, 0, b'1', b'1', 'admin', '2021-09-20 16:26:19', '1', '2022-07-20 14:51:03', b'0');
|
||||
INSERT INTO `system_menu` VALUES (100, '用户管理', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 13:13:17', b'0');
|
||||
INSERT INTO `system_menu` VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'ep:user-filled', 'system/role/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 13:13:41', b'0');
|
||||
INSERT INTO `system_menu` VALUES (102, '菜单管理', '', 2, 3, 1, 'menu', 'ep:grid', 'system/menu/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 13:13:54', b'0');
|
||||
INSERT INTO `system_menu` VALUES (103, '部门管理', '', 2, 4, 1, 'dept', 'ep:office-building', 'system/dept/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:51:31', b'0');
|
||||
INSERT INTO `system_menu` VALUES (104, '岗位管理', '', 2, 5, 1, 'post', 'ep:briefcase', 'system/post/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:41:47', b'0');
|
||||
INSERT INTO `system_menu` VALUES (105, '字典管理', '', 2, 6, 1, 'dict', 'ep:list', 'system/dict/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:42:18', b'0');
|
||||
INSERT INTO `system_menu` VALUES (106, '配置管理', '', 2, 6, 2, 'config', 'ep:edit', 'infra/config/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:48:29', b'0');
|
||||
INSERT INTO `system_menu` VALUES (107, '通知公告', '', 2, 8, 1, 'notice', 'ep:bell-filled', 'system/notice/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:42:30', b'0');
|
||||
INSERT INTO `system_menu` VALUES (108, '审计日志', '', 1, 9, 1, 'log', 'ep:document-checked', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:42:52', b'0');
|
||||
INSERT INTO `system_menu` VALUES (109, '令牌管理', '', 2, 2, 1261, 'token', 'online', 'system/oauth2/token/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-11 23:31:42', b'0');
|
||||
INSERT INTO `system_menu` VALUES (110, '定时任务', '', 2, 12, 2, 'job', 'ep:alarm-clock', 'infra/job/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:49:09', b'0');
|
||||
INSERT INTO `system_menu` VALUES (111, 'MySQL 监控', '', 2, 9, 2, 'druid', 'ep:wind-power', 'infra/druid/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:50:06', b'0');
|
||||
INSERT INTO `system_menu` VALUES (112, 'Java 监控', '', 2, 11, 2, 'admin-server', 'ep:opportunity', 'infra/server/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:49:42', b'0');
|
||||
INSERT INTO `system_menu` VALUES (113, 'Redis 监控', '', 2, 10, 2, 'redis', 'ep:set-up', 'infra/redis/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:49:52', b'0');
|
||||
INSERT INTO `system_menu` VALUES (114, '表单构建', 'infra:build:list', 2, 2, 2, 'build', 'ep:calendar', 'infra/build/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:47:29', b'0');
|
||||
INSERT INTO `system_menu` VALUES (115, '代码生成', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:connection', 'infra/codegen/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:46:41', b'0');
|
||||
INSERT INTO `system_menu` VALUES (116, '系统接口', 'infra:swagger:list', 2, 3, 2, 'swagger', 'ep:operation', 'infra/swagger/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-07-20 14:47:41', b'0');
|
||||
INSERT INTO `system_menu` VALUES (500, '操作日志', '', 2, 1, 108, 'operate-log', 'form', 'system/operatelog/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (501, '登录日志', '', 2, 2, 108, 'login-log', 'logininfor', 'system/loginlog/index', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1001, '用户查询', 'system:user:query', 3, 1, 100, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1002, '用户新增', 'system:user:create', 3, 2, 100, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1003, '用户修改', 'system:user:update', 3, 3, 100, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1004, '用户删除', 'system:user:delete', 3, 4, 100, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1005, '用户导出', 'system:user:export', 3, 5, 100, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1006, '用户导入', 'system:user:import', 3, 6, 100, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1007, '重置密码', 'system:user:update-password', 3, 7, 100, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1008, '角色查询', 'system:role:query', 3, 1, 101, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1009, '角色新增', 'system:role:create', 3, 2, 101, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1010, '角色修改', 'system:role:update', 3, 3, 101, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1011, '角色删除', 'system:role:delete', 3, 4, 101, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1012, '角色导出', 'system:role:export', 3, 5, 101, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1013, '菜单查询', 'system:menu:query', 3, 1, 102, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1014, '菜单新增', 'system:menu:create', 3, 2, 102, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1015, '菜单修改', 'system:menu:update', 3, 3, 102, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1016, '菜单删除', 'system:menu:delete', 3, 4, 102, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1017, '部门查询', 'system:dept:query', 3, 1, 103, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1018, '部门新增', 'system:dept:create', 3, 2, 103, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1019, '部门修改', 'system:dept:update', 3, 3, 103, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1020, '部门删除', 'system:dept:delete', 3, 4, 103, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1021, '岗位查询', 'system:post:query', 3, 1, 104, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1022, '岗位新增', 'system:post:create', 3, 2, 104, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1023, '岗位修改', 'system:post:update', 3, 3, 104, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1024, '岗位删除', 'system:post:delete', 3, 4, 104, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1025, '岗位导出', 'system:post:export', 3, 5, 104, '', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1026, '字典查询', 'system:dict:query', 3, 1, 105, '#', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1027, '字典新增', 'system:dict:create', 3, 2, 105, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1028, '字典修改', 'system:dict:update', 3, 3, 105, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1029, '字典删除', 'system:dict:delete', 3, 4, 105, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1030, '字典导出', 'system:dict:export', 3, 5, 105, '#', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1031, '配置查询', 'infra:config:query', 3, 1, 106, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1032, '配置新增', 'infra:config:create', 3, 2, 106, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1033, '配置修改', 'infra:config:update', 3, 3, 106, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1034, '配置删除', 'infra:config:delete', 3, 4, 106, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1035, '配置导出', 'infra:config:export', 3, 5, 106, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1037, '公告新增', 'system:notice:create', 3, 2, 107, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1038, '公告修改', 'system:notice:update', 3, 3, 107, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1039, '公告删除', 'system:notice:delete', 3, 4, 107, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1040, '操作查询', 'system:operate-log:query', 3, 1, 500, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1042, '日志导出', 'system:operate-log:export', 3, 2, 500, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1043, '登录查询', 'system:login-log:query', 3, 1, 501, '#', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1045, '日志导出', 'system:login-log:export', 3, 3, 501, '#', '#', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1046, '令牌列表', 'system:oauth2-token:page', 3, 1, 109, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:42', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1048, '令牌删除', 'system:oauth2-token:delete', 3, 2, 109, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:53', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1050, '任务新增', 'infra:job:create', 3, 2, 110, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1051, '任务修改', 'infra:job:update', 3, 3, 110, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1052, '任务删除', 'infra:job:delete', 3, 4, 110, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1053, '状态修改', 'infra:job:update', 3, 5, 110, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1054, '任务导出', 'infra:job:export', 3, 7, 110, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1056, '生成修改', 'infra:codegen:update', 3, 2, 115, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1057, '生成删除', 'infra:codegen:delete', 3, 3, 115, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1058, '导入代码', 'infra:codegen:create', 3, 2, 115, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1059, '预览代码', 'infra:codegen:preview', 3, 4, 115, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1060, '生成代码', 'infra:codegen:download', 3, 5, 115, '', '', '', 0, b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1063, '设置角色菜单权限', 'system:permission:assign-role-menu', 3, 6, 101, '', '', '', 0, b'1', b'1', '', '2021-01-06 17:53:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1064, '设置角色数据权限', 'system:permission:assign-role-data-scope', 3, 7, 101, '', '', '', 0, b'1', b'1', '', '2021-01-06 17:56:31', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1065, '设置用户角色', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', 0, b'1', b'1', '', '2021-01-07 10:23:28', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1066, '获得 Redis 监控信息', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', 0, b'1', b'1', '', '2021-01-26 01:02:31', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1067, '获得 Redis Key 列表', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', 0, b'1', b'1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1070, '代码生成示例', 'infra:test-demo:query', 2, 1, 2, 'test-demo', 'ep:baseball', 'infra/testDemo/index', 0, b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-07-20 14:46:53', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1071, '测试示例表创建', 'infra:test-demo:create', 3, 1, 1070, '', '', '', 0, b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1072, '测试示例表更新', 'infra:test-demo:update', 3, 2, 1070, '', '', '', 0, b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1073, '测试示例表删除', 'infra:test-demo:delete', 3, 3, 1070, '', '', '', 0, b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1074, '测试示例表导出', 'infra:test-demo:export', 3, 4, 1070, '', '', '', 0, b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', 0, b'1', b'1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1076, '数据库文档', '', 2, 4, 2, 'db-doc', 'ep:grid', 'infra/dbDoc/index', 0, b'1', b'1', '', '2021-02-08 01:41:47', '1', '2022-07-20 14:47:56', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1077, '监控平台', '', 2, 13, 2, 'skywalking', 'ep:aim', 'infra/skywalking/index', 0, b'1', b'1', '', '2021-02-08 20:41:31', '1', '2022-07-20 14:49:15', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'log', 'infra/apiAccessLog/index', 0, b'1', b'1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', 0, b'1', b'1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1083, 'API 日志', '', 2, 8, 2, 'log', 'ep:bell', NULL, 0, b'1', b'1', '', '2021-02-26 02:18:24', '1', '2022-07-20 14:48:36', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'log', 'infra/apiErrorLog/index', 0, b'1', b'1', '', '2021-02-26 07:53:20', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', 0, b'1', b'1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', 0, b'1', b'1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1087, '任务查询', 'infra:job:query', 3, 1, 110, '', '', '', 0, b'1', b'1', '1', '2021-03-10 01:26:19', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1088, '日志查询', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', 0, b'1', b'1', '1', '2021-03-10 01:28:04', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1089, '日志查询', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', 0, b'1', b'1', '1', '2021-03-10 01:29:09', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1090, '文件列表', '', 2, 5, 1243, 'file-list', 'upload', 'infra/fileList/index', 0, b'1', b'1', '', '2021-03-12 20:16:20', '1', '2022-07-20 12:10:47', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', 0, b'1', b'1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', 0, b'1', b'1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1093, '短信管理', '', 1, 11, 1, 'sms', 'ep:chat-dot-square', NULL, 0, b'1', b'1', '1', '2021-04-05 01:10:16', '1', '2022-07-20 14:43:32', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', 'phone', 'system/sms/smsChannel', 0, b'1', b'1', '', '2021-04-01 11:07:15', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', 0, b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', 0, b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1097, '短信渠道更新', 'system:sms-channel:update', 3, 3, 1094, '', '', '', 0, b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1098, '短信渠道删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', 0, b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1100, '短信模板', '', 2, 1, 1093, 'sms-template', 'phone', 'system/sms/smsTemplate', 0, b'1', b'1', '', '2021-04-01 17:35:17', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1101, '短信模板查询', 'system:sms-template:query', 3, 1, 1100, '', '', '', 0, b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1102, '短信模板创建', 'system:sms-template:create', 3, 2, 1100, '', '', '', 0, b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1103, '短信模板更新', 'system:sms-template:update', 3, 3, 1100, '', '', '', 0, b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1104, '短信模板删除', 'system:sms-template:delete', 3, 4, 1100, '', '', '', 0, b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1105, '短信模板导出', 'system:sms-template:export', 3, 5, 1100, '', '', '', 0, b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1106, '发送测试短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', 0, b'1', b'1', '1', '2021-04-11 00:26:40', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'phone', 'system/sms/smsLog', 0, b'1', b'1', '', '2021-04-11 08:37:05', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', 0, b'1', b'1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', 0, b'1', b'1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1110, '错误码管理', '', 2, 12, 1, 'error-code', 'ep:document-delete', 'system/errorCode/index', 0, b'1', b'1', '', '2021-04-13 21:46:42', '1', '2022-07-20 14:43:42', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1111, '错误码查询', 'system:error-code:query', 3, 1, 1110, '', '', '', 0, b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1112, '错误码创建', 'system:error-code:create', 3, 2, 1110, '', '', '', 0, b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1113, '错误码更新', 'system:error-code:update', 3, 3, 1110, '', '', '', 0, b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1114, '错误码删除', 'system:error-code:delete', 3, 4, 1110, '', '', '', 0, b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1115, '错误码导出', 'system:error-code:export', 3, 5, 1110, '', '', '', 0, b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1117, '支付管理', '', 1, 11, 0, '/pay', 'ep:goods-filled', NULL, 0, b'1', b'1', '1', '2021-12-25 16:43:41', '1', '2022-07-20 13:11:45', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1118, '请假查询', '', 2, 0, 5, 'leave', 'user', 'bpm/oa/leave/index', 0, b'1', b'1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1119, '请假申请查询', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', 0, b'1', b'1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1120, '请假申请创建', 'bpm:oa-leave:create', 3, 2, 1118, '', '', '', 0, b'1', b'1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1126, '应用信息', '', 2, 1, 1117, 'app', 'ep:cellphone', 'pay/app/index', 0, b'1', b'1', '', '2021-11-10 01:13:30', '1', '2022-07-20 14:44:17', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1127, '支付应用信息查询', 'pay:app:query', 3, 1, 1126, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1128, '支付应用信息创建', 'pay:app:create', 3, 2, 1126, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1129, '支付应用信息更新', 'pay:app:update', 3, 3, 1126, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1130, '支付应用信息删除', 'pay:app:delete', 3, 4, 1126, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1131, '支付应用信息导出', 'pay:app:export', 3, 5, 1126, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1132, '秘钥解析', 'pay:channel:parsing', 3, 6, 1129, '', '', '', 0, b'1', b'1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1133, '支付商户信息查询', 'pay:merchant:query', 3, 1, 1132, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1134, '支付商户信息创建', 'pay:merchant:create', 3, 2, 1132, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1135, '支付商户信息更新', 'pay:merchant:update', 3, 3, 1132, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1136, '支付商户信息删除', 'pay:merchant:delete', 3, 4, 1132, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1137, '支付商户信息导出', 'pay:merchant:export', 3, 5, 1132, '', '', '', 0, b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1138, '租户列表', '', 2, 0, 1224, 'list', 'peoples', 'system/tenant/index', 0, b'1', b'1', '', '2021-12-14 12:31:43', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1139, '租户查询', 'system:tenant:query', 3, 1, 1138, '', '', '', 0, b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1140, '租户创建', 'system:tenant:create', 3, 2, 1138, '', '', '', 0, b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1141, '租户更新', 'system:tenant:update', 3, 3, 1138, '', '', '', 0, b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1142, '租户删除', 'system:tenant:delete', 3, 4, 1138, '', '', '', 0, b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1143, '租户导出', 'system:tenant:export', 3, 5, 1138, '', '', '', 0, b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1150, '秘钥解析', '', 3, 6, 1129, '', '', '', 0, b'1', b'1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1161, '退款订单', '', 2, 3, 1117, 'refund', 'ep:message-box', 'pay/refund/index', 0, b'1', b'1', '', '2021-12-25 08:29:07', '1', '2022-07-20 14:45:23', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1162, '退款订单查询', 'pay:refund:query', 3, 1, 1161, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1163, '退款订单创建', 'pay:refund:create', 3, 2, 1161, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1164, '退款订单更新', 'pay:refund:update', 3, 3, 1161, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1165, '退款订单删除', 'pay:refund:delete', 3, 4, 1161, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1166, '退款订单导出', 'pay:refund:export', 3, 5, 1161, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1173, '支付订单', '', 2, 2, 1117, 'order', 'ep:histogram', 'pay/order/index', 0, b'1', b'1', '', '2021-12-25 08:49:43', '1', '2022-07-20 14:44:36', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1174, '支付订单查询', 'pay:order:query', 3, 1, 1173, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1175, '支付订单创建', 'pay:order:create', 3, 2, 1173, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1176, '支付订单更新', 'pay:order:update', 3, 3, 1173, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1177, '支付订单删除', 'pay:order:delete', 3, 4, 1173, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1178, '支付订单导出', 'pay:order:export', 3, 5, 1173, '', '', '', 0, b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1179, '商户信息', '', 2, 0, 1117, 'merchant', 'ep:goods', 'pay/merchant/index', 0, b'1', b'1', '', '2021-12-25 09:01:44', '1', '2022-07-20 14:44:58', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1180, '支付商户信息查询', 'pay:merchant:query', 3, 1, 1179, '', '', '', 0, b'1', b'1', '', '2021-12-25 09:01:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1181, '支付商户信息创建', 'pay:merchant:create', 3, 2, 1179, '', '', '', 0, b'1', b'1', '', '2021-12-25 09:01:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1182, '支付商户信息更新', 'pay:merchant:update', 3, 3, 1179, '', '', '', 0, b'1', b'1', '', '2021-12-25 09:01:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1183, '支付商户信息删除', '', 3, 4, 1179, '', '', '', 0, b'1', b'1', '', '2021-12-25 09:01:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1184, '支付商户信息导出', 'pay:merchant:export', 3, 5, 1179, '', '', '', 0, b'1', b'1', '', '2021-12-25 09:01:44', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1185, '工作流程', '', 1, 50, 0, '/bpm', 'ep:checked', NULL, 0, b'1', b'1', '1', '2021-12-30 20:26:36', '1', '2022-07-20 13:12:35', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1186, '流程管理', '', 1, 10, 1185, 'manager', 'ep:collection-tag', NULL, 0, b'1', b'1', '1', '2021-12-30 20:28:30', '1', '2022-07-20 14:50:31', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1187, '流程表单', '', 2, 0, 1186, 'form', 'form', 'bpm/form/index', 0, b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1188, '表单查询', 'bpm:form:query', 3, 1, 1187, '', '', '', 0, b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1189, '表单创建', 'bpm:form:create', 3, 2, 1187, '', '', '', 0, b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1190, '表单更新', 'bpm:form:update', 3, 3, 1187, '', '', '', 0, b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1191, '表单删除', 'bpm:form:delete', 3, 4, 1187, '', '', '', 0, b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1192, '表单导出', 'bpm:form:export', 3, 5, 1187, '', '', '', 0, b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1193, '流程模型', '', 2, 5, 1186, 'model', 'guide', 'bpm/model/index', 0, b'1', b'1', '1', '2021-12-31 23:24:58', '103', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1194, '模型查询', 'bpm:model:query', 3, 1, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-03 19:01:10', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1195, '模型创建', 'bpm:model:create', 3, 2, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-03 19:01:24', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1196, '模型导入', 'bpm:model:import', 3, 3, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-03 19:01:35', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1197, '模型更新', 'bpm:model:update', 3, 4, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-03 19:02:28', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1198, '模型删除', 'bpm:model:delete', 3, 5, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-03 19:02:43', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1199, '模型发布', 'bpm:model:deploy', 3, 6, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-03 19:03:24', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1200, '任务管理', '', 1, 20, 1185, 'task', 'ep:calendar', NULL, 0, b'1', b'1', '1', '2022-01-07 23:51:48', '1', '2022-07-20 14:50:40', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1201, '我的流程', '', 2, 0, 1200, 'my', 'people', 'bpm/processInstance/index', 0, b'1', b'1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1202, '流程实例的查询', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', 0, b'1', b'1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1207, '待办任务', '', 2, 10, 1200, 'todo', 'eye-open', 'bpm/task/todo', 0, b'1', b'1', '1', '2022-01-08 10:33:37', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1208, '已办任务', '', 2, 20, 1200, 'done', 'eye', 'bpm/task/done', 0, b'1', b'1', '1', '2022-01-08 10:34:13', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1209, '用户分组', '', 2, 2, 1186, 'user-group', 'people', 'bpm/group/index', 0, b'1', b'1', '', '2022-01-14 02:14:20', '103', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1210, '用户组查询', 'bpm:user-group:query', 3, 1, 1209, '', '', '', 0, b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1211, '用户组创建', 'bpm:user-group:create', 3, 2, 1209, '', '', '', 0, b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1212, '用户组更新', 'bpm:user-group:update', 3, 3, 1209, '', '', '', 0, b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1213, '用户组删除', 'bpm:user-group:delete', 3, 4, 1209, '', '', '', 0, b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1215, '流程定义查询', 'bpm:process-definition:query', 3, 10, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-23 00:21:43', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1216, '流程任务分配规则查询', 'bpm:task-assign-rule:query', 3, 20, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-23 00:26:53', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1217, '流程任务分配规则创建', 'bpm:task-assign-rule:create', 3, 21, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-23 00:28:15', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1218, '流程任务分配规则更新', 'bpm:task-assign-rule:update', 3, 22, 1193, '', '', '', 0, b'1', b'1', '1', '2022-01-23 00:28:41', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1219, '流程实例的创建', 'bpm:process-instance:create', 3, 2, 1201, '', '', '', 0, b'1', b'1', '1', '2022-01-23 00:36:15', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1220, '流程实例的取消', 'bpm:process-instance:cancel', 3, 3, 1201, '', '', '', 0, b'1', b'1', '1', '2022-01-23 00:36:33', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1221, '流程任务的查询', 'bpm:task:query', 3, 1, 1207, '', '', '', 0, b'1', b'1', '1', '2022-01-23 00:38:52', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1222, '流程任务的更新', 'bpm:task:update', 3, 2, 1207, '', '', '', 0, b'1', b'1', '1', '2022-01-23 00:39:24', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1224, '租户管理', '', 2, 0, 1, 'tenant', 'ep:cherry', NULL, 0, b'1', b'1', '1', '2022-02-20 01:41:13', '1', '2022-07-20 14:51:46', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1225, '租户套餐', '', 2, 0, 1224, 'package', 'eye', 'system/tenantPackage/index', 0, b'1', b'1', '', '2022-02-19 17:44:06', '1', '2022-04-21 01:21:25', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1226, '租户套餐查询', 'system:tenant-package:query', 3, 1, 1225, '', '', '', 0, b'1', b'1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1227, '租户套餐创建', 'system:tenant-package:create', 3, 2, 1225, '', '', '', 0, b'1', b'1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1228, '租户套餐更新', 'system:tenant-package:update', 3, 3, 1225, '', '', '', 0, b'1', b'1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1229, '租户套餐删除', 'system:tenant-package:delete', 3, 4, 1225, '', '', '', 0, b'1', b'1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1237, '文件配置', '', 2, 0, 1243, 'file-config', 'config', 'infra/fileConfig/index', 0, b'1', b'1', '', '2022-03-15 14:35:28', '1', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1238, '文件配置查询', 'infra:file-config:query', 3, 1, 1237, '', '', '', 0, b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1239, '文件配置创建', 'infra:file-config:create', 3, 2, 1237, '', '', '', 0, b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1240, '文件配置更新', 'infra:file-config:update', 3, 3, 1237, '', '', '', 0, b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', 0, b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', 0, b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1243, '文件管理', '', 2, 5, 2, 'file', 'ep:folder-opened', NULL, 0, b'1', b'1', '1', '2022-03-16 23:47:40', '1', '2022-07-20 14:48:19', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1247, '敏感词管理', '', 2, 13, 1, 'sensitive-word', 'ep:document-copy', 'system/sensitiveWord/index', 0, b'1', b'1', '', '2022-04-07 16:55:03', '1', '2022-07-20 14:43:53', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1248, '敏感词查询', 'system:sensitive-word:query', 3, 1, 1247, '', '', '', 0, b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1249, '敏感词创建', 'system:sensitive-word:create', 3, 2, 1247, '', '', '', 0, b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1250, '敏感词更新', 'system:sensitive-word:update', 3, 3, 1247, '', '', '', 0, b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1251, '敏感词删除', 'system:sensitive-word:delete', 3, 4, 1247, '', '', '', 0, b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1252, '敏感词导出', 'system:sensitive-word:export', 3, 5, 1247, '', '', '', 0, b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:bell-filled', NULL, 0, b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2022-07-20 13:12:43', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:coin', 'infra/dataSourceConfig/index', 0, b'1', b'1', '', '2022-04-27 14:37:32', '1', '2022-07-20 14:49:01', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', 0, b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', 0, b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1258, '数据源配置更新', 'infra:data-source-config:update', 3, 3, 1255, '', '', '', 0, b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1259, '数据源配置删除', 'infra:data-source-config:delete', 3, 4, 1255, '', '', '', 0, b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1260, '数据源配置导出', 'infra:data-source-config:export', 3, 5, 1255, '', '', '', 0, b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1261, '授权管理', '', 1, 10, 1, 'oauth2', 'ep:connection', NULL, 0, b'1', b'1', '1', '2022-05-09 23:38:17', '1', '2022-07-20 14:43:23', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1263, '应用管理', '', 2, 0, 1261, 'oauth2/application', 'tool', 'system/oauth2/client/index', 0, b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 23:31:36', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1264, '客户端查询', 'system:oauth2-client:query', 3, 1, 1263, '', '', '', 0, b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:06', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1265, '客户端创建', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', 0, b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:23', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1266, '客户端更新', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', 0, b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:28', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1267, '客户端删除', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', 0, b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1281, '可视化报表', '', 1, 12, 0, '/visualization', 'ep:histogram', NULL, 0, b'1', b'1', '1', '2022-07-10 20:22:15', '1', '2022-07-10 20:33:30', b'0');
|
||||
INSERT INTO `system_menu` VALUES (1282, '积木报表', '', 2, 1, 1281, 'jimu-report', 'ep:histogram', 'visualization/jmreport/index', 0, b'1', b'1', '1', '2022-07-10 20:26:36', '1', '2022-07-28 21:17:34', b'0');
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,85 @@
|
|||
DROP TABLE IF EXISTS `coupon`;
|
||||
CREATE TABLE `coupon`
|
||||
(
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
`type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券类型 reward-满减 discount-折扣 random-随机',
|
||||
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券名称',
|
||||
`coupon_type_id` bigint UNSIGNED DEFAULT 0 COMMENT '优惠券类型id',
|
||||
`coupon_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券编码',
|
||||
`member_id` bigint UNSIGNED NOT NULL DEFAULT 0 COMMENT '领用人',
|
||||
`use_order_id` bigint UNSIGNED NOT NULL DEFAULT 0 COMMENT '优惠券使用订单id',
|
||||
`goods_type` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '适用商品类型1-全部商品可用;2-指定商品可用;3-指定商品不可用',
|
||||
`goods_ids` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '适用商品id',
|
||||
`at_least` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最小金额',
|
||||
`money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '面额',
|
||||
`discount` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '1 =< 折扣 <= 9.9 当type为discount时需要添加',
|
||||
`discount_limit` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最多折扣金额 当type为discount时可选择性添加',
|
||||
`whether_forbid_preference` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用',
|
||||
`whether_expire_notice` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否开启过期提醒0-不开启 1-开启',
|
||||
`expire_notice_fixed_term` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '过期前N天提醒',
|
||||
`whether_noticed` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否已提醒',
|
||||
`state` tinyint(4) UNSIGNED NOT NULL DEFAULT 0 COMMENT '优惠券状态 1已领用(未使用) 2已使用 3已过期',
|
||||
`get_type` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '获取方式1订单2.直接领取3.活动领取 4转赠 5分享获取',
|
||||
`fetch_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '领取时间',
|
||||
`use_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '使用时间',
|
||||
`start_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '可使用的开始时间',
|
||||
`end_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '有效期结束时间',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB
|
||||
AUTO_INCREMENT = 119
|
||||
CHARACTER SET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci COMMENT = '优惠券';
|
||||
|
||||
DROP TABLE IF EXISTS `coupon_templete`;
|
||||
CREATE TABLE `coupon_templete`
|
||||
(
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
`type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券类型 reward-满减 discount-折扣 random-随机',
|
||||
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '优惠券名称',
|
||||
`coupon_name_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '名称备注',
|
||||
`image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '优惠券图片',
|
||||
`count` int(11) NOT NULL DEFAULT 0 COMMENT '发放数量',
|
||||
`lead_count` int(11) NOT NULL DEFAULT 0 COMMENT '已领取数量',
|
||||
`used_count` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '已使用数量',
|
||||
`goods_type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '适用商品类型1-全部商品可用;2-指定商品可用;3-指定商品不可用',
|
||||
`product_ids` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '适用商品id',
|
||||
`has_use_limit` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '使用门槛0-无门槛 1-有门槛',
|
||||
`at_least` decimal(10, 2) NOT NULL DEFAULT 0 COMMENT '满多少元使用 0代表无限制',
|
||||
`money` decimal(10, 2) NOT NULL DEFAULT 0 COMMENT '发放面额 当type为reward时需要添加',
|
||||
`discount` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '1 =< 折扣 <= 9.9 当type为discount时需要添加',
|
||||
`discount_limit` decimal(10, 2) NOT NULL DEFAULT 0 COMMENT '最多折扣金额 当type为discount时可选择性添加',
|
||||
`min_money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最低金额 当type为radom时需要添加',
|
||||
`max_money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最大金额 当type为radom时需要添加',
|
||||
`validity_type` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期',
|
||||
`start_use_time` datetime COMMENT '使用开始日期 过期类型1时必填',
|
||||
`end_use_time` datetime COMMENT '使用结束日期 过期类型1时必填',
|
||||
`fixed_term` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效',
|
||||
`whether_limitless` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否无限制0-否 1是',
|
||||
`max_fetch` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '每人最大领取个数',
|
||||
`whether_expire_notice` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否开启过期提醒0-不开启 1-开启',
|
||||
`expire_notice_fixed_term` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '过期前N天提醒',
|
||||
`whether_forbid_preference` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用',
|
||||
`whether_show` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否显示',
|
||||
`discount_order_money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '订单的优惠总金额',
|
||||
`order_money` decimal(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '用券总成交额',
|
||||
`whether_forbidden` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否禁止发放0-否 1-是',
|
||||
`order_goods_num` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '使用优惠券购买的商品数量',
|
||||
`status` tinyint(11) NOT NULL DEFAULT 0 COMMENT '状态(1进行中2已结束-1已关闭)',
|
||||
`end_time` datetime COMMENT '有效日期结束时间',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB
|
||||
AUTO_INCREMENT = 119
|
||||
CHARACTER SET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci COMMENT = '优惠券模板';
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : 127.0.0.1 MySQL
|
||||
Source Server Type : MySQL
|
||||
Source Server Version : 80026
|
||||
Source Host : localhost:3306
|
||||
Source Schema : ruoyi-vue-pro
|
||||
|
||||
Target Server Type : MySQL
|
||||
Target Server Version : 80026
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 01/08/2022 23:01:36
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for market_activity
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `market_activity`;
|
||||
CREATE TABLE `market_activity` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '活动编号',
|
||||
`title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '活动标题',
|
||||
`activity_type` tinyint NOT NULL COMMENT '活动类型',
|
||||
`status` tinyint NOT NULL DEFAULT -1 COMMENT '活动状态',
|
||||
`start_time` datetime NOT NULL COMMENT '开始时间',
|
||||
`end_time` datetime NOT NULL COMMENT '结束时间',
|
||||
`invalid_time` datetime NULL DEFAULT NULL COMMENT '失效时间',
|
||||
`delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
|
||||
`time_limited_discount` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '限制折扣字符串,使用 JSON 序列化成字符串存储',
|
||||
`full_privilege` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '限制折扣字符串,使用 JSON 序列化成字符串存储',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '促销活动';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of market_activity
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for market_banner
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `market_banner`;
|
||||
CREATE TABLE `market_banner` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'Banner编号',
|
||||
`title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT 'Banner标题',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '图片URL',
|
||||
`status` tinyint NOT NULL DEFAULT -1 COMMENT '活动状态',
|
||||
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '跳转地址',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`sort` tinyint NULL DEFAULT NULL COMMENT '排序',
|
||||
`memo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '描述',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Banner管理';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of market_banner
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for member_address
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `member_address`;
|
||||
CREATE TABLE `member_address` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '收件地址编号',
|
||||
`user_id` bigint NOT NULL COMMENT '用户编号',
|
||||
`name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收件人名称',
|
||||
`mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '手机号',
|
||||
`area_id` bigint NOT NULL COMMENT '地区编码',
|
||||
`post_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮编',
|
||||
`detail_address` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收件详细地址',
|
||||
`defaulted` bit(1) NOT NULL COMMENT '是否默认',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_userId`(`user_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户收件地址';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of member_address
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `member_address` (`id`, `user_id`, `name`, `mobile`, `area_id`, `post_code`, `detail_address`, `defaulted`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (21, 1, 'yunai', '15601691300', 610632, '200000', '芋道源码 233 号 666 室', b'1', '1', '2022-08-01 22:46:35', '1', '2022-08-01 22:46:35', b'0', 1);
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for product_brand
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_brand`;
|
||||
CREATE TABLE `product_brand` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '品牌编号',
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '品牌名称',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '品牌图片',
|
||||
`sort` int NULL DEFAULT 0 COMMENT '品牌排序',
|
||||
`description` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '品牌描述',
|
||||
`status` tinyint NOT NULL COMMENT '状态',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商品品牌';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of product_brand
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `product_brand` (`id`, `name`, `pic_url`, `sort`, `description`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '苹果', 'http://test.yudao.iocoder.cn/e3726713fa56db5717c78c011762fcc7a251db12735c3581470638b8e1fa17e2.jpeg', 0, '是上市', 0, '1', '2022-07-30 22:12:18', '1', '2022-07-30 22:13:55', b'0', 1);
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for product_category
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_category`;
|
||||
CREATE TABLE `product_category` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类编号',
|
||||
`parent_id` bigint NOT NULL COMMENT '父分类编号',
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分类名称',
|
||||
`pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分类图片',
|
||||
`sort` int NULL DEFAULT 0 COMMENT '分类排序',
|
||||
`description` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '分类描述',
|
||||
`status` tinyint NOT NULL COMMENT '开启状态',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商品分类';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of product_category
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `product_category` (`id`, `parent_id`, `name`, `pic_url`, `sort`, `description`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 0, '电脑办公', 'http://test.yudao.iocoder.cn/122d548e1b3cd5dec72fe8075c6977a70f9cc13541a684ab3685f1b5df42f6bd.jpeg', 1, '1234', 0, '1', '2022-07-30 16:36:35', '1', '2022-07-30 20:27:16', b'0', 1), (2, 1, '笔记本', 'http://test.yudao.iocoder.cn/72713ac7b947600a019a18786ed0e6562e8692e253dbd35110a0a85c2469bbec.jpg', 1, '<p>测试一下</p>', 0, '1', '2022-07-30 16:38:09', '1', '2022-07-30 16:38:09', b'0', 1), (3, 1, '游戏本', 'http://test.yudao.iocoder.cn/287c50dd9f5f575f57329a0c57b2095be6d1aeba83867b905fe549f54a296feb.jpg', 2, '<p>测试一下</p>', 0, '1', '2022-07-30 16:39:09', '1', '2022-07-30 20:26:59', b'0', 1), (4, 0, '手机', 'http://test.yudao.iocoder.cn/e1b63900c78dbb661b3e383960cee5cfea7e1dd2fb22cff2e317ff025faaf8b2.jpeg', 2, '<p>123</p>', 0, '1', '2022-07-30 16:40:00', '1', '2022-07-30 16:40:09', b'0', 1), (5, 4, '5G手机', 'http://test.yudao.iocoder.cn/3af6557ac7def6423f046f5b2e920b644793420b466959aaa996a2e19068bbde.jpeg', 1, '<p><br></p>', 0, '1', '2022-07-30 16:43:00', '1', '2022-07-30 16:43:00', b'0', 1), (6, 4, '游戏手机', 'http://test.yudao.iocoder.cn/964fe9ccd1710d64ede261dc36d231918a017641986c15293c367f9f66d94d05.jpeg', 2, NULL, 0, '1', '2022-07-30 16:43:44', '1', '2022-07-30 16:43:44', b'0', 1), (7, 5, '厉害的 5G 手机', 'http://test.yudao.iocoder.cn/b287122f277838e8de368769b96217918605743bc45f3a29bda3cc7359dc66e1.png', 0, '123', 0, '1', '2022-07-30 20:38:09', '1', '2022-07-30 20:38:09', b'0', 1);
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for product_property
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_property`;
|
||||
CREATE TABLE `product_property` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格名称',
|
||||
`status` tinyint NULL DEFAULT NULL COMMENT '状态: 0 开启 ,1 禁用',
|
||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_name`(`name`(32) ASC) USING BTREE COMMENT '规格名称索引'
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '规格名称';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of product_property
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for product_property_value
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_property_value`;
|
||||
CREATE TABLE `product_property_value` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`property_id` bigint NULL DEFAULT NULL COMMENT '规格键id',
|
||||
`name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格值名字',
|
||||
`status` tinyint NULL DEFAULT NULL COMMENT '状态: 1 开启 ,2 禁用',
|
||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '规格值';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of product_property_value
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for product_sku
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_sku`;
|
||||
CREATE TABLE `product_sku` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`spu_id` bigint NOT NULL COMMENT 'spu编号',
|
||||
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
|
||||
`name` varchar(128) DEFAULT NULL COMMENT '商品 SKU 名字',
|
||||
`properties` varchar(128) DEFAULT NULL COMMENT '规格值数组-json格式, [{propertId: , valueId: }, {propertId: , valueId: }]',
|
||||
`price` int NOT NULL DEFAULT '-1' COMMENT '销售价格,单位:分',
|
||||
`market_price` int DEFAULT NULL COMMENT '市场价',
|
||||
`cost_price` int NOT NULL DEFAULT '-1' COMMENT '成本价,单位: 分',
|
||||
`pic_url` varchar(128) NOT NULL COMMENT '图片地址',
|
||||
`stock` int DEFAULT NULL COMMENT '库存',
|
||||
`warn_stock` int DEFAULT NULL COMMENT '预警库存',
|
||||
`volume` double DEFAULT NULL COMMENT '商品体积',
|
||||
`weight` double DEFAULT NULL COMMENT '商品重量',
|
||||
`bar_code` varchar(64) DEFAULT NULL COMMENT '条形码',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态: 0-正常 1-禁用',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`updater` double(64,0) DEFAULT NULL COMMENT '更新人',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB COMMENT='商品sku';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of product_sku
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for product_spu
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `product_spu`;
|
||||
CREATE TABLE `product_spu` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
|
||||
`brand_id` bigint DEFAULT NULL COMMENT '商品品牌编号',
|
||||
`category_id` bigint NOT NULL COMMENT '分类id',
|
||||
`spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格',
|
||||
`code` varchar(128) DEFAULT NULL COMMENT '商品编码',
|
||||
`name` varchar(128) NOT NULL COMMENT '商品名称',
|
||||
`sell_point` varchar(128) DEFAULT NULL COMMENT '卖点',
|
||||
`description` text COMMENT '描述',
|
||||
`pic_urls` varchar(1024) DEFAULT '' COMMENT '商品轮播图地址\n 数组,以逗号分隔\n 最多上传15张',
|
||||
`video_url` varchar(128) DEFAULT NULL COMMENT '商品视频',
|
||||
`market_price` int DEFAULT NULL COMMENT '市场价,单位使用:分',
|
||||
`min_price` int DEFAULT NULL COMMENT '最小价格,单位使用:分',
|
||||
`max_price` int DEFAULT NULL COMMENT '最大价格,单位使用:分',
|
||||
`total_stock` int NOT NULL DEFAULT '0' COMMENT '总库存',
|
||||
`show_stock` int DEFAULT '0' COMMENT '是否展示库存',
|
||||
`sales_count` int DEFAULT '0' COMMENT '商品销量',
|
||||
`virtual_sales_count` int DEFAULT '0' COMMENT '虚拟销量',
|
||||
`click_count` int DEFAULT '0' COMMENT '商品点击量',
|
||||
`status` bit(1) DEFAULT NULL COMMENT '上下架状态: 0 上架(开启) 1 下架(禁用)-1 回收',
|
||||
`sort` int NOT NULL DEFAULT '0' COMMENT '排序字段',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`creator` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`updater` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB COMMENT='商品spu';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of product_spu
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2000, '商品中心', '', 1, 60, 0, '/product', 'merchant', NULL, 0, b'1', b'1', '', '2022-07-29 15:53:53', '1', '2022-07-30 22:26:19', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'dict', 'mall/product/category/index', 0, b'1', b'1', '', '2022-07-29 15:53:53', '1', '2022-07-30 22:23:37', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2003, '分类查询', 'product:category:query', 3, 1, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2004, '分类创建', 'product:category:create', 3, 2, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2005, '分类更新', 'product:category:update', 3, 3, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2006, '分类删除', 'product:category:delete', 3, 4, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2007, '分类导出', 'product:category:export', 3, 5, 2002, '', '', '', 0, b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-30 13:52:13', b'1');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2008, '商品品牌', '', 2, 1, 2000, 'brand', 'dashboard', 'mall/product/brand/index', 0, b'1', b'1', '', '2022-07-30 13:52:44', '1', '2022-07-30 22:23:43', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2009, '品牌查询', 'product:brand:query', 3, 1, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2010, '品牌创建', 'product:brand:create', 3, 2, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2011, '品牌更新', 'product:brand:update', 3, 3, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2012, '品牌删除', 'product:brand:delete', 3, 4, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2013, '品牌导出', 'product:brand:export', 3, 5, 2008, '', '', '', 0, b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 14:15:00', b'1');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2014, '商品管理', '', 2, 0, 2000, 'spu', 'link', 'mall/product/spu/index', 0, b'1', b'1', '', '2022-07-30 14:22:58', '1', '2022-07-30 22:26:35', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2015, '商品查询', 'product:spu:query', 3, 1, 2014, '', '', '', 0, b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2016, '商品创建', 'product:spu:create', 3, 2, 2014, '', '', '', 0, b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2017, '商品更新', 'product:spu:update', 3, 3, 2014, '', '', '', 0, b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2018, '商品删除', 'product:spu:delete', 3, 4, 2014, '', '', '', 0, b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2019, '规格管理', '', 2, 3, 2000, 'property', '', 'mall/product/property/index', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2020, '规格查询', 'product:property:query', 3, 1, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2024, '规格导出', 'product:property:export', 3, 5, 2019, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-08-01 14:55:35', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2025, 'Banner管理', '', 2, 1, 2000, 'banner', '', 'mall/market/banner/index', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2026, 'Banner查询', 'market:banner:query', 3, 1, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 'Banner创建', 'market:banner:create', 3, 2, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'market:banner:update', 3, 3, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
|
||||
INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'market:banner:delete', 3, 4, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/**todo cancelType 设置默认值 0?*/
|
||||
DROP TABLE IF EXISTS `trade_order`;
|
||||
CREATE TABLE `trade_order`
|
||||
(
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
`sn` varchar(32) NOT NULL COMMENT '订单流水号',
|
||||
`type` int NOT NULL DEFAULT '0' COMMENT '订单类型:[0:普通订单 1:秒杀订单 2:拼团订单 3:砍价订单]',
|
||||
`terminal` int NOT NULL COMMENT '订单来源终端:[1:小程序 2:H5 3:iOS 4:安卓]',
|
||||
`user_id` bigint unsigned NOT NULL COMMENT '用户编号',
|
||||
`user_ip` varchar(30) NOT NULL DEFAULT '' COMMENT '用户 IP',
|
||||
`user_remark` varchar(200) DEFAULT NULL COMMENT '用户备注',
|
||||
`status` int NOT NULL DEFAULT '0' COMMENT '订单状态:[0:待付款 1:待发货 2:待收货 3:已完成 4:已关闭]',
|
||||
`product_count` int NOT NULL COMMENT '购买的商品数量',
|
||||
`cancel_type` int DEFAULT NULL COMMENT '取消类型:[10:超时未支付 20:退款关闭 30:买家取消 40:已通过货到付款交易]',
|
||||
`remark` varchar(200) DEFAULT NULL COMMENT '商家备注',
|
||||
`payed` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已支付:[0:未支付 1:已经支付过]',
|
||||
`pay_time` datetime DEFAULT NULL COMMENT '订单支付时间',
|
||||
`finish_time` datetime DEFAULT NULL COMMENT '订单完成时间',
|
||||
`cancel_time` datetime DEFAULT NULL COMMENT '订单取消时间',
|
||||
`sku_original_price` int NOT NULL DEFAULT '0' COMMENT '商品原价(总),单位:分',
|
||||
`sku_promotion_price` int NOT NULL DEFAULT '0' COMMENT '商品优惠(总),单位:分',
|
||||
`order_promotion_price` int NOT NULL DEFAULT '0' COMMENT '订单优惠(总),单位:分',
|
||||
`delivery_price` int NOT NULL DEFAULT '0' COMMENT '运费金额,单位:分',
|
||||
`pay_price` int NOT NULL DEFAULT '0' COMMENT '应付金额(总),单位:分',
|
||||
`pay_order_id` int DEFAULT NULL COMMENT '支付订单编号',
|
||||
`pay_channel` int DEFAULT NULL COMMENT '支付成功的支付渠道',
|
||||
`delivery_type` int DEFAULT NULL DEFAULT '1' COMMENT '配送方式:[1:快递发货 2:自提]',
|
||||
`actual_delivery_type` int DEFAULT NULL DEFAULT '1' COMMENT '实际的配送方式:[1:快递发货 2:自提]',
|
||||
`delivery_template_id` int DEFAULT NULL COMMENT '配置模板的编号',
|
||||
`express_no` int DEFAULT NULL COMMENT '物流公司单号',
|
||||
`delivery_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '发货状态[0:未发货 1:已发货]',
|
||||
`delivery_time` datetime DEFAULT NULL COMMENT '发货时间',
|
||||
`receive_time` datetime DEFAULT NULL COMMENT '收货时间',
|
||||
`receiver_name` varchar(20) NOT NULL COMMENT '收件人名称',
|
||||
`receiver_mobile` varchar(20) NOT NULL COMMENT '收件人手机',
|
||||
`receiver_area_id` int NOT NULL COMMENT '收件人地区编号',
|
||||
`receiver_post_code` int DEFAULT NULL COMMENT '收件人邮编',
|
||||
`receiver_detail_address` varchar(255) NOT NULL COMMENT '收件人详细地址',
|
||||
`refund_status` int NOT NULL DEFAULT '0' COMMENT '订单状态:[0:未退款 1:部分退款 2:全部退款]',
|
||||
`refund_price` int NOT NULL DEFAULT '0' COMMENT '退款金额,单位:分',
|
||||
`coupon_id` bigint unsigned NOT NULL COMMENT '优惠劵编号',
|
||||
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB COMMENT ='交易订单表';
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `trade_order_item`;
|
||||
CREATE TABLE `trade_order_item`
|
||||
(
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
`user_id` bigint unsigned NOT NULL COMMENT '用户编号',
|
||||
`order_Id` bigint unsigned NOT NULL COMMENT '订单编号',
|
||||
`spu_id` bigint unsigned NOT NULL COMMENT '商品 SPU 编号',
|
||||
`sku_id` bigint unsigned NOT NULL COMMENT '商品 SKU 编号',
|
||||
`properties` json DEFAULT NULL COMMENT '规格值数组,JSON 格式',
|
||||
`name` varchar(128) NOT NULL DEFAULT '' COMMENT '商品名称',
|
||||
`pic_url` varchar(200) DEFAULT NULL COMMENT '商品图片',
|
||||
`count` int NOT NULL COMMENT '购买数量',
|
||||
`commented` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否评论:[0:未评论 1:已评论]',
|
||||
`original_price` int NOT NULL DEFAULT '0' COMMENT '商品原价(单),单位:分',
|
||||
`total_original_price` int NOT NULL DEFAULT '0' COMMENT '商品原价(总),单位:分',
|
||||
`total_promotion_price` int NOT NULL DEFAULT '0' COMMENT '商品级优惠(总),单位:分',
|
||||
`present_price` int NOT NULL DEFAULT '0' COMMENT '最终购买金额(单),单位:分。',
|
||||
`total_present_price` int NOT NULL DEFAULT '0' COMMENT '最终购买金额(总),单位:分。',
|
||||
`total_pay_price` int NOT NULL DEFAULT '0' COMMENT '应付金额(总),单位:分',
|
||||
`refund_status` int NOT NULL DEFAULT '0' COMMENT '退款状态:[0:未申请退款 1:申请退款 2:等待退款 3:退款成功]',
|
||||
`refund_total` int NOT NULL DEFAULT '0' COMMENT '退款总金额,单位:分',
|
||||
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB COMMENT ='交易订单明细表';
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@
|
|||
Target Server Version : 15004198
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 26/05/2022 01:01:02
|
||||
Date: 15/06/2022 08:15:45
|
||||
*/
|
||||
|
||||
|
||||
|
@ -2634,13 +2634,14 @@ CREATE TABLE [dbo].[infra_file] (
|
|||
[config_id] bigint NULL,
|
||||
[path] nvarchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[url] nvarchar(1024) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[type] nvarchar(63) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[type] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[size] int NOT NULL,
|
||||
[creator] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[create_time] datetime2(7) NOT NULL,
|
||||
[updater] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[update_time] datetime2(7) NOT NULL,
|
||||
[deleted] bit DEFAULT 0 NOT NULL
|
||||
[deleted] bit DEFAULT 0 NOT NULL,
|
||||
[name] nvarchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
|
||||
)
|
||||
GO
|
||||
|
||||
|
@ -2676,7 +2677,7 @@ EXEC sp_addextendedproperty
|
|||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'文件类型',
|
||||
'MS_Description', N'文件 MIME 类型',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'infra_file',
|
||||
'COLUMN', N'type'
|
||||
|
@ -2724,6 +2725,13 @@ EXEC sp_addextendedproperty
|
|||
'COLUMN', N'deleted'
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'文件路径',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'infra_file',
|
||||
'COLUMN', N'name'
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'文件表',
|
||||
'SCHEMA', N'dbo',
|
||||
|
@ -5537,11 +5545,7 @@ GO
|
|||
INSERT INTO [dbo].[system_dict_data] ([id], [sort], [label], [value], [dict_type], [status], [color_type], [css_class], [remark], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'63', N'1', N'已处理', N'1', N'infra_api_error_log_process_status', N'0', N'success', N'', NULL, N'', N'2021-02-26 07:07:26.0000000', N'1', N'2022-02-16 20:14:08.0000000', N'0')
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[system_dict_data] ([id], [sort], [label], [value], [dict_type], [status], [color_type], [css_class], [remark], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'64', N'2', N'已忽略', N'2', N'infra_api_error_log_process_status', N'0', N'danger', N'', NULL, N'', N'2021-02-26 07:07:34.0000000', N'1', N'2022-02-16 20:14:14.0000000', N'0')
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[system_dict_data] ([id], [sort], [label], [value], [dict_type], [status], [color_type], [css_class], [remark], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'65', N'1', N'云片', N'YUN_PIAN', N'system_sms_channel_code', N'0', N'success', N'', NULL, N'1', N'2021-04-05 01:05:14.0000000', N'1', N'2022-02-16 10:09:55.0000000', N'0')
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[system_dict_data] ([id], [sort], [label], [value], [dict_type], [status], [color_type], [css_class], [remark], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'66', N'2', N'阿里云', N'ALIYUN', N'system_sms_channel_code', N'0', N'primary', N'', NULL, N'1', N'2021-04-05 01:05:26.0000000', N'1', N'2022-02-16 10:09:52.0000000', N'0')
|
||||
GO
|
||||
|
@ -5809,18 +5813,51 @@ IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[sy
|
|||
DROP TABLE [dbo].[system_dict_type]
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[system_dict_type] (
|
||||
[id] bigint IDENTITY(1,1) NOT NULL,
|
||||
[name] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[type] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[status] tinyint NOT NULL,
|
||||
[remark] nvarchar(500) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[creator] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[create_time] datetime2(7) NOT NULL,
|
||||
[updater] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[update_time] datetime2(7) NOT NULL,
|
||||
[deleted] bit DEFAULT 0 NOT NULL
|
||||
)
|
||||
CREATE TABLE [dbo].[system_dict_type]
|
||||
(
|
||||
[
|
||||
id]
|
||||
bigint
|
||||
IDENTITY
|
||||
(
|
||||
1,
|
||||
1
|
||||
) NOT NULL,
|
||||
[name] nvarchar
|
||||
(
|
||||
100
|
||||
) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[type] nvarchar
|
||||
(
|
||||
100
|
||||
) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[status] tinyint NOT NULL,
|
||||
[remark] nvarchar
|
||||
(
|
||||
500
|
||||
) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[creator] nvarchar
|
||||
(
|
||||
64
|
||||
) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[create_time] datetime2
|
||||
(
|
||||
7
|
||||
) NOT NULL,
|
||||
[updater] nvarchar
|
||||
(
|
||||
64
|
||||
) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
[update_time] datetime2
|
||||
(
|
||||
7
|
||||
) NOT NULL,
|
||||
[deleted_time] datetime2
|
||||
(
|
||||
7
|
||||
),
|
||||
[deleted] bit DEFAULT 0 NOT NULL
|
||||
)
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[system_dict_type] SET (LOCK_ESCALATION = TABLE)
|
||||
|
@ -5878,26 +5915,29 @@ GO
|
|||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'更新者',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'system_dict_type',
|
||||
'COLUMN', N'updater'
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'更新时间',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'system_dict_type',
|
||||
'COLUMN', N'update_time'
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'是否删除',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'system_dict_type',
|
||||
'COLUMN', N'deleted'
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'字典类型表',
|
||||
'TABLE', N'system_dict_type',
|
||||
'COLUMN', N'updater'
|
||||
GO
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'更新时间',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'system_dict_type',
|
||||
'COLUMN', N'update_time'
|
||||
GO
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'删除时间',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'system_dict_type',
|
||||
'COLUMN', N'deleted_time'
|
||||
GO
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'是否删除',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'system_dict_type',
|
||||
'COLUMN', N'deleted'
|
||||
GO
|
||||
EXEC sp_addextendedproperty
|
||||
'MS_Description', N'字典类型表',
|
||||
'SCHEMA', N'dbo',
|
||||
'TABLE', N'system_dict_type'
|
||||
GO
|
||||
|
@ -9490,7 +9530,7 @@ GO
|
|||
|
||||
CREATE TABLE [dbo].[system_sms_channel] (
|
||||
[id] bigint IDENTITY(1,1) NOT NULL,
|
||||
[signature] nvarchar(10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[signature] nvarchar(12) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[code] nvarchar(63) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
[status] tinyint NOT NULL,
|
||||
[remark] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
|
@ -9615,9 +9655,6 @@ GO
|
|||
SET IDENTITY_INSERT [dbo].[system_sms_channel] ON
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[system_sms_channel] ([id], [signature], [code], [status], [remark], [api_key], [api_secret], [callback_url], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'1', N'芋道', N'YUN_PIAN', N'0', N'呵呵呵哒', N'1555a14277cb8a608cf45a9e6a80d510', NULL, N'http://vdwapu.natappfree.cc/admin-api/system/sms/callback/yunpian', N'', N'2021-03-31 06:12:20.0000000', N'1', N'2022-02-23 16:48:44.0000000', N'0')
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[system_sms_channel] ([id], [signature], [code], [status], [remark], [api_key], [api_secret], [callback_url], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'2', N'Ballcat', N'ALIYUN', N'0', N'啦啦啦', N'LTAI5tCnKso2uG3kJ5gRav88', N'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, N'', N'2021-03-31 11:53:10.0000000', N'1', N'2021-04-14 00:08:37.0000000', N'0')
|
||||
GO
|
||||
|
||||
|
@ -11340,7 +11377,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11361,7 +11398,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11370,7 +11407,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11379,7 +11416,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11388,7 +11425,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11397,7 +11434,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11406,7 +11443,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11427,7 +11464,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11448,7 +11485,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11469,7 +11506,7 @@ 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)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11485,7 +11522,7 @@ GO
|
|||
-- Primary Key structure for table bpm_form
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[bpm_form] ADD CONSTRAINT [PK__bpm_form__3213E83F86C2B27F] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11501,7 +11538,7 @@ GO
|
|||
-- Primary Key structure for table bpm_oa_leave
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[bpm_oa_leave] ADD CONSTRAINT [PK__bpm_oa_l__3213E83F3569F596] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11517,7 +11554,7 @@ GO
|
|||
-- Primary Key structure for table bpm_process_definition_ext
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[bpm_process_definition_ext] ADD CONSTRAINT [PK__bpm_proc__3213E83F0A8AB015] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11533,7 +11570,7 @@ GO
|
|||
-- Primary Key structure for table bpm_process_instance_ext
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[bpm_process_instance_ext] ADD CONSTRAINT [PK__bpm_proc__3213E83FFD88328F] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11549,7 +11586,7 @@ GO
|
|||
-- Primary Key structure for table bpm_task_assign_rule
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[bpm_task_assign_rule] ADD CONSTRAINT [PK__bpm_task__3213E83F474371C5] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11565,7 +11602,7 @@ GO
|
|||
-- Primary Key structure for table bpm_task_ext
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[bpm_task_ext] ADD CONSTRAINT [PK__bpm_task__3213E83FD8AFE1F9] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11581,7 +11618,7 @@ GO
|
|||
-- Primary Key structure for table bpm_user_group
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[bpm_user_group] ADD CONSTRAINT [PK__bpm_user__3213E83F25E4725B] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11597,7 +11634,7 @@ GO
|
|||
-- Primary Key structure for table infra_api_access_log
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_api_access_log] ADD CONSTRAINT [PK__infra_ap__3213E83F04F27A05] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11613,7 +11650,7 @@ GO
|
|||
-- Primary Key structure for table infra_api_error_log
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_api_error_log] ADD CONSTRAINT [PK__infra_ap__3213E83FCA2446D4] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11629,7 +11666,7 @@ GO
|
|||
-- Primary Key structure for table infra_codegen_column
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_codegen_column] ADD CONSTRAINT [PK__infra_co__3213E83FA9EC5005] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11645,7 +11682,7 @@ GO
|
|||
-- Primary Key structure for table infra_codegen_table
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_codegen_table] ADD CONSTRAINT [PK__infra_co__3213E83F555031D0] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11654,7 +11691,7 @@ GO
|
|||
-- Primary Key structure for table infra_config
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_config] ADD CONSTRAINT [PK__infra_co__3213E83FF4C71E85] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11670,7 +11707,7 @@ GO
|
|||
-- Primary Key structure for table infra_data_source_config
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_data_source_config] ADD CONSTRAINT [PK__infra_da__3213E83F02D21AEB] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11693,7 +11730,7 @@ GO
|
|||
-- Primary Key structure for table infra_file_config
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_file_config] ADD CONSTRAINT [PK__infra_fi__3213E83F8A7903EA] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11709,7 +11746,7 @@ GO
|
|||
-- Primary Key structure for table infra_file_content
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_file_content] ADD CONSTRAINT [PK__infra_fi__3213E83F033E6045] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11725,7 +11762,7 @@ GO
|
|||
-- Primary Key structure for table infra_job
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_job] ADD CONSTRAINT [PK__infra_jo__3213E83F3C7DE10C] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11741,7 +11778,7 @@ GO
|
|||
-- Primary Key structure for table infra_job_log
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[infra_job_log] ADD CONSTRAINT [PK__infra_jo__3213E83F4CA8F353] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11764,7 +11801,7 @@ GO
|
|||
-- Primary Key structure for table member_user
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[member_user] ADD CONSTRAINT [PK__member_u__3213E83F0A9AEC0B] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11780,7 +11817,7 @@ GO
|
|||
-- Primary Key structure for table pay_app
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[pay_app] ADD CONSTRAINT [PK__pay_app__3213E83FB26E0A6B] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11796,7 +11833,7 @@ GO
|
|||
-- Primary Key structure for table pay_channel
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[pay_channel] ADD CONSTRAINT [PK__pay_chan__3213E83F2556A7FC] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11812,7 +11849,7 @@ GO
|
|||
-- Primary Key structure for table pay_merchant
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[pay_merchant] ADD CONSTRAINT [PK__pay_merc__3213E83F010D02B8] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11828,7 +11865,7 @@ GO
|
|||
-- Primary Key structure for table pay_notify_log
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[pay_notify_log] ADD CONSTRAINT [PK__pay_noti__3213E83F5F4B3447] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11844,7 +11881,7 @@ GO
|
|||
-- Primary Key structure for table pay_notify_task
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[pay_notify_task] ADD CONSTRAINT [PK__pay_noti__3213E83FB9215103] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11860,7 +11897,7 @@ GO
|
|||
-- Primary Key structure for table pay_order
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[pay_order] ADD CONSTRAINT [PK__pay_orde__3213E83F34C95271] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11876,7 +11913,7 @@ GO
|
|||
-- Primary Key structure for table pay_order_extension
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[pay_order_extension] ADD CONSTRAINT [PK__pay_orde__3213E83F5ACB776F] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11892,7 +11929,7 @@ GO
|
|||
-- Primary Key structure for table pay_refund
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[pay_refund] ADD CONSTRAINT [PK__pay_refu__3213E83FBE1B54AC] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11908,7 +11945,7 @@ GO
|
|||
-- Primary Key structure for table system_dept
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_dept] ADD CONSTRAINT [PK__system_d__3213E83FFA72847C] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11924,7 +11961,7 @@ GO
|
|||
-- Primary Key structure for table system_dict_data
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_dict_data] ADD CONSTRAINT [PK__system_d__3213E83F20407597] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11940,7 +11977,7 @@ GO
|
|||
-- Primary Key structure for table system_dict_type
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_dict_type] ADD CONSTRAINT [PK__system_d__3213E83F7C36B1FD] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11956,7 +11993,7 @@ GO
|
|||
-- Primary Key structure for table system_error_code
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_error_code] ADD CONSTRAINT [PK__system_e__3213E83F68B8DFD0] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11972,7 +12009,7 @@ GO
|
|||
-- Primary Key structure for table system_login_log
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_login_log] ADD CONSTRAINT [PK__system_l__3213E83F717953E9] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -11988,7 +12025,7 @@ GO
|
|||
-- Primary Key structure for table system_menu
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_menu] ADD CONSTRAINT [PK__system_m__3213E83F14175801] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12004,7 +12041,7 @@ GO
|
|||
-- Primary Key structure for table system_notice
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_notice] ADD CONSTRAINT [PK__system_n__3213E83FA158BA8D] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12027,7 +12064,7 @@ GO
|
|||
-- Primary Key structure for table system_oauth2_approve
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_oauth2_approve] ADD CONSTRAINT [PK__system_o__3213E83F7CC08ED6] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12050,7 +12087,7 @@ GO
|
|||
-- Primary Key structure for table system_oauth2_code
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_oauth2_code] ADD CONSTRAINT [PK__system_o__3213E83F38C13543] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12066,7 +12103,7 @@ GO
|
|||
-- Primary Key structure for table system_oauth2_refresh_token
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_oauth2_refresh_token] ADD CONSTRAINT [PK__system_o__3213E83FCFB541CC] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12082,7 +12119,7 @@ GO
|
|||
-- Primary Key structure for table system_operate_log
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_operate_log] ADD CONSTRAINT [PK__system_o__3213E83F85EC81FD] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12098,7 +12135,7 @@ GO
|
|||
-- Primary Key structure for table system_post
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_post] ADD CONSTRAINT [PK__system_p__3213E83FBC098F34] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12114,7 +12151,7 @@ GO
|
|||
-- Primary Key structure for table system_role
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_role] ADD CONSTRAINT [PK__system_r__3213E83F209B43F2] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12130,7 +12167,7 @@ GO
|
|||
-- Primary Key structure for table system_role_menu
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_role_menu] ADD CONSTRAINT [PK__system_r__3213E83F6F1E4A9B] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12146,7 +12183,7 @@ GO
|
|||
-- Primary Key structure for table system_sensitive_word
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_sensitive_word] ADD CONSTRAINT [PK__system_s__3213E83FFFD8E555] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12162,7 +12199,7 @@ GO
|
|||
-- Primary Key structure for table system_sms_channel
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_sms_channel] ADD CONSTRAINT [PK__system_s__3213E83FA96B966E] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12178,7 +12215,7 @@ GO
|
|||
-- Primary Key structure for table system_sms_code
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_sms_code] ADD CONSTRAINT [PK__system_s__3213E83F825CBCB9] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12194,7 +12231,7 @@ GO
|
|||
-- Primary Key structure for table system_sms_log
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_sms_log] ADD CONSTRAINT [PK__system_s__3213E83F5F1968A9] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12210,7 +12247,7 @@ GO
|
|||
-- Primary Key structure for table system_sms_template
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_sms_template] ADD CONSTRAINT [PK__system_s__3213E83F5C91CA37] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12226,7 +12263,7 @@ GO
|
|||
-- Primary Key structure for table system_social_user
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_social_user] ADD CONSTRAINT [PK__system_s__3213E83F6EF3863C] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12242,7 +12279,7 @@ GO
|
|||
-- Primary Key structure for table system_social_user_bind
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_social_user_bind] ADD CONSTRAINT [PK__system_s__3213E83F21F44049] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12258,7 +12295,7 @@ GO
|
|||
-- Primary Key structure for table system_tenant
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_tenant] ADD CONSTRAINT [PK__system_t__3213E83FAF444092] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12274,7 +12311,7 @@ GO
|
|||
-- Primary Key structure for table system_tenant_package
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_tenant_package] ADD CONSTRAINT [PK__system_t__3213E83FA2213DB5] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12290,7 +12327,7 @@ GO
|
|||
-- Primary Key structure for table system_user_post
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_user_post] ADD CONSTRAINT [PK__system_u__3213E83F56DD4107] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12306,7 +12343,7 @@ GO
|
|||
-- Primary Key structure for table system_user_role
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_user_role] ADD CONSTRAINT [PK__system_u__3213E83F3593F652] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
@ -12322,7 +12359,7 @@ GO
|
|||
-- Primary Key structure for table system_users
|
||||
-- ----------------------------
|
||||
ALTER TABLE [dbo].[system_users] ADD CONSTRAINT [PK__system_u__3213E83F7CF2516E] PRIMARY KEY CLUSTERED ([id])
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
|
||||
ON [PRIMARY]
|
||||
GO
|
||||
|
||||
|
|
|
@ -14,56 +14,59 @@
|
|||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<revision>1.6.2-snapshot</revision>
|
||||
<revision>1.6.5-snapshot</revision>
|
||||
<!-- 统一依赖管理 -->
|
||||
<spring.boot.version>2.5.12</spring.boot.version>
|
||||
<spring.boot.version>2.7.6</spring.boot.version>
|
||||
<!-- Web 相关 -->
|
||||
<knife4j.version>3.0.2</knife4j.version>
|
||||
<swagger-annotations.version>1.5.22</swagger-annotations.version>
|
||||
<knife4j.version>3.0.3</knife4j.version>
|
||||
<swagger-annotations.version>1.6.8</swagger-annotations.version>
|
||||
<servlet.versoin>2.5</servlet.versoin>
|
||||
<!-- DB 相关 -->
|
||||
<druid.version>1.2.8</druid.version>
|
||||
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
||||
<druid.version>1.2.15</druid.version>
|
||||
<mybatis-plus.version>3.5.2</mybatis-plus.version>
|
||||
<mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
|
||||
<dynamic-datasource.version>3.5.0</dynamic-datasource.version>
|
||||
<redisson.version>3.17.0</redisson.version>
|
||||
<!-- Config 配置中心相关 -->
|
||||
<apollo.version>1.9.2</apollo.version>
|
||||
<!-- Job 定时任务相关 -->
|
||||
<dynamic-datasource.version>3.6.0</dynamic-datasource.version>
|
||||
<redisson.version>3.18.0</redisson.version>
|
||||
<!-- 服务保障相关 -->
|
||||
<lock4j.version>2.2.0</lock4j.version>
|
||||
<resilience4j.version>1.7.0</resilience4j.version>
|
||||
<lock4j.version>2.2.3</lock4j.version>
|
||||
<resilience4j.version>1.7.1</resilience4j.version>
|
||||
<!-- 监控相关 -->
|
||||
<skywalking.version>8.7.0</skywalking.version>
|
||||
<spring-boot-admin.version>2.6.2</spring-boot-admin.version>
|
||||
<opentracing.version>0.31.0</opentracing.version>
|
||||
<skywalking.version>8.12.0</skywalking.version>
|
||||
<spring-boot-admin.version>2.7.9</spring-boot-admin.version>
|
||||
<opentracing.version>0.33.0</opentracing.version>
|
||||
<!-- Test 测试相关 -->
|
||||
<podam.version>7.2.6.RELEASE</podam.version>
|
||||
<jedis-mock.version>0.1.16</jedis-mock.version>
|
||||
<mockito-inline.version>3.9.0</mockito-inline.version>
|
||||
<podam.version>7.2.11.RELEASE</podam.version>
|
||||
<jedis-mock.version>1.0.5</jedis-mock.version>
|
||||
<mockito-inline.version>4.8.0</mockito-inline.version>
|
||||
<!-- Bpm 工作流相关 -->
|
||||
<activiti.version>7.1.0.M6</activiti.version>
|
||||
<flowable.version>6.7.0</flowable.version>
|
||||
<flowable.version>6.7.2</flowable.version>
|
||||
<!-- 工具类相关 -->
|
||||
<jasypt-spring-boot-starter.version>3.0.4</jasypt-spring-boot-starter.version>
|
||||
<lombok.version>1.18.20</lombok.version>
|
||||
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
||||
<hutool.version>5.6.1</hutool.version>
|
||||
<easyexcel.verion>2.2.7</easyexcel.verion>
|
||||
<velocity.version>2.2</velocity.version>
|
||||
<lombok.version>1.18.24</lombok.version>
|
||||
<mapstruct.version>1.5.3.Final</mapstruct.version>
|
||||
<hutool.version>5.8.10</hutool.version>
|
||||
<easyexcel.verion>3.1.3</easyexcel.verion>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<screw.version>1.0.5</screw.version>
|
||||
<guava.version>30.1.1-jre</guava.version>
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
<guice.version>5.1.0</guice.version>
|
||||
<transmittable-thread-local.version>2.12.2</transmittable-thread-local.version>
|
||||
<transmittable-thread-local.version>2.14.2</transmittable-thread-local.version>
|
||||
<commons-net.version>3.8.0</commons-net.version>
|
||||
<jsch.version>0.1.55</jsch.version>
|
||||
<tika-core.version>2.6.0</tika-core.version>
|
||||
<aj-captcha.version>1.3.0</aj-captcha.version>
|
||||
<netty-all.version>4.1.85.Final</netty-all.version>
|
||||
<ip2region.version>2.6.6</ip2region.version>
|
||||
<!-- 三方云服务相关 -->
|
||||
<minio.version>8.2.2</minio.version>
|
||||
<aliyun-java-sdk-core.version>4.5.25</aliyun-java-sdk-core.version>
|
||||
<aliyun-java-sdk-dysmsapi.version>2.1.0</aliyun-java-sdk-dysmsapi.version>
|
||||
<tencentcloud-sdk-java.version>3.1.471</tencentcloud-sdk-java.version>
|
||||
<yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
|
||||
<okio.version>3.0.0</okio.version>
|
||||
<okhttp3.version>4.10.0</okhttp3.version>
|
||||
<minio.version>8.4.6</minio.version>
|
||||
<aliyun-java-sdk-core.version>4.6.3</aliyun-java-sdk-core.version>
|
||||
<aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
|
||||
<tencentcloud-sdk-java.version>3.1.637</tencentcloud-sdk-java.version>
|
||||
<justauth.version>1.4.0</justauth.version>
|
||||
<jimureport.version>1.5.6</jimureport.version>
|
||||
<xercesImpl.version>2.12.2</xercesImpl.version>
|
||||
<wx-java-mp.version>4.3.0</wx-java-mp.version>
|
||||
</properties>
|
||||
|
||||
|
@ -79,6 +82,11 @@
|
|||
</dependency>
|
||||
|
||||
<!-- 业务组件 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-banner</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
|
||||
|
@ -119,6 +127,21 @@
|
|||
<artifactId>yudao-spring-boot-starter-biz-social</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-error-code</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-captcha</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring 核心 -->
|
||||
<dependency>
|
||||
|
@ -207,17 +230,6 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Config 配置中心相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-config</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ctrip.framework.apollo</groupId>
|
||||
<artifactId>apollo-client</artifactId> <!-- 引入 Apollo Client 库,实现内嵌的配置中心 -->
|
||||
<version>${apollo.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 定时任务相关 -->
|
||||
<dependency>
|
||||
|
@ -365,41 +377,6 @@
|
|||
</dependency>
|
||||
|
||||
<!-- 工作流相关 -->
|
||||
<dependency>
|
||||
<groupId>org.activiti</groupId>
|
||||
<artifactId>activiti-spring-boot-starter</artifactId>
|
||||
<version>${activiti.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>de.odysseus.juel</groupId>
|
||||
<artifactId>juel-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>de.odysseus.juel</groupId>
|
||||
<artifactId>juel-spi</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>el-api</artifactId>
|
||||
<groupId>javax.el</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.activiti</groupId>
|
||||
<artifactId>activiti-image-generator</artifactId>
|
||||
<version>${activiti.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-activiti</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- 工作流相关 flowable -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-flowable</artifactId>
|
||||
|
@ -407,7 +384,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flowable</groupId>
|
||||
<artifactId>flowable-spring-boot-starter-basic</artifactId>
|
||||
<artifactId>flowable-spring-boot-starter-process</artifactId>
|
||||
<version>${flowable.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -424,12 +401,6 @@
|
|||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ulisesbocchio</groupId>
|
||||
<artifactId>jasypt-spring-boot-starter</artifactId> <!-- 加解密 -->
|
||||
<version>${jasypt-spring-boot-starter.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
||||
|
@ -470,12 +441,30 @@
|
|||
<version>${easyexcel.verion}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId> <!-- 文件类型的识别 -->
|
||||
<version>${tika-core.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.anji-plus</groupId>
|
||||
<artifactId>spring-boot-starter-captcha</artifactId>
|
||||
<version>${aj-captcha.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>cn.smallbun.screw</groupId>
|
||||
<artifactId>screw-core</artifactId> <!-- 实现数据库文档 -->
|
||||
|
@ -484,6 +473,10 @@
|
|||
<exclusion>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId> <!-- 移除 Freemarker 依赖,采用 Velocity 作为模板引擎 -->
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId> <!-- 最新版screw-core1.0.5依赖fastjson1.2.73存在漏洞,移除。 -->
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
@ -511,13 +504,36 @@
|
|||
<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>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>${netty-all.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
<version>${ip2region.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 三方云服务相关 -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okio</groupId>
|
||||
<artifactId>okio</artifactId>
|
||||
<version>${okio.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-file</artifactId>
|
||||
|
@ -530,11 +546,6 @@
|
|||
</dependency>
|
||||
|
||||
<!-- SMS SDK begin -->
|
||||
<dependency>
|
||||
<groupId>com.yunpian.sdk</groupId>
|
||||
<artifactId>yunpian-java-sdk</artifactId>
|
||||
<version>${yunpian-java-sdk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-core</artifactId>
|
||||
|
@ -557,7 +568,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.tencentcloudapi</groupId>
|
||||
<artifactId>tencentcloud-sdk-java</artifactId>
|
||||
<artifactId>tencentcloud-sdk-java-sms</artifactId>
|
||||
<version>${tencentcloud-sdk-java.version}</version>
|
||||
</dependency>
|
||||
<!-- SMS SDK end -->
|
||||
|
@ -574,6 +585,23 @@
|
|||
<version>${wx-java-mp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 积木报表-->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-spring-boot-starter</artifactId>
|
||||
<version>${jimureport.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xerces</groupId>
|
||||
<artifactId>xercesImpl</artifactId>
|
||||
<version>${xercesImpl.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- 由于方便大家拷贝,使用不使用 yudao 作为 Maven parent -->
|
||||
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-example</artifactId>
|
||||
<version>1.0.0-snapshot</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>yudao-sso-demo-by-code</module>
|
||||
<module>yudao-sso-demo-by-password</module>
|
||||
</modules>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>提供各种示例,例如说:SSO 单点登录</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,65 @@
|
|||
<?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>
|
||||
|
||||
<!-- 由于方便大家拷贝,使用不使用 yudao 作为 Maven parent -->
|
||||
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-sso-demo-by-code</artifactId>
|
||||
<version>1.0.0-snapshot</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>基于授权码模式,如何实现 SSO 单点登录?</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<!-- Maven 相关 -->
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- 统一依赖管理 -->
|
||||
<spring.boot.version>2.7.6</spring.boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- 统一依赖管理 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.10</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
package cn.iocoder.yudao.ssodemo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SSODemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SSODemoApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
package cn.iocoder.yudao.ssodemo.client;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2AccessTokenRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 客户端
|
||||
*
|
||||
* 对应调用 OAuth2OpenController 接口
|
||||
*/
|
||||
@Component
|
||||
public class OAuth2Client {
|
||||
|
||||
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2";
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*
|
||||
* 默认使用 1;如果使用别的租户,可以调整
|
||||
*/
|
||||
public static final Long TENANT_ID = 1L;
|
||||
|
||||
private static final String CLIENT_ID = "yudao-sso-demo-by-code";
|
||||
private static final String CLIENT_SECRET = "test";
|
||||
|
||||
|
||||
// @Resource // 可优化,注册一个 RestTemplate Bean,然后注入
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
/**
|
||||
* 使用 code 授权码,获得访问令牌
|
||||
*
|
||||
* @param code 授权码
|
||||
* @param redirectUri 重定向 URI
|
||||
* @return 访问令牌
|
||||
*/
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> postAccessToken(String code, String redirectUri) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", TENANT_ID.toString());
|
||||
addClientHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("grant_type", "authorization_code");
|
||||
body.add("code", code);
|
||||
body.add("redirect_uri", redirectUri);
|
||||
// body.add("state", ""); // 选填;填了会校验
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<OAuth2AccessTokenRespDTO>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/token",
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<OAuth2AccessTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验访问令牌,并返回它的基本信息
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @return 访问令牌的基本信息
|
||||
*/
|
||||
public CommonResult<OAuth2CheckTokenRespDTO> checkToken(String token) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", TENANT_ID.toString());
|
||||
addClientHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("token", token);
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<OAuth2CheckTokenRespDTO>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/check-token",
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<OAuth2CheckTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用刷新令牌,获得(刷新)访问令牌
|
||||
*
|
||||
* @param refreshToken 刷新令牌
|
||||
* @return 访问令牌
|
||||
*/
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> refreshToken(String refreshToken) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", TENANT_ID.toString());
|
||||
addClientHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("grant_type", "refresh_token");
|
||||
body.add("refresh_token", refreshToken);
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<OAuth2AccessTokenRespDTO>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/token",
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<OAuth2AccessTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除访问令牌
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @return 成功
|
||||
*/
|
||||
public CommonResult<Boolean> revokeToken(String token) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", TENANT_ID.toString());
|
||||
addClientHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("token", token);
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<Boolean>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/token",
|
||||
HttpMethod.DELETE,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<Boolean>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
private static void addClientHeader(HttpHeaders headers) {
|
||||
// client 拼接,需要 BASE64 编码
|
||||
String client = CLIENT_ID + ":" + CLIENT_SECRET;
|
||||
client = Base64Utils.encodeToString(client.getBytes(StandardCharsets.UTF_8));
|
||||
headers.add("Authorization", "Basic " + client);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package cn.iocoder.yudao.ssodemo.client;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.user.UserUpdateReqDTO;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.LoginUser;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* 用户 User 信息的客户端
|
||||
*
|
||||
* 对应调用 OAuth2UserController 接口
|
||||
*/
|
||||
@Component
|
||||
public class UserClient {
|
||||
|
||||
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api//system/oauth2/user";
|
||||
|
||||
// @Resource // 可优化,注册一个 RestTemplate Bean,然后注入
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
public CommonResult<UserInfoRespDTO> getUser() {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", OAuth2Client.TENANT_ID.toString());
|
||||
addTokenHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<UserInfoRespDTO>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/get",
|
||||
HttpMethod.GET,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<UserInfoRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
public CommonResult<Boolean> updateUser(UserUpdateReqDTO updateReqDTO) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set("tenant-id", OAuth2Client.TENANT_ID.toString());
|
||||
addTokenHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
// 使用 updateReqDTO 即可
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<Boolean>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/update",
|
||||
HttpMethod.PUT,
|
||||
new HttpEntity<>(updateReqDTO, headers),
|
||||
new ParameterizedTypeReference<CommonResult<Boolean>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
|
||||
private static void addTokenHeader(HttpHeaders headers) {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Assert.notNull(loginUser, "登录用户不能为空");
|
||||
headers.add("Authorization", "Bearer " + loginUser.getAccessToken());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 通用返回
|
||||
*
|
||||
* @param <T> 数据泛型
|
||||
*/
|
||||
@Data
|
||||
public class CommonResult<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
/**
|
||||
* 返回数据
|
||||
*/
|
||||
private T data;
|
||||
/**
|
||||
* 错误提示,用户可阅读
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto.oauth2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 访问令牌 Response DTO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OAuth2AccessTokenRespDTO {
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
@JsonProperty("access_token")
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
@JsonProperty("refresh_token")
|
||||
private String refreshToken;
|
||||
|
||||
/**
|
||||
* 令牌类型
|
||||
*/
|
||||
@JsonProperty("token_type")
|
||||
private String tokenType;
|
||||
|
||||
/**
|
||||
* 过期时间;单位:秒
|
||||
*/
|
||||
@JsonProperty("expires_in")
|
||||
private Long expiresIn;
|
||||
|
||||
/**
|
||||
* 授权范围;如果多个授权范围,使用空格分隔
|
||||
*/
|
||||
private String scope;
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto.oauth2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 校验令牌 Response DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OAuth2CheckTokenRespDTO {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@JsonProperty("user_id")
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
@JsonProperty("user_type")
|
||||
private Integer userType;
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
@JsonProperty("tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 客户端编号
|
||||
*/
|
||||
@JsonProperty("client_id")
|
||||
private String clientId;
|
||||
/**
|
||||
* 授权范围
|
||||
*/
|
||||
private List<String> scopes;
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
@JsonProperty("access_token")
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*
|
||||
* 时间戳 / 1000,即单位:秒
|
||||
*/
|
||||
private Long exp;
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto.user;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 获得用户基本信息 Response dto
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserInfoRespDTO {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 所在部门
|
||||
*/
|
||||
private Dept dept;
|
||||
|
||||
/**
|
||||
* 所属岗位数组
|
||||
*/
|
||||
private List<Post> posts;
|
||||
|
||||
/**
|
||||
* 部门
|
||||
*/
|
||||
@Data
|
||||
public static class Dept {
|
||||
|
||||
/**
|
||||
* 部门编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 岗位
|
||||
*/
|
||||
@Data
|
||||
public static class Post {
|
||||
|
||||
/**
|
||||
* 岗位编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 岗位名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto.user;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 更新用户基本信息 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserUpdateReqDTO {
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package cn.iocoder.yudao.ssodemo.controller;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.ssodemo.client.OAuth2Client;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2AccessTokenRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
@Resource
|
||||
private OAuth2Client oauth2Client;
|
||||
|
||||
/**
|
||||
* 使用 code 访问令牌,获得访问令牌
|
||||
*
|
||||
* @param code 授权码
|
||||
* @param redirectUri 重定向 URI
|
||||
* @return 访问令牌;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||
*/
|
||||
@PostMapping("/login-by-code")
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> loginByCode(@RequestParam("code") String code,
|
||||
@RequestParam("redirectUri") String redirectUri) {
|
||||
return oauth2Client.postAccessToken(code, redirectUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用刷新令牌,获得(刷新)访问令牌
|
||||
*
|
||||
* @param refreshToken 刷新令牌
|
||||
* @return 访问令牌;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||
*/
|
||||
@PostMapping("/refresh-token")
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
return oauth2Client.refreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 成功
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
||||
String token = SecurityUtils.obtainAuthorization(request, "Authorization");
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return oauth2Client.revokeToken(token);
|
||||
}
|
||||
// 返回成功
|
||||
return new CommonResult<>();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package cn.iocoder.yudao.ssodemo.controller;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.UserClient;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.user.UserUpdateReqDTO;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
public class UserController {
|
||||
|
||||
@Resource
|
||||
private UserClient userClient;
|
||||
|
||||
/**
|
||||
* 获得当前登录用户的基本信息
|
||||
*
|
||||
* @return 用户信息;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||
*/
|
||||
@GetMapping("/get")
|
||||
public CommonResult<UserInfoRespDTO> getUser() {
|
||||
return userClient.getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新当前登录用户的昵称
|
||||
*
|
||||
* @param nickname 昵称
|
||||
* @return 成功
|
||||
*/
|
||||
@PutMapping("/update")
|
||||
public CommonResult<Boolean> updateUser(@RequestParam("nickname") String nickname) {
|
||||
UserUpdateReqDTO updateReqDTO = new UserUpdateReqDTO(nickname, null, null, null);
|
||||
return userClient.updateUser(updateReqDTO);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.config;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.filter.TokenAuthenticationFilter;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.handler.AccessDeniedHandlerImpl;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfiguration{
|
||||
|
||||
@Resource
|
||||
private TokenAuthenticationFilter tokenAuthenticationFilter;
|
||||
|
||||
@Resource
|
||||
private AccessDeniedHandlerImpl accessDeniedHandler;
|
||||
@Resource
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
|
||||
@Bean
|
||||
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
||||
// 设置 URL 安全权限
|
||||
httpSecurity.csrf().disable() // 禁用 CSRF 保护
|
||||
.authorizeRequests()
|
||||
// 1. 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
|
||||
// 2. 登录相关的接口,可匿名访问
|
||||
.antMatchers("/auth/login-by-code").permitAll()
|
||||
.antMatchers("/auth/refresh-token").permitAll()
|
||||
.antMatchers("/auth/logout").permitAll()
|
||||
// last. 兜底规则,必须认证
|
||||
.and().authorizeRequests()
|
||||
.anyRequest().authenticated();
|
||||
|
||||
// 设置处理器
|
||||
httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
|
||||
.authenticationEntryPoint(authenticationEntryPoint);
|
||||
|
||||
// 添加 Token Filter
|
||||
httpSecurity.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
return httpSecurity.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 登录用户信息
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class LoginUser {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private Integer userType;
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
/**
|
||||
* 授权范围
|
||||
*/
|
||||
private List<String> scopes;
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.filter;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.OAuth2Client;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.LoginUser;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Token 过滤器,验证 token 的有效性
|
||||
* 验证通过后,获得 {@link LoginUser} 信息,并加入到 Spring Security 上下文
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
@Resource
|
||||
private OAuth2Client oauth2Client;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
// 1. 获得访问令牌
|
||||
String token = SecurityUtils.obtainAuthorization(request, "Authorization");
|
||||
if (StringUtils.hasText(token)) {
|
||||
// 2. 基于 token 构建登录用户
|
||||
LoginUser loginUser = buildLoginUserByToken(token);
|
||||
// 3. 设置当前用户
|
||||
if (loginUser != null) {
|
||||
SecurityUtils.setLoginUser(loginUser, request);
|
||||
}
|
||||
}
|
||||
|
||||
// 继续过滤链
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private LoginUser buildLoginUserByToken(String token) {
|
||||
try {
|
||||
CommonResult<OAuth2CheckTokenRespDTO> accessTokenResult = oauth2Client.checkToken(token);
|
||||
OAuth2CheckTokenRespDTO accessToken = accessTokenResult.getData();
|
||||
if (accessToken == null) {
|
||||
return null;
|
||||
}
|
||||
// 构建登录用户
|
||||
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
|
||||
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes())
|
||||
.setAccessToken(accessToken.getAccessToken());
|
||||
} catch (Exception exception) {
|
||||
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.handler;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.ServletUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 访问一个需要认证的 URL 资源,已经认证(登录)但是没有权限的情况下,返回 {@link GlobalErrorCodeConstants#FORBIDDEN} 错误码。
|
||||
*
|
||||
* 补充:Spring Security 通过 {@link ExceptionTranslationFilter#handleAccessDeniedException(HttpServletRequest, HttpServletResponse, FilterChain, AccessDeniedException)} 方法,调用当前类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
@SuppressWarnings("JavadocReference")
|
||||
@Slf4j
|
||||
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e)
|
||||
throws IOException, ServletException {
|
||||
// 打印 warn 的原因是,不定期合并 warn,看看有没恶意破坏
|
||||
log.warn("[commence][访问 URL({}) 时,用户({}) 权限不够]", request.getRequestURI(),
|
||||
SecurityUtils.getLoginUserId(), e);
|
||||
// 返回 403
|
||||
CommonResult<Object> result = new CommonResult<>();
|
||||
result.setCode(HttpStatus.FORBIDDEN.value());
|
||||
result.setMsg("没有该操作权限");
|
||||
ServletUtils.writeJSON(response, result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.handler;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.ServletUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 访问一个需要认证的 URL 资源,但是此时自己尚未认证(登录)的情况下,返回 {@link GlobalErrorCodeConstants#UNAUTHORIZED} 错误码,从而使前端重定向到登录页
|
||||
*
|
||||
* 补充:Spring Security 通过 {@link ExceptionTranslationFilter#sendStartAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, AuthenticationException)} 方法,调用当前类
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@SuppressWarnings("JavadocReference") // 忽略文档引用报错
|
||||
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
|
||||
log.debug("[commence][访问 URL({}) 时,没有登录]", request.getRequestURI(), e);
|
||||
// 返回 401
|
||||
CommonResult<Object> result = new CommonResult<>();
|
||||
result.setCode(HttpStatus.UNAUTHORIZED.value());
|
||||
result.setMsg("账号未登录");
|
||||
ServletUtils.writeJSON(response, result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.util;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.LoginUser;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 安全服务工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class SecurityUtils {
|
||||
|
||||
public static final String AUTHORIZATION_BEARER = "Bearer";
|
||||
|
||||
private SecurityUtils() {}
|
||||
|
||||
/**
|
||||
* 从请求中,获得认证 Token
|
||||
*
|
||||
* @param request 请求
|
||||
* @param header 认证 Token 对应的 Header 名字
|
||||
* @return 认证 Token
|
||||
*/
|
||||
public static String obtainAuthorization(HttpServletRequest request, String header) {
|
||||
String authorization = request.getHeader(header);
|
||||
if (!StringUtils.hasText(authorization)) {
|
||||
return null;
|
||||
}
|
||||
int index = authorization.indexOf(AUTHORIZATION_BEARER + " ");
|
||||
if (index == -1) { // 未找到
|
||||
return null;
|
||||
}
|
||||
return authorization.substring(index + 7).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前认证信息
|
||||
*
|
||||
* @return 认证信息
|
||||
*/
|
||||
public static Authentication getAuthentication() {
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
return context.getAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户
|
||||
*
|
||||
* @return 当前用户
|
||||
*/
|
||||
@Nullable
|
||||
public static LoginUser getLoginUser() {
|
||||
Authentication authentication = getAuthentication();
|
||||
if (authentication == null) {
|
||||
return null;
|
||||
}
|
||||
return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前用户的编号,从上下文中
|
||||
*
|
||||
* @return 用户编号
|
||||
*/
|
||||
@Nullable
|
||||
public static Long getLoginUserId() {
|
||||
LoginUser loginUser = getLoginUser();
|
||||
return loginUser != null ? loginUser.getId() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户
|
||||
*
|
||||
* @param loginUser 登录用户
|
||||
* @param request 请求
|
||||
*/
|
||||
public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) {
|
||||
// 创建 Authentication,并设置到上下文
|
||||
Authentication authentication = buildAuthentication(loginUser, request);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
|
||||
private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) {
|
||||
// 创建 UsernamePasswordAuthenticationToken 对象
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
||||
loginUser, null, Collections.emptyList());
|
||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.util;
|
||||
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 客户端工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ServletUtils {
|
||||
|
||||
/**
|
||||
* 返回 JSON 字符串
|
||||
*
|
||||
* @param response 响应
|
||||
* @param object 对象,会序列化成 JSON 字符串
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码
|
||||
public static void writeJSON(HttpServletResponse response, Object object) {
|
||||
String content = JSONUtil.toJsonStr(object);
|
||||
ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
server:
|
||||
port: 18080
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>SSO 授权后的回调页</title>
|
||||
<!-- jQuery:操作 dom、发起请求等 -->
|
||||
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.1.2/jquery.min.js" type="application/javascript"></script>
|
||||
<!-- 工具类 -->
|
||||
<script type="application/javascript">
|
||||
(function ($) {
|
||||
/**
|
||||
* 获得 URL 的指定参数的值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @returns 参数值
|
||||
*/
|
||||
$.getUrlParam = function (name) {
|
||||
const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
|
||||
const r = window.location.search.substr(1).match(reg);
|
||||
if (r != null) return unescape(r[2]); return null;
|
||||
}
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<script type="application/javascript">
|
||||
$(function () {
|
||||
// 获得 code 授权码
|
||||
const code = $.getUrlParam('code');
|
||||
if (!code) {
|
||||
alert('获取不到 code 参数,请排查!')
|
||||
return;
|
||||
}
|
||||
|
||||
// 提交
|
||||
const redirectUri = 'http://127.0.0.1:18080/callback.html'; // 需要修改成,你回调的地址,就是在 index.html 拼接的 redirectUri
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/auth/login-by-code?code=" + code
|
||||
+ '&redirectUri=' + redirectUri,
|
||||
method: 'POST',
|
||||
success: function( result ) {
|
||||
if (result.code !== 0) {
|
||||
alert('获得访问令牌失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert('获得访问令牌成功!点击确认,跳转回首页')
|
||||
|
||||
// 设置到 localStorage 中
|
||||
localStorage.setItem('ACCESS-TOKEN', result.data.access_token);
|
||||
localStorage.setItem('REFRESH-TOKEN', result.data.refresh_token);
|
||||
|
||||
// 跳转回首页
|
||||
window.location.href = '/index.html';
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
正在使用 code 授权码,进行 accessToken 访问令牌的获取
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,159 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>首页</title>
|
||||
<!-- jQuery:操作 dom、发起请求等 -->
|
||||
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.1.2/jquery.min.js" type="application/javascript"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
/**
|
||||
* 跳转单点登录
|
||||
*/
|
||||
function ssoLogin() {
|
||||
const clientId = 'yudao-sso-demo-by-code'; // 可以改写成,你的 clientId
|
||||
const redirectUri = encodeURIComponent('http://127.0.0.1:18080/callback.html'); // 注意,需要使用 encodeURIComponent 编码地址
|
||||
const responseType = 'code'; // 1)授权码模式,对应 code;2)简化模式,对应 token
|
||||
window.location.href = 'http://127.0.0.1:1024/sso?client_id=' + clientId
|
||||
+ '&redirect_uri=' + redirectUri
|
||||
+ '&response_type=' + responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改昵称
|
||||
*/
|
||||
function updateNickname() {
|
||||
const nickname = prompt("请输入新的昵称", "");
|
||||
if (!nickname) {
|
||||
return;
|
||||
}
|
||||
// 更新用户的昵称
|
||||
const accessToken = localStorage.getItem('ACCESS-TOKEN');
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/user/update?nickname=" + nickname,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
},
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('更新昵称失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert('更新昵称成功!');
|
||||
$('#nicknameSpan').html(nickname);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
function refreshToken() {
|
||||
const refreshToken = localStorage.getItem('REFRESH-TOKEN');
|
||||
if (!refreshToken) {
|
||||
alert("获取不到刷新令牌");
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/auth/refresh-token?refreshToken=" + refreshToken,
|
||||
method: 'POST',
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('刷新访问令牌失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert('更新访问令牌成功!');
|
||||
$('#accessTokenSpan').html(result.data.access_token);
|
||||
|
||||
// 设置到 localStorage 中
|
||||
localStorage.setItem('ACCESS-TOKEN', result.data.access_token);
|
||||
localStorage.setItem('REFRESH-TOKEN', result.data.refresh_token);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出,删除访问令牌
|
||||
*/
|
||||
function logout() {
|
||||
const accessToken = localStorage.getItem('ACCESS-TOKEN');
|
||||
if (!accessToken) {
|
||||
location.reload();
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/auth/logout",
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
},
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('退出登录失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert('退出登录成功!');
|
||||
// 删除 localStorage 中
|
||||
localStorage.removeItem('ACCESS-TOKEN');
|
||||
localStorage.removeItem('REFRESH-TOKEN');
|
||||
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
const accessToken = localStorage.getItem('ACCESS-TOKEN');
|
||||
// 情况一:未登录
|
||||
if (!accessToken) {
|
||||
$('#noLoginDiv').css("display", "block");
|
||||
return;
|
||||
}
|
||||
|
||||
// 情况二:已登录
|
||||
$('#yesLoginDiv').css("display", "block");
|
||||
$('#accessTokenSpan').html(accessToken);
|
||||
// 获得登录用户的信息
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/user/get",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
},
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('获得个人信息失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
$('#nicknameSpan').html(result.data.nickname);
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 情况一:未登录:1)跳转 ruoyi-vue-pro 的 SSO 登录页 -->
|
||||
<div id="noLoginDiv" style="display: none">
|
||||
您未登录,点击 <a href="#" onclick="ssoLogin()">跳转 </a> SSO 单点登录
|
||||
</div>
|
||||
|
||||
<!-- 情况二:已登录:1)展示用户信息;2)刷新访问令牌;3)退出登录 -->
|
||||
<div id="yesLoginDiv" style="display: none">
|
||||
您已登录!<button onclick="logout()">退出登录</button> <br />
|
||||
昵称:<span id="nicknameSpan"> 加载中... </span> <button onclick="updateNickname()">修改昵称</button> <br />
|
||||
访问令牌:<span id="accessTokenSpan"> 加载中... </span> <button onclick="refreshToken()">刷新令牌</button> <br />
|
||||
</div>
|
||||
</body>
|
||||
<style>
|
||||
body { /** 页面居中 */
|
||||
border-radius: 20px;
|
||||
height: 350px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
</style>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<?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>
|
||||
|
||||
<!-- 由于方便大家拷贝,使用不使用 yudao 作为 Maven parent -->
|
||||
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-sso-demo-by-password</artifactId>
|
||||
<version>1.0.0-snapshot</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>基于密码模式,如何实现 SSO 单点登录?</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<!-- Maven 相关 -->
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- 统一依赖管理 -->
|
||||
<spring.boot.version>2.7.6</spring.boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- 统一依赖管理 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.10</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
package cn.iocoder.yudao.ssodemo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SSODemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SSODemoApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package cn.iocoder.yudao.ssodemo.client;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2AccessTokenRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 客户端
|
||||
*
|
||||
* 对应调用 OAuth2OpenController 接口
|
||||
*/
|
||||
@Component
|
||||
public class OAuth2Client {
|
||||
|
||||
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2";
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*
|
||||
* 默认使用 1;如果使用别的租户,可以调整
|
||||
*/
|
||||
public static final Long TENANT_ID = 1L;
|
||||
|
||||
private static final String CLIENT_ID = "yudao-sso-demo-by-password";
|
||||
private static final String CLIENT_SECRET = "test";
|
||||
|
||||
|
||||
// @Resource // 可优化,注册一个 RestTemplate Bean,然后注入
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
/**
|
||||
* 校验访问令牌,并返回它的基本信息
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @return 访问令牌的基本信息
|
||||
*/
|
||||
public CommonResult<OAuth2CheckTokenRespDTO> checkToken(String token) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", TENANT_ID.toString());
|
||||
addClientHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("token", token);
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<OAuth2CheckTokenRespDTO>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/check-token",
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<OAuth2CheckTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用刷新令牌,获得(刷新)访问令牌
|
||||
*
|
||||
* @param refreshToken 刷新令牌
|
||||
* @return 访问令牌
|
||||
*/
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> refreshToken(String refreshToken) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", TENANT_ID.toString());
|
||||
addClientHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("grant_type", "refresh_token");
|
||||
body.add("refresh_token", refreshToken);
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<OAuth2AccessTokenRespDTO>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/token",
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<OAuth2AccessTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除访问令牌
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @return 成功
|
||||
*/
|
||||
public CommonResult<Boolean> revokeToken(String token) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", TENANT_ID.toString());
|
||||
addClientHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("token", token);
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<Boolean>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/token",
|
||||
HttpMethod.DELETE,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<Boolean>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
private static void addClientHeader(HttpHeaders headers) {
|
||||
// client 拼接,需要 BASE64 编码
|
||||
String client = CLIENT_ID + ":" + CLIENT_SECRET;
|
||||
client = Base64Utils.encodeToString(client.getBytes(StandardCharsets.UTF_8));
|
||||
headers.add("Authorization", "Basic " + client);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package cn.iocoder.yudao.ssodemo.client;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.user.UserUpdateReqDTO;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.LoginUser;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* 用户 User 信息的客户端
|
||||
*
|
||||
* 对应调用 OAuth2UserController 接口
|
||||
*/
|
||||
@Component
|
||||
public class UserClient {
|
||||
|
||||
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api//system/oauth2/user";
|
||||
|
||||
// @Resource // 可优化,注册一个 RestTemplate Bean,然后注入
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
public CommonResult<UserInfoRespDTO> getUser() {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("tenant-id", OAuth2Client.TENANT_ID.toString());
|
||||
addTokenHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<UserInfoRespDTO>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/get",
|
||||
HttpMethod.GET,
|
||||
new HttpEntity<>(body, headers),
|
||||
new ParameterizedTypeReference<CommonResult<UserInfoRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
public CommonResult<Boolean> updateUser(UserUpdateReqDTO updateReqDTO) {
|
||||
// 1.1 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set("tenant-id", OAuth2Client.TENANT_ID.toString());
|
||||
addTokenHeader(headers);
|
||||
// 1.2 构建请求参数
|
||||
// 使用 updateReqDTO 即可
|
||||
|
||||
// 2. 执行请求
|
||||
ResponseEntity<CommonResult<Boolean>> exchange = restTemplate.exchange(
|
||||
BASE_URL + "/update",
|
||||
HttpMethod.PUT,
|
||||
new HttpEntity<>(updateReqDTO, headers),
|
||||
new ParameterizedTypeReference<CommonResult<Boolean>>() {}); // 解决 CommonResult 的泛型丢失
|
||||
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
|
||||
private static void addTokenHeader(HttpHeaders headers) {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Assert.notNull(loginUser, "登录用户不能为空");
|
||||
headers.add("Authorization", "Bearer " + loginUser.getAccessToken());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 通用返回
|
||||
*
|
||||
* @param <T> 数据泛型
|
||||
*/
|
||||
@Data
|
||||
public class CommonResult<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
/**
|
||||
* 返回数据
|
||||
*/
|
||||
private T data;
|
||||
/**
|
||||
* 错误提示,用户可阅读
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto.oauth2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 访问令牌 Response DTO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OAuth2AccessTokenRespDTO {
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
@JsonProperty("access_token")
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
@JsonProperty("refresh_token")
|
||||
private String refreshToken;
|
||||
|
||||
/**
|
||||
* 令牌类型
|
||||
*/
|
||||
@JsonProperty("token_type")
|
||||
private String tokenType;
|
||||
|
||||
/**
|
||||
* 过期时间;单位:秒
|
||||
*/
|
||||
@JsonProperty("expires_in")
|
||||
private Long expiresIn;
|
||||
|
||||
/**
|
||||
* 授权范围;如果多个授权范围,使用空格分隔
|
||||
*/
|
||||
private String scope;
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto.oauth2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 校验令牌 Response DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OAuth2CheckTokenRespDTO {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@JsonProperty("user_id")
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
@JsonProperty("user_type")
|
||||
private Integer userType;
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
@JsonProperty("tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 客户端编号
|
||||
*/
|
||||
@JsonProperty("client_id")
|
||||
private String clientId;
|
||||
/**
|
||||
* 授权范围
|
||||
*/
|
||||
private List<String> scopes;
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
@JsonProperty("access_token")
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*
|
||||
* 时间戳 / 1000,即单位:秒
|
||||
*/
|
||||
private Long exp;
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto.user;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 获得用户基本信息 Response dto
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserInfoRespDTO {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 所在部门
|
||||
*/
|
||||
private Dept dept;
|
||||
|
||||
/**
|
||||
* 所属岗位数组
|
||||
*/
|
||||
private List<Post> posts;
|
||||
|
||||
/**
|
||||
* 部门
|
||||
*/
|
||||
@Data
|
||||
public static class Dept {
|
||||
|
||||
/**
|
||||
* 部门编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 岗位
|
||||
*/
|
||||
@Data
|
||||
public static class Post {
|
||||
|
||||
/**
|
||||
* 岗位编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 岗位名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package cn.iocoder.yudao.ssodemo.client.dto.user;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 更新用户基本信息 Request DTO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserUpdateReqDTO {
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package cn.iocoder.yudao.ssodemo.controller;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.ssodemo.client.OAuth2Client;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2AccessTokenRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
@Resource
|
||||
private OAuth2Client oauth2Client;
|
||||
|
||||
/**
|
||||
* 使用刷新令牌,获得(刷新)访问令牌
|
||||
*
|
||||
* @param refreshToken 刷新令牌
|
||||
* @return 访问令牌;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||
*/
|
||||
@PostMapping("/refresh-token")
|
||||
public CommonResult<OAuth2AccessTokenRespDTO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
return oauth2Client.refreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 成功
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
||||
String token = SecurityUtils.obtainAuthorization(request, "Authorization");
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return oauth2Client.revokeToken(token);
|
||||
}
|
||||
// 返回成功
|
||||
return new CommonResult<>();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package cn.iocoder.yudao.ssodemo.controller;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.UserClient;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.user.UserUpdateReqDTO;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
public class UserController {
|
||||
|
||||
@Resource
|
||||
private UserClient userClient;
|
||||
|
||||
/**
|
||||
* 获得当前登录用户的基本信息
|
||||
*
|
||||
* @return 用户信息;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||
*/
|
||||
@GetMapping("/get")
|
||||
public CommonResult<UserInfoRespDTO> getUser() {
|
||||
return userClient.getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新当前登录用户的昵称
|
||||
*
|
||||
* @param nickname 昵称
|
||||
* @return 成功
|
||||
*/
|
||||
@PutMapping("/update")
|
||||
public CommonResult<Boolean> updateUser(@RequestParam("nickname") String nickname) {
|
||||
UserUpdateReqDTO updateReqDTO = new UserUpdateReqDTO(nickname, null, null, null);
|
||||
return userClient.updateUser(updateReqDTO);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.config;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.filter.TokenAuthenticationFilter;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.handler.AccessDeniedHandlerImpl;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Resource
|
||||
private TokenAuthenticationFilter tokenAuthenticationFilter;
|
||||
|
||||
@Resource
|
||||
private AccessDeniedHandlerImpl accessDeniedHandler;
|
||||
@Resource
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
|
||||
@Bean
|
||||
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
||||
// 设置 URL 安全权限
|
||||
httpSecurity.csrf().disable() // 禁用 CSRF 保护
|
||||
.authorizeRequests()
|
||||
// 1. 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
|
||||
// 2. 登录相关的接口,可匿名访问
|
||||
.antMatchers("/auth/login-by-code").permitAll()
|
||||
.antMatchers("/auth/refresh-token").permitAll()
|
||||
.antMatchers("/auth/logout").permitAll()
|
||||
// last. 兜底规则,必须认证
|
||||
.and().authorizeRequests()
|
||||
.anyRequest().authenticated();
|
||||
|
||||
// 设置处理器
|
||||
httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
|
||||
.authenticationEntryPoint(authenticationEntryPoint);
|
||||
|
||||
// 添加 Token Filter
|
||||
httpSecurity.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
return httpSecurity.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 登录用户信息
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class LoginUser {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private Integer userType;
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
/**
|
||||
* 授权范围
|
||||
*/
|
||||
private List<String> scopes;
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.filter;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.OAuth2Client;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.LoginUser;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Token 过滤器,验证 token 的有效性
|
||||
* 验证通过后,获得 {@link LoginUser} 信息,并加入到 Spring Security 上下文
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
@Resource
|
||||
private OAuth2Client oauth2Client;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
// 1. 获得访问令牌
|
||||
String token = SecurityUtils.obtainAuthorization(request, "Authorization");
|
||||
if (StringUtils.hasText(token)) {
|
||||
// 2. 基于 token 构建登录用户
|
||||
LoginUser loginUser = buildLoginUserByToken(token);
|
||||
// 3. 设置当前用户
|
||||
if (loginUser != null) {
|
||||
SecurityUtils.setLoginUser(loginUser, request);
|
||||
}
|
||||
}
|
||||
|
||||
// 继续过滤链
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private LoginUser buildLoginUserByToken(String token) {
|
||||
try {
|
||||
CommonResult<OAuth2CheckTokenRespDTO> accessTokenResult = oauth2Client.checkToken(token);
|
||||
OAuth2CheckTokenRespDTO accessToken = accessTokenResult.getData();
|
||||
if (accessToken == null) {
|
||||
return null;
|
||||
}
|
||||
// 构建登录用户
|
||||
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
|
||||
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes())
|
||||
.setAccessToken(accessToken.getAccessToken());
|
||||
} catch (Exception exception) {
|
||||
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.handler;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.ServletUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 访问一个需要认证的 URL 资源,已经认证(登录)但是没有权限的情况下,返回 {@link GlobalErrorCodeConstants#FORBIDDEN} 错误码。
|
||||
*
|
||||
* 补充:Spring Security 通过 {@link ExceptionTranslationFilter#handleAccessDeniedException(HttpServletRequest, HttpServletResponse, FilterChain, AccessDeniedException)} 方法,调用当前类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
@SuppressWarnings("JavadocReference")
|
||||
@Slf4j
|
||||
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e)
|
||||
throws IOException, ServletException {
|
||||
// 打印 warn 的原因是,不定期合并 warn,看看有没恶意破坏
|
||||
log.warn("[commence][访问 URL({}) 时,用户({}) 权限不够]", request.getRequestURI(),
|
||||
SecurityUtils.getLoginUserId(), e);
|
||||
// 返回 403
|
||||
CommonResult<Object> result = new CommonResult<>();
|
||||
result.setCode(HttpStatus.FORBIDDEN.value());
|
||||
result.setMsg("没有该操作权限");
|
||||
ServletUtils.writeJSON(response, result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.handler;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.util.ServletUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 访问一个需要认证的 URL 资源,但是此时自己尚未认证(登录)的情况下,返回 {@link GlobalErrorCodeConstants#UNAUTHORIZED} 错误码,从而使前端重定向到登录页
|
||||
*
|
||||
* 补充:Spring Security 通过 {@link ExceptionTranslationFilter#sendStartAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, AuthenticationException)} 方法,调用当前类
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@SuppressWarnings("JavadocReference") // 忽略文档引用报错
|
||||
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
|
||||
log.debug("[commence][访问 URL({}) 时,没有登录]", request.getRequestURI(), e);
|
||||
// 返回 401
|
||||
CommonResult<Object> result = new CommonResult<>();
|
||||
result.setCode(HttpStatus.UNAUTHORIZED.value());
|
||||
result.setMsg("账号未登录");
|
||||
ServletUtils.writeJSON(response, result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.util;
|
||||
|
||||
import cn.iocoder.yudao.ssodemo.framework.core.LoginUser;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 安全服务工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class SecurityUtils {
|
||||
|
||||
public static final String AUTHORIZATION_BEARER = "Bearer";
|
||||
|
||||
private SecurityUtils() {}
|
||||
|
||||
/**
|
||||
* 从请求中,获得认证 Token
|
||||
*
|
||||
* @param request 请求
|
||||
* @param header 认证 Token 对应的 Header 名字
|
||||
* @return 认证 Token
|
||||
*/
|
||||
public static String obtainAuthorization(HttpServletRequest request, String header) {
|
||||
String authorization = request.getHeader(header);
|
||||
if (!StringUtils.hasText(authorization)) {
|
||||
return null;
|
||||
}
|
||||
int index = authorization.indexOf(AUTHORIZATION_BEARER + " ");
|
||||
if (index == -1) { // 未找到
|
||||
return null;
|
||||
}
|
||||
return authorization.substring(index + 7).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前认证信息
|
||||
*
|
||||
* @return 认证信息
|
||||
*/
|
||||
public static Authentication getAuthentication() {
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
return context.getAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户
|
||||
*
|
||||
* @return 当前用户
|
||||
*/
|
||||
@Nullable
|
||||
public static LoginUser getLoginUser() {
|
||||
Authentication authentication = getAuthentication();
|
||||
if (authentication == null) {
|
||||
return null;
|
||||
}
|
||||
return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前用户的编号,从上下文中
|
||||
*
|
||||
* @return 用户编号
|
||||
*/
|
||||
@Nullable
|
||||
public static Long getLoginUserId() {
|
||||
LoginUser loginUser = getLoginUser();
|
||||
return loginUser != null ? loginUser.getId() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户
|
||||
*
|
||||
* @param loginUser 登录用户
|
||||
* @param request 请求
|
||||
*/
|
||||
public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) {
|
||||
// 创建 Authentication,并设置到上下文
|
||||
Authentication authentication = buildAuthentication(loginUser, request);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
|
||||
private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) {
|
||||
// 创建 UsernamePasswordAuthenticationToken 对象
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
||||
loginUser, null, Collections.emptyList());
|
||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cn.iocoder.yudao.ssodemo.framework.core.util;
|
||||
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 客户端工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ServletUtils {
|
||||
|
||||
/**
|
||||
* 返回 JSON 字符串
|
||||
*
|
||||
* @param response 响应
|
||||
* @param object 对象,会序列化成 JSON 字符串
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码
|
||||
public static void writeJSON(HttpServletResponse response, Object object) {
|
||||
String content = JSONUtil.toJsonStr(object);
|
||||
ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
server:
|
||||
port: 18080
|
|
@ -0,0 +1,154 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>首页</title>
|
||||
<!-- jQuery:操作 dom、发起请求等 -->
|
||||
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.1.2/jquery.min.js" type="application/javascript"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
/**
|
||||
* 跳转单点登录
|
||||
*/
|
||||
function passwordLogin() {
|
||||
window.location.href = '/login.html'
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改昵称
|
||||
*/
|
||||
function updateNickname() {
|
||||
const nickname = prompt("请输入新的昵称", "");
|
||||
if (!nickname) {
|
||||
return;
|
||||
}
|
||||
// 更新用户的昵称
|
||||
const accessToken = localStorage.getItem('ACCESS-TOKEN');
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/user/update?nickname=" + nickname,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
},
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('更新昵称失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert('更新昵称成功!');
|
||||
$('#nicknameSpan').html(nickname);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
function refreshToken() {
|
||||
const refreshToken = localStorage.getItem('REFRESH-TOKEN');
|
||||
if (!refreshToken) {
|
||||
alert("获取不到刷新令牌");
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/auth/refresh-token?refreshToken=" + refreshToken,
|
||||
method: 'POST',
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('刷新访问令牌失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert('更新访问令牌成功!');
|
||||
$('#accessTokenSpan').html(result.data.access_token);
|
||||
|
||||
// 设置到 localStorage 中
|
||||
localStorage.setItem('ACCESS-TOKEN', result.data.access_token);
|
||||
localStorage.setItem('REFRESH-TOKEN', result.data.refresh_token);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出,删除访问令牌
|
||||
*/
|
||||
function logout() {
|
||||
const accessToken = localStorage.getItem('ACCESS-TOKEN');
|
||||
if (!accessToken) {
|
||||
location.reload();
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/auth/logout",
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
},
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('退出登录失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert('退出登录成功!');
|
||||
// 删除 localStorage 中
|
||||
localStorage.removeItem('ACCESS-TOKEN');
|
||||
localStorage.removeItem('REFRESH-TOKEN');
|
||||
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
const accessToken = localStorage.getItem('ACCESS-TOKEN');
|
||||
// 情况一:未登录
|
||||
if (!accessToken) {
|
||||
$('#noLoginDiv').css("display", "block");
|
||||
return;
|
||||
}
|
||||
|
||||
// 情况二:已登录
|
||||
$('#yesLoginDiv').css("display", "block");
|
||||
$('#accessTokenSpan').html(accessToken);
|
||||
// 获得登录用户的信息
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:18080/user/get",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
},
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('获得个人信息失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
$('#nicknameSpan').html(result.data.nickname);
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 情况一:未登录:1)跳转 ruoyi-vue-pro 的 SSO 登录页 -->
|
||||
<div id="noLoginDiv" style="display: none">
|
||||
您未登录,点击 <a href="#" onclick="passwordLogin()">跳转 </a> 账号密码登录
|
||||
</div>
|
||||
|
||||
<!-- 情况二:已登录:1)展示用户信息;2)刷新访问令牌;3)退出登录 -->
|
||||
<div id="yesLoginDiv" style="display: none">
|
||||
您已登录!<button onclick="logout()">退出登录</button> <br />
|
||||
昵称:<span id="nicknameSpan"> 加载中... </span> <button onclick="updateNickname()">修改昵称</button> <br />
|
||||
访问令牌:<span id="accessTokenSpan"> 加载中... </span> <button onclick="refreshToken()">刷新令牌</button> <br />
|
||||
</div>
|
||||
</body>
|
||||
<style>
|
||||
body { /** 页面居中 */
|
||||
border-radius: 20px;
|
||||
height: 350px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
</style>
|
||||
</html>
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>登录</title>
|
||||
<!-- jQuery:操作 dom、发起请求等 -->
|
||||
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.1.2/jquery.min.js" type="application/javascript"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
/**
|
||||
* 账号密码登录
|
||||
*/
|
||||
function login() {
|
||||
const clientId = 'yudao-sso-demo-by-password'; // 可以改写成,你的 clientId
|
||||
const clientSecret = 'test'; // 可以改写成,你的 clientSecret
|
||||
const grantType = 'password'; // 密码模式
|
||||
|
||||
// 账号 + 密码
|
||||
const username = $('#username').val();
|
||||
const password = $('#password').val();
|
||||
if (username.length === 0 || password.length === 0) {
|
||||
alert('账号或密码未输入');
|
||||
return;
|
||||
}
|
||||
|
||||
// 发起请求
|
||||
$.ajax({
|
||||
url: "http://127.0.0.1:48080/admin-api/system/oauth2/token?"
|
||||
// 客户端
|
||||
+ "client_id=" + clientId
|
||||
+ "&client_secret=" + clientSecret
|
||||
// 密码模式的参数
|
||||
+ "&grant_type=" + grantType
|
||||
+ "&username=" + username
|
||||
+ "&password=" + password
|
||||
+ '&scope=user.read user.write',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'tenant-id': '1', // 多租户编号,写死
|
||||
},
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('登录失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
// 设置到 localStorage 中
|
||||
localStorage.setItem('ACCESS-TOKEN', result.data.access_token);
|
||||
localStorage.setItem('REFRESH-TOKEN', result.data.refresh_token);
|
||||
|
||||
// 提示登录成功
|
||||
alert('登录成功!点击确认,跳转回首页');
|
||||
window.location.href = '/index.html';
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
账号:<input id="username" value="admin" /> <br />
|
||||
密码:<input id="password" value="admin123" > <br />
|
||||
<button style="float: right; margin-top: 5px;" onclick="login()">登录</button>
|
||||
</body>
|
||||
<style>
|
||||
body { /** 页面居中 */
|
||||
border-radius: 20px;
|
||||
height: 350px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
</style>
|
||||
</html>
|
|
@ -11,6 +11,7 @@
|
|||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>yudao-common</module>
|
||||
<module>yudao-spring-boot-starter-banner</module>
|
||||
<module>yudao-spring-boot-starter-mybatis</module>
|
||||
<module>yudao-spring-boot-starter-redis</module>
|
||||
<module>yudao-spring-boot-starter-web</module>
|
||||
|
@ -19,24 +20,26 @@
|
|||
<module>yudao-spring-boot-starter-file</module>
|
||||
<module>yudao-spring-boot-starter-monitor</module>
|
||||
<module>yudao-spring-boot-starter-protection</module>
|
||||
<module>yudao-spring-boot-starter-config</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-extension</module>
|
||||
|
||||
<module>yudao-spring-boot-starter-biz-operatelog</module>
|
||||
<module>yudao-spring-boot-starter-biz-dict</module>
|
||||
<module>yudao-spring-boot-starter-biz-sms</module>
|
||||
<module>yudao-spring-boot-starter-activiti</module>
|
||||
|
||||
<module>yudao-spring-boot-starter-biz-pay</module>
|
||||
<module>yudao-spring-boot-starter-biz-weixin</module>
|
||||
<module>yudao-spring-boot-starter-biz-social</module>
|
||||
<module>yudao-spring-boot-starter-biz-tenant</module>
|
||||
<module>yudao-spring-boot-starter-biz-data-permission</module>
|
||||
<module>yudao-spring-boot-starter-biz-error-code</module>
|
||||
<module>yudao-spring-boot-starter-biz-ip</module>
|
||||
|
||||
<module>yudao-spring-boot-starter-flowable</module>
|
||||
<module>yudao-spring-boot-starter-captcha</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>yudao-framework</artifactId>
|
||||
|
|
|
@ -105,6 +105,11 @@
|
|||
<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>
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package cn.iocoder.yudao.framework.common.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 通用状态枚举
|
||||
*
|
||||
|
@ -10,11 +13,13 @@ import lombok.Getter;
|
|||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CommonStatusEnum {
|
||||
public enum CommonStatusEnum implements IntArrayValuable {
|
||||
|
||||
ENABLE(0, "开启"),
|
||||
DISABLE(1, "关闭");
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CommonStatusEnum::getStatus).toArray();
|
||||
|
||||
/**
|
||||
* 状态值
|
||||
*/
|
||||
|
@ -24,4 +29,9 @@ public enum CommonStatusEnum {
|
|||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ import lombok.Getter;
|
|||
@AllArgsConstructor
|
||||
public enum DocumentEnum {
|
||||
|
||||
REDIS_INSTALL("https://gitee.com/zhijiantianya/ruoyi-vue-pro/issues/I4VCSJ", "Redis 安装文档");
|
||||
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;
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package cn.iocoder.yudao.framework.common.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 终端的枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum TerminalEnum implements IntArrayValuable {
|
||||
|
||||
WECHAT_MINI_PROGRAM(10, "微信小程序"),
|
||||
WECHAT_WAP(11, "微信公众号"),
|
||||
H5(20, "H5 网页"),
|
||||
IOS(31, "苹果 App"),
|
||||
ANDROID(32, "安卓 App"),
|
||||
;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TerminalEnum::getTerminal).toArray();
|
||||
|
||||
/**
|
||||
* 终端
|
||||
*/
|
||||
private final Integer terminal;
|
||||
/**
|
||||
* 终端名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.common.enums;
|
|||
/**
|
||||
* Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期
|
||||
*
|
||||
* 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下
|
||||
* 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 enums 包下
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ public interface GlobalErrorCodeConstants {
|
|||
// ========== 服务端错误段 ==========
|
||||
|
||||
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
|
||||
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
|
||||
|
||||
// ========== 自定义错误段 ==========
|
||||
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
|
||||
|
@ -36,9 +37,15 @@ public interface GlobalErrorCodeConstants {
|
|||
|
||||
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
||||
|
||||
static boolean isMatch(Integer code) {
|
||||
/**
|
||||
* 是否为服务端错误,参考 HTTP 5XX 错误码段
|
||||
*
|
||||
* @param code 错误码
|
||||
* @return 是否
|
||||
*/
|
||||
static boolean isServerErrorCode(Integer code) {
|
||||
return code != null
|
||||
&& code >= SUCCESS.getCode() && code <= UNKNOWN.getCode();
|
||||
&& code >= INTERNAL_SERVER_ERROR.getCode() && code <= INTERNAL_SERVER_ERROR.getCode() + 99;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,10 @@ package cn.iocoder.yudao.framework.common.exception.enums;
|
|||
*/
|
||||
public class ServiceErrorCodeRange {
|
||||
|
||||
// 模块 system 错误码区间 [1-000-001-000 ~ 1-000-002-000]
|
||||
// 模块 infra 错误码区间 [1-001-000-000 ~ 1-002-000-000)
|
||||
// 模块 system 错误码区间 [1-002-000-000 ~ 1-003-000-000)
|
||||
// 模块 member 错误码区间 [1-004-000-000 ~ 1-005-000-000)
|
||||
// 模块 pay 错误码区间 [1-007-000-000 ~ 1-008-000-000)
|
||||
// 模块 bpm 错误码区间 [1-009-000-000 ~ 1-010-000-000)
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.framework.common.pojo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServerException;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
@ -91,10 +92,24 @@ public class CommonResult<T> implements Serializable {
|
|||
if (isSuccess()) {
|
||||
return;
|
||||
}
|
||||
// 服务端异常
|
||||
if (GlobalErrorCodeConstants.isServerErrorCode(code)) {
|
||||
throw new ServerException(code, msg);
|
||||
}
|
||||
// 业务异常
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ public class PageParam implements Serializable {
|
|||
|
||||
@ApiModelProperty(value = "每页条数,最大值为 100", required = true, example = "10")
|
||||
@NotNull(message = "每页条数不能为空")
|
||||
@Min(value = 1, message = "页码最小值为 1")
|
||||
@Max(value = 100, message = "页码最大值为 100")
|
||||
@Min(value = 1, message = "每页条数最小值为 1")
|
||||
@Max(value = 100, message = "每页条数最大值为 100")
|
||||
private Integer pageSize = PAGE_SIZE;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
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 {
|
||||
|
||||
public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(Duration duration, CacheLoader<K, V> loader) {
|
||||
return CacheBuilder.newBuilder()
|
||||
// 只阻塞当前数据加载线程,其他线程返回旧值
|
||||
.refreshAfterWrite(duration)
|
||||
// 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程
|
||||
.build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿:可能要思考下,未来要不要做成可配置
|
||||
}
|
||||
|
||||
}
|
|
@ -1,15 +1,10 @@
|
|||
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 cn.hutool.core.util.TypeUtil;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
@ -50,7 +45,14 @@ public class ArrayUtils {
|
|||
if (CollectionUtil.isEmpty(from)) {
|
||||
return (T[]) (new Object[0]);
|
||||
}
|
||||
return ArrayUtil.toArray(from, (Class<T>) CollectionUtil.getElementType(from.iterator()));
|
||||
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];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -173,6 +173,23 @@ public class CollectionUtils {
|
|||
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>> V getSumValue(List<T> from, Function<T, V> valueFunc, BinaryOperator<V> accumulator) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return null;
|
||||
}
|
||||
assert from.size() > 0; // 断言,避免告警
|
||||
return from.stream().map(valueFunc).reduce(accumulator).get();
|
||||
}
|
||||
|
||||
public static <T> void addIfNotNull(Collection<T> coll, T item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Set;
|
|||
*/
|
||||
public class SetUtils {
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> Set<T> asSet(T... objs) {
|
||||
return new HashSet<>(Arrays.asList(objs));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cn.iocoder.yudao.framework.common.util.date;
|
||||
|
||||
import java.time.Duration;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
|
@ -23,6 +25,37 @@ public class DateUtils {
|
|||
|
||||
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss";
|
||||
|
||||
/**
|
||||
* 将 LocalDateTime 转换成 Date
|
||||
*
|
||||
* @param date LocalDateTime
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public static Date of(LocalDateTime date) {
|
||||
// 将此日期时间与时区相结合以创建 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) {
|
||||
// 转为时间戳
|
||||
Instant instant = date.toInstant();
|
||||
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Date addTime(Duration duration) {
|
||||
return new Date(System.currentTimeMillis() + duration.toMillis());
|
||||
}
|
||||
|
@ -31,6 +64,11 @@ public class DateUtils {
|
|||
return System.currentTimeMillis() > time.getTime();
|
||||
}
|
||||
|
||||
public static boolean isExpired(LocalDateTime time) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return now.isAfter(time);
|
||||
}
|
||||
|
||||
public static long diff(Date endTime, Date startTime) {
|
||||
return endTime.getTime() - startTime.getTime();
|
||||
}
|
||||
|
@ -38,9 +76,9 @@ public class DateUtils {
|
|||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param day 日
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param day 日
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static Date buildTime(int year, int mouth, int day) {
|
||||
|
@ -50,12 +88,12 @@ public class DateUtils {
|
|||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param day 日
|
||||
* @param hour 小时
|
||||
* @param minute 分钟
|
||||
* @param second 秒
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param day 日
|
||||
* @param hour 小时
|
||||
* @param minute 分钟
|
||||
* @param second 秒
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static Date buildTime(int year, int mouth, int day,
|
||||
|
@ -81,12 +119,14 @@ public class DateUtils {
|
|||
return a.compareTo(b) > 0 ? a : b;
|
||||
}
|
||||
|
||||
public static boolean beforeNow(Date date) {
|
||||
return date.getTime() < System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public static boolean afterNow(Date date) {
|
||||
return date.getTime() >= System.currentTimeMillis();
|
||||
public static LocalDateTime max(LocalDateTime a, LocalDateTime b) {
|
||||
if (a == null) {
|
||||
return b;
|
||||
}
|
||||
if (b == null) {
|
||||
return a;
|
||||
}
|
||||
return a.isAfter(b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,4 +160,14 @@ public class DateUtils {
|
|||
return c.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否今天
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isToday(LocalDateTime date) {
|
||||
return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package cn.iocoder.yudao.framework.common.util.date;
|
||||
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 时间工具类,用于 {@link java.time.LocalDateTime}
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class LocalDateTimeUtils {
|
||||
|
||||
/**
|
||||
* 空的 LocalDateTime 对象,主要用于 DB 唯一索引的默认值
|
||||
*/
|
||||
public static LocalDateTime EMPTY = buildTime(1970, 1, 1);
|
||||
|
||||
public static LocalDateTime addTime(Duration duration) {
|
||||
return LocalDateTime.now().plus(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 mouth 月
|
||||
* @param day 日
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static LocalDateTime buildTime(int year, int mouth, int day) {
|
||||
return LocalDateTime.of(year, mouth, day, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前时间是否在该时间范围内
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,14 @@
|
|||
package cn.iocoder.yudao.framework.common.util.io;
|
||||
|
||||
import cn.hutool.core.io.FileTypeUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
|
@ -58,4 +63,22 @@ public class FileUtils {
|
|||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文件路径
|
||||
*
|
||||
* @param content 文件内容
|
||||
* @param originalName 原始文件名
|
||||
* @return path,唯一不可重复
|
||||
*/
|
||||
public static String generatePath(byte[] content, String originalName) {
|
||||
String sha256Hex = DigestUtil.sha256Hex(content);
|
||||
// 情况一:如果存在 name,则优先使用 name 的后缀
|
||||
if (StrUtil.isNotBlank(originalName)) {
|
||||
String extName = FileNameUtil.extName(originalName);
|
||||
return StrUtil.isBlank(extName) ? sha256Hex : sha256Hex + "." + extName;
|
||||
}
|
||||
// 情况二:基于 content 计算
|
||||
return sha256Hex + '.' + FileTypeUtil.getType(new ByteArrayInputStream(content));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
|||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -28,6 +29,7 @@ public class JsonUtils {
|
|||
|
||||
static {
|
||||
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,6 +53,10 @@ public class JsonUtils {
|
|||
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)) {
|
||||
|
@ -132,7 +138,7 @@ public class JsonUtils {
|
|||
}
|
||||
|
||||
public static boolean isJson(String text) {
|
||||
return JSONUtil.isJson(text);
|
||||
return JSONUtil.isTypeJSON(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package cn.iocoder.yudao.framework.common.util.object;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
|
@ -47,6 +45,7 @@ public class ObjectUtils {
|
|||
return obj1.compareTo(obj2) > 0 ? obj1 : obj2;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> T defaultIfNull(T... array) {
|
||||
for (T item : array) {
|
||||
if (item != null) {
|
||||
|
@ -56,6 +55,7 @@ public class ObjectUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> boolean equalsAny(T obj, T... array) {
|
||||
return Arrays.asList(array).contains(obj);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,10 @@ package cn.iocoder.yudao.framework.common.util.string;
|
|||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 字符串工具类
|
||||
|
@ -37,4 +40,9 @@ public class StrUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static List<Long> splitToLong(String value, CharSequence separator) {
|
||||
long[] longs = StrUtil.splitToLong(value, separator);
|
||||
return Arrays.stream(longs).boxed().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,16 +17,15 @@ import java.util.regex.Pattern;
|
|||
*/
|
||||
public class ValidationUtils {
|
||||
|
||||
private static final Pattern PATTERN_MOBILE = Pattern.compile("^(?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[189]))\\d{8}$");
|
||||
|
||||
private static final Pattern PATTERN_URL = Pattern.compile("^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]");
|
||||
|
||||
private static final Pattern PATTERN_XML_NCNAME = Pattern.compile("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*");
|
||||
|
||||
public static boolean isMobile(String mobile) {
|
||||
if (StrUtil.length(mobile) != 11) {
|
||||
return false;
|
||||
}
|
||||
// TODO 芋艿,后面完善手机校验
|
||||
return true;
|
||||
return StringUtils.hasText(mobile)
|
||||
&& PATTERN_MOBILE.matcher(mobile).matches();
|
||||
}
|
||||
|
||||
public static boolean isURL(String url) {
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.activiti.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.activiti.core.web.ActivitiWebFilter;
|
||||
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
|
||||
import org.activiti.image.ProcessDiagramGenerator;
|
||||
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
|
||||
import org.activiti.spring.SpringProcessEngineConfiguration;
|
||||
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.transaction.TransactionFactory;
|
||||
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
@Configuration
|
||||
public class YudaoActivitiConfiguration {
|
||||
|
||||
/**
|
||||
* Activiti 流程图的生成器。目前管理后台的流程图 svg,通过它绘制生成。
|
||||
*/
|
||||
@Bean
|
||||
public ProcessDiagramGenerator processDiagramGenerator() {
|
||||
return new DefaultProcessDiagramGenerator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<ActivitiWebFilter> activitiWebFilter() {
|
||||
FilterRegistrationBean<ActivitiWebFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(new ActivitiWebFilter());
|
||||
registrationBean.setOrder(WebFilterOrderEnum.ACTIVITI_FILTER);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* ProcessEngineConfigurationConfigurer 实现类,设置事务管理器,保证 ACT_ 表和自己的表的事务一致性
|
||||
*/
|
||||
@Bean
|
||||
public ProcessEngineConfigurationConfigurer processEngineConfigurationConfigurer(
|
||||
PlatformTransactionManager platformTransactionManager) {
|
||||
return processEngineConfiguration -> processEngineConfiguration.setTransactionManager(platformTransactionManager);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.activiti.core.util;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import org.activiti.bpmn.converter.BpmnXMLConverter;
|
||||
import org.activiti.bpmn.model.BpmnModel;
|
||||
import org.activiti.bpmn.model.FlowElement;
|
||||
import org.activiti.bpmn.model.Process;
|
||||
import org.activiti.engine.impl.identity.Authentication;
|
||||
import org.activiti.engine.impl.util.io.BytesStreamSource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Activiti 工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ActivitiUtils {
|
||||
|
||||
static {
|
||||
setAuthenticationThreadLocal();
|
||||
}
|
||||
|
||||
// ========== Authentication 相关 ==========
|
||||
|
||||
/**
|
||||
* 反射修改 Authentication 的 authenticatedUserIdThreadLocal 静态变量,使用 TTL 线程变量
|
||||
* 目的:保证 @Async 等异步执行时,变量丢失的问题
|
||||
*/
|
||||
private static void setAuthenticationThreadLocal() {
|
||||
ReflectUtil.setFieldValue(Authentication.class, "authenticatedUserIdThreadLocal",
|
||||
new TransmittableThreadLocal<String>());
|
||||
}
|
||||
|
||||
public static void setAuthenticatedUserId(Long userId) {
|
||||
Authentication.setAuthenticatedUserId(String.valueOf(userId));
|
||||
}
|
||||
|
||||
public static void clearAuthenticatedUserId() {
|
||||
Authentication.setAuthenticatedUserId(null);
|
||||
}
|
||||
|
||||
public static boolean equals(String userIdStr, Long userId) {
|
||||
return Objects.equals(userId, NumberUtils.parseLong(userIdStr));
|
||||
}
|
||||
|
||||
// ========== BPMN XML 相关 ==========
|
||||
|
||||
/**
|
||||
* 构建对应的 BPMN Model
|
||||
*
|
||||
* @param bpmnBytes 原始的 BPMN XML 字节数组
|
||||
* @return BPMN Model
|
||||
*/
|
||||
public static BpmnModel buildBpmnModel(byte[] bpmnBytes) {
|
||||
// 转换成 BpmnModel 对象
|
||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
||||
return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 BPMN 流程中,指定的元素们
|
||||
*
|
||||
* @param model
|
||||
* @param clazz 指定元素。例如说,{@link org.activiti.bpmn.model.UserTask}、{@link org.activiti.bpmn.model.Gateway} 等等
|
||||
* @return 元素们
|
||||
*/
|
||||
public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) {
|
||||
List<T> result = new ArrayList<>();
|
||||
model.getProcesses().forEach(process -> {
|
||||
process.getFlowElements().forEach(flowElement -> {
|
||||
if (flowElement.getClass().isAssignableFrom(clazz)) {
|
||||
result.add((T) flowElement);
|
||||
}
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getBpmnXml(BpmnModel model) {
|
||||
if (model == null) {
|
||||
return null;
|
||||
}
|
||||
return StrUtil.utf8Str(getBpmnBytes(model));
|
||||
}
|
||||
|
||||
public static byte[] getBpmnBytes(BpmnModel model) {
|
||||
if (model == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
||||
return converter.convertToXML(model);
|
||||
}
|
||||
|
||||
public static boolean equals(BpmnModel oldModel, BpmnModel newModel) {
|
||||
// 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较
|
||||
return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.activiti.core.web;
|
||||
|
||||
import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Activiti Web 过滤器,将 userId 设置到 {@link org.activiti.engine.impl.identity.Authentication} 中
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ActivitiWebFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws ServletException, IOException {
|
||||
try {
|
||||
// 设置工作流的用户
|
||||
Long userId = SecurityFrameworkUtils.getLoginUserId();
|
||||
if (userId != null) {
|
||||
ActivitiUtils.setAuthenticatedUserId(userId);
|
||||
}
|
||||
// 过滤
|
||||
chain.doFilter(request, response);
|
||||
} finally {
|
||||
// 清理
|
||||
ActivitiUtils.clearAuthenticatedUserId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package cn.iocoder.yudao.framework.activiti;
|
|
@ -1,2 +0,0 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.iocoder.yudao.framework.activiti.config.YudaoActivitiConfiguration
|
|
@ -3,16 +3,16 @@
|
|||
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>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>yudao-spring-boot-starter-config</artifactId>
|
||||
<artifactId>yudao-spring-boot-starter-banner</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>配置中心,基于 Apollo 魔改实现</description>
|
||||
<description>Banner 用于在 console 控制台,打印开发文档、接口文档等</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<dependencies>
|
||||
|
@ -21,17 +21,10 @@
|
|||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring 核心 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Config 配置中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.ctrip.framework.apollo</groupId>
|
||||
<artifactId>apollo-client</artifactId> <!-- 引入 Apollo Client 库,实现内嵌的配置中心 -->
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,20 @@
|
|||
package cn.iocoder.yudao.framework.banner.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.banner.core.BannerApplicationRunner;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Banner 的自动配置类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class YudaoBannerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public BannerApplicationRunner bannerApplicationRunner() {
|
||||
return new BannerApplicationRunner();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +1,20 @@
|
|||
package cn.iocoder.yudao.server.framework.tip.core;
|
||||
package cn.iocoder.yudao.framework.banner.core;
|
||||
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 项目启动成功后,提供文档相关的地址
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class TipApplicationRunner implements ApplicationRunner {
|
||||
public class BannerApplicationRunner implements ApplicationRunner {
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
|
@ -30,7 +31,20 @@ public class TipApplicationRunner implements ApplicationRunner {
|
|||
"https://doc.iocoder.cn",
|
||||
"https://t.zsxq.com/02Yf6M7Qn",
|
||||
"https://t.zsxq.com/02B6ujIee");
|
||||
|
||||
// 数据报表
|
||||
if (isNotPresent("cn.iocoder.yudao.module.visualization.framework.security.config.SecurityConfiguration")) {
|
||||
System.out.println("[报表模块 yudao-module-visualization - 已禁用][参考 https://doc.iocoder.cn/report/ 开启]");
|
||||
}
|
||||
// 工作流
|
||||
if (isNotPresent("cn.iocoder.yudao.framework.flowable.config.YudaoFlowableConfiguration")) {
|
||||
System.out.println("[工作流模块 yudao-module-bpm - 已禁用][参考 https://doc.iocoder.cn/bpm/ 开启]");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isNotPresent(String className) {
|
||||
return !ClassUtils.isPresent(className, ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* Banner 用于在 console 控制台,打印开发文档、接口文档等
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
package cn.iocoder.yudao.framework.banner;
|
|
@ -0,0 +1 @@
|
|||
cn.iocoder.yudao.framework.banner.config.YudaoBannerAutoConfiguration
|
|
@ -7,17 +7,17 @@ import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFac
|
|||
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactoryImpl;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据全新啊的自动配置类
|
||||
* 数据权限的自动配置类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfiguration
|
||||
public class YudaoDataPermissionAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
|
@ -27,9 +27,8 @@ public class YudaoDataPermissionAutoConfiguration {
|
|||
|
||||
@Bean
|
||||
public DataPermissionDatabaseInterceptor dataPermissionDatabaseInterceptor(MybatisPlusInterceptor interceptor,
|
||||
List<DataPermissionRule> rules) {
|
||||
DataPermissionRuleFactory ruleFactory) {
|
||||
// 创建 DataPermissionDatabaseInterceptor 拦截器
|
||||
DataPermissionRuleFactory ruleFactory = dataPermissionRuleFactory(rules);
|
||||
DataPermissionDatabaseInterceptor inner = new DataPermissionDatabaseInterceptor(ruleFactory);
|
||||
// 添加到 interceptor 中
|
||||
// 需要加在首个,主要是为了在分页插件前面。这个是 MyBatis Plus 的规定
|
||||
|
|
|
@ -4,10 +4,10 @@ import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissi
|
|||
import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -16,7 +16,7 @@ import java.util.List;
|
|||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass(LoginUser.class)
|
||||
@ConditionalOnBean(value = {PermissionApi.class, DeptDataPermissionRuleCustomizer.class})
|
||||
public class YudaoDeptDataPermissionAutoConfiguration {
|
||||
|
|
|
@ -18,7 +18,6 @@ import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
|||
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.delete.Delete;
|
||||
import net.sf.jsqlparser.statement.select.*;
|
||||
|
@ -37,7 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
/**
|
||||
* 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现
|
||||
* 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, Table)} 方法
|
||||
* 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, List)} 方法
|
||||
*
|
||||
* 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。
|
||||
* 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更!
|
||||
|
@ -53,8 +52,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
private final MappedStatementCache mappedStatementCache = new MappedStatementCache();
|
||||
|
||||
@Override // SELECT 场景
|
||||
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter,
|
||||
RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
||||
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
||||
// 获得 Mapper 对应的数据权限的规则
|
||||
List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId());
|
||||
if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过
|
||||
|
@ -68,12 +66,14 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
// 处理 SQL
|
||||
mpBs.sql(parserSingle(mpBs.sql(), null));
|
||||
} finally {
|
||||
// 添加是否需要重写的缓存
|
||||
addMappedStatementCache(ms);
|
||||
// 清空上下文
|
||||
ContextHolder.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景
|
||||
@Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景(因为 INSERT 不需要数据权限)
|
||||
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
||||
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
||||
MappedStatement ms = mpSh.mappedStatement();
|
||||
|
@ -92,7 +92,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
// 处理 SQL
|
||||
mpBs.sql(parserMulti(mpBs.sql(), null));
|
||||
} finally {
|
||||
// 添加是否需要重写的缓存
|
||||
addMappedStatementCache(ms);
|
||||
// 清空上下文
|
||||
ContextHolder.clear();
|
||||
}
|
||||
}
|
||||
|
@ -107,24 +109,6 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
}
|
||||
}
|
||||
|
||||
protected void processSelectBody(SelectBody selectBody) {
|
||||
if (selectBody == null) {
|
||||
return;
|
||||
}
|
||||
if (selectBody instanceof PlainSelect) {
|
||||
processPlainSelect((PlainSelect) selectBody);
|
||||
} else if (selectBody instanceof WithItem) {
|
||||
WithItem withItem = (WithItem) selectBody;
|
||||
processSelectBody(withItem.getSubSelect().getSelectBody());
|
||||
} else {
|
||||
SetOperationList operationList = (SetOperationList) selectBody;
|
||||
List<SelectBody> selectBodys = operationList.getSelects();
|
||||
if (CollectionUtils.isNotEmpty(selectBodys)) {
|
||||
selectBodys.forEach(this::processSelectBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update 语句处理
|
||||
*/
|
||||
|
@ -142,28 +126,77 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
delete.setWhere(this.builderExpression(delete.getWhere(), delete.getTable()));
|
||||
}
|
||||
|
||||
// ========== 和 TenantLineInnerInterceptor 一致的逻辑 ==========
|
||||
|
||||
protected void processSelectBody(SelectBody selectBody) {
|
||||
if (selectBody == null) {
|
||||
return;
|
||||
}
|
||||
if (selectBody instanceof PlainSelect) {
|
||||
processPlainSelect((PlainSelect) selectBody);
|
||||
} else if (selectBody instanceof WithItem) {
|
||||
WithItem withItem = (WithItem) selectBody;
|
||||
processSelectBody(withItem.getSubSelect().getSelectBody());
|
||||
} else {
|
||||
SetOperationList operationList = (SetOperationList) selectBody;
|
||||
List<SelectBody> selectBodyList = operationList.getSelects();
|
||||
if (CollectionUtils.isNotEmpty(selectBodyList)) {
|
||||
selectBodyList.forEach(this::processSelectBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 PlainSelect
|
||||
*/
|
||||
protected void processPlainSelect(PlainSelect plainSelect) {
|
||||
FromItem fromItem = plainSelect.getFromItem();
|
||||
Expression where = plainSelect.getWhere();
|
||||
processWhereSubSelect(where);
|
||||
if (fromItem instanceof Table) {
|
||||
Table fromTable = (Table) fromItem;
|
||||
plainSelect.setWhere(builderExpression(where, fromTable));
|
||||
} else {
|
||||
processFromItem(fromItem);
|
||||
}
|
||||
//#3087 github
|
||||
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||
if (CollectionUtils.isNotEmpty(selectItems)) {
|
||||
selectItems.forEach(this::processSelectItem);
|
||||
}
|
||||
|
||||
// 处理 where 中的子查询
|
||||
Expression where = plainSelect.getWhere();
|
||||
processWhereSubSelect(where);
|
||||
|
||||
// 处理 fromItem
|
||||
FromItem fromItem = plainSelect.getFromItem();
|
||||
List<Table> list = processFromItem(fromItem);
|
||||
List<Table> mainTables = new ArrayList<>(list);
|
||||
|
||||
// 处理 join
|
||||
List<Join> joins = plainSelect.getJoins();
|
||||
if (CollectionUtils.isNotEmpty(joins)) {
|
||||
processJoins(joins);
|
||||
mainTables = processJoins(mainTables, joins);
|
||||
}
|
||||
|
||||
// 当有 mainTable 时,进行 where 条件追加
|
||||
if (CollectionUtils.isNotEmpty(mainTables)) {
|
||||
plainSelect.setWhere(builderExpression(where, mainTables));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Table> processFromItem(FromItem fromItem) {
|
||||
// 处理括号括起来的表达式
|
||||
while (fromItem instanceof ParenthesisFromItem) {
|
||||
fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
|
||||
}
|
||||
|
||||
List<Table> mainTables = new ArrayList<>();
|
||||
// 无 join 时的处理逻辑
|
||||
if (fromItem instanceof Table) {
|
||||
Table fromTable = (Table) fromItem;
|
||||
mainTables.add(fromTable);
|
||||
} else if (fromItem instanceof SubJoin) {
|
||||
// SubJoin 类型则还需要添加上 where 条件
|
||||
List<Table> tables = processSubJoin((SubJoin) fromItem);
|
||||
mainTables.addAll(tables);
|
||||
} else {
|
||||
// 处理下 fromItem
|
||||
processOtherFromItem(fromItem);
|
||||
}
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,7 +224,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
return;
|
||||
}
|
||||
if (where instanceof FromItem) {
|
||||
processFromItem((FromItem) where);
|
||||
processOtherFromItem((FromItem) where);
|
||||
return;
|
||||
}
|
||||
if (where.toString().indexOf("SELECT") > 0) {
|
||||
|
@ -204,9 +237,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
} else if (where instanceof InExpression) {
|
||||
// in
|
||||
InExpression expression = (InExpression) where;
|
||||
ItemsList itemsList = expression.getRightItemsList();
|
||||
if (itemsList instanceof SubSelect) {
|
||||
processSelectBody(((SubSelect) itemsList).getSelectBody());
|
||||
Expression inExpression = expression.getRightExpression();
|
||||
if (inExpression instanceof SubSelect) {
|
||||
processSelectBody(((SubSelect) inExpression).getSelectBody());
|
||||
}
|
||||
} else if (where instanceof ExistsExpression) {
|
||||
// exists
|
||||
|
@ -239,7 +272,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
* <p>支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)<p>
|
||||
* <p> fixed gitee pulls/141</p>
|
||||
*
|
||||
* @param function 函数
|
||||
* @param function
|
||||
*/
|
||||
protected void processFunction(Function function) {
|
||||
ExpressionList parameters = function.getParameters();
|
||||
|
@ -257,22 +290,19 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
/**
|
||||
* 处理子查询等
|
||||
*/
|
||||
protected void processFromItem(FromItem fromItem) {
|
||||
if (fromItem instanceof SubJoin) {
|
||||
SubJoin subJoin = (SubJoin) fromItem;
|
||||
if (subJoin.getJoinList() != null) {
|
||||
processJoins(subJoin.getJoinList());
|
||||
}
|
||||
if (subJoin.getLeft() != null) {
|
||||
processFromItem(subJoin.getLeft());
|
||||
}
|
||||
} else if (fromItem instanceof SubSelect) {
|
||||
protected void processOtherFromItem(FromItem fromItem) {
|
||||
// 去除括号
|
||||
while (fromItem instanceof ParenthesisFromItem) {
|
||||
fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
|
||||
}
|
||||
|
||||
if (fromItem instanceof SubSelect) {
|
||||
SubSelect subSelect = (SubSelect) fromItem;
|
||||
if (subSelect.getSelectBody() != null) {
|
||||
processSelectBody(subSelect.getSelectBody());
|
||||
}
|
||||
} else if (fromItem instanceof ValuesList) {
|
||||
logger.debug("Perform a subquery, if you do not give us feedback");
|
||||
logger.debug("Perform a subQuery, if you do not give us feedback");
|
||||
} else if (fromItem instanceof LateralSubSelect) {
|
||||
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
|
||||
if (lateralSubSelect.getSubSelect() != null) {
|
||||
|
@ -284,75 +314,176 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 sub join
|
||||
*
|
||||
* @param subJoin subJoin
|
||||
* @return Table subJoin 中的主表
|
||||
*/
|
||||
private List<Table> processSubJoin(SubJoin subJoin) {
|
||||
List<Table> mainTables = new ArrayList<>();
|
||||
if (subJoin.getJoinList() != null) {
|
||||
List<Table> list = processFromItem(subJoin.getLeft());
|
||||
mainTables.addAll(list);
|
||||
mainTables = processJoins(mainTables, subJoin.getJoinList());
|
||||
}
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 joins
|
||||
*
|
||||
* @param joins join 集合
|
||||
* @param mainTables 可以为 null
|
||||
* @param joins join 集合
|
||||
* @return List<Table> 右连接查询的 Table 列表
|
||||
*/
|
||||
private void processJoins(List<Join> joins) {
|
||||
private List<Table> processJoins(List<Table> mainTables, List<Join> joins) {
|
||||
// join 表达式中最终的主表
|
||||
Table mainTable = null;
|
||||
// 当前 join 的左表
|
||||
Table leftTable = null;
|
||||
|
||||
if (mainTables == null) {
|
||||
mainTables = new ArrayList<>();
|
||||
} else if (mainTables.size() == 1) {
|
||||
mainTable = mainTables.get(0);
|
||||
leftTable = mainTable;
|
||||
}
|
||||
|
||||
//对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名
|
||||
Deque<Table> tables = new LinkedList<>();
|
||||
Deque<List<Table>> onTableDeque = new LinkedList<>();
|
||||
for (Join join : joins) {
|
||||
// 处理 on 表达式
|
||||
FromItem fromItem = join.getRightItem();
|
||||
if (fromItem instanceof Table) {
|
||||
Table fromTable = (Table) fromItem;
|
||||
FromItem joinItem = join.getRightItem();
|
||||
|
||||
// 获取当前 join 的表,subJoint 可以看作是一张表
|
||||
List<Table> joinTables = null;
|
||||
if (joinItem instanceof Table) {
|
||||
joinTables = new ArrayList<>();
|
||||
joinTables.add((Table) joinItem);
|
||||
} else if (joinItem instanceof SubJoin) {
|
||||
joinTables = processSubJoin((SubJoin) joinItem);
|
||||
}
|
||||
|
||||
if (joinTables != null) {
|
||||
|
||||
// 如果是隐式内连接
|
||||
if (join.isSimple()) {
|
||||
mainTables.addAll(joinTables);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 当前表是否忽略
|
||||
Table joinTable = joinTables.get(0);
|
||||
|
||||
List<Table> onTables = null;
|
||||
// 如果不要忽略,且是右连接,则记录下当前表
|
||||
if (join.isRight()) {
|
||||
mainTable = joinTable;
|
||||
if (leftTable != null) {
|
||||
onTables = Collections.singletonList(leftTable);
|
||||
}
|
||||
} else if (join.isLeft()) {
|
||||
onTables = Collections.singletonList(joinTable);
|
||||
} else if (join.isInner()) {
|
||||
if (mainTable == null) {
|
||||
onTables = Collections.singletonList(joinTable);
|
||||
} else {
|
||||
onTables = Arrays.asList(mainTable, joinTable);
|
||||
}
|
||||
mainTable = null;
|
||||
}
|
||||
|
||||
mainTables = new ArrayList<>();
|
||||
if (mainTable != null) {
|
||||
mainTables.add(mainTable);
|
||||
}
|
||||
|
||||
// 获取 join 尾缀的 on 表达式列表
|
||||
Collection<Expression> originOnExpressions = join.getOnExpressions();
|
||||
// 正常 join on 表达式只有一个,立刻处理
|
||||
if (originOnExpressions.size() == 1) {
|
||||
processJoin(join);
|
||||
if (originOnExpressions.size() == 1 && onTables != null) {
|
||||
List<Expression> onExpressions = new LinkedList<>();
|
||||
onExpressions.add(builderExpression(originOnExpressions.iterator().next(), onTables));
|
||||
join.setOnExpressions(onExpressions);
|
||||
leftTable = joinTable;
|
||||
continue;
|
||||
}
|
||||
tables.push(fromTable);
|
||||
// 表名压栈,忽略的表压入 null,以便后续不处理
|
||||
onTableDeque.push(onTables);
|
||||
// 尾缀多个 on 表达式的时候统一处理
|
||||
if (originOnExpressions.size() > 1) {
|
||||
Collection<Expression> onExpressions = new LinkedList<>();
|
||||
for (Expression originOnExpression : originOnExpressions) {
|
||||
Table currentTable = tables.poll();
|
||||
onExpressions.add(builderExpression(originOnExpression, currentTable));
|
||||
List<Table> currentTableList = onTableDeque.poll();
|
||||
if (CollectionUtils.isEmpty(currentTableList)) {
|
||||
onExpressions.add(originOnExpression);
|
||||
} else {
|
||||
onExpressions.add(builderExpression(originOnExpression, currentTableList));
|
||||
}
|
||||
}
|
||||
join.setOnExpressions(onExpressions);
|
||||
}
|
||||
leftTable = joinTable;
|
||||
} else {
|
||||
// 处理右边连接的子表达式
|
||||
processFromItem(fromItem);
|
||||
processOtherFromItem(joinItem);
|
||||
leftTable = null;
|
||||
}
|
||||
}
|
||||
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
// ========== 和 TenantLineInnerInterceptor 存在差异的逻辑:关键,实现权限条件的拼接 ==========
|
||||
|
||||
/**
|
||||
* 处理联接语句
|
||||
* 处理条件
|
||||
*
|
||||
* @param currentExpression 当前 where 条件
|
||||
* @param table 单个表
|
||||
*/
|
||||
protected void processJoin(Join join) {
|
||||
if (join.getRightItem() instanceof Table) {
|
||||
Table fromTable = (Table) join.getRightItem();
|
||||
Expression originOnExpression = CollUtil.getFirst(join.getOnExpressions());
|
||||
originOnExpression = builderExpression(originOnExpression, fromTable);
|
||||
join.setOnExpressions(CollUtil.newArrayList(originOnExpression));
|
||||
}
|
||||
protected Expression builderExpression(Expression currentExpression, Table table) {
|
||||
return this.builderExpression(currentExpression, Collections.singletonList(table));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理条件
|
||||
*
|
||||
* @param currentExpression 当前 where 条件
|
||||
* @param tables 多个表
|
||||
*/
|
||||
protected Expression builderExpression(Expression currentExpression, Table table) {
|
||||
// 获得 Table 对应的数据权限条件
|
||||
Expression equalsTo = buildDataPermissionExpression(table);
|
||||
if (equalsTo == null) { // 如果没条件,则返回 currentExpression 默认
|
||||
protected Expression builderExpression(Expression currentExpression, List<Table> tables) {
|
||||
// 没有表需要处理直接返回
|
||||
if (CollectionUtils.isEmpty(tables)) {
|
||||
return currentExpression;
|
||||
}
|
||||
|
||||
// 表达式为空,则直接返回 equalsTo
|
||||
// 第一步,获得 Table 对应的数据权限条件
|
||||
Expression dataPermissionExpression = null;
|
||||
for (Table table : tables) {
|
||||
// 构建每个表的权限 Expression 条件
|
||||
Expression expression = buildDataPermissionExpression(table);
|
||||
if (expression == null) {
|
||||
continue;
|
||||
}
|
||||
// 合并到 dataPermissionExpression 中
|
||||
dataPermissionExpression = dataPermissionExpression == null ? expression
|
||||
: new AndExpression(dataPermissionExpression, expression);
|
||||
}
|
||||
|
||||
// 第二步,合并多个 Expression 条件
|
||||
if (dataPermissionExpression == null) {
|
||||
return currentExpression;
|
||||
}
|
||||
if (currentExpression == null) {
|
||||
return equalsTo;
|
||||
return dataPermissionExpression;
|
||||
}
|
||||
// 如果表达式为 Or,则需要 (currentExpression) AND equalsTo
|
||||
// ① 如果表达式为 Or,则需要 (currentExpression) AND dataPermissionExpression
|
||||
if (currentExpression instanceof OrExpression) {
|
||||
return new AndExpression(new Parenthesis(currentExpression), equalsTo);
|
||||
return new AndExpression(new Parenthesis(currentExpression), dataPermissionExpression);
|
||||
}
|
||||
// 如果表达式为 And,则直接返回 currentExpression AND equalsTo
|
||||
return new AndExpression(currentExpression, equalsTo);
|
||||
// ② 如果表达式为 And,则直接返回 where AND dataPermissionExpression
|
||||
return new AndExpression(currentExpression, dataPermissionExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
|||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
|
||||
import cn.iocoder.yudao.framework.expression.OrExpressionX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
|
@ -20,7 +21,6 @@ import net.sf.jsqlparser.expression.Alias;
|
|||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
import net.sf.jsqlparser.expression.NullValue;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
|
@ -143,8 +143,8 @@ public class DeptDataPermissionRule implements DataPermissionRule {
|
|||
if (userExpression == null) {
|
||||
return deptExpression;
|
||||
}
|
||||
// 目前,如果有指定部门 + 可查看自己,采用 OR 条件。即,WHERE dept_id IN ? OR user_id = ?
|
||||
return new OrExpression(deptExpression, userExpression);
|
||||
// 目前,如果有指定部门 + 可查看自己,采用 OR 条件。即,WHERE (dept_id IN ? OR user_id = ?)
|
||||
return new OrExpressionX(deptExpression, userExpression);
|
||||
}
|
||||
|
||||
private Expression buildDeptExpression(String tableName, Alias tableAlias, Set<Long> deptIds) {
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.iocoder.yudao.framework.datapermission.config.YudaoDataPermissionAutoConfiguration,\
|
||||
cn.iocoder.yudao.framework.datapermission.config.YudaoDeptDataPermissionAutoConfiguration
|
|
@ -0,0 +1,2 @@
|
|||
cn.iocoder.yudao.framework.datapermission.config.YudaoDataPermissionAutoConfiguration
|
||||
cn.iocoder.yudao.framework.datapermission.config.YudaoDeptDataPermissionAutoConfiguration
|
|
@ -62,7 +62,7 @@ public class DataPermissionDatabaseInterceptorTest extends BaseMockitoUnitTest {
|
|||
// 调用
|
||||
interceptor.beforeQuery(null, mappedStatement, null, null, null, boundSql);
|
||||
// 断言
|
||||
pluginUtilsMock.verify(never(), () -> PluginUtils.mpBoundSql(boundSql));
|
||||
pluginUtilsMock.verify(() -> PluginUtils.mpBoundSql(boundSql), never());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class DataPermissionDatabaseInterceptorTest extends BaseMockitoUnitTest {
|
|||
interceptor.beforeQuery(null, mappedStatement, null, null, null, boundSql);
|
||||
// 断言
|
||||
verify(mpBs, times(1)).sql(
|
||||
eq("SELECT * FROM t_user WHERE id = 1 AND dept_id = 100"));
|
||||
eq("SELECT * FROM t_user WHERE id = 1 AND t_user.dept_id = 100"));
|
||||
// 断言缓存
|
||||
assertTrue(interceptor.getMappedStatementCache().getNoRewritableMappedStatements().isEmpty());
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
|||
|
||||
@Override
|
||||
public Set<String> getTableNames() {
|
||||
return asSet("entity", "entity1", "entity2", "t1", "t2", // 支持 MyBatis Plus 的单元测试
|
||||
return asSet("entity", "entity1", "entity2", "entity3", "t1", "t2", "sys_dict_item", // 支持 MyBatis Plus 的单元测试
|
||||
"t_user", "t_role"); // 满足自己的单元测试
|
||||
}
|
||||
|
||||
|
@ -84,30 +84,30 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
|||
@Test
|
||||
void delete() {
|
||||
assertSql("delete from entity where id = ?",
|
||||
"DELETE FROM entity WHERE id = ? AND tenant_id = 1");
|
||||
"DELETE FROM entity WHERE id = ? AND entity.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void update() {
|
||||
assertSql("update entity set name = ? where id = ?",
|
||||
"UPDATE entity SET name = ? WHERE id = ? AND tenant_id = 1");
|
||||
"UPDATE entity SET name = ? WHERE id = ? AND entity.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectSingle() {
|
||||
// 单表
|
||||
assertSql("select * from entity where id = ?",
|
||||
"SELECT * FROM entity WHERE id = ? AND tenant_id = 1");
|
||||
"SELECT * FROM entity WHERE id = ? AND entity.tenant_id = 1");
|
||||
|
||||
assertSql("select * from entity where id = ? or name = ?",
|
||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND tenant_id = 1");
|
||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity WHERE (id = ? OR name = ?)",
|
||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND tenant_id = 1");
|
||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||
|
||||
/* not */
|
||||
assertSql("SELECT * FROM entity WHERE not (id = ? OR name = ?)",
|
||||
"SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND tenant_id = 1");
|
||||
"SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -167,10 +167,12 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
|||
assertSql("SELECT * FROM entity e WHERE e.id >= (select e1.id from entity1 e1 where e1.id = ?)",
|
||||
"SELECT * FROM entity e WHERE e.id >= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||
|
||||
|
||||
/* <= */
|
||||
assertSql("SELECT * FROM entity e WHERE e.id <= (select e1.id from entity1 e1 where e1.id = ?)",
|
||||
"SELECT * FROM entity e WHERE e.id <= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||
|
||||
|
||||
/* <> */
|
||||
assertSql("SELECT * FROM entity e WHERE e.id <> (select e1.id from entity1 e1 where e1.id = ?)",
|
||||
"SELECT * FROM entity e WHERE e.id <> (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||
|
@ -204,6 +206,14 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
|||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"left join entity1 e1 on e1.id = e.id " +
|
||||
"left join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " +
|
||||
"WHERE e.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -212,17 +222,125 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
|||
assertSql("SELECT * FROM entity e " +
|
||||
"right join entity1 e1 on e1.id = e.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e.tenant_id = 1");
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM with_as_1 e " +
|
||||
"right join entity1 e1 on e1.id = e.id",
|
||||
"SELECT * FROM with_as_1 e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"right join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE e.id = ? OR e.name = ?",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"right join entity1 e1 on e1.id = e.id " +
|
||||
"right join entity2 e2 on e1.id = e2.id ",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||
"RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e2.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectMixJoin() {
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"right join entity1 e1 on e1.id = e.id " +
|
||||
"left join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"left join entity1 e1 on e1.id = e.id " +
|
||||
"right join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e2.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"left join entity1 e1 on e1.id = e.id " +
|
||||
"inner join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"INNER JOIN entity2 e2 ON e1.id = e2.id AND e.tenant_id = 1 AND e2.tenant_id = 1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void selectJoinSubSelect() {
|
||||
assertSql("select * from (select * from entity) e1 " +
|
||||
"left join entity2 e2 on e1.id = e2.id",
|
||||
"SELECT * FROM (SELECT * FROM entity WHERE entity.tenant_id = 1) e1 " +
|
||||
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1");
|
||||
|
||||
assertSql("select * from entity1 e1 " +
|
||||
"left join (select * from entity2) e2 " +
|
||||
"on e1.id = e2.id",
|
||||
"SELECT * FROM entity1 e1 " +
|
||||
"LEFT JOIN (SELECT * FROM entity2 WHERE entity2.tenant_id = 1) e2 " +
|
||||
"ON e1.id = e2.id " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectSubJoin() {
|
||||
|
||||
assertSql("select * FROM " +
|
||||
"(entity1 e1 right JOIN entity2 e2 ON e1.id = e2.id)",
|
||||
"SELECT * FROM " +
|
||||
"(entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " +
|
||||
"WHERE e2.tenant_id = 1");
|
||||
|
||||
assertSql("select * FROM " +
|
||||
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id)",
|
||||
"SELECT * FROM " +
|
||||
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
|
||||
|
||||
assertSql("select * FROM " +
|
||||
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id) " +
|
||||
"right join entity3 e3 on e1.id = e3.id",
|
||||
"SELECT * FROM " +
|
||||
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||
"RIGHT JOIN entity3 e3 ON e1.id = e3.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e3.tenant_id = 1");
|
||||
|
||||
|
||||
assertSql("select * FROM entity e " +
|
||||
"LEFT JOIN (entity1 e1 right join entity2 e2 ON e1.id = e2.id) " +
|
||||
"on e.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN (entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " +
|
||||
"ON e.id = e2.id AND e2.tenant_id = 1 " +
|
||||
"WHERE e.tenant_id = 1");
|
||||
|
||||
assertSql("select * FROM entity e " +
|
||||
"LEFT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " +
|
||||
"on e.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"LEFT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||
"ON e.id = e2.id AND e1.tenant_id = 1 " +
|
||||
"WHERE e.tenant_id = 1");
|
||||
|
||||
assertSql("select * FROM entity e " +
|
||||
"RIGHT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " +
|
||||
"on e.id = e2.id",
|
||||
"SELECT * FROM entity e " +
|
||||
"RIGHT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||
"ON e.id = e2.id AND e.tenant_id = 1 " +
|
||||
"WHERE e1.tenant_id = 1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void selectLeftJoinMultipleTrailingOn() {
|
||||
// 多个 on 尾缀的
|
||||
|
@ -256,51 +374,97 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
|||
"inner join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE e.id = ? OR e.name = ?",
|
||||
"SELECT * FROM entity e " +
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " +
|
||||
"WHERE e.id = ? OR e.name = ?");
|
||||
|
||||
assertSql("SELECT * FROM entity e " +
|
||||
"inner join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE (e.id = ? OR e.name = ?)",
|
||||
"SELECT * FROM entity e " +
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?)");
|
||||
|
||||
// 隐式内连接
|
||||
assertSql("SELECT * FROM entity,entity1 " +
|
||||
"WHERE entity.id = entity1.id",
|
||||
"SELECT * FROM entity, entity1 " +
|
||||
"WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||
|
||||
// 隐式内连接
|
||||
assertSql("SELECT * FROM entity a, with_as_entity1 b " +
|
||||
"WHERE a.id = b.id",
|
||||
"SELECT * FROM entity a, with_as_entity1 b " +
|
||||
"WHERE a.id = b.id AND a.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM with_as_entity a, with_as_entity1 b " +
|
||||
"WHERE a.id = b.id",
|
||||
"SELECT * FROM with_as_entity a, with_as_entity1 b " +
|
||||
"WHERE a.id = b.id");
|
||||
|
||||
// SubJoin with 隐式内连接
|
||||
assertSql("SELECT * FROM (entity,entity1) " +
|
||||
"WHERE entity.id = entity1.id",
|
||||
"SELECT * FROM (entity, entity1) " +
|
||||
"WHERE entity.id = entity1.id " +
|
||||
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM ((entity,entity1),entity2) " +
|
||||
"WHERE entity.id = entity1.id and entity.id = entity2.id",
|
||||
"SELECT * FROM ((entity, entity1), entity2) " +
|
||||
"WHERE entity.id = entity1.id AND entity.id = entity2.id " +
|
||||
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1");
|
||||
|
||||
assertSql("SELECT * FROM (entity,(entity1,entity2)) " +
|
||||
"WHERE entity.id = entity1.id and entity.id = entity2.id",
|
||||
"SELECT * FROM (entity, (entity1, entity2)) " +
|
||||
"WHERE entity.id = entity1.id AND entity.id = entity2.id " +
|
||||
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1");
|
||||
|
||||
// 沙雕的括号写法
|
||||
assertSql("SELECT * FROM (((entity,entity1))) " +
|
||||
"WHERE entity.id = entity1.id",
|
||||
"SELECT * FROM (((entity, entity1))) " +
|
||||
"WHERE entity.id = entity1.id " +
|
||||
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||
|
||||
// 垃圾 inner join todo
|
||||
// assertSql("SELECT * FROM entity,entity1 " +
|
||||
// "WHERE entity.id = entity1.id",
|
||||
// "SELECT * FROM entity e " +
|
||||
// "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
// "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void selectWithAs() {
|
||||
assertSql("with with_as_A as (select * from entity) select * from with_as_A",
|
||||
"WITH with_as_A AS (SELECT * FROM entity WHERE tenant_id = 1) SELECT * FROM with_as_A");
|
||||
"WITH with_as_A AS (SELECT * FROM entity WHERE entity.tenant_id = 1) SELECT * FROM with_as_A");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void selectIgnoreTable() {
|
||||
assertSql(" SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)",
|
||||
"SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id AND item.tenant_id = 1 WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)");
|
||||
}
|
||||
|
||||
private void assertSql(String sql, String targetSql) {
|
||||
assertEquals(targetSql, interceptor.parserSingle(sql, null));
|
||||
}
|
||||
|
||||
|
||||
// ========== 额外的测试 ==========
|
||||
|
||||
@Test
|
||||
public void testSelectSingle() {
|
||||
// 单表
|
||||
assertSql("select * from t_user where id = ?",
|
||||
"SELECT * FROM t_user WHERE id = ? AND tenant_id = 1 AND dept_id IN (10, 20)");
|
||||
"SELECT * FROM t_user WHERE id = ? AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||
|
||||
assertSql("select * from t_user where id = ? or name = ?",
|
||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||
|
||||
assertSql("SELECT * FROM t_user WHERE (id = ? OR name = ?)",
|
||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||
|
||||
/* not */
|
||||
assertSql("SELECT * FROM t_user WHERE not (id = ? OR name = ?)",
|
||||
"SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
||||
"SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -329,16 +493,16 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
|||
"right join t_role e1 on e1.id = e.id " +
|
||||
"WHERE e.id = ? OR e.name = ?",
|
||||
"SELECT * FROM t_user e " +
|
||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||
|
||||
// 条件 e.id = ? OR e.name = ? 带括号
|
||||
assertSql("SELECT * FROM t_user e " +
|
||||
"right join t_role e1 on e1.id = e.id " +
|
||||
"WHERE (e.id = ? OR e.name = ?)",
|
||||
"SELECT * FROM t_user e " +
|
||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -348,23 +512,22 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
|||
"inner join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE e.id = ? OR e.name = ?",
|
||||
"SELECT * FROM t_user e " +
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " +
|
||||
"WHERE e.id = ? OR e.name = ?");
|
||||
|
||||
// 条件 e.id = ? OR e.name = ? 带括号
|
||||
assertSql("SELECT * FROM t_user e " +
|
||||
"inner join t_role e1 on e1.id = e.id " +
|
||||
"inner join entity1 e1 on e1.id = e.id " +
|
||||
"WHERE (e.id = ? OR e.name = ?)",
|
||||
"SELECT * FROM t_user e " +
|
||||
"INNER JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " +
|
||||
"WHERE (e.id = ? OR e.name = ?)");
|
||||
|
||||
// 垃圾 inner join todo
|
||||
// assertSql("SELECT * FROM entity,entity1 " +
|
||||
// "WHERE entity.id = entity1.id",
|
||||
// "SELECT * FROM entity e " +
|
||||
// "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||
// "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||
// 没有 On 的 inner join
|
||||
assertSql("SELECT * FROM entity,entity1 " +
|
||||
"WHERE entity.id = entity1.id",
|
||||
"SELECT * FROM entity, entity1 " +
|
||||
"WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||
// 调用
|
||||
Expression expression = rule.getExpression(tableName, tableAlias);
|
||||
// 断言
|
||||
assertEquals("u.dept_id IN (10, 20) OR u.id = 1", expression.toString());
|
||||
assertEquals("(u.dept_id IN (10, 20) OR u.id = 1)", expression.toString());
|
||||
assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,5 +26,18 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务组件 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-system-api</artifactId> <!-- 需要使用它,进行 Token 的校验 -->
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue