mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-01-19 03:30:06 +08:00
Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/bpm-back
This commit is contained in:
commit
741dda8d75
26
.gitee/ISSUE_TEMPLATE.zh-CN.md
Normal file
26
.gitee/ISSUE_TEMPLATE.zh-CN.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
### 基本信息
|
||||||
|
|
||||||
|
- ruoyi-vue-pro 版本:
|
||||||
|
- 操作系统:
|
||||||
|
- 数据库:
|
||||||
|
|
||||||
|
### 复现步骤
|
||||||
|
|
||||||
|
第一步,
|
||||||
|
|
||||||
|
第二步,
|
||||||
|
|
||||||
|
第三步,
|
||||||
|
|
||||||
|
### 报错信息
|
||||||
|
|
||||||
|
[截图]
|
||||||
|
|
||||||
|
[截图]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
建议:项目不是很难,碰到问题时,建议先花 2-4 小时的时间进行自查。
|
||||||
|
|
||||||
|
Issue 中如果带上自己的分析,可以被更快更高效的解决。
|
||||||
|
|
34
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
34
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
name: 问题反馈
|
||||||
|
about: 请详细描述,以便更高快的获得到解决
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 基本信息
|
||||||
|
|
||||||
|
- ruoyi-vue-pro 版本:
|
||||||
|
- 操作系统:
|
||||||
|
- 数据库:
|
||||||
|
|
||||||
|
### 复现步骤
|
||||||
|
|
||||||
|
第一步,
|
||||||
|
|
||||||
|
第二步,
|
||||||
|
|
||||||
|
第三步,
|
||||||
|
|
||||||
|
### 报错信息
|
||||||
|
|
||||||
|
[截图]
|
||||||
|
|
||||||
|
[截图]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
建议:项目不是很难,碰到问题时,建议先花 2-4 小时的时间进行自查。
|
||||||
|
|
||||||
|
Issue 中如果带上自己的分析,可以被更快更高效的解决。
|
@ -5,6 +5,10 @@
|
|||||||
**「我喜欢写代码,乐此不疲」**
|
**「我喜欢写代码,乐此不疲」**
|
||||||
**「我喜欢做开源,以此为乐」**
|
**「我喜欢做开源,以此为乐」**
|
||||||
|
|
||||||
|
我 🐶 在上海艰苦奋斗,早中晚在 top3 大厂认真搬砖,夜里为开源做贡献。
|
||||||
|
|
||||||
|
如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。
|
||||||
|
|
||||||
## 🐯 平台简介
|
## 🐯 平台简介
|
||||||
|
|
||||||
**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。
|
**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。
|
||||||
@ -15,6 +19,7 @@
|
|||||||
|
|
||||||
* 前端采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) ,正在支持 Vue 3 + ElementUI Plus 最新方案。
|
* 前端采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) ,正在支持 Vue 3 + ElementUI Plus 最新方案。
|
||||||
* 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson。
|
* 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson。
|
||||||
|
* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等
|
||||||
* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统。
|
* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统。
|
||||||
* 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能。
|
* 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能。
|
||||||
* 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装。
|
* 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装。
|
||||||
@ -26,7 +31,7 @@
|
|||||||
| 项目名 | 说明 | 传说门 |
|
| 项目名 | 说明 | 传说门 |
|
||||||
|--------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `ruoyi-vue-pro` | Spring Boot 多模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro)** [Github](https://github.com/YunaiV/ruoyi-vue-pro) |
|
| `ruoyi-vue-pro` | Spring Boot 多模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro)** [Github](https://github.com/YunaiV/ruoyi-vue-pro) |
|
||||||
| `ruoyi-vue-cloud` | Spring Cloud 微服务 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-cloud)** [Github](https://github.com/YunaiV/onemall) |
|
| `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) |
|
| `Spring-Boot-Labs` | Spring Boot & Cloud 入门 | **[Gitee](https://gitee.com/zhijiantianya/SpringBoot-Labs)** [Github](https://github.com/YunaiV/SpringBoot-Labs) |
|
||||||
|
|
||||||
## 🐶 在线体验
|
## 🐶 在线体验
|
||||||
|
4380
sql/bpm-activiti.sql
4380
sql/bpm-activiti.sql
File diff suppressed because one or more lines are too long
1517
sql/bpm-flowable.sql
1517
sql/bpm-flowable.sql
File diff suppressed because one or more lines are too long
3
sql/db2/README.md
Normal file
3
sql/db2/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
暂未适配 IBM DB2 数据库,如果你有需要,可以微信联系 wangwenbin-server 一起建设。
|
||||||
|
|
||||||
|
你需要把表结构与数据导入到 DM 数据库,我来测试与适配代码。
|
3
sql/dm/README.md
Normal file
3
sql/dm/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
暂未适配国产 DM 数据库,如果你有需要,可以微信联系 wangwenbin-server 一起建设。
|
||||||
|
|
||||||
|
你需要把表结构与数据导入到 DM 数据库,我来测试与适配代码。
|
2570
sql/mysql/ruoyi-vue-pro.sql
Normal file
2570
sql/mysql/ruoyi-vue-pro.sql
Normal file
File diff suppressed because it is too large
Load Diff
6036
sql/oracle/ruoyi-vue-pro.sql
Normal file
6036
sql/oracle/ruoyi-vue-pro.sql
Normal file
File diff suppressed because it is too large
Load Diff
5211
sql/postgresql/ruoyi-vue-pro.sql
Normal file
5211
sql/postgresql/ruoyi-vue-pro.sql
Normal file
File diff suppressed because it is too large
Load Diff
288
sql/quartz.sql
288
sql/quartz.sql
@ -1,288 +0,0 @@
|
|||||||
/*
|
|
||||||
Navicat Premium Data Transfer
|
|
||||||
|
|
||||||
Source Server : 127.0.0.1
|
|
||||||
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: 05/02/2022 00:50:30
|
|
||||||
*/
|
|
||||||
|
|
||||||
SET NAMES utf8mb4;
|
|
||||||
SET FOREIGN_KEY_CHECKS = 0;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_BLOB_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`;
|
|
||||||
CREATE TABLE `QRTZ_BLOB_TRIGGERS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`BLOB_DATA` blob,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
|
||||||
KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
|
||||||
CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_BLOB_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_CALENDARS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_CALENDARS`;
|
|
||||||
CREATE TABLE `QRTZ_CALENDARS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`CALENDAR_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`CALENDAR` blob NOT NULL,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_CALENDARS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_CRON_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`;
|
|
||||||
CREATE TABLE `QRTZ_CRON_TRIGGERS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`CRON_EXPRESSION` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TIME_ZONE_ID` varchar(80) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
|
||||||
CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_CRON_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO `QRTZ_CRON_TRIGGERS` VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai');
|
|
||||||
INSERT INTO `QRTZ_CRON_TRIGGERS` VALUES ('schedulerName', 'userSessionTimeoutJob', 'DEFAULT', '0 * * * * ? *', 'Asia/Shanghai');
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_FIRED_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`;
|
|
||||||
CREATE TABLE `QRTZ_FIRED_TRIGGERS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`ENTRY_ID` varchar(95) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`INSTANCE_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`FIRED_TIME` bigint NOT NULL,
|
|
||||||
`SCHED_TIME` bigint NOT NULL,
|
|
||||||
`PRIORITY` int NOT NULL,
|
|
||||||
`STATE` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`JOB_NAME` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`JOB_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`IS_NONCONCURRENT` varchar(1) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`REQUESTS_RECOVERY` varchar(1) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
|
|
||||||
KEY `IDX_QRTZ_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
|
|
||||||
KEY `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
|
|
||||||
KEY `IDX_QRTZ_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
|
|
||||||
KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
|
|
||||||
KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
|
||||||
KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_FIRED_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_JOB_DETAILS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`;
|
|
||||||
CREATE TABLE `QRTZ_JOB_DETAILS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`JOB_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`JOB_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`DESCRIPTION` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`JOB_CLASS_NAME` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`IS_DURABLE` varchar(1) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`IS_NONCONCURRENT` varchar(1) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`IS_UPDATE_DATA` varchar(1) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`REQUESTS_RECOVERY` varchar(1) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`JOB_DATA` blob,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
|
|
||||||
KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
|
|
||||||
KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_JOB_DETAILS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO `QRTZ_JOB_DETAILS` VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800);
|
|
||||||
INSERT INTO `QRTZ_JOB_DETAILS` VALUES ('schedulerName', 'userSessionTimeoutJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000000D7400104A4F425F48414E444C45525F4E414D457400157573657253657373696F6E54696D656F75744A6F627800);
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_LOCKS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_LOCKS`;
|
|
||||||
CREATE TABLE `QRTZ_LOCKS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`LOCK_NAME` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_LOCKS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO `QRTZ_LOCKS` VALUES ('schedulerName', 'STATE_ACCESS');
|
|
||||||
INSERT INTO `QRTZ_LOCKS` VALUES ('schedulerName', 'TRIGGER_ACCESS');
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`;
|
|
||||||
CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_PAUSED_TRIGGER_GRPS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_SCHEDULER_STATE
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`;
|
|
||||||
CREATE TABLE `QRTZ_SCHEDULER_STATE` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`INSTANCE_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`LAST_CHECKIN_TIME` bigint NOT NULL,
|
|
||||||
`CHECKIN_INTERVAL` bigint NOT NULL,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_SCHEDULER_STATE
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO `QRTZ_SCHEDULER_STATE` VALUES ('schedulerName', 'Yunai.local1635571630493', 1635572537879, 15000);
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_SIMPLE_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_SIMPLE_TRIGGERS`;
|
|
||||||
CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`REPEAT_COUNT` bigint NOT NULL,
|
|
||||||
`REPEAT_INTERVAL` bigint NOT NULL,
|
|
||||||
`TIMES_TRIGGERED` bigint NOT NULL,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
|
||||||
CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_SIMPLE_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_SIMPROP_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`;
|
|
||||||
CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`STR_PROP_1` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`STR_PROP_2` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`STR_PROP_3` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`INT_PROP_1` int DEFAULT NULL,
|
|
||||||
`INT_PROP_2` int DEFAULT NULL,
|
|
||||||
`LONG_PROP_1` bigint DEFAULT NULL,
|
|
||||||
`LONG_PROP_2` bigint DEFAULT NULL,
|
|
||||||
`DEC_PROP_1` decimal(13,4) DEFAULT NULL,
|
|
||||||
`DEC_PROP_2` decimal(13,4) DEFAULT NULL,
|
|
||||||
`BOOL_PROP_1` varchar(1) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`BOOL_PROP_2` varchar(1) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
|
||||||
CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_SIMPROP_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for QRTZ_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
DROP TABLE IF EXISTS `QRTZ_TRIGGERS`;
|
|
||||||
CREATE TABLE `QRTZ_TRIGGERS` (
|
|
||||||
`SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`JOB_NAME` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`JOB_GROUP` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`DESCRIPTION` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`NEXT_FIRE_TIME` bigint DEFAULT NULL,
|
|
||||||
`PREV_FIRE_TIME` bigint DEFAULT NULL,
|
|
||||||
`PRIORITY` int DEFAULT NULL,
|
|
||||||
`TRIGGER_STATE` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`TRIGGER_TYPE` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`START_TIME` bigint NOT NULL,
|
|
||||||
`END_TIME` bigint DEFAULT NULL,
|
|
||||||
`CALENDAR_NAME` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`MISFIRE_INSTR` smallint DEFAULT NULL,
|
|
||||||
`JOB_DATA` blob,
|
|
||||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
|
||||||
KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
|
|
||||||
KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
|
|
||||||
KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
|
|
||||||
KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
|
|
||||||
KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
|
|
||||||
KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
|
|
||||||
KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
|
|
||||||
KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
|
|
||||||
KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
|
|
||||||
KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
|
|
||||||
KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
|
|
||||||
KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
|
|
||||||
CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- Records of QRTZ_TRIGGERS
|
|
||||||
-- ----------------------------
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO `QRTZ_TRIGGERS` VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', 'payNotifyJob', 'DEFAULT', NULL, 1635572540000, 1635572539000, 5, 'WAITING', 'CRON', 1635294882000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800);
|
|
||||||
INSERT INTO `QRTZ_TRIGGERS` VALUES ('schedulerName', 'userSessionTimeoutJob', 'DEFAULT', 'userSessionTimeoutJob', 'DEFAULT', NULL, 1643993400000, -1, 5, 'WAITING', 'CRON', 1643993386000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000007D074000F4A4F425F52455452595F434F554E547371007E0009000000037800);
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
SET FOREIGN_KEY_CHECKS = 1;
|
|
File diff suppressed because one or more lines are too long
335
sql/sqlserver/ruoyi-vue-pro.sql
Normal file
335
sql/sqlserver/ruoyi-vue-pro.sql
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
Navicat Premium Data Transfer
|
||||||
|
|
||||||
|
Source Server : 127.0.0.1 SQLServer
|
||||||
|
Source Server Type : SQL Server
|
||||||
|
Source Server Version : 15004198
|
||||||
|
Source Host : 127.0.0.1:1433
|
||||||
|
Source Catalog : ruoyi-vue-pro
|
||||||
|
Source Schema : dbo
|
||||||
|
|
||||||
|
Target Server Type : SQL Server
|
||||||
|
Target Server Version : 15004198
|
||||||
|
File Encoding : 65001
|
||||||
|
|
||||||
|
Date: 17/05/2022 09:46:25
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[BLOB_DATA] varbinary(max) NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_BLOB_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_BLOB_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_CALENDARS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_CALENDARS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[CALENDAR_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[CALENDAR] varbinary(max) NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_CALENDARS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_CALENDARS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_CRON_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[CRON_EXPRESSION] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TIME_ZONE_ID] varchar(80) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_CRON_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
INSERT INTO [dbo].[QRTZ_CRON_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP], [CRON_EXPRESSION], [TIME_ZONE_ID]) VALUES (N'schedulerName', N'userSessionTimeoutJob', N'DEFAULT', N'0 * * * * ? *', N'Asia/Shanghai')
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[ENTRY_ID] varchar(95) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[INSTANCE_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[FIRED_TIME] bigint NOT NULL,
|
||||||
|
[SCHED_TIME] bigint NOT NULL,
|
||||||
|
[PRIORITY] int NOT NULL,
|
||||||
|
[STATE] varchar(16) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[JOB_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[IS_NONCONCURRENT] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[REQUESTS_RECOVERY] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_FIRED_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_JOB_DETAILS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_JOB_DETAILS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[DESCRIPTION] varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[JOB_CLASS_NAME] varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[IS_DURABLE] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[IS_NONCONCURRENT] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[IS_UPDATE_DATA] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[REQUESTS_RECOVERY] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[JOB_DATA] varbinary(max) NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_JOB_DETAILS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
INSERT INTO [dbo].[QRTZ_JOB_DETAILS] ([SCHED_NAME], [JOB_NAME], [JOB_GROUP], [DESCRIPTION], [JOB_CLASS_NAME], [IS_DURABLE], [IS_NONCONCURRENT], [IS_UPDATE_DATA], [REQUESTS_RECOVERY], [JOB_DATA]) VALUES (N'schedulerName', N'userSessionTimeoutJob', N'DEFAULT', NULL, N'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', N'0', N'1', N'1', N'0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000107400104A4F425F48414E444C45525F4E414D457400157573657253657373696F6E54696D656F75744A6F627800)
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_LOCKS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_LOCKS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[LOCK_NAME] varchar(40) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_LOCKS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_LOCKS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
INSERT INTO [dbo].[QRTZ_LOCKS] ([SCHED_NAME], [LOCK_NAME]) VALUES (N'schedulerName', N'STATE_ACCESS')
|
||||||
|
GO
|
||||||
|
|
||||||
|
INSERT INTO [dbo].[QRTZ_LOCKS] ([SCHED_NAME], [LOCK_NAME]) VALUES (N'schedulerName', N'TRIGGER_ACCESS')
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_SCHEDULER_STATE]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[INSTANCE_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[LAST_CHECKIN_TIME] bigint NOT NULL,
|
||||||
|
[CHECKIN_INTERVAL] bigint NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_SCHEDULER_STATE
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
INSERT INTO [dbo].[QRTZ_SCHEDULER_STATE] ([SCHED_NAME], [INSTANCE_NAME], [LAST_CHECKIN_TIME], [CHECKIN_INTERVAL]) VALUES (N'schedulerName', N'Yunai1651483828928', N'1651484588813', N'15000')
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[REPEAT_COUNT] bigint NOT NULL,
|
||||||
|
[REPEAT_INTERVAL] bigint NOT NULL,
|
||||||
|
[TIMES_TRIGGERED] bigint NOT NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of QRTZ_SIMPLE_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN TRANSACTION
|
||||||
|
GO
|
||||||
|
|
||||||
|
COMMIT
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for QRTZ_SIMPROP_TRIGGERS
|
||||||
|
-- ----------------------------
|
||||||
|
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND type IN ('U'))
|
||||||
|
DROP TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] (
|
||||||
|
[SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||||
|
[STR_PROP_1] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[STR_PROP_2] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[STR_PROP_3] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[INT_PROP_1] int NULL,
|
||||||
|
[INT_PROP_2] int NULL,
|
||||||
|
[LONG_PROP_1] bigint NULL,
|
||||||
|
[LONG_PROP_2] bigint NULL,
|
||||||
|
[DEC_PROP_1] numeric(13,4) NULL,
|
||||||
|
[DEC_PROP_2] numeric(13,4) NULL,
|
||||||
|
[BOOL_PROP_1] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||||
|
[BOOL_PROP_2] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
|
||||||
|
)
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] SET (LOCK_ESCALATION = TABLE)
|
||||||
|
GO
|
||||||
|
|
@ -22,7 +22,6 @@
|
|||||||
<swagger-annotations.version>1.5.22</swagger-annotations.version>
|
<swagger-annotations.version>1.5.22</swagger-annotations.version>
|
||||||
<servlet.versoin>2.5</servlet.versoin>
|
<servlet.versoin>2.5</servlet.versoin>
|
||||||
<!-- DB 相关 -->
|
<!-- DB 相关 -->
|
||||||
<mysql.version>5.1.46</mysql.version>
|
|
||||||
<druid.version>1.2.8</druid.version>
|
<druid.version>1.2.8</druid.version>
|
||||||
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
||||||
<mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
|
<mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
|
||||||
@ -76,12 +75,6 @@
|
|||||||
<version>${spring.boot.version}</version>
|
<version>${spring.boot.version}</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 业务组件 -->
|
<!-- 业务组件 -->
|
||||||
@ -179,11 +172,6 @@
|
|||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
<version>${mysql.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>druid-spring-boot-starter</artifactId>
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
|
@ -54,6 +54,13 @@ public class CollectionUtils {
|
|||||||
return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toList());
|
return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T, U> List<U> convertList(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
|
public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
|
||||||
if (CollUtil.isEmpty(from)) {
|
if (CollUtil.isEmpty(from)) {
|
||||||
return new HashSet<>();
|
return new HashSet<>();
|
||||||
@ -61,6 +68,13 @@ public class CollectionUtils {
|
|||||||
return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
|
||||||
|
if (CollUtil.isEmpty(from)) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
|
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||||
if (CollUtil.isEmpty(from)) {
|
if (CollUtil.isEmpty(from)) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
package cn.iocoder.yudao.framework.common.util.http;
|
package cn.iocoder.yudao.framework.common.util.http;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
import cn.hutool.core.map.TableMap;
|
import cn.hutool.core.map.TableMap;
|
||||||
import cn.hutool.core.net.url.UrlBuilder;
|
import cn.hutool.core.net.url.UrlBuilder;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.util.UriComponents;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.net.URI;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP 工具类
|
* HTTP 工具类
|
||||||
@ -25,4 +33,94 @@ public class HttpUtils {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String append(String base, Map<String, ?> query, boolean fragment) {
|
||||||
|
return append(base, query, null, fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼接 URL
|
||||||
|
*
|
||||||
|
* copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 append 方法
|
||||||
|
*
|
||||||
|
* @param base 基础 URL
|
||||||
|
* @param query 查询参数
|
||||||
|
* @param keys query 的 key,对应的原本的 key 的映射。例如说 query 里有个 key 是 xx,实际它的 key 是 extra_xx,则通过 keys 里添加这个映射
|
||||||
|
* @param fragment URL 的 fragment,即拼接到 # 中
|
||||||
|
* @return 拼接后的 URL
|
||||||
|
*/
|
||||||
|
public static String append(String base, Map<String, ?> query, Map<String, String> keys, boolean fragment) {
|
||||||
|
UriComponentsBuilder template = UriComponentsBuilder.newInstance();
|
||||||
|
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(base);
|
||||||
|
URI redirectUri;
|
||||||
|
try {
|
||||||
|
// assume it's encoded to start with (if it came in over the wire)
|
||||||
|
redirectUri = builder.build(true).toUri();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ... but allow client registrations to contain hard-coded non-encoded values
|
||||||
|
redirectUri = builder.build().toUri();
|
||||||
|
builder = UriComponentsBuilder.fromUri(redirectUri);
|
||||||
|
}
|
||||||
|
template.scheme(redirectUri.getScheme()).port(redirectUri.getPort()).host(redirectUri.getHost())
|
||||||
|
.userInfo(redirectUri.getUserInfo()).path(redirectUri.getPath());
|
||||||
|
|
||||||
|
if (fragment) {
|
||||||
|
StringBuilder values = new StringBuilder();
|
||||||
|
if (redirectUri.getFragment() != null) {
|
||||||
|
String append = redirectUri.getFragment();
|
||||||
|
values.append(append);
|
||||||
|
}
|
||||||
|
for (String key : query.keySet()) {
|
||||||
|
if (values.length() > 0) {
|
||||||
|
values.append("&");
|
||||||
|
}
|
||||||
|
String name = key;
|
||||||
|
if (keys != null && keys.containsKey(key)) {
|
||||||
|
name = keys.get(key);
|
||||||
|
}
|
||||||
|
values.append(name).append("={").append(key).append("}");
|
||||||
|
}
|
||||||
|
if (values.length() > 0) {
|
||||||
|
template.fragment(values.toString());
|
||||||
|
}
|
||||||
|
UriComponents encoded = template.build().expand(query).encode();
|
||||||
|
builder.fragment(encoded.getFragment());
|
||||||
|
} else {
|
||||||
|
for (String key : query.keySet()) {
|
||||||
|
String name = key;
|
||||||
|
if (keys != null && keys.containsKey(key)) {
|
||||||
|
name = keys.get(key);
|
||||||
|
}
|
||||||
|
template.queryParam(name, "{" + key + "}");
|
||||||
|
}
|
||||||
|
template.fragment(redirectUri.getFragment());
|
||||||
|
UriComponents encoded = template.build().expand(query).encode();
|
||||||
|
builder.query(encoded.getQuery());
|
||||||
|
}
|
||||||
|
return builder.build().toUriString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] obtainBasicAuthorization(HttpServletRequest request) {
|
||||||
|
String clientId;
|
||||||
|
String clientSecret;
|
||||||
|
// 先从 Header 中获取
|
||||||
|
String authorization = request.getHeader("Authorization");
|
||||||
|
authorization = StrUtil.subAfter(authorization, "Basic ", true);
|
||||||
|
if (StringUtils.hasText(authorization)) {
|
||||||
|
authorization = Base64.decodeStr(authorization);
|
||||||
|
clientId = StrUtil.subBefore(authorization, ":", false);
|
||||||
|
clientSecret = StrUtil.subAfter(authorization, ":", false);
|
||||||
|
// 再从 Param 中获取
|
||||||
|
} else {
|
||||||
|
clientId = request.getParameter("client_id");
|
||||||
|
clientSecret = request.getParameter("client_secret");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果两者非空,则返回
|
||||||
|
if (StrUtil.isNotEmpty(clientId) && StrUtil.isNotEmpty(clientSecret)) {
|
||||||
|
return new String[]{clientId, clientSecret};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -113,8 +113,7 @@ public class JsonUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @Li:和上面的风格保持一致哈。parseTree
|
public static JsonNode parseTree(String text) {
|
||||||
public static JsonNode readTree(String text) {
|
|
||||||
try {
|
try {
|
||||||
return objectMapper.readTree(text);
|
return objectMapper.readTree(text);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -123,7 +122,7 @@ public class JsonUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JsonNode readTree(byte[] text) {
|
public static JsonNode parseTree(byte[] text) {
|
||||||
try {
|
try {
|
||||||
return objectMapper.readTree(text);
|
return objectMapper.readTree(text);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -132,4 +131,8 @@ public class JsonUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isJson(String text) {
|
||||||
|
return JSONUtil.isJson(text);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package cn.iocoder.yudao.framework.common.util.string;
|
package cn.iocoder.yudao.framework.common.util.string;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串工具类
|
* 字符串工具类
|
||||||
@ -17,21 +17,24 @@ public class StrUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指定字符串的
|
* 给定字符串是否以任何一个字符串开始
|
||||||
* @param str
|
* 给定字符串和数组为空都返回 false
|
||||||
* @param replaceMap
|
*
|
||||||
* @return
|
* @param str 给定字符串
|
||||||
|
* @param prefixes 需要检测的开始字符串
|
||||||
|
* @since 3.0.6
|
||||||
*/
|
*/
|
||||||
public static String replace(String str, Map<String, String> replaceMap) {
|
public static boolean startWithAny(String str, Collection<String> prefixes) {
|
||||||
assert StrUtil.isNotBlank(str);
|
if (StrUtil.isEmpty(str) || ArrayUtil.isEmpty(prefixes)) {
|
||||||
if (ObjectUtil.isEmpty(replaceMap)) {
|
return false;
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
String result = null;
|
|
||||||
for (String key : replaceMap.keySet()) {
|
for (CharSequence suffix : prefixes) {
|
||||||
result = str.replace(key, replaceMap.get(key));
|
if (StrUtil.startWith(str, suffix, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,13 @@
|
|||||||
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
|
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 业务组件 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-module-system-api</artifactId> <!-- 需要使用它,进行数据权限的获取 -->
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Test 测试相关 -->
|
<!-- Test 测试相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package cn.iocoder.yudao.framework.datapermission.config;
|
package cn.iocoder.yudao.framework.datapermission.config;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRule;
|
import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRuleCustomizer;
|
import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -18,14 +18,14 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnClass(LoginUser.class)
|
@ConditionalOnClass(LoginUser.class)
|
||||||
@ConditionalOnBean(value = {DeptDataPermissionFrameworkService.class, DeptDataPermissionRuleCustomizer.class})
|
@ConditionalOnBean(value = {PermissionApi.class, DeptDataPermissionRuleCustomizer.class})
|
||||||
public class YudaoDeptDataPermissionAutoConfiguration {
|
public class YudaoDeptDataPermissionAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DeptDataPermissionRule deptDataPermissionRule(DeptDataPermissionFrameworkService service,
|
public DeptDataPermissionRule deptDataPermissionRule(PermissionApi permissionApi,
|
||||||
List<DeptDataPermissionRuleCustomizer> customizers) {
|
List<DeptDataPermissionRuleCustomizer> customizers) {
|
||||||
// 创建 DeptDataPermissionRule 对象
|
// 创建 DeptDataPermissionRule 对象
|
||||||
DeptDataPermissionRule rule = new DeptDataPermissionRule(service);
|
DeptDataPermissionRule rule = new DeptDataPermissionRule(permissionApi);
|
||||||
// 补全表配置
|
// 补全表配置
|
||||||
customizers.forEach(customizer -> customizer.customize(rule));
|
customizers.forEach(customizer -> customizer.customize(rule));
|
||||||
return rule;
|
return rule;
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package cn.iocoder.yudao.framework.datapermission.core.dept.service;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 基于部门的数据权限 Framework Service 接口
|
|
||||||
* 目前的实现类是 SysPermissionServiceImpl 类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface DeptDataPermissionFrameworkService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得登陆用户的部门数据权限
|
|
||||||
*
|
|
||||||
* @param loginUser 登陆用户
|
|
||||||
* @return 部门数据权限
|
|
||||||
*/
|
|
||||||
DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser);
|
|
||||||
|
|
||||||
}
|
|
@ -1,9 +1,9 @@
|
|||||||
package cn.iocoder.yudao.framework.datapermission.core.dept.rule;
|
package cn.iocoder.yudao.framework.datapermission.core.rule.dept;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
|
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
|
||||||
@ -11,9 +11,10 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
|
||||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.sf.jsqlparser.expression.Alias;
|
import net.sf.jsqlparser.expression.Alias;
|
||||||
import net.sf.jsqlparser.expression.Expression;
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
@ -50,12 +51,17 @@ import java.util.Set;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class DeptDataPermissionRule implements DataPermissionRule {
|
public class DeptDataPermissionRule implements DataPermissionRule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LoginUser 的 Context 缓存 Key
|
||||||
|
*/
|
||||||
|
protected static final String CONTEXT_KEY = DeptDataPermissionRule.class.getSimpleName();
|
||||||
|
|
||||||
private static final String DEPT_COLUMN_NAME = "dept_id";
|
private static final String DEPT_COLUMN_NAME = "dept_id";
|
||||||
private static final String USER_COLUMN_NAME = "user_id";
|
private static final String USER_COLUMN_NAME = "user_id";
|
||||||
|
|
||||||
static final Expression EXPRESSION_NULL = new NullValue();
|
static final Expression EXPRESSION_NULL = new NullValue();
|
||||||
|
|
||||||
private final DeptDataPermissionFrameworkService deptDataPermissionService;
|
private final PermissionApi permissionApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于部门的表字段配置
|
* 基于部门的表字段配置
|
||||||
@ -90,13 +96,23 @@ public class DeptDataPermissionRule implements DataPermissionRule {
|
|||||||
if (loginUser == null) {
|
if (loginUser == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// 只有管理员类型的用户,才进行数据权限的处理
|
||||||
|
if (ObjectUtil.notEqual(loginUser.getUserType(), UserTypeEnum.ADMIN.getValue())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// 获得数据权限
|
// 获得数据权限
|
||||||
DeptDataPermissionRespDTO deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser);
|
DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class);
|
||||||
|
// 从上下文中拿不到,则调用逻辑进行获取
|
||||||
if (deptDataPermission == null) {
|
if (deptDataPermission == null) {
|
||||||
log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser));
|
deptDataPermission = permissionApi.getDeptDataPermission(loginUser.getId());
|
||||||
throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限",
|
if (deptDataPermission == null) {
|
||||||
loginUser.getId(), tableName, tableAlias.getName()));
|
log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser));
|
||||||
|
throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限",
|
||||||
|
loginUser.getId(), tableName, tableAlias.getName()));
|
||||||
|
}
|
||||||
|
// 添加到上下文中,避免重复计算
|
||||||
|
loginUser.setContext(CONTEXT_KEY, deptDataPermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 情况一,如果是 ALL 可查看全部,则无需拼接条件
|
// 情况一,如果是 ALL 可查看全部,则无需拼接条件
|
||||||
@ -111,8 +127,8 @@ public class DeptDataPermissionRule implements DataPermissionRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 情况三,拼接 Dept 和 User 的条件,最后组合
|
// 情况三,拼接 Dept 和 User 的条件,最后组合
|
||||||
Expression deptExpression = this.buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds());
|
Expression deptExpression = buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds());
|
||||||
Expression userExpression = this.buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId());
|
Expression userExpression = buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId());
|
||||||
if (deptExpression == null && userExpression == null) {
|
if (deptExpression == null && userExpression == null) {
|
||||||
// TODO 芋艿:获得不到条件的时候,暂时不抛出异常,而是不返回数据
|
// TODO 芋艿:获得不到条件的时候,暂时不抛出异常,而是不返回数据
|
||||||
log.warn("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]",
|
log.warn("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]",
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.framework.datapermission.core.dept.rule;
|
package cn.iocoder.yudao.framework.datapermission.core.rule.dept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DeptDataPermissionRule} 的自定义配置接口
|
* {@link DeptDataPermissionRule} 的自定义配置接口
|
@ -3,4 +3,4 @@
|
|||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
package cn.iocoder.yudao.framework.datapermission.core.dept;
|
package cn.iocoder.yudao.framework.datapermission.core.rule.dept;
|
@ -1,10 +1,11 @@
|
|||||||
package cn.iocoder.yudao.framework.datapermission.core.dept.rule;
|
package cn.iocoder.yudao.framework.datapermission.core.rule.dept;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
|
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||||
@ -18,7 +19,7 @@ import org.mockito.MockedStatic;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRule.EXPRESSION_NULL;
|
import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule.EXPRESSION_NULL;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
@ -37,7 +38,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
private DeptDataPermissionRule rule;
|
private DeptDataPermissionRule rule;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private DeptDataPermissionFrameworkService deptDataPermissionFrameworkService;
|
private PermissionApi permissionApi;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -69,7 +70,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
String tableName = "t_user";
|
String tableName = "t_user";
|
||||||
Alias tableAlias = new Alias("u");
|
Alias tableAlias = new Alias("u");
|
||||||
// mock 方法
|
// mock 方法
|
||||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
|
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||||
|
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
@ -88,16 +90,18 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
String tableName = "t_user";
|
String tableName = "t_user";
|
||||||
Alias tableAlias = new Alias("u");
|
Alias tableAlias = new Alias("u");
|
||||||
// mock 方法(LoginUser)
|
// mock 方法(LoginUser)
|
||||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
|
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||||
|
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
||||||
// mock 方法(DeptDataPermissionRespDTO)
|
// mock 方法(DeptDataPermissionRespDTO)
|
||||||
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO().setAll(true);
|
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO().setAll(true);
|
||||||
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
|
when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
Expression expression = rule.getExpression(tableName, tableAlias);
|
Expression expression = rule.getExpression(tableName, tableAlias);
|
||||||
// 断言
|
// 断言
|
||||||
assertNull(expression);
|
assertNull(expression);
|
||||||
|
assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,16 +113,18 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
String tableName = "t_user";
|
String tableName = "t_user";
|
||||||
Alias tableAlias = new Alias("u");
|
Alias tableAlias = new Alias("u");
|
||||||
// mock 方法(LoginUser)
|
// mock 方法(LoginUser)
|
||||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
|
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||||
|
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
||||||
// mock 方法(DeptDataPermissionRespDTO)
|
// mock 方法(DeptDataPermissionRespDTO)
|
||||||
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO();
|
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO();
|
||||||
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
|
when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
Expression expression = rule.getExpression(tableName, tableAlias);
|
Expression expression = rule.getExpression(tableName, tableAlias);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals("null = null", expression.toString());
|
assertEquals("null = null", expression.toString());
|
||||||
|
assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,17 +136,19 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
String tableName = "t_user";
|
String tableName = "t_user";
|
||||||
Alias tableAlias = new Alias("u");
|
Alias tableAlias = new Alias("u");
|
||||||
// mock 方法(LoginUser)
|
// mock 方法(LoginUser)
|
||||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
|
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||||
|
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
||||||
// mock 方法(DeptDataPermissionRespDTO)
|
// mock 方法(DeptDataPermissionRespDTO)
|
||||||
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
|
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
|
||||||
.setDeptIds(SetUtils.asSet(10L, 20L)).setSelf(true);
|
.setDeptIds(SetUtils.asSet(10L, 20L)).setSelf(true);
|
||||||
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
|
when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
Expression expression = rule.getExpression(tableName, tableAlias);
|
Expression expression = rule.getExpression(tableName, tableAlias);
|
||||||
// 断言
|
// 断言
|
||||||
assertSame(EXPRESSION_NULL, expression);
|
assertSame(EXPRESSION_NULL, expression);
|
||||||
|
assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,12 +160,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
String tableName = "t_user";
|
String tableName = "t_user";
|
||||||
Alias tableAlias = new Alias("u");
|
Alias tableAlias = new Alias("u");
|
||||||
// mock 方法(LoginUser)
|
// mock 方法(LoginUser)
|
||||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
|
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||||
|
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
||||||
// mock 方法(DeptDataPermissionRespDTO)
|
// mock 方法(DeptDataPermissionRespDTO)
|
||||||
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
|
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
|
||||||
.setSelf(true);
|
.setSelf(true);
|
||||||
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
|
when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
|
||||||
// 添加 user 字段配置
|
// 添加 user 字段配置
|
||||||
rule.addUserColumn("t_user", "id");
|
rule.addUserColumn("t_user", "id");
|
||||||
|
|
||||||
@ -165,6 +174,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
Expression expression = rule.getExpression(tableName, tableAlias);
|
Expression expression = rule.getExpression(tableName, tableAlias);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals("u.id = 1", expression.toString());
|
assertEquals("u.id = 1", expression.toString());
|
||||||
|
assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,12 +186,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
String tableName = "t_user";
|
String tableName = "t_user";
|
||||||
Alias tableAlias = new Alias("u");
|
Alias tableAlias = new Alias("u");
|
||||||
// mock 方法(LoginUser)
|
// mock 方法(LoginUser)
|
||||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
|
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||||
|
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
||||||
// mock 方法(DeptDataPermissionRespDTO)
|
// mock 方法(DeptDataPermissionRespDTO)
|
||||||
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
|
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
|
||||||
.setDeptIds(CollUtil.newLinkedHashSet(10L, 20L));
|
.setDeptIds(CollUtil.newLinkedHashSet(10L, 20L));
|
||||||
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
|
when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
|
||||||
// 添加 dept 字段配置
|
// 添加 dept 字段配置
|
||||||
rule.addDeptColumn("t_user", "dept_id");
|
rule.addDeptColumn("t_user", "dept_id");
|
||||||
|
|
||||||
@ -189,6 +200,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
Expression expression = rule.getExpression(tableName, tableAlias);
|
Expression expression = rule.getExpression(tableName, tableAlias);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals("u.dept_id IN (10, 20)", expression.toString());
|
assertEquals("u.dept_id IN (10, 20)", expression.toString());
|
||||||
|
assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,12 +212,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
String tableName = "t_user";
|
String tableName = "t_user";
|
||||||
Alias tableAlias = new Alias("u");
|
Alias tableAlias = new Alias("u");
|
||||||
// mock 方法(LoginUser)
|
// mock 方法(LoginUser)
|
||||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
|
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||||
|
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
||||||
// mock 方法(DeptDataPermissionRespDTO)
|
// mock 方法(DeptDataPermissionRespDTO)
|
||||||
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
|
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
|
||||||
.setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)).setSelf(true);
|
.setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)).setSelf(true);
|
||||||
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
|
when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
|
||||||
// 添加 user 字段配置
|
// 添加 user 字段配置
|
||||||
rule.addUserColumn("t_user", "id");
|
rule.addUserColumn("t_user", "id");
|
||||||
// 添加 dept 字段配置
|
// 添加 dept 字段配置
|
||||||
@ -215,6 +228,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
|||||||
Expression expression = rule.getExpression(tableName, tableAlias);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,29 +4,40 @@ import cn.hutool.core.collection.CollUtil;
|
|||||||
import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
|
import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import net.sf.jsqlparser.expression.Expression;
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
import net.sf.jsqlparser.expression.LongValue;
|
import net.sf.jsqlparser.expression.LongValue;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能
|
* 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@AllArgsConstructor
|
|
||||||
public class TenantDatabaseInterceptor implements TenantLineHandler {
|
public class TenantDatabaseInterceptor implements TenantLineHandler {
|
||||||
|
|
||||||
private final TenantProperties properties;
|
private final Set<String> ignoreTables = new HashSet<>();
|
||||||
|
|
||||||
|
public TenantDatabaseInterceptor(TenantProperties properties) {
|
||||||
|
// 不同 DB 下,大小写的习惯不同,所以需要都添加进去
|
||||||
|
properties.getIgnoreTables().forEach(table -> {
|
||||||
|
ignoreTables.add(table.toLowerCase());
|
||||||
|
ignoreTables.add(table.toUpperCase());
|
||||||
|
});
|
||||||
|
// 在 OracleKeyGenerator 中,生成主键时,会查询这个表,查询这个表后,会自动拼接 TENANT_ID 导致报错
|
||||||
|
ignoreTables.add("DUAL");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Expression getTenantId() {
|
public Expression getTenantId() {
|
||||||
return new LongValue( TenantContextHolder.getRequiredTenantId());
|
return new LongValue(TenantContextHolder.getRequiredTenantId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean ignoreTable(String tableName) {
|
public boolean ignoreTable(String tableName) {
|
||||||
return TenantContextHolder.isIgnore() // 情况一,全局忽略多租户
|
return TenantContextHolder.isIgnore() // 情况一,全局忽略多租户
|
||||||
|| CollUtil.contains(properties.getIgnoreTables(), tableName); // 情况二,忽略多租户的表
|
|| CollUtil.contains(ignoreTables, tableName); // 情况二,忽略多租户的表
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cn.iocoder.yudao.framework.tenant.core.web;
|
package cn.iocoder.yudao.framework.tenant.core.web;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
@ -24,9 +24,9 @@ public class TenantContextWebFilter extends OncePerRequestFilter {
|
|||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
// 设置
|
// 设置
|
||||||
String tenantId = request.getHeader(HEADER_TENANT_ID);
|
Long tenantId = WebFrameworkUtils.getTenantId(request);
|
||||||
if (StrUtil.isNotEmpty(tenantId)) {
|
if (tenantId != null) {
|
||||||
TenantContextHolder.setTenantId(Long.valueOf(tenantId));
|
TenantContextHolder.setTenantId(tenantId);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
|
@ -15,12 +15,12 @@ import java.util.List;
|
|||||||
public interface ConfigFrameworkDAO {
|
public interface ConfigFrameworkDAO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询是否存在比 maxUpdateTime 更新记录更晚的配置
|
* 查询是否存在比 maxUpdateTime 的更新记录数量
|
||||||
*
|
*
|
||||||
* @param maxUpdateTime 最大更新时间
|
* @param maxUpdateTime 最大更新时间
|
||||||
* @return 是否存在
|
* @return 是否存在
|
||||||
*/
|
*/
|
||||||
boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime);
|
int selectCountByUpdateTimeGt(Date maxUpdateTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询配置列表
|
* 查询配置列表
|
||||||
|
@ -24,7 +24,6 @@ import java.util.List;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class DBConfigRepository extends AbstractConfigRepository {
|
public class DBConfigRepository extends AbstractConfigRepository {
|
||||||
@ -172,7 +171,7 @@ public class DBConfigRepository extends AbstractConfigRepository {
|
|||||||
if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
|
if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
|
||||||
log.info("[loadConfigIfUpdate][首次加载全量配置]");
|
log.info("[loadConfigIfUpdate][首次加载全量配置]");
|
||||||
} else { // 判断数据库中是否有更新的配置
|
} else { // 判断数据库中是否有更新的配置
|
||||||
if (!configFrameworkDAO.selectExistsByUpdateTimeAfter(maxUpdateTime)) {
|
if (configFrameworkDAO.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
log.info("[loadConfigIfUpdate][增量加载全量配置]");
|
log.info("[loadConfigIfUpdate][增量加载全量配置]");
|
||||||
|
@ -27,9 +27,11 @@ public class FtpFileClient extends AbstractFileClient<FtpFileClientConfig> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doInit() {
|
protected void doInit() {
|
||||||
// 补全风格。例如说 Linux 是 /,Windows 是 \
|
// 把配置的 \ 替换成 /, 如果路径配置 \a\test, 替换成 /a/test, 替换方法已经处理 null 情况
|
||||||
if (!config.getBasePath().endsWith(File.separator)) {
|
config.setBasePath(StrUtil.replace(config.getBasePath(), StrUtil.BACKSLASH, StrUtil.SLASH));
|
||||||
config.setBasePath(config.getBasePath() + File.separator);
|
// ftp的路径是 / 结尾
|
||||||
|
if (!config.getBasePath().endsWith(StrUtil.SLASH)) {
|
||||||
|
config.setBasePath(config.getBasePath() + StrUtil.SLASH);
|
||||||
}
|
}
|
||||||
// 初始化 Ftp 对象
|
// 初始化 Ftp 对象
|
||||||
this.ftp = new Ftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword(),
|
this.ftp = new Ftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword(),
|
||||||
@ -42,6 +44,7 @@ public class FtpFileClient extends AbstractFileClient<FtpFileClientConfig> {
|
|||||||
String filePath = getFilePath(path);
|
String filePath = getFilePath(path);
|
||||||
String fileName = FileUtil.getName(filePath);
|
String fileName = FileUtil.getName(filePath);
|
||||||
String dir = StrUtil.removeSuffix(filePath, fileName);
|
String dir = StrUtil.removeSuffix(filePath, fileName);
|
||||||
|
ftp.reconnectIfTimeout();
|
||||||
boolean success = ftp.upload(dir, fileName, new ByteArrayInputStream(content));
|
boolean success = ftp.upload(dir, fileName, new ByteArrayInputStream(content));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new FtpException(StrUtil.format("上传文件到目标目录 ({}) 失败", filePath));
|
throw new FtpException(StrUtil.format("上传文件到目标目录 ({}) 失败", filePath));
|
||||||
@ -53,6 +56,7 @@ public class FtpFileClient extends AbstractFileClient<FtpFileClientConfig> {
|
|||||||
@Override
|
@Override
|
||||||
public void delete(String path) {
|
public void delete(String path) {
|
||||||
String filePath = getFilePath(path);
|
String filePath = getFilePath(path);
|
||||||
|
ftp.reconnectIfTimeout();
|
||||||
ftp.delFile(filePath);
|
ftp.delFile(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +64,9 @@ public class FtpFileClient extends AbstractFileClient<FtpFileClientConfig> {
|
|||||||
public byte[] getContent(String path) {
|
public byte[] getContent(String path) {
|
||||||
String filePath = getFilePath(path);
|
String filePath = getFilePath(path);
|
||||||
String fileName = FileUtil.getName(filePath);
|
String fileName = FileUtil.getName(filePath);
|
||||||
String dir = StrUtil.removeSuffix(path, fileName);
|
String dir = StrUtil.removeSuffix(filePath, fileName);
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ftp.reconnectIfTimeout();
|
||||||
ftp.download(dir, fileName, out);
|
ftp.download(dir, fileName, out);
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
@ -70,4 +75,4 @@ public class FtpFileClient extends AbstractFileClient<FtpFileClientConfig> {
|
|||||||
return config.getBasePath() + path;
|
return config.getBasePath() + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -36,7 +36,6 @@
|
|||||||
<artifactId>jakarta.validation-api</artifactId>
|
<artifactId>jakarta.validation-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -15,10 +15,6 @@
|
|||||||
<description>数据库连接池、多数据源、事务、MyBatis 拓展</description>
|
<description>数据库连接池、多数据源、事务、MyBatis 拓展</description>
|
||||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<mysql.version>5.1.46</mysql.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
@ -36,12 +32,19 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>${mysql.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.oracle.database.jdbc</groupId>
|
<groupId>com.oracle.database.jdbc</groupId>
|
||||||
<artifactId>ojdbc8</artifactId>
|
<artifactId>ojdbc8</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.sqlserver</groupId>
|
||||||
|
<artifactId>mssql-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
@ -55,6 +58,14 @@
|
|||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
|
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 工具类相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ulisesbocchio</groupId>
|
||||||
|
<artifactId>jasypt-spring-boot-starter</artifactId> <!-- 加解密 -->
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -0,0 +1,108 @@
|
|||||||
|
package cn.iocoder.yudao.framework.mybatis.config;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当 IdType 为 {@link IdType#NONE} 时,根据 PRIMARY 数据源所使用的数据库,自动设置
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class IdTypeEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||||
|
|
||||||
|
private static final String ID_TYPE_KEY = "mybatis-plus.global-config.db-config.id-type";
|
||||||
|
|
||||||
|
private static final String DATASOURCE_DYNAMIC_KEY = "spring.datasource.dynamic";
|
||||||
|
|
||||||
|
private static final String QUARTZ_JOB_STORE_DRIVER_KEY = "spring.quartz.properties.org.quartz.jobStore.driverDelegateClass";
|
||||||
|
|
||||||
|
private static final Set<DbType> INPUT_ID_TYPES = SetUtils.asSet(DbType.ORACLE, DbType.ORACLE_12C,
|
||||||
|
DbType.POSTGRE_SQL, DbType.KINGBASE_ES, DbType.DB2, DbType.H2);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||||
|
// 如果获取不到 DbType,则不进行处理
|
||||||
|
DbType dbType = getDbType(environment);
|
||||||
|
if (dbType == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置 Quartz JobStore 对应的 Driver
|
||||||
|
// TODO 芋艿:暂时没有找到特别合适的地方,先放在这里
|
||||||
|
setJobStoreDriverIfPresent(environment, dbType);
|
||||||
|
|
||||||
|
// 初始化 SQL 静态变量
|
||||||
|
SqlConstants.init(dbType);
|
||||||
|
|
||||||
|
// 如果非 NONE,则不进行处理
|
||||||
|
IdType idType = getIdType(environment);
|
||||||
|
if (idType != IdType.NONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 情况一,用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
|
||||||
|
if (INPUT_ID_TYPES.contains(dbType)) {
|
||||||
|
setIdType(environment, IdType.INPUT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 情况二,自增 ID,适合 MySQL 等直接自增的数据库
|
||||||
|
setIdType(environment, IdType.AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdType getIdType(ConfigurableEnvironment environment) {
|
||||||
|
return environment.getProperty(ID_TYPE_KEY, IdType.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdType(ConfigurableEnvironment environment, IdType idType) {
|
||||||
|
environment.getSystemProperties().put(ID_TYPE_KEY, idType);
|
||||||
|
log.info("[setIdType][修改 MyBatis Plus 的 idType 为({})]", idType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobStoreDriverIfPresent(ConfigurableEnvironment environment, DbType dbType) {
|
||||||
|
String driverClass = environment.getProperty(QUARTZ_JOB_STORE_DRIVER_KEY);
|
||||||
|
if (StrUtil.isNotEmpty(driverClass)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 根据 dbType 类型,获取对应的 driverClass
|
||||||
|
switch (dbType) {
|
||||||
|
case POSTGRE_SQL:
|
||||||
|
driverClass = "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate";
|
||||||
|
break;
|
||||||
|
case ORACLE:
|
||||||
|
case ORACLE_12C:
|
||||||
|
driverClass = "org.quartz.impl.jdbcjobstore.oracle.OracleDelegate";
|
||||||
|
break;
|
||||||
|
case SQL_SERVER:
|
||||||
|
case SQL_SERVER2005:
|
||||||
|
driverClass = "org.quartz.impl.jdbcjobstore.MSSQLDelegate";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 设置 driverClass 变量
|
||||||
|
if (StrUtil.isNotEmpty(driverClass)) {
|
||||||
|
environment.getSystemProperties().put(QUARTZ_JOB_STORE_DRIVER_KEY, driverClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DbType getDbType(ConfigurableEnvironment environment) {
|
||||||
|
String primary = environment.getProperty(DATASOURCE_DYNAMIC_KEY + "." + "primary");
|
||||||
|
if (StrUtil.isEmpty(primary)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String url = environment.getProperty(DATASOURCE_DYNAMIC_KEY + ".datasource." + primary + ".url");
|
||||||
|
if (StrUtil.isEmpty(url)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JdbcUtils.getDbType(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,13 +1,22 @@
|
|||||||
package cn.iocoder.yudao.framework.mybatis.config;
|
package cn.iocoder.yudao.framework.mybatis.config;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
|
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
|
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
|
||||||
|
import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator;
|
||||||
|
import com.baomidou.mybatisplus.extension.incrementer.KingbaseKeyGenerator;
|
||||||
|
import com.baomidou.mybatisplus.extension.incrementer.OracleKeyGenerator;
|
||||||
|
import com.baomidou.mybatisplus.extension.incrementer.PostgreKeyGenerator;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MyBaits 配置类
|
* MyBaits 配置类
|
||||||
@ -31,4 +40,25 @@ public class YudaoMybatisAutoConfiguration {
|
|||||||
return new DefaultDBFieldHandler(); // 自动填充参数类
|
return new DefaultDBFieldHandler(); // 自动填充参数类
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(prefix = "mybatis-plus.global-config.db-config", name = "id-type", havingValue = "INPUT")
|
||||||
|
public IKeyGenerator keyGenerator(ConfigurableEnvironment environment) {
|
||||||
|
DbType dbType = IdTypeEnvironmentPostProcessor.getDbType(environment);
|
||||||
|
if (dbType != null) {
|
||||||
|
switch (dbType) {
|
||||||
|
case POSTGRE_SQL:
|
||||||
|
return new PostgreKeyGenerator();
|
||||||
|
case ORACLE:
|
||||||
|
case ORACLE_12C:
|
||||||
|
return new OracleKeyGenerator();
|
||||||
|
case H2:
|
||||||
|
return new H2KeyGenerator();
|
||||||
|
case KINGBASE_ES:
|
||||||
|
return new KingbaseKeyGenerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 找不到合适的 IKeyGenerator 实现类
|
||||||
|
throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.mybatis.core.dataobject;
|
|||||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -32,14 +32,14 @@ public abstract class BaseDO implements Serializable {
|
|||||||
*
|
*
|
||||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||||
*/
|
*/
|
||||||
@TableField(fill = FieldFill.INSERT)
|
@TableField(fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR)
|
||||||
private String creator;
|
private String creator;
|
||||||
/**
|
/**
|
||||||
* 更新者,目前使用 SysUser 的 id 编号
|
* 更新者,目前使用 SysUser 的 id 编号
|
||||||
*
|
*
|
||||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||||
*/
|
*/
|
||||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
@TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR)
|
||||||
private String updater;
|
private String updater;
|
||||||
/**
|
/**
|
||||||
* 是否删除
|
* 是否删除
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
package cn.iocoder.yudao.framework.mybatis.core.enums;
|
package cn.iocoder.yudao.framework.mybatis.core.enums;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SQL相关常量类
|
* SQL相关常量类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
public interface SqlConstants {
|
public class SqlConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据库的类型
|
||||||
|
*/
|
||||||
|
public static DbType DB_TYPE;
|
||||||
|
|
||||||
String LIMIT1 = "LIMIT 1";
|
public static void init(DbType dbType) {
|
||||||
|
DB_TYPE = dbType;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package cn.iocoder.yudao.framework.mybatis.core.query;
|
package cn.iocoder.yudao.framework.mybatis.core.query;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
|
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||||
@ -124,4 +126,28 @@ public class QueryWrapperX<T> extends QueryWrapper<T> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置只返回最后一条
|
||||||
|
*
|
||||||
|
* TODO 芋艿:不是完美解,需要在思考下。如果使用多数据源,并且数据源是多种类型时,可能会存在问题:实现之返回一条的语法不同
|
||||||
|
*
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public QueryWrapperX<T> limit1() {
|
||||||
|
Assert.notNull(SqlConstants.DB_TYPE, "获取不到数据库的类型");
|
||||||
|
switch (SqlConstants.DB_TYPE) {
|
||||||
|
case ORACLE:
|
||||||
|
case ORACLE_12C:
|
||||||
|
super.eq("ROWNUM", 1);
|
||||||
|
break;
|
||||||
|
case SQL_SERVER:
|
||||||
|
case SQL_SERVER2005:
|
||||||
|
super.select("TOP 1 *"); // 由于 SQL Server 是通过 SELECT TOP 1 实现限制一条,所以只好使用 * 查询剩余字段
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super.last("LIMIT 1");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
package cn.iocoder.yudao.framework.mybatis.core.type;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
import org.apache.ibatis.type.BaseTypeHandler;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
import org.jasypt.encryption.StringEncryptor;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段字段的 TypeHandler 实现类,基于 {@link StringEncryptor} 实现
|
||||||
|
* 可通过 jasypt.encryptor.password 配置项,设置密钥
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class EncryptTypeHandler extends BaseTypeHandler<String> {
|
||||||
|
|
||||||
|
private static StringEncryptor encryptor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
|
||||||
|
ps.setString(i, getEncryptor().encrypt(parameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||||
|
String value = rs.getString(columnName);
|
||||||
|
return decrypt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||||
|
String value = rs.getString(columnIndex);
|
||||||
|
return decrypt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||||
|
String value = cs.getString(columnIndex);
|
||||||
|
return decrypt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String decrypt(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getEncryptor().decrypt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encrypt(String rawValue) {
|
||||||
|
if (rawValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getEncryptor().encrypt(rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StringEncryptor getEncryptor() {
|
||||||
|
if (encryptor != null) {
|
||||||
|
return encryptor;
|
||||||
|
}
|
||||||
|
encryptor = SpringUtil.getBean(StringEncryptor.class);
|
||||||
|
Assert.notNull(encryptor, "StringEncryptor 不能为空");
|
||||||
|
return encryptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -21,7 +21,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@MappedJdbcTypes(JdbcType.VARCHAR)
|
@MappedJdbcTypes(JdbcType.VARCHAR)
|
||||||
@MappedTypes(List.class)
|
@MappedTypes(List.class)
|
||||||
public class StringLiSTTypeHandler implements TypeHandler<List<String>> {
|
public class StringListTypeHandler implements TypeHandler<List<String>> {
|
||||||
|
|
||||||
private static final String COMMA = ",";
|
private static final String COMMA = ",";
|
||||||
|
|
@ -1,5 +1,7 @@
|
|||||||
package cn.iocoder.yudao.framework.mybatis.core.util;
|
package cn.iocoder.yudao.framework.mybatis.core.util;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
|
|
||||||
@ -26,4 +28,15 @@ public class JdbcUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得 URL 对应的 DB 类型
|
||||||
|
*
|
||||||
|
* @param url URL
|
||||||
|
* @return DB 类型
|
||||||
|
*/
|
||||||
|
public static DbType getDbType(String url) {
|
||||||
|
String name = com.alibaba.druid.util.JdbcUtils.getDbType(url, null);
|
||||||
|
return DbType.getDbType(name);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration,\
|
cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration,\
|
||||||
cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration
|
cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration
|
||||||
|
org.springframework.boot.env.EnvironmentPostProcessor=\
|
||||||
|
cn.iocoder.yudao.framework.mybatis.config.IdTypeEnvironmentPostProcessor
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package cn.iocoder.yudao.framework.lock4j.config;
|
package cn.iocoder.yudao.framework.lock4j.config;
|
||||||
|
|
||||||
import cn.hutool.core.util.ClassUtil;
|
import cn.hutool.core.util.ClassUtil;
|
||||||
|
import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration;
|
||||||
import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy;
|
import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy;
|
||||||
import cn.iocoder.yudao.framework.lock4j.core.Lock4jRedisKeyConstants;
|
import cn.iocoder.yudao.framework.lock4j.core.Lock4jRedisKeyConstants;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@AutoConfigureBefore(LockAutoConfiguration.class)
|
||||||
public class YudaoLock4jConfiguration {
|
public class YudaoLock4jConfiguration {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -44,18 +44,11 @@
|
|||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- TODO 芋艿: -->
|
<!-- 业务组件 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.activiti</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<artifactId>activiti-engine</artifactId>
|
<artifactId>yudao-module-system-api</artifactId> <!-- 需要使用它,进行 Token 的校验 -->
|
||||||
<version>7.1.0.M6</version>
|
<version>${revision}</version>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>*</groupId>
|
|
||||||
<artifactId>*</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "yudao.security")
|
@ConfigurationProperties(prefix = "yudao.security")
|
||||||
@Validated
|
@Validated
|
||||||
@ -18,18 +17,6 @@ public class SecurityProperties {
|
|||||||
*/
|
*/
|
||||||
@NotEmpty(message = "Token Header 不能为空")
|
@NotEmpty(message = "Token Header 不能为空")
|
||||||
private String tokenHeader;
|
private String tokenHeader;
|
||||||
/**
|
|
||||||
* Token 过期时间
|
|
||||||
*/
|
|
||||||
@NotNull(message = "Token 过期时间不能为空")
|
|
||||||
private Duration tokenTimeout;
|
|
||||||
/**
|
|
||||||
* Session 过期时间
|
|
||||||
*
|
|
||||||
* 当 User 用户超过当前时间未操作,则 Session 会过期
|
|
||||||
*/
|
|
||||||
@NotNull(message = "Session 过期时间不能为空")
|
|
||||||
private Duration sessionTimeout;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mock 模式的开关
|
* mock 模式的开关
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package cn.iocoder.yudao.framework.security.config;
|
package cn.iocoder.yudao.framework.security.config;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect;
|
import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect;
|
||||||
import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy;
|
import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy;
|
||||||
import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter;
|
import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter;
|
||||||
import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl;
|
import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl;
|
||||||
import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl;
|
import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl;
|
||||||
import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl;
|
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
|
||||||
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
|
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkServiceImpl;
|
||||||
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
|
import cn.iocoder.yudao.module.system.api.auth.OAuth2TokenApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -19,10 +19,8 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Security 自动配置类,主要用于相关组件的配置
|
* Spring Security 自动配置类,主要用于相关组件的配置
|
||||||
@ -63,14 +61,6 @@ public class YudaoSecurityAutoConfiguration {
|
|||||||
return new AccessDeniedHandlerImpl();
|
return new AccessDeniedHandlerImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出处理类 Bean
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public LogoutSuccessHandler logoutSuccessHandler(MultiUserDetailsAuthenticationProvider authenticationProvider) {
|
|
||||||
return new LogoutSuccessHandlerImpl(securityProperties, authenticationProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Security 加密器
|
* Spring Security 加密器
|
||||||
* 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器
|
* 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器
|
||||||
@ -86,19 +76,14 @@ public class YudaoSecurityAutoConfiguration {
|
|||||||
* Token 认证过滤器 Bean
|
* Token 认证过滤器 Bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public JWTAuthenticationTokenFilter authenticationTokenFilter(MultiUserDetailsAuthenticationProvider authenticationProvider,
|
public TokenAuthenticationFilter authenticationTokenFilter(GlobalExceptionHandler globalExceptionHandler,
|
||||||
GlobalExceptionHandler globalExceptionHandler) {
|
OAuth2TokenApi oauth2TokenApi) {
|
||||||
return new JWTAuthenticationTokenFilter(securityProperties, authenticationProvider, globalExceptionHandler);
|
return new TokenAuthenticationFilter(securityProperties, globalExceptionHandler, oauth2TokenApi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Bean("ss") // 使用 Spring Security 的缩写,方便食用
|
||||||
* 身份验证的 Provider Bean,通过它实现账号 + 密码的认证
|
public SecurityFrameworkService securityFrameworkService(PermissionApi permissionApi) {
|
||||||
*/
|
return new SecurityFrameworkServiceImpl(permissionApi);
|
||||||
@Bean
|
|
||||||
public MultiUserDetailsAuthenticationProvider authenticationProvider(
|
|
||||||
List<SecurityAuthFrameworkService> securityFrameworkServices,
|
|
||||||
WebProperties webProperties, PasswordEncoder passwordEncoder) {
|
|
||||||
return new MultiUserDetailsAuthenticationProvider(securityFrameworkServices, webProperties, passwordEncoder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
package cn.iocoder.yudao.framework.security.config;
|
package cn.iocoder.yudao.framework.security.config;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter;
|
||||||
import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter;
|
|
||||||
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
@ -17,7 +14,6 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
|||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -34,8 +30,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
|||||||
@Resource
|
@Resource
|
||||||
private WebProperties webProperties;
|
private WebProperties webProperties;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MultiUserDetailsAuthenticationProvider authenticationProvider;
|
|
||||||
/**
|
/**
|
||||||
* 认证失败处理类 Bean
|
* 认证失败处理类 Bean
|
||||||
*/
|
*/
|
||||||
@ -46,16 +40,11 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
|||||||
*/
|
*/
|
||||||
@Resource
|
@Resource
|
||||||
private AccessDeniedHandler accessDeniedHandler;
|
private AccessDeniedHandler accessDeniedHandler;
|
||||||
/**
|
|
||||||
* 退出处理类 Bean
|
|
||||||
*/
|
|
||||||
@Resource
|
|
||||||
private LogoutSuccessHandler logoutSuccessHandler;
|
|
||||||
/**
|
/**
|
||||||
* Token 认证过滤器 Bean
|
* Token 认证过滤器 Bean
|
||||||
*/
|
*/
|
||||||
@Resource
|
@Resource
|
||||||
private JWTAuthenticationTokenFilter authenticationTokenFilter;
|
private TokenAuthenticationFilter authenticationTokenFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义的权限映射 Bean 们
|
* 自定义的权限映射 Bean 们
|
||||||
@ -76,14 +65,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
|||||||
return super.authenticationManagerBean();
|
return super.authenticationManagerBean();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 身份认证接口
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
|
||||||
auth.authenticationProvider(authenticationProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置 URL 的安全配置
|
* 配置 URL 的安全配置
|
||||||
*
|
*
|
||||||
@ -114,11 +95,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
|||||||
.headers().frameOptions().disable().and()
|
.headers().frameOptions().disable().and()
|
||||||
// 一堆自定义的 Spring Security 处理器
|
// 一堆自定义的 Spring Security 处理器
|
||||||
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
|
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
|
||||||
.accessDeniedHandler(accessDeniedHandler).and()
|
.accessDeniedHandler(accessDeniedHandler);
|
||||||
// 登出地址的配置
|
// 登录、登录暂时不使用 Spring Security 的拓展点,主要考虑一方面拓展多用户、多种登录方式相对复杂,一方面用户的学习成本较高
|
||||||
.logout().logoutSuccessHandler(logoutSuccessHandler).logoutRequestMatcher(request -> // 匹配多种用户类型的登出
|
|
||||||
StrUtil.equalsAny(request.getRequestURI(), buildAdminApi("/system/logout"),
|
|
||||||
buildAppApi("/member/logout")));
|
|
||||||
|
|
||||||
// 设置每个请求的权限
|
// 设置每个请求的权限
|
||||||
httpSecurity
|
httpSecurity
|
||||||
@ -140,11 +118,7 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
|||||||
// 添加 JWT Filter
|
// 添加 JWT Filter
|
||||||
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildAdminApi(String url) {
|
|
||||||
return webProperties.getAdminApi().getPrefix() + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buildAppApi(String url) {
|
private String buildAppApi(String url) {
|
||||||
return webProperties.getAppApi().getPrefix() + url;
|
return webProperties.getAppApi().getPrefix() + url;
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
package cn.iocoder.yudao.framework.security.core;
|
package cn.iocoder.yudao.framework.security.core;
|
||||||
|
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录用户信息
|
* 登录用户信息
|
||||||
@ -16,7 +15,7 @@ import java.util.*;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class LoginUser implements UserDetails {
|
public class LoginUser {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户编号
|
* 用户编号
|
||||||
@ -28,38 +27,14 @@ public class LoginUser implements UserDetails {
|
|||||||
* 关联 {@link UserTypeEnum}
|
* 关联 {@link UserTypeEnum}
|
||||||
*/
|
*/
|
||||||
private Integer userType;
|
private Integer userType;
|
||||||
/**
|
|
||||||
* 最后更新时间
|
|
||||||
*/
|
|
||||||
private Date updateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户名
|
|
||||||
*/
|
|
||||||
private String username;
|
|
||||||
/**
|
|
||||||
* 密码
|
|
||||||
*/
|
|
||||||
private String password;
|
|
||||||
/**
|
|
||||||
* 状态
|
|
||||||
*/
|
|
||||||
private Integer status;
|
|
||||||
/**
|
/**
|
||||||
* 租户编号
|
* 租户编号
|
||||||
*/
|
*/
|
||||||
private Long tenantId;
|
private Long tenantId;
|
||||||
|
|
||||||
// ========== UserTypeEnum.ADMIN 独有字段 ==========
|
|
||||||
// TODO 芋艿:可以通过定义一个 Map<String, String> exts 的方式,去除管理员的字段。不过这样会导致系统比较复杂,所以暂时不去掉先;
|
|
||||||
/**
|
/**
|
||||||
* 角色编号数组
|
* 授权范围
|
||||||
*/
|
*/
|
||||||
private Set<Long> roleIds;
|
private List<String> scopes;
|
||||||
/**
|
|
||||||
* 部门编号
|
|
||||||
*/
|
|
||||||
private Long deptId;
|
|
||||||
|
|
||||||
// ========== 上下文 ==========
|
// ========== 上下文 ==========
|
||||||
/**
|
/**
|
||||||
@ -70,49 +45,6 @@ public class LoginUser implements UserDetails {
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private Map<String, Object> context;
|
private Map<String, Object> context;
|
||||||
|
|
||||||
@Override
|
|
||||||
@JsonIgnore// 避免序列化
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@JsonIgnore// 避免序列化
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return CommonStatusEnum.ENABLE.getStatus().equals(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@JsonIgnore// 避免序列化
|
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
|
||||||
return new HashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@JsonIgnore// 避免序列化
|
|
||||||
public boolean isAccountNonExpired() {
|
|
||||||
return true; // 返回 true,不依赖 Spring Security 判断
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@JsonIgnore// 避免序列化
|
|
||||||
public boolean isAccountNonLocked() {
|
|
||||||
return true; // 返回 true,不依赖 Spring Security 判断
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@JsonIgnore// 避免序列化
|
|
||||||
public boolean isCredentialsNonExpired() {
|
|
||||||
return true; // 返回 true,不依赖 Spring Security 判断
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========== 上下文 ==========
|
|
||||||
|
|
||||||
public void setContext(String key, Object value) {
|
public void setContext(String key, Object value) {
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
context = new HashMap<>();
|
context = new HashMap<>();
|
||||||
|
@ -1,149 +0,0 @@
|
|||||||
package cn.iocoder.yudao.framework.security.core.authentication;
|
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
|
|
||||||
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支持多用户类型的 AuthenticationProvider 实现类
|
|
||||||
*
|
|
||||||
* 为什么不用 {@link org.springframework.security.authentication.ProviderManager} 呢?
|
|
||||||
* 原因是,需要每个用户类型实现对应的 {@link AuthenticationProvider} + authentication,略显麻烦。实际,也是可以实现的。
|
|
||||||
*
|
|
||||||
* 另外,额外支持 verifyTokenAndRefresh 校验令牌、logout 登出、mockLogin 模拟登陆等操作。
|
|
||||||
* 实际上,它就是 {@link SecurityAuthFrameworkService} 定义的三个接口。
|
|
||||||
* 因为需要支持多种类型,所以需要根据请求的 URL,判断出对应的用户类型,从而使用对应的 SecurityAuthFrameworkService 是吸纳
|
|
||||||
*
|
|
||||||
* @see cn.iocoder.yudao.framework.common.enums.UserTypeEnum
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
|
|
||||||
|
|
||||||
private final Map<UserTypeEnum, SecurityAuthFrameworkService> services = new HashMap<>();
|
|
||||||
|
|
||||||
private final WebProperties properties;
|
|
||||||
|
|
||||||
private final PasswordEncoder passwordEncoder;
|
|
||||||
|
|
||||||
public MultiUserDetailsAuthenticationProvider(List<SecurityAuthFrameworkService> serviceList,
|
|
||||||
WebProperties properties, PasswordEncoder passwordEncoder) {
|
|
||||||
serviceList.forEach(service -> services.put(service.getUserType(), service));
|
|
||||||
this.properties = properties;
|
|
||||||
this.passwordEncoder = passwordEncoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========== AuthenticationProvider 相关 ==========
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
|
|
||||||
throws AuthenticationException {
|
|
||||||
// 执行用户的加载
|
|
||||||
return selectService(authentication).loadUserByUsername(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SecurityAuthFrameworkService selectService(UsernamePasswordAuthenticationToken authentication) {
|
|
||||||
// 第一步,获得用户类型
|
|
||||||
UserTypeEnum userType = getUserType(authentication);
|
|
||||||
// 第二步,获得 SecurityAuthFrameworkService
|
|
||||||
SecurityAuthFrameworkService service = services.get(userType);
|
|
||||||
Assert.notNull(service, "用户类型({}) 找不到 SecurityAuthFrameworkService 实现类", userType);
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserTypeEnum getUserType(UsernamePasswordAuthenticationToken authentication) {
|
|
||||||
Assert.isInstanceOf(MultiUsernamePasswordAuthenticationToken.class, authentication);
|
|
||||||
MultiUsernamePasswordAuthenticationToken multiAuthentication = (MultiUsernamePasswordAuthenticationToken) authentication;
|
|
||||||
UserTypeEnum userType = multiAuthentication.getUserType();
|
|
||||||
Assert.notNull(userType, "用户类型不能为空");
|
|
||||||
return userType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override // copy 自 DaoAuthenticationProvider 的 additionalAuthenticationChecks 方法
|
|
||||||
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
|
|
||||||
throws AuthenticationException {
|
|
||||||
// 校验 credentials
|
|
||||||
if (authentication.getCredentials() == null) {
|
|
||||||
this.logger.debug("Failed to authenticate since no credentials provided");
|
|
||||||
throw new BadCredentialsException(this.messages.getMessage(
|
|
||||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
|
||||||
}
|
|
||||||
// 校验 password
|
|
||||||
String presentedPassword = authentication.getCredentials().toString();
|
|
||||||
if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
|
|
||||||
this.logger.debug("Failed to authenticate since password does not match stored value");
|
|
||||||
throw new BadCredentialsException(this.messages.getMessage(
|
|
||||||
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========== SecurityAuthFrameworkService 相关 ==========
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验 token 的有效性,并获取用户信息
|
|
||||||
* 通过后,刷新 token 的过期时间
|
|
||||||
*
|
|
||||||
* @param request 请求
|
|
||||||
* @param token token
|
|
||||||
* @return 用户信息
|
|
||||||
*/
|
|
||||||
public LoginUser verifyTokenAndRefresh(HttpServletRequest request, String token) {
|
|
||||||
return selectService(request).verifyTokenAndRefresh(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模拟指定用户编号的 LoginUser
|
|
||||||
*
|
|
||||||
* @param request 请求
|
|
||||||
* @param userId 用户编号
|
|
||||||
* @return 登录用户
|
|
||||||
*/
|
|
||||||
public LoginUser mockLogin(HttpServletRequest request, Long userId) {
|
|
||||||
return selectService(request).mockLogin(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 基于 token 退出登录
|
|
||||||
*
|
|
||||||
* @param request 请求
|
|
||||||
* @param token token
|
|
||||||
*/
|
|
||||||
public void logout(HttpServletRequest request, String token) {
|
|
||||||
selectService(request).logout(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SecurityAuthFrameworkService selectService(HttpServletRequest request) {
|
|
||||||
// 第一步,获得用户类型
|
|
||||||
UserTypeEnum userType = getUserType(request);
|
|
||||||
// 第二步,获得 SecurityAuthFrameworkService
|
|
||||||
SecurityAuthFrameworkService service = services.get(userType);
|
|
||||||
Assert.notNull(service, "URI({}) 用户类型({}) 找不到 SecurityAuthFrameworkService 实现类",
|
|
||||||
request.getRequestURI(), userType);
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserTypeEnum getUserType(HttpServletRequest request) {
|
|
||||||
if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) {
|
|
||||||
return UserTypeEnum.ADMIN;
|
|
||||||
}
|
|
||||||
if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) {
|
|
||||||
return UserTypeEnum.MEMBER;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException(StrUtil.format("URI({}) 找不到匹配的用户类型", request.getRequestURI()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package cn.iocoder.yudao.framework.security.core.authentication;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支持多用户的 UsernamePasswordAuthenticationToken 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public class MultiUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户类型
|
|
||||||
*/
|
|
||||||
private UserTypeEnum userType;
|
|
||||||
|
|
||||||
public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials) {
|
|
||||||
super(principal, credentials);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials,
|
|
||||||
Collection<? extends GrantedAuthority> authorities) {
|
|
||||||
super(principal, credentials, authorities);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials, UserTypeEnum userType) {
|
|
||||||
super(principal, credentials);
|
|
||||||
this.userType = userType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials,
|
|
||||||
Collection<? extends GrantedAuthority> authorities, UserTypeEnum userType) {
|
|
||||||
super(principal, credentials, authorities);
|
|
||||||
this.userType = userType;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,14 +1,19 @@
|
|||||||
package cn.iocoder.yudao.framework.security.core.filter;
|
package cn.iocoder.yudao.framework.security.core.filter;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
|
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
|
import cn.iocoder.yudao.module.system.api.auth.OAuth2TokenApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
@ -18,34 +23,36 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JWT 过滤器,验证 token 的有效性
|
* Token 过滤器,验证 token 的有效性
|
||||||
* 验证通过后,获得 {@link LoginUser} 信息,并加入到 Spring Security 上下文
|
* 验证通过后,获得 {@link LoginUser} 信息,并加入到 Spring Security 上下文
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
|
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
private final SecurityProperties securityProperties;
|
private final SecurityProperties securityProperties;
|
||||||
|
|
||||||
private final MultiUserDetailsAuthenticationProvider authenticationProvider;
|
|
||||||
|
|
||||||
private final GlobalExceptionHandler globalExceptionHandler;
|
private final GlobalExceptionHandler globalExceptionHandler;
|
||||||
|
|
||||||
|
private final OAuth2TokenApi oauth2TokenApi;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("NullableProblems")
|
@SuppressWarnings("NullableProblems")
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
||||||
if (StrUtil.isNotEmpty(token)) {
|
if (StrUtil.isNotEmpty(token)) {
|
||||||
|
Integer userType = WebFrameworkUtils.getLoginUserType(request);
|
||||||
try {
|
try {
|
||||||
// 验证 token 有效性
|
// 1.1 基于 token 构建登录用户
|
||||||
LoginUser loginUser = authenticationProvider.verifyTokenAndRefresh(request, token);
|
LoginUser loginUser = buildLoginUserByToken(token, userType);
|
||||||
// 模拟 Login 功能,方便日常开发调试
|
// 1.2 模拟 Login 功能,方便日常开发调试
|
||||||
if (loginUser == null) {
|
if (loginUser == null) {
|
||||||
loginUser = this.mockLoginUser(request, token);
|
loginUser = mockLoginUser(request, token, userType);
|
||||||
}
|
}
|
||||||
// 设置当前用户
|
|
||||||
|
// 2. 设置当前用户
|
||||||
if (loginUser != null) {
|
if (loginUser != null) {
|
||||||
SecurityFrameworkUtils.setLoginUser(loginUser, request);
|
SecurityFrameworkUtils.setLoginUser(loginUser, request);
|
||||||
}
|
}
|
||||||
@ -60,6 +67,25 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LoginUser buildLoginUserByToken(String token, Integer userType) {
|
||||||
|
try {
|
||||||
|
OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token);
|
||||||
|
if (accessToken == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 用户类型不匹配,无权限
|
||||||
|
if (ObjectUtil.notEqual(accessToken.getUserType(), userType)) {
|
||||||
|
throw new AccessDeniedException("错误的用户类型");
|
||||||
|
}
|
||||||
|
// 构建登录用户
|
||||||
|
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
|
||||||
|
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes());
|
||||||
|
} catch (ServiceException serviceException) {
|
||||||
|
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模拟登录用户,方便日常开发调试
|
* 模拟登录用户,方便日常开发调试
|
||||||
*
|
*
|
||||||
@ -67,9 +93,10 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||||||
*
|
*
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @param token 模拟的 token,格式为 {@link SecurityProperties#getMockSecret()} + 用户编号
|
* @param token 模拟的 token,格式为 {@link SecurityProperties#getMockSecret()} + 用户编号
|
||||||
|
* @param userType 用户类型
|
||||||
* @return 模拟的 LoginUser
|
* @return 模拟的 LoginUser
|
||||||
*/
|
*/
|
||||||
private LoginUser mockLoginUser(HttpServletRequest request, String token) {
|
private LoginUser mockLoginUser(HttpServletRequest request, String token, Integer userType) {
|
||||||
if (!securityProperties.getMockEnable()) {
|
if (!securityProperties.getMockEnable()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -77,8 +104,10 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||||||
if (!token.startsWith(securityProperties.getMockSecret())) {
|
if (!token.startsWith(securityProperties.getMockSecret())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// 构建模拟用户
|
||||||
Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length()));
|
Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length()));
|
||||||
return authenticationProvider.mockLogin(request, userId);
|
return new LoginUser().setId(userId).setUserType(userType)
|
||||||
|
.setTenantId(WebFrameworkUtils.getTenantId(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,40 +0,0 @@
|
|||||||
package cn.iocoder.yudao.framework.security.core.handler;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
|
||||||
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义退出处理器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
|
|
||||||
|
|
||||||
private final SecurityProperties securityProperties;
|
|
||||||
|
|
||||||
private final MultiUserDetailsAuthenticationProvider authenticationProvider;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
|
||||||
// 执行退出
|
|
||||||
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
|
||||||
if (StrUtil.isNotBlank(token)) {
|
|
||||||
authenticationProvider.logout(request, token);
|
|
||||||
}
|
|
||||||
// 返回成功
|
|
||||||
ServletUtils.writeJSON(response, CommonResult.success(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package cn.iocoder.yudao.framework.security.core.service;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Security 框架 Auth Service 接口,定义不同用户类型的 {@link UserTypeEnum} 需要实现的方法
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface SecurityAuthFrameworkService extends UserDetailsService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验 token 的有效性,并获取用户信息
|
|
||||||
* 通过后,刷新 token 的过期时间
|
|
||||||
*
|
|
||||||
* @param token token
|
|
||||||
* @return 用户信息
|
|
||||||
*/
|
|
||||||
LoginUser verifyTokenAndRefresh(String token);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模拟指定用户编号的 LoginUser
|
|
||||||
*
|
|
||||||
* @param userId 用户编号
|
|
||||||
* @return 登录用户
|
|
||||||
*/
|
|
||||||
LoginUser mockLogin(Long userId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 基于 token 退出登录
|
|
||||||
*
|
|
||||||
* @param token token
|
|
||||||
*/
|
|
||||||
void logout(String token);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得用户类型。每个用户类型,对应一个 SecurityAuthFrameworkService 实现类。
|
|
||||||
*
|
|
||||||
* @return 用户类型
|
|
||||||
*/
|
|
||||||
UserTypeEnum getUserType();
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +1,11 @@
|
|||||||
package cn.iocoder.yudao.framework.security.core.service;
|
package cn.iocoder.yudao.framework.security.core.service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Security 框架 Permission Service 接口,定义 security 组件需要的功能
|
* Security 框架 Service 接口,定义权限相关的校验操作
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
public interface SecurityPermissionFrameworkService {
|
public interface SecurityFrameworkService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否有权限
|
* 判断是否有权限
|
||||||
@ -41,4 +41,19 @@ public interface SecurityPermissionFrameworkService {
|
|||||||
*/
|
*/
|
||||||
boolean hasAnyRoles(String... roles);
|
boolean hasAnyRoles(String... roles);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否有授权
|
||||||
|
*
|
||||||
|
* @param scope 授权
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
boolean hasScope(String scope);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否有授权范围,任一一个即可
|
||||||
|
*
|
||||||
|
* @param scope 授权范围数组
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
boolean hasAnyScopes(String... scope);
|
||||||
}
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package cn.iocoder.yudao.framework.security.core.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认的 {@link SecurityFrameworkService} 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
|
||||||
|
|
||||||
|
private final PermissionApi permissionApi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String permission) {
|
||||||
|
return hasAnyPermissions(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAnyPermissions(String... permissions) {
|
||||||
|
return permissionApi.hasAnyPermissions(getLoginUserId(), permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasRole(String role) {
|
||||||
|
return hasAnyRoles(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAnyRoles(String... roles) {
|
||||||
|
return permissionApi.hasAnyRoles(getLoginUserId(), roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasScope(String scope) {
|
||||||
|
return hasAnyScopes(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAnyScopes(String... scope) {
|
||||||
|
LoginUser user = SecurityFrameworkUtils.getLoginUser();
|
||||||
|
if (user == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return CollUtil.containsAny(user.getScopes(), Arrays.asList(scope));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,7 +11,7 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.Set;
|
import java.util.Collections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 安全服务工具类
|
* 安全服务工具类
|
||||||
@ -20,6 +20,8 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class SecurityFrameworkUtils {
|
public class SecurityFrameworkUtils {
|
||||||
|
|
||||||
|
public static final String AUTHORIZATION_BEARER = "Bearer";
|
||||||
|
|
||||||
private SecurityFrameworkUtils() {}
|
private SecurityFrameworkUtils() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +36,7 @@ public class SecurityFrameworkUtils {
|
|||||||
if (!StringUtils.hasText(authorization)) {
|
if (!StringUtils.hasText(authorization)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int index = authorization.indexOf("Bearer ");
|
int index = authorization.indexOf(AUTHORIZATION_BEARER + " ");
|
||||||
if (index == -1) { // 未找到
|
if (index == -1) { // 未找到
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -79,17 +81,6 @@ public class SecurityFrameworkUtils {
|
|||||||
return loginUser != null ? loginUser.getId() : null;
|
return loginUser != null ? loginUser.getId() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得当前用户的角色编号数组
|
|
||||||
*
|
|
||||||
* @return 角色编号数组
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static Set<Long> getLoginUserRoleIds() {
|
|
||||||
LoginUser loginUser = getLoginUser();
|
|
||||||
return loginUser != null ? loginUser.getRoleIds() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置当前用户
|
* 设置当前用户
|
||||||
*
|
*
|
||||||
@ -110,7 +101,7 @@ public class SecurityFrameworkUtils {
|
|||||||
private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) {
|
private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) {
|
||||||
// 创建 UsernamePasswordAuthenticationToken 对象
|
// 创建 UsernamePasswordAuthenticationToken 对象
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
||||||
loginUser, null, loginUser.getAuthorities());
|
loginUser, null, Collections.emptyList());
|
||||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
return authenticationToken;
|
return authenticationToken;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.web.core.filter.DemoFilter;
|
|||||||
import cn.iocoder.yudao.framework.web.core.filter.XssFilter;
|
import cn.iocoder.yudao.framework.web.core.filter.XssFilter;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
@ -65,6 +66,13 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
|
|||||||
return new GlobalResponseBodyHandler();
|
return new GlobalResponseBodyHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SuppressWarnings("InstantiationOfUtilityClass")
|
||||||
|
public WebFrameworkUtils webFrameworkUtils(WebProperties webProperties) {
|
||||||
|
// 由于 WebFrameworkUtils 需要使用到 webProperties 属性,所以注册为一个 Bean
|
||||||
|
return new WebFrameworkUtils(webProperties);
|
||||||
|
}
|
||||||
|
|
||||||
// ========== Filter 相关 ==========
|
// ========== Filter 相关 ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package cn.iocoder.yudao.framework.web.core.util;
|
package cn.iocoder.yudao.framework.web.core.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
||||||
import org.springframework.web.context.request.RequestAttributes;
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
@ -21,16 +23,43 @@ public class WebFrameworkUtils {
|
|||||||
|
|
||||||
private static final String REQUEST_ATTRIBUTE_COMMON_RESULT = "common_result";
|
private static final String REQUEST_ATTRIBUTE_COMMON_RESULT = "common_result";
|
||||||
|
|
||||||
|
private static final String HEADER_TENANT_ID = "tenant-id";
|
||||||
|
|
||||||
|
private static WebProperties properties;
|
||||||
|
|
||||||
|
public WebFrameworkUtils(WebProperties webProperties) {
|
||||||
|
WebFrameworkUtils.properties = webProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得租户编号,从 header 中
|
||||||
|
* 考虑到其它 framework 组件也会使用到租户编号,所以不得不放在 WebFrameworkUtils 统一提供
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @return 租户编号
|
||||||
|
*/
|
||||||
|
public static Long getTenantId(HttpServletRequest request) {
|
||||||
|
String tenantId = request.getHeader(HEADER_TENANT_ID);
|
||||||
|
return StrUtil.isNotEmpty(tenantId) ? Long.valueOf(tenantId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setLoginUserId(ServletRequest request, Long userId) {
|
public static void setLoginUserId(ServletRequest request, Long userId) {
|
||||||
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId);
|
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置用户类型
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @param userType 用户类型
|
||||||
|
*/
|
||||||
public static void setLoginUserType(ServletRequest request, Integer userType) {
|
public static void setLoginUserType(ServletRequest request, Integer userType) {
|
||||||
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE, userType);
|
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE, userType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得当前用户的编号,从请求中
|
* 获得当前用户的编号,从请求中
|
||||||
|
* 注意:该方法仅限于 framework 框架使用!!!
|
||||||
*
|
*
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @return 用户编号
|
* @return 用户编号
|
||||||
@ -43,7 +72,8 @@ public class WebFrameworkUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得当前用户的类型,从请求中
|
* 获得当前用户的类型
|
||||||
|
* 注意:该方法仅限于 web 相关的 framework 组件使用!!!
|
||||||
*
|
*
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @return 用户编号
|
* @return 用户编号
|
||||||
@ -52,7 +82,19 @@ public class WebFrameworkUtils {
|
|||||||
if (request == null) {
|
if (request == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE);
|
// 1. 优先,从 Attribute 中获取
|
||||||
|
Integer userType = (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE);
|
||||||
|
if (userType != null) {
|
||||||
|
return userType;
|
||||||
|
}
|
||||||
|
// 2. 其次,基于 URL 前缀的约定
|
||||||
|
if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) {
|
||||||
|
return UserTypeEnum.ADMIN.getValue();
|
||||||
|
}
|
||||||
|
if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) {
|
||||||
|
return UserTypeEnum.MEMBER.getValue();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer getLoginUserType() {
|
public static Integer getLoginUserType() {
|
||||||
|
@ -3,12 +3,8 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
|
|||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@ApiModel("管理后台 - 通过流程任务的 Request VO")
|
@ApiModel("管理后台 - 通过流程任务的 Request VO")
|
||||||
@Data
|
@Data
|
||||||
@ -20,6 +16,6 @@ public class BpmTaskApproveReqVO {
|
|||||||
|
|
||||||
@ApiModelProperty(value = "审批意见", required = true, example = "不错不错!")
|
@ApiModelProperty(value = "审批意见", required = true, example = "不错不错!")
|
||||||
@NotEmpty(message = "审批意见不能为空")
|
@NotEmpty(message = "审批意见不能为空")
|
||||||
private String comment;
|
private String reason;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,6 @@ public class BpmTaskDonePageItemRespVO extends BpmTaskTodoPageItemRespVO {
|
|||||||
@ApiModelProperty(value = "任务结果", required = true, notes = "参见 bpm_process_instance_result", example = "2")
|
@ApiModelProperty(value = "任务结果", required = true, notes = "参见 bpm_process_instance_result", example = "2")
|
||||||
private Integer result;
|
private Integer result;
|
||||||
@ApiModelProperty(value = "审批建议", required = true, example = "不请假了!")
|
@ApiModelProperty(value = "审批建议", required = true, example = "不请假了!")
|
||||||
private String comment;
|
private String reason;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,6 @@ public class BpmTaskRejectReqVO {
|
|||||||
|
|
||||||
@ApiModelProperty(value = "审批意见", required = true, example = "不错不错!")
|
@ApiModelProperty(value = "审批意见", required = true, example = "不错不错!")
|
||||||
@NotEmpty(message = "审批意见不能为空")
|
@NotEmpty(message = "审批意见不能为空")
|
||||||
private String comment;
|
private String reason;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
|
package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@ -16,6 +17,7 @@ import java.util.List;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "bpm_form", autoResultMap = true)
|
@TableName(value = "bpm_form", autoResultMap = true)
|
||||||
|
@KeySequence("bpm_form_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@ -17,6 +18,7 @@ import java.util.List;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "bpm_process_definition_ext", autoResultMap = true)
|
@TableName(value = "bpm_process_definition_ext", autoResultMap = true)
|
||||||
|
@KeySequence("bpm_process_definition_ext_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
|
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@ -21,6 +22,7 @@ import java.util.Set;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "bpm_task_assign_rule", autoResultMap = true)
|
@TableName(value = "bpm_task_assign_rule", autoResultMap = true)
|
||||||
|
@KeySequence("bpm_task_assign_rule_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -31,8 +33,9 @@ public class BpmTaskAssignRuleDO extends BaseDO {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link #processDefinitionId} 空串,用于标识属于流程模型,而不属于流程定义
|
* {@link #processDefinitionId} 空串,用于标识属于流程模型,而不属于流程定义
|
||||||
|
* 不使用空串的原因,Oracle 针对空串,会处理成 null,进而导致无法检索
|
||||||
*/
|
*/
|
||||||
public static final String PROCESS_DEFINITION_ID_NULL = "";
|
public static final String PROCESS_DEFINITION_ID_NULL = "DEFAULT";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编号
|
* 编号
|
||||||
@ -64,7 +67,6 @@ public class BpmTaskAssignRuleDO extends BaseDO {
|
|||||||
*
|
*
|
||||||
* 枚举 {@link BpmTaskAssignRuleTypeEnum}
|
* 枚举 {@link BpmTaskAssignRuleTypeEnum}
|
||||||
*/
|
*/
|
||||||
@TableField("`type`")
|
|
||||||
private Integer type;
|
private Integer type;
|
||||||
/**
|
/**
|
||||||
* 规则值数组,一般关联指定表的编号
|
* 规则值数组,一般关联指定表的编号
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
|
|||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
|
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@ -16,6 +17,7 @@ import java.util.Set;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "bpm_user_group", autoResultMap = true)
|
@TableName(value = "bpm_user_group", autoResultMap = true)
|
||||||
|
@KeySequence("bpm_user_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.dal.dataobject.oa;
|
package cn.iocoder.yudao.module.bpm.dal.dataobject.oa;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
|
||||||
import lombok.*;
|
|
||||||
import java.util.*;
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OA 请假申请 DO
|
* OA 请假申请 DO
|
||||||
@ -15,6 +18,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName("bpm_oa_leave")
|
@TableName("bpm_oa_leave")
|
||||||
|
@KeySequence("bpm_oa_leave_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -37,8 +41,7 @@ public class BpmOALeaveDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 请假类型
|
* 请假类型
|
||||||
*/
|
*/
|
||||||
@TableField("`type`")
|
private Integer type;
|
||||||
private String type;
|
|
||||||
/**
|
/**
|
||||||
* 原因
|
* 原因
|
||||||
*/
|
*/
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.task;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@ -21,6 +22,7 @@ import java.util.Map;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "bpm_process_instance_ext", autoResultMap = true)
|
@TableName(value = "bpm_process_instance_ext", autoResultMap = true)
|
||||||
|
@KeySequence("bpm_process_instance_ext_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.task;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -17,6 +19,7 @@ import java.util.Date;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "bpm_task_ext", autoResultMap = true)
|
@TableName(value = "bpm_task_ext", autoResultMap = true)
|
||||||
|
@KeySequence("bpm_task_ext_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -60,7 +63,7 @@ public class BpmTaskExtDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 审批建议
|
* 审批建议
|
||||||
*/
|
*/
|
||||||
private String comment;
|
private String reason;
|
||||||
/**
|
/**
|
||||||
* 任务的结束时间
|
* 任务的结束时间
|
||||||
*
|
*
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.dal.mysql.definition;
|
package cn.iocoder.yudao.module.bpm.dal.mysql.definition;
|
||||||
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,9 +17,9 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
public interface BpmFormMapper extends BaseMapperX<BpmFormDO> {
|
public interface BpmFormMapper extends BaseMapperX<BpmFormDO> {
|
||||||
|
|
||||||
default PageResult<BpmFormDO> selectPage(BpmFormPageReqVO reqVO) {
|
default PageResult<BpmFormDO> selectPage(BpmFormPageReqVO reqVO) {
|
||||||
return selectPage(reqVO, new QueryWrapperX<BpmFormDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<BpmFormDO>()
|
||||||
.likeIfPresent("name", reqVO.getName())
|
.likeIfPresent(BpmFormDO::getName, reqVO.getName())
|
||||||
.orderByDesc("id"));
|
.orderByDesc(BpmFormDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.dal.mysql.definition;
|
package cn.iocoder.yudao.module.bpm.dal.mysql.definition;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -12,11 +11,11 @@ import java.util.List;
|
|||||||
public interface BpmProcessDefinitionExtMapper extends BaseMapperX<BpmProcessDefinitionExtDO> {
|
public interface BpmProcessDefinitionExtMapper extends BaseMapperX<BpmProcessDefinitionExtDO> {
|
||||||
|
|
||||||
default List<BpmProcessDefinitionExtDO> selectListByProcessDefinitionIds(Collection<String> processDefinitionIds) {
|
default List<BpmProcessDefinitionExtDO> selectListByProcessDefinitionIds(Collection<String> processDefinitionIds) {
|
||||||
return selectList("process_definition_id", processDefinitionIds);
|
return selectList(BpmProcessDefinitionExtDO::getProcessDefinitionId, processDefinitionIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
default BpmProcessDefinitionExtDO selectByProcessDefinitionId(String processDefinitionId) {
|
default BpmProcessDefinitionExtDO selectByProcessDefinitionId(String processDefinitionId) {
|
||||||
return selectOne("process_definition_id", processDefinitionId);
|
return selectOne(BpmProcessDefinitionExtDO::getProcessDefinitionId, processDefinitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.dal.mysql.definition;
|
package cn.iocoder.yudao.module.bpm.dal.mysql.definition;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
@ -13,23 +13,23 @@ public interface BpmTaskAssignRuleMapper extends BaseMapperX<BpmTaskAssignRuleDO
|
|||||||
|
|
||||||
default List<BpmTaskAssignRuleDO> selectListByProcessDefinitionId(String processDefinitionId,
|
default List<BpmTaskAssignRuleDO> selectListByProcessDefinitionId(String processDefinitionId,
|
||||||
@Nullable String taskDefinitionKey) {
|
@Nullable String taskDefinitionKey) {
|
||||||
return selectList(new QueryWrapperX<BpmTaskAssignRuleDO>()
|
return selectList(new LambdaQueryWrapperX<BpmTaskAssignRuleDO>()
|
||||||
.eq("process_definition_id", processDefinitionId)
|
.eq(BpmTaskAssignRuleDO::getProcessDefinitionId, processDefinitionId)
|
||||||
.eqIfPresent("task_definition_key", taskDefinitionKey));
|
.eqIfPresent(BpmTaskAssignRuleDO::getTaskDefinitionKey, taskDefinitionKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<BpmTaskAssignRuleDO> selectListByModelId(String modelId) {
|
default List<BpmTaskAssignRuleDO> selectListByModelId(String modelId) {
|
||||||
return selectList(new QueryWrapperX<BpmTaskAssignRuleDO>()
|
return selectList(new LambdaQueryWrapperX<BpmTaskAssignRuleDO>()
|
||||||
.eq("model_id", modelId)
|
.eq(BpmTaskAssignRuleDO::getModelId, modelId)
|
||||||
.eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL));
|
.eq(BpmTaskAssignRuleDO::getProcessDefinitionId, BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
default BpmTaskAssignRuleDO selectListByModelIdAndTaskDefinitionKey(String modelId,
|
default BpmTaskAssignRuleDO selectListByModelIdAndTaskDefinitionKey(String modelId,
|
||||||
String taskDefinitionKey) {
|
String taskDefinitionKey) {
|
||||||
return selectOne(new QueryWrapperX<BpmTaskAssignRuleDO>()
|
return selectOne(new LambdaQueryWrapperX<BpmTaskAssignRuleDO>()
|
||||||
.eq("model_id", modelId)
|
.eq(BpmTaskAssignRuleDO::getModelId, modelId)
|
||||||
.eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL)
|
.eq(BpmTaskAssignRuleDO::getProcessDefinitionId, BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL)
|
||||||
.eq("task_definition_key", taskDefinitionKey));
|
.eq(BpmTaskAssignRuleDO::getTaskDefinitionKey, taskDefinitionKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,34 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.dal.mysql.task;
|
package cn.iocoder.yudao.module.bpm.dal.mysql.task;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface BpmProcessInstanceExtMapper extends BaseMapperX<BpmProcessInstanceExtDO> {
|
public interface BpmProcessInstanceExtMapper extends BaseMapperX<BpmProcessInstanceExtDO> {
|
||||||
|
|
||||||
default PageResult<BpmProcessInstanceExtDO> selectPage(Long userId, BpmProcessInstanceMyPageReqVO reqVO) {
|
default PageResult<BpmProcessInstanceExtDO> selectPage(Long userId, BpmProcessInstanceMyPageReqVO reqVO) {
|
||||||
return selectPage(reqVO, new QueryWrapperX<BpmProcessInstanceExtDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<BpmProcessInstanceExtDO>()
|
||||||
.eqIfPresent("start_user_id", userId)
|
.eqIfPresent(BpmProcessInstanceExtDO::getStartUserId, userId)
|
||||||
.likeIfPresent("name", reqVO.getName())
|
.likeIfPresent(BpmProcessInstanceExtDO::getName, reqVO.getName())
|
||||||
.eqIfPresent("process_definition_id", reqVO.getProcessDefinitionId())
|
.eqIfPresent(BpmProcessInstanceExtDO::getProcessDefinitionId, reqVO.getProcessDefinitionId())
|
||||||
.eqIfPresent("category", reqVO.getCategory())
|
.eqIfPresent(BpmProcessInstanceExtDO::getCategory, reqVO.getCategory())
|
||||||
.eqIfPresent("status", reqVO.getStatus())
|
.eqIfPresent(BpmProcessInstanceExtDO::getStatus, reqVO.getStatus())
|
||||||
.eqIfPresent("result", reqVO.getResult())
|
.eqIfPresent(BpmProcessInstanceExtDO::getResult, reqVO.getResult())
|
||||||
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
|
.betweenIfPresent(BpmProcessInstanceExtDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
|
||||||
.orderByDesc("id"));
|
.orderByDesc(BpmProcessInstanceExtDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
default BpmProcessInstanceExtDO selectByProcessInstanceId(String processDefinitionId) {
|
default BpmProcessInstanceExtDO selectByProcessInstanceId(String processDefinitionId) {
|
||||||
return selectOne("process_instance_id", processDefinitionId);
|
return selectOne(BpmProcessInstanceExtDO::getProcessInstanceId, processDefinitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
default void updateByProcessInstanceId(BpmProcessInstanceExtDO updateObj) {
|
default void updateByProcessInstanceId(BpmProcessInstanceExtDO updateObj) {
|
||||||
update(updateObj, new QueryWrapper<BpmProcessInstanceExtDO>()
|
update(updateObj, new LambdaQueryWrapperX<BpmProcessInstanceExtDO>()
|
||||||
.eq("process_instance_id", updateObj.getProcessInstanceId()));
|
.eq(BpmProcessInstanceExtDO::getProcessInstanceId, updateObj.getProcessInstanceId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.dal.mysql.task;
|
package cn.iocoder.yudao.module.bpm.dal.mysql.task;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@ -20,6 +20,6 @@ public interface BpmTaskExtMapper extends BaseMapperX<BpmTaskExtDO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default List<BpmTaskExtDO> selectListByProcessInstanceId(String processInstanceId) {
|
default List<BpmTaskExtDO> selectListByProcessInstanceId(String processInstanceId) {
|
||||||
return selectList("process_instance_id", processInstanceId);
|
return selectList(BpmTaskExtDO::getProcessInstanceId, processInstanceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public class BpmMessageServiceImpl implements BpmMessageService {
|
|||||||
public void sendMessageWhenProcessInstanceReject(BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO) {
|
public void sendMessageWhenProcessInstanceReject(BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO) {
|
||||||
Map<String, Object> templateParams = new HashMap<>();
|
Map<String, Object> templateParams = new HashMap<>();
|
||||||
templateParams.put("processInstanceName", reqDTO.getProcessInstanceName());
|
templateParams.put("processInstanceName", reqDTO.getProcessInstanceName());
|
||||||
templateParams.put("comment", reqDTO.getComment());
|
templateParams.put("reason", reqDTO.getReason());
|
||||||
templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId()));
|
templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId()));
|
||||||
smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(),
|
smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(),
|
||||||
BpmMessageEnum.PROCESS_INSTANCE_REJECT.getSmsTemplateCode(), templateParams));
|
BpmMessageEnum.PROCESS_INSTANCE_REJECT.getSmsTemplateCode(), templateParams));
|
||||||
|
@ -28,6 +28,6 @@ public class BpmMessageSendWhenProcessInstanceRejectReqDTO {
|
|||||||
* 不通过理由
|
* 不通过理由
|
||||||
*/
|
*/
|
||||||
@NotEmpty(message = "不通过理由不能为空")
|
@NotEmpty(message = "不通过理由不能为空")
|
||||||
private String comment;
|
private String reason;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -116,10 +116,10 @@ public interface BpmProcessInstanceConvert {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
default BpmMessageSendWhenProcessInstanceRejectReqDTO convert(ProcessInstance processInstance, String comment) {
|
default BpmMessageSendWhenProcessInstanceRejectReqDTO convert(ProcessInstance processInstance, String reason) {
|
||||||
BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO = new BpmMessageSendWhenProcessInstanceRejectReqDTO();
|
BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO = new BpmMessageSendWhenProcessInstanceRejectReqDTO();
|
||||||
copyTo(processInstance, reqDTO);
|
copyTo(processInstance, reqDTO);
|
||||||
reqDTO.setComment(comment);
|
reqDTO.setReason(reason);
|
||||||
return reqDTO;
|
return reqDTO;
|
||||||
}
|
}
|
||||||
@Mapping(source = "name", target = "processInstanceName")
|
@Mapping(source = "name", target = "processInstanceName")
|
||||||
|
@ -158,8 +158,8 @@ public interface BpmProcessInstanceService {
|
|||||||
* 更新 ProcessInstance 拓展记录为不通过
|
* 更新 ProcessInstance 拓展记录为不通过
|
||||||
*
|
*
|
||||||
* @param id 流程编号
|
* @param id 流程编号
|
||||||
* @param comment 理由。例如说,审批不通过时,需要传递该值
|
* @param reason 理由。例如说,审批不通过时,需要传递该值
|
||||||
*/
|
*/
|
||||||
void updateProcessInstanceExtReject(String id, String comment);
|
void updateProcessInstanceExtReject(String id, String reason);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -285,11 +285,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateProcessInstanceExtReject(String id, String comment) {
|
public void updateProcessInstanceExtReject(String id, String reason) {
|
||||||
// 需要主动查询,因为 instance 只有 id 属性
|
// 需要主动查询,因为 instance 只有 id 属性
|
||||||
ProcessInstance processInstance = getProcessInstance(id);
|
ProcessInstance processInstance = getProcessInstance(id);
|
||||||
// 删除流程实例,以实现驳回任务时,取消整个审批流程
|
// 删除流程实例,以实现驳回任务时,取消整个审批流程
|
||||||
deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(comment)));
|
deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason)));
|
||||||
|
|
||||||
// 更新 status + result
|
// 更新 status + result
|
||||||
// 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法,
|
// 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法,
|
||||||
@ -300,7 +300,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||||||
processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
|
processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
|
||||||
|
|
||||||
// 发送流程被不通过的消息
|
// 发送流程被不通过的消息
|
||||||
messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert(processInstance, comment));
|
messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert(processInstance, reason));
|
||||||
|
|
||||||
// 发送流程实例的状态事件
|
// 发送流程实例的状态事件
|
||||||
processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
|
processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
|
||||||
|
@ -226,7 +226,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||||||
taskService.complete(task.getId(), instance.getProcessVariables()); // TODO 芋艿:variables 的选择
|
taskService.complete(task.getId(), instance.getProcessVariables()); // TODO 芋艿:variables 的选择
|
||||||
// 更新任务拓展表为通过
|
// 更新任务拓展表为通过
|
||||||
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
|
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
|
||||||
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()).setComment(reqVO.getComment()));
|
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()).setReason(reqVO.getReason()));
|
||||||
|
|
||||||
// TODO 芋艿:添加评论
|
// TODO 芋艿:添加评论
|
||||||
// taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
|
// taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
|
||||||
@ -250,11 +250,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新流程实例为不通过
|
// 更新流程实例为不通过
|
||||||
processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getComment());
|
processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason());
|
||||||
|
|
||||||
// 更新任务拓展表为不通过
|
// 更新任务拓展表为不通过
|
||||||
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
|
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
|
||||||
.setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment()));
|
.setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setReason(reqVO.getReason()));
|
||||||
|
|
||||||
// TODO 芋艿:添加评论
|
// TODO 芋艿:添加评论
|
||||||
// taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
|
// taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
|
||||||
|
@ -18,12 +18,10 @@ import org.flowable.task.api.Task;
|
|||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.MappingTarget;
|
import org.mapstruct.MappingTarget;
|
||||||
import org.mapstruct.Mappings;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程实例 Convert
|
* 流程实例 Convert
|
||||||
@ -105,11 +103,11 @@ public interface BpmProcessInstanceConvert {
|
|||||||
.setProcessInstanceName(instance.getName());
|
.setProcessInstanceName(instance.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
default BpmMessageSendWhenProcessInstanceRejectReqDTO convert2RejectReq(ProcessInstance instance, String comment) {
|
default BpmMessageSendWhenProcessInstanceRejectReqDTO convert2RejectReq(ProcessInstance instance, String reason) {
|
||||||
return new BpmMessageSendWhenProcessInstanceRejectReqDTO()
|
return new BpmMessageSendWhenProcessInstanceRejectReqDTO()
|
||||||
.setProcessInstanceName(instance.getName())
|
.setProcessInstanceName(instance.getName())
|
||||||
.setProcessInstanceId(instance.getId())
|
.setProcessInstanceId(instance.getId())
|
||||||
.setComment(comment)
|
.setReason(reason)
|
||||||
.setStartUserId(NumberUtils.parseLong(instance.getStartUserId()));
|
.setStartUserId(NumberUtils.parseLong(instance.getStartUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,9 +141,9 @@ public interface BpmProcessInstanceService {
|
|||||||
* 更新 ProcessInstance 拓展记录为不通过
|
* 更新 ProcessInstance 拓展记录为不通过
|
||||||
*
|
*
|
||||||
* @param id 流程编号
|
* @param id 流程编号
|
||||||
* @param comment 理由。例如说,审批不通过时,需要传递该值
|
* @param reason 理由。例如说,审批不通过时,需要传递该值
|
||||||
*/
|
*/
|
||||||
void updateProcessInstanceExtReject(String id, String comment);
|
void updateProcessInstanceExtReject(String id, String reason);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -251,11 +251,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateProcessInstanceExtReject(String id, String comment) {
|
public void updateProcessInstanceExtReject(String id, String reason) {
|
||||||
// 需要主动查询,因为 instance 只有 id 属性
|
// 需要主动查询,因为 instance 只有 id 属性
|
||||||
ProcessInstance processInstance = getProcessInstance(id);
|
ProcessInstance processInstance = getProcessInstance(id);
|
||||||
// 删除流程实例,以实现驳回任务时,取消整个审批流程
|
// 删除流程实例,以实现驳回任务时,取消整个审批流程
|
||||||
deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(comment)));
|
deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason)));
|
||||||
|
|
||||||
// 更新 status + result
|
// 更新 status + result
|
||||||
// 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法,
|
// 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法,
|
||||||
@ -266,7 +266,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|||||||
processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
|
processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
|
||||||
|
|
||||||
// 发送流程被不通过的消息
|
// 发送流程被不通过的消息
|
||||||
messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, comment));
|
messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason));
|
||||||
|
|
||||||
// 发送流程实例的状态事件
|
// 发送流程实例的状态事件
|
||||||
processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
|
processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
|
||||||
|
@ -185,7 +185,7 @@ public class BpmTaskServiceImpl implements BpmTaskService{
|
|||||||
taskService.complete(task.getId(), instance.getProcessVariables());
|
taskService.complete(task.getId(), instance.getProcessVariables());
|
||||||
// 更新任务拓展表为通过
|
// 更新任务拓展表为通过
|
||||||
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
|
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
|
||||||
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()).setComment(reqVO.getComment()));
|
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()).setReason(reqVO.getReason()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -199,11 +199,11 @@ public class BpmTaskServiceImpl implements BpmTaskService{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新流程实例为不通过
|
// 更新流程实例为不通过
|
||||||
processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getComment());
|
processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason());
|
||||||
|
|
||||||
// 更新任务拓展表为不通过
|
// 更新任务拓展表为不通过
|
||||||
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
|
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
|
||||||
.setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment()));
|
.setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setReason(reqVO.getReason()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -13,7 +13,7 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode CONFIG_NOT_EXISTS = new ErrorCode(1001000001, "参数配置不存在");
|
ErrorCode CONFIG_NOT_EXISTS = new ErrorCode(1001000001, "参数配置不存在");
|
||||||
ErrorCode CONFIG_KEY_DUPLICATE = new ErrorCode(1001000002, "参数配置 key 重复");
|
ErrorCode CONFIG_KEY_DUPLICATE = new ErrorCode(1001000002, "参数配置 key 重复");
|
||||||
ErrorCode CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE = new ErrorCode(1001000003, "不能删除类型为系统内置的参数配置");
|
ErrorCode CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE = new ErrorCode(1001000003, "不能删除类型为系统内置的参数配置");
|
||||||
ErrorCode CONFIG_GET_VALUE_ERROR_IF_SENSITIVE = new ErrorCode(1001000004, "不允许获取敏感配置到前端");
|
ErrorCode CONFIG_GET_VALUE_ERROR_IF_VISIBLE = new ErrorCode(1001000004, "获取参数配置失败,原因:不允许获取不可见配置");
|
||||||
|
|
||||||
// ========== 定时任务 1001001000 ==========
|
// ========== 定时任务 1001001000 ==========
|
||||||
ErrorCode JOB_NOT_EXISTS = new ErrorCode(1001001000, "定时任务不存在");
|
ErrorCode JOB_NOT_EXISTS = new ErrorCode(1001001000, "定时任务不存在");
|
||||||
@ -36,11 +36,12 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1003001000, "表定义已经存在");
|
ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1003001000, "表定义已经存在");
|
||||||
ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1003001001, "导入的表不存在");
|
ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1003001001, "导入的表不存在");
|
||||||
ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1003001002, "导入的字段不存在");
|
ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1003001002, "导入的字段不存在");
|
||||||
ErrorCode CODEGEN_PARSE_SQL_ERROR = new ErrorCode(1003001003, "解析 SQL 失败,请检查");
|
|
||||||
ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1003001004, "表定义不存在");
|
ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1003001004, "表定义不存在");
|
||||||
ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1003001005, "字段义不存在");
|
ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1003001005, "字段义不存在");
|
||||||
ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1003001006, "同步的字段不存在");
|
ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1003001006, "同步的字段不存在");
|
||||||
ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1003001007, "同步失败,不存在改变");
|
ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1003001007, "同步失败,不存在改变");
|
||||||
|
ErrorCode CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL = new ErrorCode(1003001008, "数据库的表注释未填写");
|
||||||
|
ErrorCode CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL = new ErrorCode(1003001009, "数据库的表字段({})注释未填写");
|
||||||
|
|
||||||
// ========== 字典类型(测试)1001005000 ==========
|
// ========== 字典类型(测试)1001005000 ==========
|
||||||
ErrorCode TEST_DEMO_NOT_EXISTS = new ErrorCode(1001005000, "测试示例不存在");
|
ErrorCode TEST_DEMO_NOT_EXISTS = new ErrorCode(1001005000, "测试示例不存在");
|
||||||
|
@ -68,15 +68,15 @@ public class ConfigController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/get-value-by-key")
|
@GetMapping(value = "/get-value-by-key")
|
||||||
@ApiOperation(value = "根据参数键名查询参数值", notes = "敏感配置,不允许返回给前端")
|
@ApiOperation(value = "根据参数键名查询参数值", notes = "不可见的配置,不允许返回给前端")
|
||||||
@ApiImplicitParam(name = "key", value = "参数键", required = true, example = "yunai.biz.username", dataTypeClass = String.class)
|
@ApiImplicitParam(name = "key", value = "参数键", required = true, example = "yunai.biz.username", dataTypeClass = String.class)
|
||||||
public CommonResult<String> getConfigKey(@RequestParam("key") String key) {
|
public CommonResult<String> getConfigKey(@RequestParam("key") String key) {
|
||||||
ConfigDO config = configService.getConfigByKey(key);
|
ConfigDO config = configService.getConfigByKey(key);
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (config.getSensitive()) {
|
if (config.getVisible()) {
|
||||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_SENSITIVE);
|
throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_VISIBLE);
|
||||||
}
|
}
|
||||||
return success(config.getValue());
|
return success(config.getValue());
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ public class ConfigBaseVO {
|
|||||||
@ApiModelProperty(value = "参数分组", required = true, example = "biz")
|
@ApiModelProperty(value = "参数分组", required = true, example = "biz")
|
||||||
@NotEmpty(message = "参数分组不能为空")
|
@NotEmpty(message = "参数分组不能为空")
|
||||||
@Size(max = 50, message = "参数名称不能超过50个字符")
|
@Size(max = 50, message = "参数名称不能超过50个字符")
|
||||||
private String group;
|
private String category;
|
||||||
|
|
||||||
@ApiModelProperty(value = "参数名称", required = true, example = "数据库名")
|
@ApiModelProperty(value = "参数名称", required = true, example = "数据库名")
|
||||||
@NotBlank(message = "参数名称不能为空")
|
@NotBlank(message = "参数名称不能为空")
|
||||||
@ -32,7 +32,7 @@ public class ConfigBaseVO {
|
|||||||
|
|
||||||
@ApiModelProperty(value = "是否敏感", required = true, example = "true")
|
@ApiModelProperty(value = "是否敏感", required = true, example = "true")
|
||||||
@NotNull(message = "是否敏感不能为空")
|
@NotNull(message = "是否敏感不能为空")
|
||||||
private Boolean sensitive;
|
private Boolean visible;
|
||||||
|
|
||||||
@ApiModelProperty(value = "备注", example = "备注一下很帅气!")
|
@ApiModelProperty(value = "备注", example = "备注一下很帅气!")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil;
|
|||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
|
||||||
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileRespVO;
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileRespVO;
|
||||||
import cn.iocoder.yudao.module.infra.convert.file.FileConvert;
|
import cn.iocoder.yudao.module.infra.convert.file.FileConvert;
|
||||||
@ -42,8 +43,9 @@ public class FileController {
|
|||||||
@ApiImplicitParam(name = "file", value = "文件附件", required = true, dataTypeClass = MultipartFile.class),
|
@ApiImplicitParam(name = "file", value = "文件附件", required = true, dataTypeClass = MultipartFile.class),
|
||||||
@ApiImplicitParam(name = "path", value = "文件路径", example = "yudaoyuanma.png", dataTypeClass = String.class)
|
@ApiImplicitParam(name = "path", value = "文件路径", example = "yudaoyuanma.png", dataTypeClass = String.class)
|
||||||
})
|
})
|
||||||
|
@OperateLog(logArgs = false) // 上传文件,没有记录操作日志的必要
|
||||||
public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
|
public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
|
||||||
@RequestParam("path") String path) throws Exception {
|
@RequestParam(value = "path", required = false) String path) throws Exception {
|
||||||
return success(fileService.createFile(path, IoUtil.readBytes(file.getInputStream())));
|
return success(fileService.createFile(path, IoUtil.readBytes(file.getInputStream())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigRespVO;
|
|||||||
import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigUpdateReqVO;
|
import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigUpdateReqVO;
|
||||||
import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO;
|
import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,12 +19,15 @@ public interface ConfigConvert {
|
|||||||
|
|
||||||
PageResult<ConfigRespVO> convertPage(PageResult<ConfigDO> page);
|
PageResult<ConfigRespVO> convertPage(PageResult<ConfigDO> page);
|
||||||
|
|
||||||
|
@Mapping(source = "configKey", target = "key")
|
||||||
ConfigRespVO convert(ConfigDO bean);
|
ConfigRespVO convert(ConfigDO bean);
|
||||||
|
|
||||||
|
@Mapping(source = "key", target = "configKey")
|
||||||
ConfigDO convert(ConfigCreateReqVO bean);
|
ConfigDO convert(ConfigCreateReqVO bean);
|
||||||
|
|
||||||
ConfigDO convert(ConfigUpdateReqVO bean);
|
ConfigDO convert(ConfigUpdateReqVO bean);
|
||||||
|
|
||||||
|
@Mapping(source = "configKey", target = "key")
|
||||||
List<ConfigExcelVO> convertList(List<ConfigDO> list);
|
List<ConfigExcelVO> convertList(List<ConfigDO> list);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.codegen;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnHtmlTypeEnum;
|
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnHtmlTypeEnum;
|
||||||
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnListConditionEnum;
|
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnListConditionEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -15,6 +16,7 @@ import lombok.experimental.Accessors;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "infra_codegen_column", autoResultMap = true)
|
@TableName(value = "infra_codegen_column", autoResultMap = true)
|
||||||
|
@KeySequence("infra_codegen_column_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|||||||
import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
|
import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
|
||||||
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
|
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
|
||||||
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
|
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@ -15,6 +16,7 @@ import lombok.experimental.Accessors;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "infra_codegen_table", autoResultMap = true)
|
@TableName(value = "infra_codegen_table", autoResultMap = true)
|
||||||
|
@KeySequence("infra_codegen_table_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.config;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum;
|
import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -15,6 +15,7 @@ import lombok.ToString;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName("infra_config")
|
@TableName("infra_config")
|
||||||
|
@KeySequence("infra_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -26,19 +27,19 @@ public class ConfigDO extends BaseDO {
|
|||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
/**
|
||||||
* 参数分组
|
* 参数分类
|
||||||
*/
|
*/
|
||||||
@TableField("`group`")
|
private String category;
|
||||||
private String group;
|
|
||||||
/**
|
/**
|
||||||
* 参数名称
|
* 参数名称
|
||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
/**
|
/**
|
||||||
* 参数键名
|
* 参数键名
|
||||||
|
*
|
||||||
|
* 支持多 DB 类型时,无法直接使用 key + @TableField("config_key") 来实现转换,原因是 "config_key" AS key 而存在报错
|
||||||
*/
|
*/
|
||||||
@TableField("`key`")
|
private String configKey;
|
||||||
private String key;
|
|
||||||
/**
|
/**
|
||||||
* 参数键值
|
* 参数键值
|
||||||
*/
|
*/
|
||||||
@ -48,15 +49,13 @@ public class ConfigDO extends BaseDO {
|
|||||||
*
|
*
|
||||||
* 枚举 {@link ConfigTypeEnum}
|
* 枚举 {@link ConfigTypeEnum}
|
||||||
*/
|
*/
|
||||||
@TableField("`type`")
|
|
||||||
private Integer type;
|
private Integer type;
|
||||||
/**
|
/**
|
||||||
* 是否敏感
|
* 是否可见
|
||||||
*
|
*
|
||||||
* 对于敏感配置,需要管理权限才能查看
|
* 不可见的参数,一般是敏感参数,前端不可获取
|
||||||
*/
|
*/
|
||||||
@TableField("`sensitive`")
|
private Boolean visible;
|
||||||
private Boolean sensitive;
|
|
||||||
/**
|
/**
|
||||||
* 备注
|
* 备注
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package cn.iocoder.yudao.module.infra.dal.dataobject.db;
|
package cn.iocoder.yudao.module.infra.dal.dataobject.db;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.type.EncryptTypeHandler;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@ -9,7 +12,8 @@ import lombok.Data;
|
|||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName("infra_data_source_config")
|
@TableName(value = "infra_data_source_config", autoResultMap = true)
|
||||||
|
@KeySequence("infra_data_source_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
public class DataSourceConfigDO extends BaseDO {
|
public class DataSourceConfigDO extends BaseDO {
|
||||||
|
|
||||||
@ -38,6 +42,7 @@ public class DataSourceConfigDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 密码
|
* 密码
|
||||||
*/
|
*/
|
||||||
|
@TableField(typeHandler = EncryptTypeHandler.class)
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.file;
|
|||||||
import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
|
import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
|
||||||
import cn.iocoder.yudao.framework.file.core.enums.FileStorageEnum;
|
import cn.iocoder.yudao.framework.file.core.enums.FileStorageEnum;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||||
@ -13,8 +14,9 @@ import lombok.*;
|
|||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
@TableName(value = "infra_file_config", autoResultMap = true)
|
@TableName(value = "infra_file_config", autoResultMap = true)
|
||||||
|
@KeySequence("infra_file_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@Builder
|
@Builder
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.file;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -13,8 +14,9 @@ import lombok.*;
|
|||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
@TableName("infra_file_content")
|
@TableName("infra_file_content")
|
||||||
|
@KeySequence("infra_file_content_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@Builder
|
@Builder
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.infra.dal.dataobject.file;
|
package cn.iocoder.yudao.module.infra.dal.dataobject.file;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@ -13,8 +13,9 @@ import java.io.InputStream;
|
|||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
@TableName("infra_file")
|
@TableName("infra_file")
|
||||||
|
@KeySequence("infra_file_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@Builder
|
@Builder
|
||||||
@ -45,7 +46,6 @@ public class FileDO extends BaseDO {
|
|||||||
*
|
*
|
||||||
* 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取
|
* 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取
|
||||||
*/
|
*/
|
||||||
@TableField(value = "`type`")
|
|
||||||
private String type;
|
private String type;
|
||||||
/**
|
/**
|
||||||
* 文件大小
|
* 文件大小
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.job;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum;
|
import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -12,6 +13,7 @@ import lombok.*;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName("infra_job")
|
@TableName("infra_job")
|
||||||
|
@KeySequence("infra_job_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.job;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
||||||
import cn.iocoder.yudao.module.infra.enums.job.JobLogStatusEnum;
|
import cn.iocoder.yudao.module.infra.enums.job.JobLogStatusEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ import java.util.Date;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName("infra_job_log")
|
@TableName("infra_job_log")
|
||||||
|
@KeySequence("infra_job_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.logger;
|
|||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -15,6 +16,7 @@ import java.util.Date;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName("infra_api_access_log")
|
@TableName("infra_api_access_log")
|
||||||
|
@KeySequence(value = "infra_api_access_log_seq")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.logger;
|
|||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum;
|
import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -21,6 +22,7 @@ import java.util.Date;
|
|||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@KeySequence(value = "infra_api_error_log_seq")
|
||||||
public class ApiErrorLogDO extends BaseDO {
|
public class ApiErrorLogDO extends BaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.infra.dal.dataobject.test;
|
package cn.iocoder.yudao.module.infra.dal.dataobject.test;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -11,6 +12,7 @@ import lombok.*;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName("infra_test_demo")
|
@TableName("infra_test_demo")
|
||||||
|
@KeySequence("infra_test_demo_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package cn.iocoder.yudao.module.infra.dal.mysql.codegen;
|
package cn.iocoder.yudao.module.infra.dal.mysql.codegen;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
|
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -11,12 +11,14 @@ import java.util.List;
|
|||||||
public interface CodegenColumnMapper extends BaseMapperX<CodegenColumnDO> {
|
public interface CodegenColumnMapper extends BaseMapperX<CodegenColumnDO> {
|
||||||
|
|
||||||
default List<CodegenColumnDO> selectListByTableId(Long tableId) {
|
default List<CodegenColumnDO> selectListByTableId(Long tableId) {
|
||||||
return selectList(new QueryWrapper<CodegenColumnDO>().eq("table_id", tableId)
|
return selectList(new LambdaQueryWrapperX<CodegenColumnDO>()
|
||||||
.orderByAsc("ordinal_position"));
|
.eq(CodegenColumnDO::getTableId, tableId)
|
||||||
|
.orderByAsc(CodegenColumnDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
default void deleteListByTableId(Long tableId) {
|
default void deleteListByTableId(Long tableId) {
|
||||||
delete(new QueryWrapper<CodegenColumnDO>().eq("table_id", tableId));
|
delete(new LambdaQueryWrapperX<CodegenColumnDO>()
|
||||||
|
.eq(CodegenColumnDO::getTableId, tableId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user