diff --git a/pom.xml b/pom.xml index 9298957..41c25d3 100644 --- a/pom.xml +++ b/pom.xml @@ -8,21 +8,10 @@ ${revision} pom - tashow-platform-dependencies - - - - - - - - - - - - - - + tashow-dependencies + tashow-platform-framework + tashow-module + tashow-gateway ${project.artifactId} @@ -48,7 +37,7 @@ com.tashow.cloud - tashow-platform-dependencies + tashow-dependencies ${revision} pom import diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index 0cf9794..9a8261f 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -388,8 +388,8 @@ COMMENT ON TABLE infra_file_config IS '文件配置表'; -- ---------------------------- -- @formatter:off SET IDENTITY_INSERT infra_file_config ON; -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"db.client.core.file.framework.com.tashow.cloud.infraapi.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); COMMIT; SET IDENTITY_INSERT infra_file_config OFF; -- @formatter:on diff --git a/sql/kingbase/ruoyi-vue-pro.sql b/sql/kingbase/ruoyi-vue-pro.sql index 37f3b9b..16c66ba 100644 --- a/sql/kingbase/ruoyi-vue-pro.sql +++ b/sql/kingbase/ruoyi-vue-pro.sql @@ -493,8 +493,8 @@ COMMENT ON TABLE infra_file_config IS '文件配置表'; -- ---------------------------- -- @formatter:off BEGIN; -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"db.client.core.file.framework.com.tashow.cloud.infraapi.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); COMMIT; -- @formatter:on diff --git a/sql/mysql/quartz.sql b/sql/mysql/quartz.sql index 21ae391..d158189 100644 --- a/sql/mysql/quartz.sql +++ b/sql/mysql/quartz.sql @@ -132,7 +132,7 @@ CREATE TABLE `QRTZ_JOB_DETAILS` ( -- Records of QRTZ_JOB_DETAILS -- ---------------------------- BEGIN; -INSERT INTO `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 ('schedulerName', 'accessLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000197400104A4F425F48414E444C45525F4E414D457400116163636573734C6F67436C65616E4A6F627800), ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000187400104A4F425F48414E444C45525F4E414D4574001A62726F6B65726167655265636F7264556E667265657A654A6F627800), ('schedulerName', 'errorLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001A7400104A4F425F48414E444C45525F4E414D457400106572726F724C6F67436C65616E4A6F627800), ('schedulerName', 'jobLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001B7400104A4F425F48414E444C45525F4E414D4574000E6A6F624C6F67436C65616E4A6F627800), ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800), ('schedulerName', 'payOrderExpireJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000127400104A4F425F48414E444C45525F4E414D457400117061794F726465724578706972654A6F627800), ('schedulerName', 'payOrderSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000117400104A4F425F48414E444C45525F4E414D4574000F7061794F7264657253796E634A6F627800), ('schedulerName', 'payRefundSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000137400104A4F425F48414E444C45525F4E414D45740010706179526566756E6453796E634A6F627800), ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000157400104A4F425F48414E444C45525F4E414D4574001774726164654F726465724175746F43616E63656C4A6F627800), ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000177400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F436F6D6D656E744A6F627800), ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000167400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F526563656976654A6F627800); +INSERT INTO `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 ('schedulerName', 'accessLogCleanJob', 'DEFAULT', NULL, 'com.tashow.cloud.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000197400104A4F425F48414E444C45525F4E414D457400116163636573734C6F67436C65616E4A6F627800), ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000187400104A4F425F48414E444C45525F4E414D4574001A62726F6B65726167655265636F7264556E667265657A654A6F627800), ('schedulerName', 'errorLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001A7400104A4F425F48414E444C45525F4E414D457400106572726F724C6F67436C65616E4A6F627800), ('schedulerName', 'jobLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001B7400104A4F425F48414E444C45525F4E414D4574000E6A6F624C6F67436C65616E4A6F627800), ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800), ('schedulerName', 'payOrderExpireJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000127400104A4F425F48414E444C45525F4E414D457400117061794F726465724578706972654A6F627800), ('schedulerName', 'payOrderSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000117400104A4F425F48414E444C45525F4E414D4574000F7061794F7264657253796E634A6F627800), ('schedulerName', 'payRefundSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000137400104A4F425F48414E444C45525F4E414D45740010706179526566756E6453796E634A6F627800), ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000157400104A4F425F48414E444C45525F4E414D4574001774726164654F726465724175746F43616E63656C4A6F627800), ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000177400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F436F6D6D656E744A6F627800), ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000167400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F526563656976654A6F627800); COMMIT; -- ---------------------------- diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 0c810be..730cb34 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -281,13 +281,13 @@ CREATE TABLE `infra_file_config` ( -- Records of infra_file_config -- ---------------------------- BEGIN; -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库(示例)', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2024-11-09 18:09:28', b'0'); -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器(示例)', 20, '请换成你自己的密钥!!!', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\"}', '1', '2024-01-13 22:11:12', '1', '2024-11-09 18:09:28', b'0'); -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '腾讯云存储(示例)', 20, '请换成你的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\"}', '1', '2024-11-09 16:03:22', '1', '2024-11-09 18:15:39', b'0'); -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '阿里云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\"}', '1', '2024-11-09 16:47:08', '1', '2024-11-09 18:15:43', b'0'); -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '火山云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\"}', '1', '2024-11-09 16:56:42', '1', '2024-11-09 18:15:46', b'0'); -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '华为云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\"}', '1', '2024-11-09 17:18:41', '1', '2024-11-09 18:15:49', b'0'); -INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\"}', '1', '2024-11-09 17:43:10', '1', '2024-11-09 18:15:52', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库(示例)', 1, '我是数据库', b'0', '{\"@class\":\"db.client.core.file.framework.com.tashow.cloud.infraapi.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2024-11-09 18:09:28', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器(示例)', 20, '请换成你自己的密钥!!!', b'1', '{\"@class\":\"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\"}', '1', '2024-01-13 22:11:12', '1', '2024-11-09 18:09:28', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '腾讯云存储(示例)', 20, '请换成你的密钥!!!', b'0', '{\"@class\":\"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\"}', '1', '2024-11-09 16:03:22', '1', '2024-11-09 18:15:39', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '阿里云存储(示例)', 20, '', b'0', '{\"@class\":\"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\"}', '1', '2024-11-09 16:47:08', '1', '2024-11-09 18:15:43', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '火山云存储(示例)', 20, '', b'0', '{\"@class\":\"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\"}', '1', '2024-11-09 16:56:42', '1', '2024-11-09 18:15:46', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '华为云存储(示例)', 20, '', b'0', '{\"@class\":\"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\"}', '1', '2024-11-09 17:18:41', '1', '2024-11-09 18:15:49', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 存储(示例)', 20, '', b'0', '{\"@class\":\"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\"}', '1', '2024-11-09 17:43:10', '1', '2024-11-09 18:15:52', b'0'); COMMIT; -- ---------------------------- diff --git a/sql/opengauss/ruoyi-vue-pro.sql b/sql/opengauss/ruoyi-vue-pro.sql index 9ff0033..8ae66b7 100644 --- a/sql/opengauss/ruoyi-vue-pro.sql +++ b/sql/opengauss/ruoyi-vue-pro.sql @@ -493,8 +493,8 @@ COMMENT ON TABLE infra_file_config IS '文件配置表'; -- ---------------------------- -- @formatter:off BEGIN; -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"db.client.core.file.framework.com.tashow.cloud.infraapi.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); COMMIT; -- @formatter:on diff --git a/sql/oracle/ruoyi-vue-pro.sql b/sql/oracle/ruoyi-vue-pro.sql index 9fbf8d5..94ce5af 100644 --- a/sql/oracle/ruoyi-vue-pro.sql +++ b/sql/oracle/ruoyi-vue-pro.sql @@ -458,8 +458,8 @@ COMMENT ON TABLE infra_file_config IS '文件配置表'; -- Records of infra_file_config -- ---------------------------- -- @formatter:off -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', to_date('2022-03-15 23:56:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-28 22:54:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', to_date('2024-01-13 22:11:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-03 19:38:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"db.client.core.file.framework.com.tashow.cloud.infraapi.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', to_date('2022-03-15 23:56:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-28 22:54:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', to_date('2024-01-13 22:11:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-03 19:38:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); COMMIT; -- @formatter:on diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index e5e6d1e..fbc6855 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -493,8 +493,8 @@ COMMENT ON TABLE infra_file_config IS '文件配置表'; -- ---------------------------- -- @formatter:off BEGIN; -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"db.client.core.file.framework.com.tashow.cloud.infraapi.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); COMMIT; -- @formatter:on diff --git a/sql/sqlserver/ruoyi-vue-pro.sql b/sql/sqlserver/ruoyi-vue-pro.sql index 9368057..ac6fba5 100644 --- a/sql/sqlserver/ruoyi-vue-pro.sql +++ b/sql/sqlserver/ruoyi-vue-pro.sql @@ -1390,9 +1390,9 @@ BEGIN TRANSACTION GO SET IDENTITY_INSERT infra_file_config ON GO -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, N'数据库', 1, N'我是数据库', N'0', N'{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', N'1', N'2022-03-15 23:56:24', N'1', N'2024-02-28 22:54:07', N'0') +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, N'数据库', 1, N'我是数据库', N'0', N'{"@class":"db.client.core.file.framework.com.tashow.cloud.infraapi.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', N'1', N'2022-03-15 23:56:24', N'1', N'2024-02-28 22:54:07', N'0') GO -INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, N'七牛存储器', 20, N'', N'1', N'{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', N'1', N'2024-01-13 22:11:12', N'1', N'2024-04-03 19:38:34', N'0') +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, N'七牛存储器', 20, N'', N'1', N'{"@class":"s3.client.core.file.framework.com.tashow.cloud.infraapi.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', N'1', N'2024-01-13 22:11:12', N'1', N'2024-04-03 19:38:34', N'0') GO SET IDENTITY_INSERT infra_file_config OFF GO diff --git a/tashow-platform-dependencies/pom.xml b/tashow-dependencies/pom.xml similarity index 93% rename from tashow-platform-dependencies/pom.xml rename to tashow-dependencies/pom.xml index 83ba252..cf83e10 100644 --- a/tashow-platform-dependencies/pom.xml +++ b/tashow-dependencies/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.tashow.cloud - tashow-platform-dependencies + tashow-dependencies ${revision} pom @@ -125,7 +125,27 @@ com.tashow.cloud - yudao-spring-boot-starter-biz-tenant + tashow-module-system-api + ${revision} + + + com.tashow.cloud + tashow-module-system-biz + ${revision} + + + com.tashow.cloud + tashow-module-infra-api + ${revision} + + + com.tashow.cloud + tashow-module-infra-biz + ${revision} + + + com.tashow.cloud + tashow-framework-tenant ${revision} @@ -135,7 +155,7 @@ com.tashow.cloud - yudao-spring-boot-starter-biz-ip + tashow-framework-ip ${revision} @@ -149,26 +169,26 @@ com.tashow.cloud - yudao-spring-boot-starter-env + tashow-framework-env ${revision} com.tashow.cloud - yudao-spring-boot-starter-web + tashow-framework-web ${revision} com.tashow.cloud - yudao-spring-boot-starter-security + tashow-framework-security ${revision} com.tashow.cloud - yudao-spring-boot-starter-websocket + tashow-framework-websocket ${revision} @@ -191,7 +211,7 @@ com.tashow.cloud - yudao-spring-boot-starter-mybatis + tashow-data-mybatis ${revision} @@ -259,7 +279,7 @@ com.tashow.cloud - yudao-spring-boot-starter-redis + tashow-data-redis ${revision} @@ -290,7 +310,7 @@ com.tashow.cloud - yudao-spring-boot-starter-rpc + tashow-framework-rpc ${revision} @@ -306,14 +326,14 @@ com.tashow.cloud - yudao-spring-boot-starter-job + tashow-framework-job ${revision} com.tashow.cloud - yudao-spring-boot-starter-mq + tashow-framework-mq ${revision} @@ -326,7 +346,7 @@ com.tashow.cloud - yudao-spring-boot-starter-protection + tashow-framework-protection ${revision} @@ -345,7 +365,7 @@ com.tashow.cloud - yudao-spring-boot-starter-monitor + tashow-framework-monitor ${revision} @@ -458,7 +478,7 @@ com.tashow.cloud - yudao-spring-boot-starter-excel + tashow-data-excel ${revision} diff --git a/tashow-gateway/Dockerfile b/tashow-gateway/Dockerfile new file mode 100644 index 0000000..46037b7 --- /dev/null +++ b/tashow-gateway/Dockerfile @@ -0,0 +1,19 @@ +## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 +## 感谢复旦核博士的建议!灰子哥,牛皮! +FROM eclipse-temurin:21-jre + +## 创建目录,并使用它作为工作目录 +RUN mkdir -p /yudao-gateway +WORKDIR /yudao-gateway +## 将后端项目的 Jar 文件,复制到镜像中 +COPY ./target/yudao-gateway.jar app.jar + +## 设置 TZ 时区 +## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖 +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx512m" + +## 暴露后端项目的 48080 端口 +EXPOSE 48080 + +## 启动后端项目 +CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar diff --git a/tashow-gateway/pom.xml b/tashow-gateway/pom.xml new file mode 100644 index 0000000..9d3a847 --- /dev/null +++ b/tashow-gateway/pom.xml @@ -0,0 +1,94 @@ + + + + com.tashow.cloud + tashow-platform + ${revision} + + 4.0.0 + tashow-gateway + jar + + ${project.artifactId} + API 服务网关,基于 Spring Cloud Gateway 实现 + + + + + com.tashow.cloud + tashow-module-system-api + ${revision} + + + org.springdoc + springdoc-openapi-webmvc-core + + + + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + com.github.xiaoymin + knife4j-gateway-spring-boot-starter + + + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + + com.tashow.cloud + tashow-framework-monitor + + + + + com.google.guava + guava + + + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + + diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/GatewayServerApplication.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/GatewayServerApplication.java new file mode 100644 index 0000000..b18a000 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/GatewayServerApplication.java @@ -0,0 +1,14 @@ +package com.tashow.cloud.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GatewayServerApplication { + + public static void main(String[] args) { + // 启动 Spring Boot 应用 + SpringApplication.run(GatewayServerApplication.class, args); + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/cors/CorsFilter.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/cors/CorsFilter.java new file mode 100644 index 0000000..c83e19f --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/cors/CorsFilter.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.gateway.filter.cors; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.cors.reactive.CorsUtils; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +/** + * 跨域 Filter + * + * @author 芋道源码 + */ +@Component +public class CorsFilter implements WebFilter { + + private static final String ALL = "*"; + private static final String MAX_AGE = "3600L"; + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + // 非跨域请求,直接放行 + ServerHttpRequest request = exchange.getRequest(); + if (!CorsUtils.isCorsRequest(request)) { + return chain.filter(exchange); + } + + // 设置跨域响应头 + ServerHttpResponse response = exchange.getResponse(); + HttpHeaders headers = response.getHeaders(); + headers.add("Access-Control-Allow-Origin", ALL); + headers.add("Access-Control-Allow-Methods", ALL); + headers.add("Access-Control-Allow-Headers", ALL); + headers.add("Access-Control-Max-Age", MAX_AGE); + if (request.getMethod() == HttpMethod.OPTIONS) { + response.setStatusCode(HttpStatus.OK); + return Mono.empty(); + } + return chain.filter(exchange); + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/cors/CorsResponseHeaderFilter.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/cors/CorsResponseHeaderFilter.java new file mode 100644 index 0000000..31519a2 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/cors/CorsResponseHeaderFilter.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.gateway.filter.cors; + +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter; +import org.springframework.core.Ordered; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; + +/** + * 解决 Spring Cloud Gateway 2.x 跨域时,出现重复 Origin 的 BUG + * + * 参考文档: + * + * @author 芋道源码 + */ +@Component +public class CorsResponseHeaderFilter implements GlobalFilter, Ordered { + + @Override + public int getOrder() { + // 指定此过滤器位于 NettyWriteResponseFilter 之后 + // 即待处理完响应体后接着处理响应头 + return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1; + } + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + return chain.filter(exchange).then(Mono.defer(() -> { + exchange.getResponse().getHeaders().entrySet().stream() + .filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1)) + .filter(kv -> (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) + || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS))) + .forEach(kv -> kv.setValue(new ArrayList() {{ + add(kv.getValue().get(0)); + }})); + return chain.filter(exchange); + })); + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/grey/GrayLoadBalancer.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/grey/GrayLoadBalancer.java new file mode 100644 index 0000000..71fc5fc --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/grey/GrayLoadBalancer.java @@ -0,0 +1,111 @@ +package com.tashow.cloud.gateway.filter.grey; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.gateway.util.EnvUtils; +import com.alibaba.cloud.nacos.balancer.NacosBalancer; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.*; +import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.http.HttpHeaders; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * 灰度 {@link GrayLoadBalancer} 实现类 + * + * 根据请求的 header[version] 匹配,筛选满足 metadata[version] 相等的服务实例列表,然后随机 + 权重进行选择一个 + * 1. 假如请求的 header[version] 为空,则不进行筛选,所有服务实例都进行选择 + * 2. 如果 metadata[version] 都不相等,则不进行筛选,所有服务实例都进行选择 + * + * 注意,考虑到实现的简易,它的权重是使用 Nacos 的 nacos.weight,所以随机 + 权重也是基于 {@link NacosBalancer} 筛选。 + * 也就是说,如果你不使用 Nacos 作为注册中心,需要微调一下筛选的实现逻辑 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Slf4j +public class GrayLoadBalancer implements ReactorServiceInstanceLoadBalancer { + + private static final String VERSION = "version"; + + /** + * 用于获取 serviceId 对应的服务实例的列表 + */ + private final ObjectProvider serviceInstanceListSupplierProvider; + /** + * 需要获取的服务实例名 + * + * 暂时用于打印 logger 日志 + */ + private final String serviceId; + + @Override + public Mono> choose(Request request) { + // 获得 HttpHeaders 属性,实现从 header 中获取 version + HttpHeaders headers = ((RequestDataContext) request.getContext()).getClientRequest().getHeaders(); + // 选择实例 + ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new); + return supplier.get(request).next().map(list -> getInstanceResponse(list, headers)); + } + + private Response getInstanceResponse(List instances, HttpHeaders headers) { + // 如果服务实例为空,则直接返回 + if (CollUtil.isEmpty(instances)) { + log.warn("[getInstanceResponse][serviceId({}) 服务实例列表为空]", serviceId); + return new EmptyResponse(); + } + + // 筛选满足 version 条件的实例列表 + String version = headers.getFirst(VERSION); + List chooseInstances; + if (StrUtil.isEmpty(version)) { + chooseInstances = instances; + } else { + chooseInstances = CollectionUtils.filterList(instances, instance -> version.equals(instance.getMetadata().get("version"))); + if (CollUtil.isEmpty(chooseInstances)) { + log.warn("[getInstanceResponse][serviceId({}) 没有满足版本({})的服务实例列表,直接使用所有服务实例列表]", serviceId, version); + chooseInstances = instances; + } + } + + // 基于 tag 过滤实例列表 + chooseInstances = filterTagServiceInstances(chooseInstances, headers); + + // 随机 + 权重获取实例列表 TODO 芋艿:目前直接使用 Nacos 提供的方法,如果替换注册中心,需要重新失败该方法 + return new DefaultResponse(NacosBalancer.getHostByRandomWeight3(chooseInstances)); + } + + /** + * 基于 tag 请求头,过滤匹配 tag 的服务实例列表 + * + * copy from EnvLoadBalancerClient + * + * @param instances 服务实例列表 + * @param headers 请求头 + * @return 服务实例列表 + */ + private List filterTagServiceInstances(List instances, HttpHeaders headers) { + // 情况一,没有 tag 时,直接返回 + String tag = EnvUtils.getTag(headers); + if (StrUtil.isEmpty(tag)) { + return instances; + } + + // 情况二,有 tag 时,使用 tag 匹配服务实例 + List chooseInstances = CollectionUtils.filterList(instances, instance -> tag.equals(EnvUtils.getTag(instance))); + if (CollUtil.isEmpty(chooseInstances)) { + log.warn("[filterTagServiceInstances][serviceId({}) 没有满足 tag({}) 的服务实例列表,直接使用所有服务实例列表]", serviceId, tag); + chooseInstances = instances; + } + return chooseInstances; + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/grey/GrayReactiveLoadBalancerClientFilter.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/grey/GrayReactiveLoadBalancerClientFilter.java new file mode 100644 index 0000000..1c0c31f --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/grey/GrayReactiveLoadBalancerClientFilter.java @@ -0,0 +1,138 @@ +package com.tashow.cloud.gateway.filter.grey; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.*; +import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter; +import org.springframework.cloud.gateway.support.DelegatingServiceInstance; +import org.springframework.cloud.gateway.support.NotFoundException; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.*; + +/** + * 支持灰度功能的 {@link ReactiveLoadBalancerClientFilter} 实现类 + * + * 由于 {@link ReactiveLoadBalancerClientFilter#choose(Request, String, Set)} 是 private 方法,无法进行重写。 + * 因此,这里只好 copy 它所有的代码,手动重写 choose 方法 + * + * 具体的使用与实现原理,可阅读如下两个文章: + * 1. https://www.jianshu.com/p/6db15bc0be8f + * 2. https://cloud.tencent.com/developer/article/1620795 + * + * @author 芋道源码 + */ +@Component +@AllArgsConstructor +@Slf4j +@SuppressWarnings({"JavadocReference", "rawtypes", "unchecked", "ConstantConditions"}) +public class GrayReactiveLoadBalancerClientFilter implements GlobalFilter, Ordered { + + private final LoadBalancerClientFactory clientFactory; + + private final GatewayLoadBalancerProperties properties; + + @Override + public int getOrder() { + return ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; + } + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR); + String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR); + // 修改 by 芋道源码:将 lb 替换成 grayLb,表示灰度负载均衡 + if (url == null || (!"grayLb".equals(url.getScheme()) && !"grayLb".equals(schemePrefix))) { + return chain.filter(exchange); + } + // preserve the original url + addOriginalRequestUrl(exchange, url); + + if (log.isTraceEnabled()) { + log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url); + } + + URI requestUri = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR); + String serviceId = requestUri.getHost(); + Set supportedLifecycleProcessors = LoadBalancerLifecycleValidator + .getSupportedLifecycleProcessors(clientFactory.getInstances(serviceId, LoadBalancerLifecycle.class), + RequestDataContext.class, ResponseData.class, ServiceInstance.class); + DefaultRequest lbRequest = new DefaultRequest<>( + new RequestDataContext(new RequestData(exchange.getRequest()), getHint(serviceId))); + return choose(lbRequest, serviceId, supportedLifecycleProcessors).doOnNext(response -> { + + if (!response.hasServer()) { + supportedLifecycleProcessors.forEach(lifecycle -> lifecycle + .onComplete(new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, response))); + throw NotFoundException.create(properties.isUse404(), "Unable to find instance for " + url.getHost()); + } + + ServiceInstance retrievedInstance = response.getServer(); + + URI uri = exchange.getRequest().getURI(); + + // if the `lb:` mechanism was used, use `` as the default, + // if the loadbalancer doesn't provide one. + String overrideScheme = retrievedInstance.isSecure() ? "https" : "http"; + if (schemePrefix != null) { + overrideScheme = url.getScheme(); + } + + DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance, + overrideScheme); + + URI requestUrl = reconstructURI(serviceInstance, uri); + + if (log.isTraceEnabled()) { + log.trace("LoadBalancerClientFilter url chosen: " + requestUrl); + } + exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl); + exchange.getAttributes().put(GATEWAY_LOADBALANCER_RESPONSE_ATTR, response); + supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, response)); + }).then(chain.filter(exchange)) + .doOnError(throwable -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle + .onComplete(new CompletionContext( + CompletionContext.Status.FAILED, throwable, lbRequest, + exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR))))) + .doOnSuccess(aVoid -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle + .onComplete(new CompletionContext( + CompletionContext.Status.SUCCESS, lbRequest, + exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR), + new ResponseData(exchange.getResponse(), new RequestData(exchange.getRequest())))))); + } + + protected URI reconstructURI(ServiceInstance serviceInstance, URI original) { + return LoadBalancerUriTools.reconstructURI(serviceInstance, original); + } + + private Mono> choose(Request lbRequest, String serviceId, + Set supportedLifecycleProcessors) { + // 修改 by 芋道源码:直接创建 GrayLoadBalancer 对象 + GrayLoadBalancer loadBalancer = new GrayLoadBalancer( + clientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class), serviceId); + supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest)); + return loadBalancer.choose(lbRequest); + } + + private String getHint(String serviceId) { + LoadBalancerProperties loadBalancerProperties = clientFactory.getProperties(serviceId); + Map hints = loadBalancerProperties.getHint(); + String defaultHint = hints.getOrDefault("default", "default"); + String hintPropertyValue = hints.get(serviceId); + return hintPropertyValue != null ? hintPropertyValue : defaultHint; + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/logging/AccessLog.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/logging/AccessLog.java new file mode 100644 index 0000000..f2c5b6a --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/logging/AccessLog.java @@ -0,0 +1,92 @@ +package com.tashow.cloud.gateway.filter.logging; + +import lombok.Data; +import org.springframework.cloud.gateway.route.Route; +import org.springframework.http.HttpStatus; +import org.springframework.util.MultiValueMap; + +import java.time.LocalDateTime; + +/** + * 网关的访问日志 + */ +@Data +public class AccessLog { + + /** + * 链路追踪编号 + */ + private String traceId; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 路由 + * + * 类似 ApiAccessLogCreateReqDTO 的 applicationName + */ + private Route route; + + /** + * 协议 + */ + private String schema; + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 访问地址 + */ + private String requestUrl; + /** + * 查询参数 + */ + private MultiValueMap queryParams; + /** + * 请求体 + */ + private String requestBody; + /** + * 请求头 + */ + private MultiValueMap requestHeaders; + /** + * 用户 IP + */ + private String userIp; + + /** + * 响应体 + * + * 类似 ApiAccessLogCreateReqDTO 的 resultCode + resultMsg + */ + private String responseBody; + /** + * 响应头 + */ + private MultiValueMap responseHeaders; + /** + * 响应结果 + */ + private HttpStatus httpStatus; + + /** + * 开始请求时间 + */ + private LocalDateTime startTime; + /** + * 结束请求时间 + */ + private LocalDateTime endTime; + /** + * 执行时长,单位:毫秒 + */ + private Integer duration; + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/logging/AccessLogFilter.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/logging/AccessLogFilter.java new file mode 100644 index 0000000..adc070a --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/logging/AccessLogFilter.java @@ -0,0 +1,263 @@ +package com.tashow.cloud.gateway.filter.logging; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.json.JSONUtil; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.gateway.util.SecurityFrameworkUtils; +import com.tashow.cloud.gateway.util.WebFrameworkUtils; +import com.alibaba.nacos.common.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage; +import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory; +import org.springframework.cloud.gateway.support.BodyInserterContext; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.core.Ordered; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ReactiveHttpOutputMessage; +import org.springframework.http.codec.CodecConfigurer; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpResponseDecorator; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import jakarta.annotation.Resource; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +import static cn.hutool.core.date.DatePattern.NORM_DATETIME_MS_FORMATTER; + +/** + * 网关的访问日志过滤器 + * + * 从功能上,它类似 yudao-spring-boot-starter-web 的 ApiAccessLogFilter 过滤器 + * + * TODO 芋艿:如果网关执行异常,不会记录访问日志,后续研究下 https://github.com/Silvmike/webflux-demo/blob/master/tests/src/test/java/ru/hardcoders/demo/webflux/web_handler/filters/logging + * + * @author 芋道源码 + */ +@Slf4j +@Component +public class AccessLogFilter implements GlobalFilter, Ordered { + + @Resource + private CodecConfigurer codecConfigurer; + + /** + * 打印日志 + * + * @param gatewayLog 网关日志 + */ + private void writeAccessLog(AccessLog gatewayLog) { + // 方式一:打印 Logger 后,通过 ELK 进行收集 + // log.info("[writeAccessLog][日志内容:{}]", JsonUtils.toJsonString(gatewayLog)); + + // 方式二:调用远程服务,记录到数据库中 + // TODO 芋艿:暂未实现 + + // 方式三:打印到控制台,方便排查错误 + Map values = MapUtil.newHashMap(15, true); // 手工拼接,保证排序;15 保证不用扩容 + values.put("userId", gatewayLog.getUserId()); + values.put("userType", gatewayLog.getUserType()); + values.put("routeId", gatewayLog.getRoute() != null ? gatewayLog.getRoute().getId() : null); + values.put("schema", gatewayLog.getSchema()); + values.put("requestUrl", gatewayLog.getRequestUrl()); + values.put("queryParams", gatewayLog.getQueryParams().toSingleValueMap()); + values.put("requestBody", JsonUtils.isJson(gatewayLog.getRequestBody()) ? // 保证 body 的展示好看 + JSONUtil.parse(gatewayLog.getRequestBody()) : gatewayLog.getRequestBody()); + values.put("requestHeaders", JsonUtils.toJsonString(gatewayLog.getRequestHeaders().toSingleValueMap())); + values.put("userIp", gatewayLog.getUserIp()); + values.put("responseBody", JsonUtils.isJson(gatewayLog.getResponseBody()) ? // 保证 body 的展示好看 + JSONUtil.parse(gatewayLog.getResponseBody()) : gatewayLog.getResponseBody()); + values.put("responseHeaders", gatewayLog.getResponseHeaders() != null ? + JsonUtils.toJsonString(gatewayLog.getResponseHeaders().toSingleValueMap()) : null); + values.put("httpStatus", gatewayLog.getHttpStatus()); + values.put("startTime", LocalDateTimeUtil.format(gatewayLog.getStartTime(), NORM_DATETIME_MS_FORMATTER)); + values.put("endTime", LocalDateTimeUtil.format(gatewayLog.getEndTime(), NORM_DATETIME_MS_FORMATTER)); + values.put("duration", gatewayLog.getDuration() != null ? gatewayLog.getDuration() + " ms" : null); + log.info("[writeAccessLog][网关日志:{}]", JsonUtils.toJsonPrettyString(values)); + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + // 将 Request 中可以直接获取到的参数,设置到网关日志 + ServerHttpRequest request = exchange.getRequest(); + // TODO traceId + AccessLog gatewayLog = new AccessLog(); + gatewayLog.setRoute(WebFrameworkUtils.getGatewayRoute(exchange)); + gatewayLog.setSchema(request.getURI().getScheme()); + gatewayLog.setRequestMethod(request.getMethod().name()); + gatewayLog.setRequestUrl(request.getURI().getRawPath()); + gatewayLog.setQueryParams(request.getQueryParams()); + gatewayLog.setRequestHeaders(request.getHeaders()); + gatewayLog.setStartTime(LocalDateTime.now()); + gatewayLog.setUserIp(WebFrameworkUtils.getClientIP(exchange)); + + // 继续 filter 过滤 + MediaType mediaType = request.getHeaders().getContentType(); + if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType) + || MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)) { // 适合 JSON 和 Form 提交的请求 + return filterWithRequestBody(exchange, chain, gatewayLog); + } + return filterWithoutRequestBody(exchange, chain, gatewayLog); + } + + private Mono filterWithoutRequestBody(ServerWebExchange exchange, GatewayFilterChain chain, AccessLog accessLog) { + // 包装 Response,用于记录 Response Body + ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, accessLog); + return chain.filter(exchange.mutate().response(decoratedResponse).build()) + .then(Mono.fromRunnable(() -> writeAccessLog(accessLog))); // 打印日志 + } + + /** + * 参考 {@link ModifyRequestBodyGatewayFilterFactory} 实现 + * + * 差别主要在于使用 modifiedBody 来读取 Request Body 数据 + */ + private Mono filterWithRequestBody(ServerWebExchange exchange, GatewayFilterChain chain, AccessLog gatewayLog) { + // 设置 Request Body 读取时,设置到网关日志 + // 此处 codecConfigurer.getReaders() 的目的,是解决 spring.codec.max-in-memory-size 不生效 + ServerRequest serverRequest = ServerRequest.create(exchange, codecConfigurer.getReaders()); + Mono modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> { + gatewayLog.setRequestBody(body); + return Mono.just(body); + }); + + // 创建 BodyInserter 对象 + BodyInserter, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class); + // 创建 CachedBodyOutputMessage 对象 + HttpHeaders headers = new HttpHeaders(); + headers.putAll(exchange.getRequest().getHeaders()); + // the new content type will be computed by bodyInserter + // and then set in the request decorator + headers.remove(HttpHeaders.CONTENT_LENGTH); // 移除 + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers); + // 通过 BodyInserter 将 Request Body 写入到 CachedBodyOutputMessage 中 + return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> { + // 包装 Request,用于缓存 Request Body + ServerHttpRequest decoratedRequest = requestDecorate(exchange, headers, outputMessage); + // 包装 Response,用于记录 Response Body + ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, gatewayLog); + // 记录普通的 + return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build()) + .then(Mono.fromRunnable(() -> writeAccessLog(gatewayLog))); // 打印日志 + + })); + } + + /** + * 记录响应日志 + * 通过 DataBufferFactory 解决响应体分段传输问题。 + */ + private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange, AccessLog gatewayLog) { + ServerHttpResponse response = exchange.getResponse(); + return new ServerHttpResponseDecorator(response) { + + @Override + public Mono writeWith(Publisher body) { + if (body instanceof Flux) { + DataBufferFactory bufferFactory = response.bufferFactory(); + // 计算执行时间 + gatewayLog.setEndTime(LocalDateTime.now()); + gatewayLog.setDuration((int) (LocalDateTimeUtil.between(gatewayLog.getStartTime(), + gatewayLog.getEndTime()).toMillis())); + // 设置其它字段 + gatewayLog.setUserId(SecurityFrameworkUtils.getLoginUserId(exchange)); + gatewayLog.setUserType(SecurityFrameworkUtils.getLoginUserType(exchange)); + gatewayLog.setResponseHeaders(response.getHeaders()); + gatewayLog.setHttpStatus((HttpStatus) response.getStatusCode()); + + // 获取响应类型,如果是 json 就打印 + String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR); + if (StringUtils.isNotBlank(originalResponseContentType) + && originalResponseContentType.contains("application/json")) { + Flux fluxBody = Flux.from(body); + return super.writeWith(fluxBody.buffer().map(dataBuffers -> { + // 设置 response body 到网关日志 + byte[] content = readContent(dataBuffers); + String responseResult = new String(content, StandardCharsets.UTF_8); + gatewayLog.setResponseBody(responseResult); + + // 响应 + return bufferFactory.wrap(content); + })); + } + } + // if body is not a flux. never got there. + return super.writeWith(body); + } + }; + } + + // ========== 参考 ModifyRequestBodyGatewayFilterFactory 中的方法 ========== + + /** + * 请求装饰器,支持重新计算 headers、body 缓存 + * + * @param exchange 请求 + * @param headers 请求头 + * @param outputMessage body 缓存 + * @return 请求装饰器 + */ + private ServerHttpRequestDecorator requestDecorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage) { + return new ServerHttpRequestDecorator(exchange.getRequest()) { + + @Override + public HttpHeaders getHeaders() { + long contentLength = headers.getContentLength(); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.putAll(super.getHeaders()); + if (contentLength > 0) { + httpHeaders.setContentLength(contentLength); + } else { + // TODO: this causes a 'HTTP/1.1 411 Length Required' // on + // httpbin.org + httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); + } + return httpHeaders; + } + + @Override + public Flux getBody() { + return outputMessage.getBody(); + } + }; + } + + // ========== 参考 ModifyResponseBodyGatewayFilterFactory 中的方法 ========== + + private byte[] readContent(List dataBuffers) { + // 合并多个流集合,解决返回体分段传输 + DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); + DataBuffer join = dataBufferFactory.join(dataBuffers); + byte[] content = new byte[join.readableByteCount()]; + join.read(content); + // 释放掉内存 + DataBufferUtils.release(join); + return content; + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/security/LoginUser.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/security/LoginUser.java new file mode 100644 index 0000000..0247913 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/security/LoginUser.java @@ -0,0 +1,44 @@ +package com.tashow.cloud.gateway.filter.security; + +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * 登录用户信息 + * + * copy from yudao-spring-boot-starter-security 的 LoginUser 类 + * + * @author 芋道源码 + */ +@Data +public class LoginUser { + + /** + * 用户编号 + */ + private Long id; + /** + * 用户类型 + */ + private Integer userType; + /** + * 额外的用户信息 + */ + private Map info; + /** + * 租户编号 + */ + private Long tenantId; + /** + * 授权范围 + */ + private List scopes; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/security/TokenAuthenticationFilter.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/security/TokenAuthenticationFilter.java new file mode 100644 index 0000000..f5a3699 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/filter/security/TokenAuthenticationFilter.java @@ -0,0 +1,168 @@ +package com.tashow.cloud.gateway.filter.security; + +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.core.type.TypeReference; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.date.LocalDateTimeUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.gateway.util.SecurityFrameworkUtils; +import com.tashow.cloud.gateway.util.WebFrameworkUtils; +import com.tashow.cloud.systemapi.api.oauth2.OAuth2TokenApi; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.Objects; +import java.util.function.Function; + +import static com.tashow.cloud.common.util.cache.CacheUtils.buildAsyncReloadingCache; + + +/** + * Token 过滤器,验证 token 的有效性 + * 1. 验证通过时,将 userId、userType、tenantId 通过 Header 转发给服务 + * 2. 验证不通过,还是会转发给服务。因为,接口是否需要登录的校验,还是交给服务自身处理 + * + * @author 芋道源码 + */ +@Component +public class TokenAuthenticationFilter implements GlobalFilter, Ordered { + + /** + * CommonResult 对应的 TypeReference 结果,用于解析 checkToken 的结果 + */ + private static final TypeReference> CHECK_RESULT_TYPE_REFERENCE + = new TypeReference>() {}; + + /** + * 空的 LoginUser 的结果 + * + * 用于解决如下问题: + * 1. {@link #getLoginUser(ServerWebExchange, String)} 返回 Mono.empty() 时,会导致后续的 flatMap 无法进行处理的问题。 + * 2. {@link #buildUser(String)} 时,如果 Token 已经过期,返回 LOGIN_USER_EMPTY 对象,避免缓存无法刷新 + */ + private static final LoginUser LOGIN_USER_EMPTY = new LoginUser(); + + private final WebClient webClient; + + /** + * 登录用户的本地缓存 + * + * key1:多租户的编号 + * key2:访问令牌 + */ + private final LoadingCache, LoginUser> loginUserCache = buildAsyncReloadingCache(Duration.ofMinutes(1), + new CacheLoader, LoginUser>() { + + @Override + public LoginUser load(KeyValue token) { + String body = checkAccessToken(token.getKey(), token.getValue()).block(); + return buildUser(body); + } + + }); + + public TokenAuthenticationFilter(ReactorLoadBalancerExchangeFilterFunction lbFunction) { + // Q:为什么不使用 OAuth2TokenApi 进行调用? + // A1:Spring Cloud OpenFeign 官方未内置 Reactive 的支持 https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#reactive-support + // A2:校验 Token 的 API 需要使用到 header[tenant-id] 传递租户编号,暂时不想编写 RequestInterceptor 实现 + // 因此,这里采用 WebClient,通过 lbFunction 实现负载均衡 + this.webClient = WebClient.builder().filter(lbFunction).build(); + } + + @Override + public Mono filter(final ServerWebExchange exchange, GatewayFilterChain chain) { + // 移除 login-user 的请求头,避免伪造模拟 + SecurityFrameworkUtils.removeLoginUser(exchange); + + // 情况一,如果没有 Token 令牌,则直接继续 filter + String token = SecurityFrameworkUtils.obtainAuthorization(exchange); + if (StrUtil.isEmpty(token)) { + return chain.filter(exchange); + } + + // 情况二,如果有 Token 令牌,则解析对应 userId、userType、tenantId 等字段,并通过 通过 Header 转发给服务 + // 重要说明:defaultIfEmpty 作用,保证 Mono.empty() 情况,可以继续执行 `flatMap 的 chain.filter(exchange)` 逻辑,避免返回给前端空的 Response!! + return getLoginUser(exchange, token).defaultIfEmpty(LOGIN_USER_EMPTY).flatMap(user -> { + // 1. 无用户,直接 filter 继续请求 + if (user == LOGIN_USER_EMPTY || // 下面 expiresTime 的判断,为了解决 token 实际已经过期的情况 + user.getExpiresTime() == null || LocalDateTimeUtils.beforeNow(user.getExpiresTime())) { + return chain.filter(exchange); + } + + // 2.1 有用户,则设置登录用户 + SecurityFrameworkUtils.setLoginUser(exchange, user); + // 2.2 将 user 并设置到 login-user 的请求头,使用 json 存储值 + ServerWebExchange newExchange = exchange.mutate() + .request(builder -> SecurityFrameworkUtils.setLoginUserHeader(builder, user)).build(); + return chain.filter(newExchange); + }); + } + + private Mono getLoginUser(ServerWebExchange exchange, String token) { + // 从缓存中,获取 LoginUser + Long tenantId = WebFrameworkUtils.getTenantId(exchange); + KeyValue cacheKey = new KeyValue().setKey(tenantId).setValue(token); + LoginUser localUser = loginUserCache.getIfPresent(cacheKey); + if (localUser != null) { + return Mono.just(localUser); + } + + // 缓存不存在,则请求远程服务 + return checkAccessToken(tenantId, token).flatMap((Function>) body -> { + LoginUser remoteUser = buildUser(body); + if (remoteUser != null) { + // 非空,则进行缓存 + loginUserCache.put(cacheKey, remoteUser); + return Mono.just(remoteUser); + } + return Mono.empty(); + }); + } + + private Mono checkAccessToken(Long tenantId, String token) { + return webClient.get() + .uri(OAuth2TokenApi.URL_CHECK, uriBuilder -> uriBuilder.queryParam("accessToken", token).build()) + .headers(httpHeaders -> WebFrameworkUtils.setTenantIdHeader(tenantId, httpHeaders)) // 设置租户的 Header + .retrieve().bodyToMono(String.class); + } + + private LoginUser buildUser(String body) { + // 处理结果,结果不正确 + CommonResult result = JsonUtils.parseObject(body, CHECK_RESULT_TYPE_REFERENCE); + if (result == null) { + return null; + } + if (result.isError()) { + // 特殊情况:令牌已经过期(code = 401),需要返回 LOGIN_USER_EMPTY,避免 Token 一直因为缓存,被误判为有效 + if (Objects.equals(result.getCode(), HttpStatus.UNAUTHORIZED.value())) { + return LOGIN_USER_EMPTY; + } + return null; + } + + // 创建登录用户 + OAuth2AccessTokenCheckRespDTO tokenInfo = result.getData(); + return new LoginUser().setId(tokenInfo.getUserId()).setUserType(tokenInfo.getUserType()) + .setInfo(tokenInfo.getUserInfo()) // 额外的用户信息 + .setTenantId(tokenInfo.getTenantId()).setScopes(tokenInfo.getScopes()) + .setExpiresTime(tokenInfo.getExpiresTime()); + } + + @Override + public int getOrder() { + return -100; // 和 Spring Security Filter 的顺序对齐 + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/handler/GlobalExceptionHandler.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..34d04ab --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/handler/GlobalExceptionHandler.java @@ -0,0 +1,75 @@ +package com.tashow.cloud.gateway.handler; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.gateway.util.WebFrameworkUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.core.annotation.Order; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import static com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + + +/** + * Gateway 的全局异常处理器,将 Exception 翻译成 CommonResult + 对应的异常编号 + * + * 在功能上,和 yudao-spring-boot-starter-web 的 GlobalExceptionHandler 类是一致的 + * + * @author 芋道源码 + */ +@Component +@Order(-1) // 保证优先级高于默认的 Spring Cloud Gateway 的 ErrorWebExceptionHandler 实现 +@Slf4j +public class GlobalExceptionHandler implements ErrorWebExceptionHandler { + + @Override + public Mono handle(ServerWebExchange exchange, Throwable ex) { + // 已经 commit,则直接返回异常 + ServerHttpResponse response = exchange.getResponse(); + if (response.isCommitted()) { + return Mono.error(ex); + } + + // 转换成 CommonResult + CommonResult result; + if (ex instanceof ResponseStatusException) { + result = responseStatusExceptionHandler(exchange, (ResponseStatusException) ex); + } else { + result = defaultExceptionHandler(exchange, ex); + } + + // 返回给前端 + return WebFrameworkUtils.writeJSON(exchange, result); + } + + /** + * 处理 Spring Cloud Gateway 默认抛出的 ResponseStatusException 异常 + */ + private CommonResult responseStatusExceptionHandler(ServerWebExchange exchange, + ResponseStatusException ex) { + // TODO 芋艿:这里要精细化翻译,默认返回用户是看不懂的 + ServerHttpRequest request = exchange.getRequest(); + log.error("[responseStatusExceptionHandler][uri({}/{}) 发生异常]", request.getURI(), request.getMethod(), ex); + return CommonResult.error(ex.getStatusCode().value(), ex.getReason()); + } + + /** + * 处理系统异常,兜底处理所有的一切 + */ + @ExceptionHandler(value = Exception.class) + public CommonResult defaultExceptionHandler(ServerWebExchange exchange, + Throwable ex) { + ServerHttpRequest request = exchange.getRequest(); + log.error("[defaultExceptionHandler][uri({}/{}) 发生异常]", request.getURI(), request.getMethod(), ex); + // TODO 芋艿:是否要插入异常日志呢? + // 返回 ERROR CommonResult + return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/jackson/JacksonAutoConfiguration.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/jackson/JacksonAutoConfiguration.java new file mode 100644 index 0000000..0daa016 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/jackson/JacksonAutoConfiguration.java @@ -0,0 +1,51 @@ +package com.tashow.cloud.gateway.jackson; + +import cn.hutool.core.collection.CollUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.common.util.json.databind.NumberSerializer; +import com.tashow.cloud.common.util.json.databind.TimestampLocalDateTimeDeserializer; +import com.tashow.cloud.common.util.json.databind.TimestampLocalDateTimeSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.List; + +@Configuration +@Slf4j +public class JacksonAutoConfiguration { + + @Bean + public JsonUtils jsonUtils(List objectMappers) { + // 1.1 创建 SimpleModule 对象 + SimpleModule simpleModule = new SimpleModule(); + simpleModule + // 新增 Long 类型序列化规则,数值超过 2^53-1,在 JS 会出现精度丢失问题,因此 Long 自动序列化为字符串类型 + .addSerializer(Long.class, NumberSerializer.INSTANCE) + .addSerializer(Long.TYPE, NumberSerializer.INSTANCE) + .addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE) + .addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE) + .addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE) + .addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE) + // 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳 + .addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) + .addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); + // 1.2 注册到 objectMapper + objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule)); + + // 2. 设置 objectMapper 到 JsonUtils + JsonUtils.init(CollUtil.getFirst(objectMappers)); + log.info("[init][初始化 JsonUtils 成功]"); + return new JsonUtils(); + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/route/dynamic/package-info.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/route/dynamic/package-info.java new file mode 100644 index 0000000..2c8f4c2 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/route/dynamic/package-info.java @@ -0,0 +1,10 @@ +/** + * 在 Nacos 配置发生变化时,Spring Cloud Alibaba Nacos Config 内置的监听器,会监听到配置刷新,最终触发 Gateway 的路由信息刷新。 + * + * 参见 https://www.iocoder.cn/Spring-Cloud/Spring-Cloud-Gateway/?yudao 博客的「6. 基于配置中心 Nacos 实现动态路由」小节 + * + * 使用方式:在 Nacos 修改 DataId 为 gateway-server.yaml 的配置,修改 spring.cloud.gateway.routes 配置项 + * + * @author 芋道源码 + */ +package com.tashow.cloud.gateway.route.dynamic; diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/route/package-info.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/route/package-info.java new file mode 100644 index 0000000..34db8d6 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/route/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符 + */ +package com.tashow.cloud.gateway.route; diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/BannerApplicationRunner.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/BannerApplicationRunner.java new file mode 100644 index 0000000..b21990d --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/BannerApplicationRunner.java @@ -0,0 +1,55 @@ +package com.tashow.cloud.gateway.util; + +import cn.hutool.core.thread.ThreadUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +/** + * 项目启动成功后,提供文档相关的地址 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class BannerApplicationRunner implements ApplicationRunner { + + @Override + public void run(ApplicationArguments args) { + ThreadUtil.execute(() -> { + ThreadUtil.sleep(1, TimeUnit.SECONDS); // 延迟 1 秒,保证输出到结尾 + log.info("\n----------------------------------------------------------\n\t" + + "项目启动成功!\n\t" + + "接口文档: \t{} \n\t" + + "开发文档: \t{} \n\t" + + "视频教程: \t{} \n" + + "----------------------------------------------------------", + "https://cloud.iocoder.cn/api-doc/", + "https://cloud.iocoder.cn", + "https://t.zsxq.com/02Yf6M7Qn"); + + // 数据报表 + System.out.println("[报表模块 yudao-module-report 教程][参考 https://cloud.iocoder.cn/report/ 开启]"); + // 工作流 + System.out.println("[工作流模块 yudao-module-bpm 教程][参考 https://cloud.iocoder.cn/bpm/ 开启]"); + // 商城系统 + System.out.println("[商城系统 yudao-module-mall 教程][参考 https://cloud.iocoder.cn/mall/build/ 开启]"); + // ERP 系统 + System.out.println("[ERP 系统 yudao-module-erp - 教程][参考 https://cloud.iocoder.cn/erp/build/ 开启]"); + // CRM 系统 + System.out.println("[CRM 系统 yudao-module-crm - 教程][参考 https://cloud.iocoder.cn/crm/build/ 开启]"); + // 微信公众号 + System.out.println("[微信公众号 yudao-module-mp 教程][参考 https://cloud.iocoder.cn/mp/build/ 开启]"); + // 支付平台 + System.out.println("[支付系统 yudao-module-pay - 教程][参考 https://doc.iocoder.cn/pay/build/ 开启]"); + // AI 大模型 + System.out.println("[AI 大模型 yudao-module-ai - 教程][参考 https://cloud.iocoder.cn/ai/build/ 开启]"); + // IOT 物联网 + System.out.println("[IOT 物联网 yudao-module-iot - 教程][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + }); + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/EnvUtils.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/EnvUtils.java new file mode 100644 index 0000000..6a48147 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/EnvUtils.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.gateway.util; + +import cn.hutool.core.net.NetUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.http.HttpHeaders; + +import java.util.Objects; + +/** + * 环境 Utils + * + * copy from yudao-spring-boot-starter-env 的 EnvUtils 类 + * + * @author 芋道源码 + */ +public class EnvUtils { + + private static final String HEADER_TAG = "tag"; + + public static final String HOST_NAME_VALUE = "${HOSTNAME}"; + + public static String getTag(HttpHeaders headers) { + String tag = headers.getFirst(HEADER_TAG); + // 如果请求的是 "${HOSTNAME}",则解析成对应的本地主机名 + // 目的:特殊逻辑,解决 IDEA Rest Client 不支持环境变量的读取,所以就服务器来做 + return Objects.equals(tag, HOST_NAME_VALUE) ? getHostName() : tag; + } + + public static String getTag(ServiceInstance instance) { + return instance.getMetadata().get(HEADER_TAG); + } + + public static String getHostName() { + return StrUtil.blankToDefault(NetUtil.getLocalHostName(), IdUtil.fastSimpleUUID()); + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/SecurityFrameworkUtils.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/SecurityFrameworkUtils.java new file mode 100644 index 0000000..c311674 --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/SecurityFrameworkUtils.java @@ -0,0 +1,118 @@ +package com.tashow.cloud.gateway.util; + +import cn.hutool.core.map.MapUtil; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.gateway.filter.security.LoginUser; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.StringUtils; +import org.springframework.web.server.ServerWebExchange; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * 安全服务工具类 + * + * copy from yudao-spring-boot-starter-security 的 SecurityFrameworkUtils 类 + * + * @author 芋道源码 + */ +@Slf4j +public class SecurityFrameworkUtils { + + private static final String AUTHORIZATION_HEADER = "Authorization"; + + private static final String AUTHORIZATION_BEARER = "Bearer"; + + private static final String LOGIN_USER_HEADER = "login-user"; + + private static final String LOGIN_USER_ID_ATTR = "login-user-id"; + private static final String LOGIN_USER_TYPE_ATTR = "login-user-type"; + + private SecurityFrameworkUtils() {} + + /** + * 从请求中,获得认证 Token + * + * @param exchange 请求 + * @return 认证 Token + */ + public static String obtainAuthorization(ServerWebExchange exchange) { + String authorization = exchange.getRequest().getHeaders().getFirst(AUTHORIZATION_HEADER); + if (!StringUtils.hasText(authorization)) { + return null; + } + int index = authorization.indexOf(AUTHORIZATION_BEARER + " "); + if (index == -1) { // 未找到 + return null; + } + return authorization.substring(index + 7).trim(); + } + + /** + * 设置登录用户 + * + * @param exchange 请求 + * @param user 用户 + */ + public static void setLoginUser(ServerWebExchange exchange, LoginUser user) { + exchange.getAttributes().put(LOGIN_USER_ID_ATTR, user.getId()); + exchange.getAttributes().put(LOGIN_USER_TYPE_ATTR, user.getUserType()); + } + + /** + * 移除请求头的用户 + * + * @param exchange 请求 + * @return 请求 + */ + public static ServerWebExchange removeLoginUser(ServerWebExchange exchange) { + // 如果不包含,直接返回 + if (!exchange.getRequest().getHeaders().containsKey(LOGIN_USER_HEADER)) { + return exchange; + } + // 如果包含,则移除。参考 RemoveRequestHeaderGatewayFilterFactory 实现 + ServerHttpRequest request = exchange.getRequest().mutate() + .headers(httpHeaders -> httpHeaders.remove(LOGIN_USER_HEADER)).build(); + return exchange.mutate().request(request).build(); + } + + /** + * 获得登录用户的编号 + * + * @param exchange 请求 + * @return 用户编号 + */ + public static Long getLoginUserId(ServerWebExchange exchange) { + return MapUtil.getLong(exchange.getAttributes(), LOGIN_USER_ID_ATTR); + } + + /** + * 获得登录用户的类型 + * + * @param exchange 请求 + * @return 用户类型 + */ + public static Integer getLoginUserType(ServerWebExchange exchange) { + return MapUtil.getInt(exchange.getAttributes(), LOGIN_USER_TYPE_ATTR); + } + + /** + * 将 user 并设置到 login-user 的请求头,使用 json 存储值 + * + * @param builder 请求 + * @param user 用户 + */ + public static void setLoginUserHeader(ServerHttpRequest.Builder builder, LoginUser user) { + try { + String userStr = JsonUtils.toJsonString(user); + userStr = URLEncoder.encode(userStr, StandardCharsets.UTF_8); // 编码,避免中文乱码 + builder.header(LOGIN_USER_HEADER, userStr); + } catch (Exception ex) { + log.error("[setLoginUserHeader][序列化 user({}) 发生异常]", user, ex); + throw ex; + } + } + +} diff --git a/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/WebFrameworkUtils.java b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/WebFrameworkUtils.java new file mode 100644 index 0000000..fa83c3a --- /dev/null +++ b/tashow-gateway/src/main/java/com/tashow/cloud/gateway/util/WebFrameworkUtils.java @@ -0,0 +1,116 @@ +package com.tashow.cloud.gateway.util; + +import cn.hutool.core.net.NetUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.extra.servlet.ServletUtil; +import com.tashow.cloud.common.util.json.JsonUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.route.Route; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * Web 工具类 + * + * copy from yudao-spring-boot-starter-web 的 WebFrameworkUtils 类 + * + * @author 芋道源码 + */ +@Slf4j +public class WebFrameworkUtils { + + private static final String HEADER_TENANT_ID = "tenant-id"; + + private WebFrameworkUtils() {} + + /** + * 将 Gateway 请求中的 header,设置到 HttpHeaders 中 + * + * @param tenantId 租户编号 + * @param httpHeaders WebClient 的请求 + */ + public static void setTenantIdHeader(Long tenantId, HttpHeaders httpHeaders) { + if (tenantId == null) { + return; + } + httpHeaders.set(HEADER_TENANT_ID, String.valueOf(tenantId)); + } + + public static Long getTenantId(ServerWebExchange exchange) { + String tenantId = exchange.getRequest().getHeaders().getFirst(HEADER_TENANT_ID); + return NumberUtil.isNumber(tenantId) ? Long.valueOf(tenantId) : null; + } + + /** + * 返回 JSON 字符串 + * + * @param exchange 响应 + * @param object 对象,会序列化成 JSON 字符串 + */ + @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码 + public static Mono writeJSON(ServerWebExchange exchange, Object object) { + // 设置 header + ServerHttpResponse response = exchange.getResponse(); + response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8); + // 设置 body + return response.writeWith(Mono.fromSupplier(() -> { + DataBufferFactory bufferFactory = response.bufferFactory(); + try { + return bufferFactory.wrap(JsonUtils.toJsonByte(object)); + } catch (Exception ex) { + ServerHttpRequest request = exchange.getRequest(); + log.error("[writeJSON][uri({}/{}) 发生异常]", request.getURI(), request.getMethod(), ex); + return bufferFactory.wrap(new byte[0]); + } + })); + } + + /** + * 获得客户端 IP + * + * 参考 {@link ServletUtil} 的 getClientIP 方法 + * + * @param exchange 请求 + * @param otherHeaderNames 其它 header 名字的数组 + * @return 客户端 IP + */ + public static String getClientIP(ServerWebExchange exchange, String... otherHeaderNames) { + String[] headers = { "X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR" }; + if (ArrayUtil.isNotEmpty(otherHeaderNames)) { + headers = ArrayUtil.addAll(headers, otherHeaderNames); + } + // 方式一,通过 header 获取 + String ip; + for (String header : headers) { + ip = exchange.getRequest().getHeaders().getFirst(header); + if (!NetUtil.isUnknown(ip)) { + return NetUtil.getMultistageReverseProxyIp(ip); + } + } + + // 方式二,通过 remoteAddress 获取 + if (exchange.getRequest().getRemoteAddress() == null) { + return null; + } + ip = exchange.getRequest().getRemoteAddress().getHostString(); + return NetUtil.getMultistageReverseProxyIp(ip); + } + + /** + * 获得请求匹配的 Route 路由 + * + * @param exchange 请求 + * @return 路由 + */ + public static Route getGatewayRoute(ServerWebExchange exchange) { + return exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); + } + +} diff --git a/tashow-gateway/src/main/resources/application-dev.yaml b/tashow-gateway/src/main/resources/application-dev.yaml new file mode 100644 index 0000000..570439c --- /dev/null +++ b/tashow-gateway/src/main/resources/application-dev.yaml @@ -0,0 +1,14 @@ +--- #################### 注册中心 + 配置中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + username: # Nacos 账号 + password: # Nacos 密码 + discovery: # 【配置中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + config: # 【注册中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP \ No newline at end of file diff --git a/tashow-gateway/src/main/resources/application-local.yaml b/tashow-gateway/src/main/resources/application-local.yaml new file mode 100644 index 0000000..a7132bd --- /dev/null +++ b/tashow-gateway/src/main/resources/application-local.yaml @@ -0,0 +1,19 @@ +--- #################### 注册中心 + 配置中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + username: # Nacos 账号 + password: # Nacos 密码 + discovery: # 【配置中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + config: # 【注册中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + +# 日志文件配置 +logging: + level: + org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 diff --git a/tashow-gateway/src/main/resources/application.yaml b/tashow-gateway/src/main/resources/application.yaml new file mode 100644 index 0000000..f594352 --- /dev/null +++ b/tashow-gateway/src/main/resources/application.yaml @@ -0,0 +1,232 @@ +spring: + application: + name: gateway-server + + profiles: + active: local + + main: + allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 + + config: + import: + - optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置 + - optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置 + + cloud: + # Spring Cloud Gateway 配置项,对应 GatewayProperties 类 + gateway: + # 路由配置项,对应 RouteDefinition 数组 + routes: + ## system-server 服务 + - id: system-admin-api # 路由的编号 + uri: grayLb://system-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/system/** + filters: + - RewritePath=/admin-api/system/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + - id: system-app-api # 路由的编号 + uri: grayLb://system-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/system/** + filters: + - RewritePath=/app-api/system/v3/api-docs, /v3/api-docs + ## infra-server 服务 + - id: infra-admin-api # 路由的编号 + uri: grayLb://infra-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/infra/** + filters: + - RewritePath=/admin-api/infra/v3/api-docs, /v3/api-docs + - id: infra-app-api # 路由的编号 + uri: grayLb://infra-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/infra/** + filters: + - RewritePath=/app-api/infra/v3/api-docs, /v3/api-docs + - id: infra-spring-boot-admin # 路由的编号(Spring Boot Admin) + uri: grayLb://infra-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin/** + - id: infra-websocket # 路由的编号(WebSocket) + uri: grayLb://infra-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/infra/ws/** + ## member-server 服务 + - id: member-admin-api # 路由的编号 + uri: grayLb://member-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/member/** + filters: + - RewritePath=/admin-api/member/v3/api-docs, /v3/api-docs + - id: member-app-api # 路由的编号 + uri: grayLb://member-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/member/** + filters: + - RewritePath=/app-api/member/v3/api-docs, /v3/api-docs + ## bpm-server 服务 + - id: bpm-admin-api # 路由的编号 + uri: grayLb://bpm-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/bpm/** + filters: + - RewritePath=/admin-api/bpm/v3/api-docs, /v3/api-docs + ## report-server 服务 + - id: report-admin-api # 路由的编号 + uri: grayLb://report-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/report/** + filters: + - RewritePath=/admin-api/report/v3/api-docs, /v3/api-docs + - id: report-jimu # 路由的编号(积木报表) + uri: grayLb://report-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/jmreport/** + ## pay-server 服务 + - id: pay-admin-api # 路由的编号 + uri: grayLb://pay-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/pay/** + filters: + - RewritePath=/admin-api/pay/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + - id: pay-app-api # 路由的编号 + uri: grayLb://pay-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/pay/** + filters: + - RewritePath=/app-api/pay/v3/api-docs, /v3/api-docs + ## mp-server 服务 + - id: mp-admin-api # 路由的编号 + uri: grayLb://mp-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/mp/** + filters: + - RewritePath=/admin-api/mp/v3/api-docs, /v3/api-docs + ## product-server 服务 + - id: product-admin-api # 路由的编号 + uri: grayLb://product-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/product/** + filters: + - RewritePath=/admin-api/product/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + - id: product-app-api # 路由的编号 + uri: grayLb://product-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/product/** + filters: + - RewritePath=/app-api/product/v3/api-docs, /v3/api-docs + ## promotion-server 服务 + - id: promotion-admin-api # 路由的编号 + uri: grayLb://promotion-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/promotion/** + filters: + - RewritePath=/admin-api/promotion/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + - id: promotion-app-api # 路由的编号 + uri: grayLb://promotion-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/promotion/** + filters: + - RewritePath=/app-api/promotion/v3/api-docs, /v3/api-docs + ## trade-server 服务 + - id: trade-admin-api # 路由的编号 + uri: grayLb://trade-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/trade/** + filters: + - RewritePath=/admin-api/trade/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + - id: trade-app-api # 路由的编号 + uri: grayLb://trade-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/trade/** + filters: + - RewritePath=/app-api/trade/v3/api-docs, /v3/api-docs + ## statistics-server 服务 + - id: statistics-admin-api # 路由的编号 + uri: grayLb://statistics-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/statistics/** + filters: + - RewritePath=/admin-api/statistics/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + ## erp-server 服务 + - id: erp-admin-api # 路由的编号 + uri: grayLb://erp-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/erp/** + filters: + - RewritePath=/admin-api/erp/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + ## crm-server 服务 + - id: crm-admin-api # 路由的编号 + uri: grayLb://crm-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/crm/** + filters: + - RewritePath=/admin-api/crm/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + ## ai-server 服务 + - id: ai-admin-api # 路由的编号 + uri: grayLb://ai-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/ai/** + filters: + - RewritePath=/admin-api/ai/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + x-forwarded: + prefix-enabled: false # 避免 Swagger 重复带上额外的 /admin-api/system 前缀 + +server: + port: 48080 + +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + +knife4j: + # 聚合 Swagger 文档,参考 https://doc.xiaominfo.com/docs/action/springcloud-gateway 文档 + gateway: + enabled: true + routes: + - name: system-server + service-name: system-server + url: /admin-api/system/v3/api-docs + - name: infra-server + service-name: infra-server + url: /admin-api/infra/v3/api-docs + - name: member-server + service-name: member-server + url: /admin-api/member/v3/api-docs + - name: bpm-server + service-name: bpm-server + url: /admin-api/bpm/v3/api-docs + - name: pay-server + service-name: pay-server + url: /admin-api/pay/v3/api-docs + - name: mp-server + service-name: mp-server + url: /admin-api/mp/v3/api-docs + - name: product-server + service-name: product-server + url: /admin-api/product/v3/api-docs + - name: promotion-server + service-name: promotion-server + url: /admin-api/promotion/v3/api-docs + - name: trade-server + service-name: trade-server + url: /admin-api/trade/v3/api-docs + - name: statistics-server + service-name: statistics-server + url: /admin-api/statistics/v3/api-docs + - name: erp-server + service-name: erp-server + url: /admin-api/erp/v3/api-docs + - name: crm-server + service-name: crm-server + url: /admin-api/crm/v3/api-docs + - name: ai-server + service-name: ai-server + url: /admin-api/ai/v3/api-docs + +--- #################### 芋道相关配置 #################### + +yudao: + info: + version: 1.0.0 \ No newline at end of file diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/resources/banner.txt b/tashow-gateway/src/main/resources/banner.txt similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/resources/banner.txt rename to tashow-gateway/src/main/resources/banner.txt diff --git a/tashow-gateway/src/main/resources/logback-spring.xml b/tashow-gateway/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..411578b --- /dev/null +++ b/tashow-gateway/src/main/resources/logback-spring.xml @@ -0,0 +1,76 @@ + + + + + + + + + +       + + + ${PATTERN_DEFAULT} + + + + + + + + + + ${PATTERN_DEFAULT} + + + + ${LOG_FILE} + + + ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} + + ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} + + ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} + + ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} + + ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30} + + + + + + 0 + + 256 + + + + + + + + ${PATTERN_DEFAULT} + + + + + + + + + + + + + + + + + + + + + + diff --git a/tashow-gateway/src/main/resources/static/favicon.ico b/tashow-gateway/src/main/resources/static/favicon.ico new file mode 100644 index 0000000..30053fa Binary files /dev/null and b/tashow-gateway/src/main/resources/static/favicon.ico differ diff --git a/tashow-module/pom.xml b/tashow-module/pom.xml new file mode 100644 index 0000000..24e63d2 --- /dev/null +++ b/tashow-module/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + + com.tashow.cloud + tashow-platform + ${revision} + + + tashow-module + pom + + + tashow-module-system + tashow-module-infra + + + diff --git a/tashow-module/tashow-module-infra/pom.xml b/tashow-module/tashow-module-infra/pom.xml new file mode 100644 index 0000000..b882186 --- /dev/null +++ b/tashow-module/tashow-module-infra/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + com.tashow.cloud + tashow-module + ${revision} + + + tashow-module-infra-api + tashow-module-infra-biz + + tashow-module-infra + pom + + ${project.artifactId} + + infra 模块,主要提供两块能力: + 1. 我们放基础设施的运维与管理,支撑上层的通用与核心业务。 例如说:定时任务的管理、服务器的信息等等 + 2. 研发工具,提升研发效率与质量。 例如说:代码生成器、接口文档等等 + + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/pom.xml b/tashow-module/tashow-module-infra/tashow-module-infra-api/pom.xml new file mode 100644 index 0000000..604aaef --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + com.tashow.cloud + tashow-module-infra + ${revision} + + tashow-module-infra-api + jar + + ${project.artifactId} + + infra 模块 API,暴露给其它模块调用 + + + + + com.tashow.cloud + tashow-common + + + + + org.springdoc + springdoc-openapi-starter-webmvc-api + provided + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + true + + + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/config/ConfigApi.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/config/ConfigApi.java new file mode 100644 index 0000000..a9feef0 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/config/ConfigApi.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.infraapi.api.config; + +import com.tashow.cloud.infraapi.enums.ApiConstants; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infraapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 参数配置") +public interface ConfigApi { + + String PREFIX = ApiConstants.PREFIX + "/config"; + + @GetMapping(PREFIX + "/get-value-by-key") + @Operation(summary = "根据参数键查询参数值") + CommonResult getConfigValueByKey(@RequestParam("key") String key); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/file/FileApi.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/file/FileApi.java new file mode 100644 index 0000000..3ce144b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/file/FileApi.java @@ -0,0 +1,62 @@ +package com.tashow.cloud.infraapi.api.file; + +import com.tashow.cloud.infraapi.api.file.dto.FileCreateReqDTO; +import com.tashow.cloud.infraapi.enums.ApiConstants; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infraapi.api.file.dto.FileCreateReqDTO; +import com.tashow.cloud.infraapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 文件") +public interface FileApi { + + String PREFIX = ApiConstants.PREFIX + "/file"; + + /** + * 保存文件,并返回文件的访问路径 + * + * @param content 文件内容 + * @return 文件路径 + */ + default String createFile(byte[] content) { + return createFile(null, null, content); + } + + /** + * 保存文件,并返回文件的访问路径 + * + * @param path 文件路径 + * @param content 文件内容 + * @return 文件路径 + */ + default String createFile(String path, byte[] content) { + return createFile(null, path, content); + } + + /** + * 保存文件,并返回文件的访问路径 + * + * @param name 原文件名称 + * @param path 文件路径 + * @param content 文件内容 + * @return 文件路径 + */ + default String createFile(@RequestParam("name") String name, + @RequestParam("path") String path, + @RequestParam("content") byte[] content) { + return createFile(new FileCreateReqDTO().setName(name).setPath(path).setContent(content)).getCheckedData(); + } + + @PostMapping(PREFIX + "/create") + @Operation(summary = "保存文件,并返回文件的访问路径") + CommonResult createFile(@Valid @RequestBody FileCreateReqDTO createReqDTO); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/file/dto/FileCreateReqDTO.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/file/dto/FileCreateReqDTO.java new file mode 100644 index 0000000..ec64d5a --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/file/dto/FileCreateReqDTO.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.infraapi.api.file.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; + +@Schema(description = "RPC 服务 - 文件创建 Request DTO") +@Data +public class FileCreateReqDTO { + + @Schema(description = "原文件名称", example = "xxx.png") + private String name; + + @Schema(description = "文件路径", example = "xxx.png") + private String path; + + @Schema(description = "文件内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "文件内容不能为空") + private byte[] content; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/ApiAccessLogApi.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/ApiAccessLogApi.java new file mode 100644 index 0000000..0d7b280 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/ApiAccessLogApi.java @@ -0,0 +1,37 @@ +package com.tashow.cloud.infraapi.api.logger; + +import com.tashow.cloud.infraapi.api.logger.dto.ApiAccessLogCreateReqDTO; +import com.tashow.cloud.infraapi.enums.ApiConstants; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infraapi.api.logger.dto.ApiAccessLogCreateReqDTO; +import com.tashow.cloud.infraapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.scheduling.annotation.Async; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - API 访问日志") +public interface ApiAccessLogApi { + + String PREFIX = ApiConstants.PREFIX + "/api-access-log"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "创建 API 访问日志") + CommonResult createApiAccessLog(@Valid @RequestBody ApiAccessLogCreateReqDTO createDTO); + + /** + * 【异步】创建 API 访问日志 + * + * @param createDTO 访问日志 DTO + */ + @Async + default void createApiAccessLogAsync(ApiAccessLogCreateReqDTO createDTO) { + createApiAccessLog(createDTO).checkError(); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/ApiErrorLogApi.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/ApiErrorLogApi.java new file mode 100644 index 0000000..4c6205f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/ApiErrorLogApi.java @@ -0,0 +1,37 @@ +package com.tashow.cloud.infraapi.api.logger; + +import com.tashow.cloud.infraapi.api.logger.dto.ApiErrorLogCreateReqDTO; +import com.tashow.cloud.infraapi.enums.ApiConstants; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infraapi.api.logger.dto.ApiErrorLogCreateReqDTO; +import com.tashow.cloud.infraapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.scheduling.annotation.Async; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - API 异常日志") +public interface ApiErrorLogApi { + + String PREFIX = ApiConstants.PREFIX + "/api-error-log"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "创建 API 异常日志") + CommonResult createApiErrorLog(@Valid @RequestBody ApiErrorLogCreateReqDTO createDTO); + + /** + * 【异步】创建 API 异常日志 + * + * @param createDTO 异常日志 DTO + */ + @Async + default void createApiErrorLogAsync(ApiErrorLogCreateReqDTO createDTO) { + createApiErrorLog(createDTO).checkError(); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/dto/ApiAccessLogCreateReqDTO.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/dto/ApiAccessLogCreateReqDTO.java new file mode 100644 index 0000000..62d33df --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/dto/ApiAccessLogCreateReqDTO.java @@ -0,0 +1,63 @@ +package com.tashow.cloud.infraapi.api.logger.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "RPC 服务 - API 访问日志创建 Request DTO") +@Data +public class ApiAccessLogCreateReqDTO { + + @Schema(description = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer userType; + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system-server") + @NotNull(message = "应用名不能为空") + private String applicationName; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @NotNull(message = "http 请求方法不能为空") + private String requestMethod; + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy") + @NotNull(message = "访问地址不能为空") + private String requestUrl; + @Schema(description = "请求参数") + private String requestParams; + @Schema(description = "响应结果") + private String responseBody; + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @NotNull(message = "ip 不能为空") + private String userIp; + @Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + @NotNull(message = "User-Agent 不能为空") + private String userAgent; + + @Schema(description = "操作模块", requiredMode = Schema.RequiredMode.REQUIRED, example = "商品模块") + private String operateModule; + @Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "商品新增") + private String operateName; + @Schema(description = "操作分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer operateType; // 参见 OperateTypeEnum 枚举 + + @Schema(description = "开始时间",requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "开始请求时间不能为空") + private LocalDateTime beginTime; + @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "结束请求时间不能为空") + private LocalDateTime endTime; + @Schema(description = "执行时长,单位:毫秒", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "执行时长不能为空") + private Integer duration; + @Schema(description = "结果码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "错误码不能为空") + private Integer resultCode; + @Schema(description = "结果提示") + private String resultMsg; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/dto/ApiErrorLogCreateReqDTO.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/dto/ApiErrorLogCreateReqDTO.java new file mode 100644 index 0000000..942123e --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/logger/dto/ApiErrorLogCreateReqDTO.java @@ -0,0 +1,68 @@ +package com.tashow.cloud.infraapi.api.logger.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "RPC 服务 - API 错误日志创建 Request DTO") +@Data +public class ApiErrorLogCreateReqDTO { + + @Schema(description = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer userType; + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system-server") + @NotNull(message = "应用名不能为空") + private String applicationName; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @NotNull(message = "http 请求方法不能为空") + private String requestMethod; + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy") + @NotNull(message = "访问地址不能为空") + private String requestUrl; + @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "请求参数不能为空") + private String requestParams; + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @NotNull(message = "ip 不能为空") + private String userIp; + @Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + @NotNull(message = "User-Agent 不能为空") + private String userAgent; + + @Schema(description = "异常时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常时间不能为空") + private LocalDateTime exceptionTime; + @Schema(description = "异常名", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常名不能为空") + private String exceptionName; + @Schema(description = "异常发生的类全名", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常发生的类全名不能为空") + private String exceptionClassName; + @Schema(description = "异常发生的类文件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常发生的类文件不能为空") + private String exceptionFileName; + @Schema(description = "异常发生的方法名", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常发生的方法名不能为空") + private String exceptionMethodName; + @Schema(description = "异常发生的方法所在行", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常发生的方法所在行不能为空") + private Integer exceptionLineNumber; + @Schema(description = "异常的栈轨迹异常的栈轨迹", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常的栈轨迹不能为空") + private String exceptionStackTrace; + @Schema(description = "异常导致的根消息", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常导致的根消息不能为空") + private String exceptionRootCauseMessage; + @Schema(description = "异常导致的消息", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "异常导致的消息不能为空") + private String exceptionMessage; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/package-info.java new file mode 100644 index 0000000..061202d --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/package-info.java @@ -0,0 +1,4 @@ +/** + * infra API 包,定义暴露给其它模块的 API + */ +package com.tashow.cloud.infraapi.api; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/websocket/WebSocketSenderApi.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/websocket/WebSocketSenderApi.java new file mode 100644 index 0000000..452eada --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/websocket/WebSocketSenderApi.java @@ -0,0 +1,75 @@ +package com.tashow.cloud.infraapi.api.websocket; + +import com.tashow.cloud.infraapi.api.websocket.dto.WebSocketSendReqDTO; +import com.tashow.cloud.infraapi.enums.ApiConstants; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.infraapi.api.websocket.dto.WebSocketSendReqDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - WebSocket 发送器的") // 对 WebSocketMessageSender 进行封装,提供给其它模块使用 +public interface WebSocketSenderApi { + + String PREFIX = ApiConstants.PREFIX + "/websocket"; + + @PostMapping(PREFIX + "/send") + @Operation(summary = "发送 WebSocket 消息") + CommonResult send(@Valid @RequestBody WebSocketSendReqDTO message); + + /** + * 发送消息给指定用户 + * + * @param userType 用户类型 + * @param userId 用户编号 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + default void send(Integer userType, Long userId, String messageType, String messageContent) { + send(new WebSocketSendReqDTO().setUserType(userType).setUserId(userId) + .setMessageType(messageType).setMessageContent(messageContent)).checkError(); + } + + /** + * 发送消息给指定用户类型 + * + * @param userType 用户类型 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + default void send(Integer userType, String messageType, String messageContent) { + send(new WebSocketSendReqDTO().setUserType(userType) + .setMessageType(messageType).setMessageContent(messageContent)).checkError(); + } + + /** + * 发送消息给指定 Session + * + * @param sessionId Session 编号 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + default void send(String sessionId, String messageType, String messageContent) { + send(new WebSocketSendReqDTO().setSessionId(sessionId) + .setMessageType(messageType).setMessageContent(messageContent)).checkError(); + } + + default void sendObject(Integer userType, Long userId, String messageType, Object messageContent) { + send(userType, userId, messageType, JsonUtils.toJsonString(messageContent)); + } + + default void sendObject(Integer userType, String messageType, Object messageContent) { + send(userType, messageType, JsonUtils.toJsonString(messageContent)); + } + + default void sendObject(String sessionId, String messageType, Object messageContent) { + send(sessionId, messageType, JsonUtils.toJsonString(messageContent)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/websocket/dto/WebSocketSendReqDTO.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/websocket/dto/WebSocketSendReqDTO.java new file mode 100644 index 0000000..4f65487 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/api/websocket/dto/WebSocketSendReqDTO.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.infraapi.api.websocket.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; + +@Schema(description = "RPC 服务 - WebSocket 消息发送 Request DTO") +@Data +public class WebSocketSendReqDTO { + + @Schema(description = "Session 编号", example = "abc") + private String sessionId; + @Schema(description = "用户编号", example = "1024") + private Long userId; + @Schema(description = "用户类型", example = "1") + private Integer userType; + + @Schema(description = "消息类型", example = "demo-message") + @NotEmpty(message = "消息类型不能为空") + private String messageType; + @Schema(description = "消息内容", example = "{\"name\":\"李四\"}}") + @NotEmpty(message = "消息内容不能为空") + private String messageContent; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/ApiConstants.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/ApiConstants.java new file mode 100644 index 0000000..4b64329 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/ApiConstants.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.infraapi.enums; + + +import com.tashow.cloud.common.enums.RpcConstants; + +/** + * API 相关的枚举 + * + * @author 芋道源码 + */ +public class ApiConstants { + + /** + * 服务名 + * + * 注意,需要保证和 spring.application.name 保持一致 + */ + public static final String NAME = "infra-server"; + + public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/infra"; + + public static final String VERSION = "1.0.0"; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/DictTypeConstants.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/DictTypeConstants.java new file mode 100644 index 0000000..7667950 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/DictTypeConstants.java @@ -0,0 +1,20 @@ +package com.tashow.cloud.infraapi.enums; + +/** + * Infra 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String JOB_STATUS = "infra_job_status"; // 定时任务状态的枚举 + String JOB_LOG_STATUS = "infra_job_log_status"; // 定时任务日志状态的枚举 + + String API_ERROR_LOG_PROCESS_STATUS = "infra_api_error_log_process_status"; // API 错误日志的处理状态的枚举 + + String CONFIG_TYPE = "infra_config_type"; // 参数配置类型 + String BOOLEAN_STRING = "infra_boolean_string"; // Boolean 是否类型 + + String OPERATE_TYPE = "infra_operate_type"; // 操作类型 + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/ErrorCodeConstants.java b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..509a2de --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-api/src/main/java/com/tashow/cloud/infraapi/enums/ErrorCodeConstants.java @@ -0,0 +1,72 @@ +package com.tashow.cloud.infraapi.enums; + + +import com.tashow.cloud.common.exception.ErrorCode; + +/** + * Infra 错误码枚举类 + * + * infra 系统,使用 1-001-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 参数配置 1-001-000-000 ========== + ErrorCode CONFIG_NOT_EXISTS = new ErrorCode(1_001_000_001, "参数配置不存在"); + ErrorCode CONFIG_KEY_DUPLICATE = new ErrorCode(1_001_000_002, "参数配置 key 重复"); + ErrorCode CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE = new ErrorCode(1_001_000_003, "不能删除类型为系统内置的参数配置"); + ErrorCode CONFIG_GET_VALUE_ERROR_IF_VISIBLE = new ErrorCode(1_001_000_004, "获取参数配置失败,原因:不允许获取不可见配置"); + + // ========== 定时任务 1-001-001-000 ========== + ErrorCode JOB_NOT_EXISTS = new ErrorCode(1_001_001_000, "定时任务不存在"); + ErrorCode JOB_HANDLER_EXISTS = new ErrorCode(1_001_001_001, "定时任务的处理器已经存在"); + ErrorCode JOB_CHANGE_STATUS_INVALID = new ErrorCode(1_001_001_002, "只允许修改为开启或者关闭状态"); + ErrorCode JOB_CHANGE_STATUS_EQUALS = new ErrorCode(1_001_001_003, "定时任务已经处于该状态,无需修改"); + ErrorCode JOB_UPDATE_ONLY_NORMAL_STATUS = new ErrorCode(1_001_001_004, "只有开启状态的任务,才可以修改"); + ErrorCode JOB_CRON_EXPRESSION_VALID = new ErrorCode(1_001_001_005, "CRON 表达式不正确"); + ErrorCode JOB_HANDLER_BEAN_NOT_EXISTS = new ErrorCode(1_001_001_006, "定时任务的处理器 Bean 不存在,注意 Bean 默认首字母小写"); + ErrorCode JOB_HANDLER_BEAN_TYPE_ERROR = new ErrorCode(1_001_001_007, "定时任务的处理器 Bean 类型不正确,未实现 JobHandler 接口"); + + // ========== API 错误日志 1-001-002-000 ========== + ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1_001_002_000, "API 错误日志不存在"); + ErrorCode API_ERROR_LOG_PROCESSED = new ErrorCode(1_001_002_001, "API 错误日志已处理"); + + // ========= 文件相关 1-001-003-000 ================= + ErrorCode FILE_PATH_EXISTS = new ErrorCode(1_001_003_000, "文件路径已存在"); + ErrorCode FILE_NOT_EXISTS = new ErrorCode(1_001_003_001, "文件不存在"); + ErrorCode FILE_IS_EMPTY = new ErrorCode(1_001_003_002, "文件为空"); + + // ========== 代码生成器 1-001-004-000 ========== + ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1_001_004_002, "表定义已经存在"); + ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1_001_004_001, "导入的表不存在"); + ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1_001_004_002, "导入的字段不存在"); + ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_004, "表定义不存在"); + ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_005, "字段义不存在"); + ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1_001_004_006, "同步的字段不存在"); + ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1_001_004_007, "同步失败,不存在改变"); + ErrorCode CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL = new ErrorCode(1_001_004_008, "数据库的表注释未填写"); + ErrorCode CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL = new ErrorCode(1_001_004_009, "数据库的表字段({})注释未填写"); + ErrorCode CODEGEN_MASTER_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_010, "主表(id={})定义不存在,请检查"); + ErrorCode CODEGEN_SUB_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_011, "子表的字段(id={})不存在,请检查"); + ErrorCode CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE = new ErrorCode(1_001_004_012, "主表生成代码失败,原因:它没有子表"); + + // ========== 文件配置 1-001-006-000 ========== + ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_006_000, "文件配置不存在"); + ErrorCode FILE_CONFIG_DELETE_FAIL_MASTER = new ErrorCode(1_001_006_001, "该文件配置不允许删除,原因:它是主配置,删除会导致无法上传文件"); + + // ========== 数据源配置 1-001-007-000 ========== + ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_007_000, "数据源配置不存在"); + ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1_001_007_001, "数据源配置不正确,无法进行连接"); + + // ========== 学生 1-001-201-000 ========== + ErrorCode DEMO01_CONTACT_NOT_EXISTS = new ErrorCode(1_001_201_000, "示例联系人不存在"); + ErrorCode DEMO02_CATEGORY_NOT_EXISTS = new ErrorCode(1_001_201_001, "示例分类不存在"); + ErrorCode DEMO02_CATEGORY_EXITS_CHILDREN = new ErrorCode(1_001_201_002, "存在存在子示例分类,无法删除"); + ErrorCode DEMO02_CATEGORY_PARENT_NOT_EXITS = new ErrorCode(1_001_201_003,"父级示例分类不存在"); + ErrorCode DEMO02_CATEGORY_PARENT_ERROR = new ErrorCode(1_001_201_004, "不能设置自己为父示例分类"); + ErrorCode DEMO02_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_001_201_005, "已经存在该名字的示例分类"); + ErrorCode DEMO02_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_001_201_006, "不能设置自己的子示例分类为父示例分类"); + ErrorCode DEMO03_STUDENT_NOT_EXISTS = new ErrorCode(1_001_201_007, "学生不存在"); + ErrorCode DEMO03_GRADE_NOT_EXISTS = new ErrorCode(1_001_201_008, "学生班级不存在"); + ErrorCode DEMO03_GRADE_EXISTS = new ErrorCode(1_001_201_009, "学生班级已存在"); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/Dockerfile b/tashow-module/tashow-module-infra/tashow-module-infra-biz/Dockerfile new file mode 100644 index 0000000..32d8274 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/Dockerfile @@ -0,0 +1,19 @@ +## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 +## 感谢复旦核博士的建议!灰子哥,牛皮! +FROM eclipse-temurin:21-jre + +## 创建目录,并使用它作为工作目录 +RUN mkdir -p /yudao-module-infra-biz +WORKDIR /yudao-module-infra-biz +## 将后端项目的 Jar 文件,复制到镜像中 +COPY ./target/yudao-module-infra-biz.jar app.jar + +## 设置 TZ 时区 +## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖 +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx512m" + +## 暴露后端项目的 48080 端口 +EXPOSE 48082 + +## 启动后端项目 +CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/pom.xml b/tashow-module/tashow-module-infra/tashow-module-infra-biz/pom.xml new file mode 100644 index 0000000..eafc02f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/pom.xml @@ -0,0 +1,164 @@ + + + 4.0.0 + + com.tashow.cloud + tashow-module-infra + ${revision} + + tashow-module-infra-biz + jar + + ${project.artifactId} + + infra 模块,主要提供两块能力: + 1. 我们放基础设施的运维与管理,支撑上层的通用与核心业务。 例如说:定时任务的管理、服务器的信息等等 + 2. 研发工具,提升研发效率与质量。 例如说:代码生成器、接口文档等等 + + + + + + com.tashow.cloud + tashow-framework-env + + + + + com.tashow.cloud + tashow-module-system-api + ${revision} + + + com.tashow.cloud + tashow-module-infra-api + ${revision} + + + + + com.tashow.cloud + tashow-framework-tenant + + + + + com.tashow.cloud + tashow-framework-security + + + + com.tashow.cloud + tashow-framework-websocket + + + + + com.tashow.cloud + tashow-data-mybatis + + + com.baomidou + mybatis-plus-generator + + + + com.tashow.cloud + tashow-data-redis + + + + + com.tashow.cloud + tashow-framework-rpc + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + + com.tashow.cloud + tashow-framework-job + + + + + com.tashow.cloud + tashow-framework-mq + + + + + com.tashow.cloud + tashow-data-excel + + + + org.apache.velocity + velocity-engine-core + + + + + com.tashow.cloud + tashow-framework-monitor + + + + de.codecentric + spring-boot-admin-starter-server + + + + + commons-net + commons-net + + + com.jcraft + jsch + + + com.amazonaws + aws-java-sdk-s3 + + + + org.apache.tika + tika-core + + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/InfraServerApplication.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/InfraServerApplication.java new file mode 100644 index 0000000..bc69e5a --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/InfraServerApplication.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.infra; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 项目的启动类 + *

+ * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * + * @author 芋道源码 + */ +@SpringBootApplication +public class InfraServerApplication { + + public static void main(String[] args) { + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + + SpringApplication.run(InfraServerApplication.class, args); + + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/config/ConfigApiImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/config/ConfigApiImpl.java new file mode 100644 index 0000000..82f7268 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/config/ConfigApiImpl.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.infra.api.config; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infra.service.config.ConfigService; +import com.tashow.cloud.infraapi.api.config.ConfigApi; +import com.tashow.cloud.infra.dal.dataobject.config.ConfigDO; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class ConfigApiImpl implements ConfigApi { + + @Resource + private ConfigService configService; + + @Override + public CommonResult getConfigValueByKey(String key) { + ConfigDO config = configService.getConfigByKey(key); + return success(config != null ? config.getValue() : null); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/file/FileApiImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/file/FileApiImpl.java new file mode 100644 index 0000000..cb57d40 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/file/FileApiImpl.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.infra.api.file; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infra.service.file.FileService; +import com.tashow.cloud.infraapi.api.file.FileApi; +import com.tashow.cloud.infraapi.api.file.dto.FileCreateReqDTO; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class FileApiImpl implements FileApi { + + @Resource + private FileService fileService; + + @Override + public CommonResult createFile(FileCreateReqDTO createReqDTO) { + return success(fileService.createFile(createReqDTO.getName(), createReqDTO.getPath(), + createReqDTO.getContent())); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/logger/ApiAccessLogApiImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/logger/ApiAccessLogApiImpl.java new file mode 100644 index 0000000..00effcd --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/logger/ApiAccessLogApiImpl.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.infra.api.logger; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infra.service.logger.ApiAccessLogService; +import com.tashow.cloud.infraapi.api.logger.ApiAccessLogApi; +import com.tashow.cloud.infraapi.api.logger.dto.ApiAccessLogCreateReqDTO; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class ApiAccessLogApiImpl implements ApiAccessLogApi { + + @Resource + private ApiAccessLogService apiAccessLogService; + + @Override + public CommonResult createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) { + apiAccessLogService.createApiAccessLog(createDTO); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/logger/ApiErrorLogApiImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/logger/ApiErrorLogApiImpl.java new file mode 100644 index 0000000..24d6e56 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/logger/ApiErrorLogApiImpl.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.infra.api.logger; + + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infra.service.logger.ApiErrorLogService; +import com.tashow.cloud.infraapi.api.logger.ApiErrorLogApi; +import com.tashow.cloud.infraapi.api.logger.dto.ApiErrorLogCreateReqDTO; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class ApiErrorLogApiImpl implements ApiErrorLogApi { + + @Resource + private ApiErrorLogService apiErrorLogService; + + @Override + public CommonResult createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) { + apiErrorLogService.createApiErrorLog(createDTO); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/package-info.java new file mode 100644 index 0000000..b389e58 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/package-info.java @@ -0,0 +1 @@ +package com.tashow.cloud.infra.api; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/websocket/WebSocketSenderApiImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/websocket/WebSocketSenderApiImpl.java new file mode 100644 index 0000000..9833991 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/api/websocket/WebSocketSenderApiImpl.java @@ -0,0 +1,37 @@ +package com.tashow.cloud.infra.api.websocket; + + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infraapi.api.websocket.WebSocketSenderApi; +import com.tashow.cloud.infraapi.api.websocket.dto.WebSocketSendReqDTO; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class WebSocketSenderApiImpl implements WebSocketSenderApi { + + @Resource + private WebSocketMessageSender webSocketMessageSender; + + @Override + public CommonResult send(WebSocketSendReqDTO message) { + if (StrUtil.isNotEmpty(message.getSessionId())) { + webSocketMessageSender.send(message.getSessionId(), + message.getMessageType(), message.getMessageContent()); + } else if (message.getUserType() != null && message.getUserId() != null) { + webSocketMessageSender.send(message.getUserType(), message.getUserId(), + message.getMessageType(), message.getMessageContent()); + } else if (message.getUserType() != null) { + webSocketMessageSender.send(message.getUserType(), + message.getMessageType(), message.getMessageContent()); + } + return success(true); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/CodegenController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/CodegenController.java new file mode 100644 index 0000000..27c57d0 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/CodegenController.java @@ -0,0 +1,151 @@ +package com.tashow.cloud.infra.controller.admin.codegen; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.ZipUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenDetailRespVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenPreviewRespVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import com.tashow.cloud.infra.convert.codegen.CodegenConvert; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTableRespVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import com.tashow.cloud.infra.service.codegen.CodegenService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.infra.framework.file.core.utils.FileTypeUtils.writeAttachment; +import static com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 代码生成器") +@RestController +@RequestMapping("/infra/codegen") +@Validated +public class CodegenController { + + @Resource + private CodegenService codegenService; + + @GetMapping("/db/table/list") + @Operation(summary = "获得数据库自带的表定义列表", description = "会过滤掉已经导入 Codegen 的表") + @Parameters({ + @Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1"), + @Parameter(name = "name", description = "表名,模糊匹配", example = "yudao"), + @Parameter(name = "comment", description = "描述,模糊匹配", example = "芋道") + }) + @PreAuthorize("@ss.hasPermission('infra:codegen:query')") + public CommonResult> getDatabaseTableList( + @RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId, + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "comment", required = false) String comment) { + return success(codegenService.getDatabaseTableList(dataSourceConfigId, name, comment)); + } + + @GetMapping("/table/list") + @Operation(summary = "获得表定义列表") + @Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('infra:codegen:query')") + public CommonResult> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) { + List list = codegenService.getCodegenTableList(dataSourceConfigId); + return success(BeanUtils.toBean(list, CodegenTableRespVO.class)); + } + + @GetMapping("/table/page") + @Operation(summary = "获得表定义分页") + @PreAuthorize("@ss.hasPermission('infra:codegen:query')") + public CommonResult> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) { + PageResult pageResult = codegenService.getCodegenTablePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, CodegenTableRespVO.class)); + } + + @GetMapping("/detail") + @Operation(summary = "获得表和字段的明细") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:query')") + public CommonResult getCodegenDetail(@RequestParam("tableId") Long tableId) { + CodegenTableDO table = codegenService.getCodegenTable(tableId); + List columns = codegenService.getCodegenColumnListByTableId(tableId); + // 拼装返回 + return success(CodegenConvert.INSTANCE.convert(table, columns)); + } + + @Operation(summary = "基于数据库的表结构,创建代码生成器的表和字段定义") + @PostMapping("/create-list") + @PreAuthorize("@ss.hasPermission('infra:codegen:create')") + public CommonResult> createCodegenList(@Valid @RequestBody CodegenCreateListReqVO reqVO) { + return success(codegenService.createCodegenList(getLoginUserId(), reqVO)); + } + + @Operation(summary = "更新数据库的表和字段定义") + @PutMapping("/update") + @PreAuthorize("@ss.hasPermission('infra:codegen:update')") + public CommonResult updateCodegen(@Valid @RequestBody CodegenUpdateReqVO updateReqVO) { + codegenService.updateCodegen(updateReqVO); + return success(true); + } + + @Operation(summary = "基于数据库的表结构,同步数据库的表和字段定义") + @PutMapping("/sync-from-db") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:update')") + public CommonResult syncCodegenFromDB(@RequestParam("tableId") Long tableId) { + codegenService.syncCodegenFromDB(tableId); + return success(true); + } + + @Operation(summary = "删除数据库的表和字段定义") + @DeleteMapping("/delete") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:delete')") + public CommonResult deleteCodegen(@RequestParam("tableId") Long tableId) { + codegenService.deleteCodegen(tableId); + return success(true); + } + + @Operation(summary = "预览生成代码") + @GetMapping("/preview") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:preview')") + public CommonResult> previewCodegen(@RequestParam("tableId") Long tableId) { + Map codes = codegenService.generationCodes(tableId); + return success(CodegenConvert.INSTANCE.convert(codes)); + } + + @Operation(summary = "下载生成代码") + @GetMapping("/download") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:download')") + public void downloadCodegen(@RequestParam("tableId") Long tableId, + HttpServletResponse response) throws IOException { + // 生成代码 + Map codes = codegenService.generationCodes(tableId); + // 构建 zip 包 + String[] paths = codes.keySet().toArray(new String[0]); + ByteArrayInputStream[] ins = codes.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipUtil.zip(outputStream, paths, ins); + // 输出 + writeAttachment(response, "codegen.zip", outputStream.toByteArray()); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenCreateListReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenCreateListReqVO.java new file mode 100644 index 0000000..6db6e08 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenCreateListReqVO.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 基于数据库的表结构,创建代码生成器的表和字段定义 Request VO") +@Data +public class CodegenCreateListReqVO { + + @Schema(description = "数据源配置的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数据源配置的编号不能为空") + private Long dataSourceConfigId; + + @Schema(description = "表名数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]") + @NotNull(message = "表名数组不能为空") + private List tableNames; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenDetailRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenDetailRespVO.java new file mode 100644 index 0000000..8ceb95c --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenDetailRespVO.java @@ -0,0 +1,20 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo; + +import com.tashow.cloud.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTableRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 代码生成表和字段的明细 Response VO") +@Data +public class CodegenDetailRespVO { + + @Schema(description = "表定义") + private CodegenTableRespVO table; + + @Schema(description = "字段定义") + private List columns; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenPreviewRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenPreviewRespVO.java new file mode 100644 index 0000000..5744dc7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenPreviewRespVO.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 代码生成预览 Response VO,注意,每个文件都是一个该对象") +@Data +public class CodegenPreviewRespVO { + + @Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "java/cn/iocoder/yudao/adminserver/modules/system/controller/test/SysTestDemoController.java") + private String filePath; + + @Schema(description = "代码", requiredMode = Schema.RequiredMode.REQUIRED, example = "Hello World") + private String code; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java new file mode 100644 index 0000000..fb99274 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo; + +import com.tashow.cloud.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTableSaveReqVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 代码生成表和字段的修改 Request VO") +@Data +public class CodegenUpdateReqVO { + + @Valid // 校验内嵌的字段 + @NotNull(message = "表定义不能为空") + private CodegenTableSaveReqVO table; + + @Valid // 校验内嵌的字段 + @NotNull(message = "字段定义不能为空") + private List columns; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java new file mode 100644 index 0000000..2e56cde --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java @@ -0,0 +1,69 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo.column; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 代码生成字段定义 Response VO") +@Data +public class CodegenColumnRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long tableId; + + @Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age") + private String columnName; + + @Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)") + private String dataType; + + @Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄") + private String columnComment; + + @Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean nullable; + + @Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean primaryKey; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer ordinalPosition; + + @Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge") + private String javaType; + + @Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer") + private String javaField; + + @Schema(description = "字典类型", example = "sys_gender") + private String dictType; + + @Schema(description = "数据示例", example = "1024") + private String example; + + @Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean createOperation; + + @Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean updateOperation; + + @Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean listOperation; + + @Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE") + private String listOperationCondition; + + @Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean listOperationResult; + + @Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input") + private String htmlType; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java new file mode 100644 index 0000000..1286724 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java @@ -0,0 +1,81 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo.column; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 代码生成字段定义创建/修改 Request VO") +@Data +public class CodegenColumnSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "表编号不能为空") + private Long tableId; + + @Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age") + @NotNull(message = "字段名不能为空") + private String columnName; + + @Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)") + @NotNull(message = "字段类型不能为空") + private String dataType; + + @Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄") + @NotNull(message = "字段描述不能为空") + private String columnComment; + + @Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否允许为空不能为空") + private Boolean nullable; + + @Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + @NotNull(message = "是否主键不能为空") + private Boolean primaryKey; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "排序不能为空") + private Integer ordinalPosition; + + @Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge") + @NotNull(message = "Java 属性类型不能为空") + private String javaType; + + @Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer") + @NotNull(message = "Java 属性名不能为空") + private String javaField; + + @Schema(description = "字典类型", example = "sys_gender") + private String dictType; + + @Schema(description = "数据示例", example = "1024") + private String example; + + @Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否为 Create 创建操作的字段不能为空") + private Boolean createOperation; + + @Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + @NotNull(message = "是否为 Update 更新操作的字段不能为空") + private Boolean updateOperation; + + @Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否为 List 查询操作的字段不能为空") + private Boolean listOperation; + + @Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE") + @NotNull(message = "List 查询操作的条件类型不能为空") + private String listOperationCondition; + + @Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否为 List 查询操作的返回字段不能为空") + private Boolean listOperationResult; + + @Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input") + @NotNull(message = "显示类型不能为空") + private String htmlType; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java new file mode 100644 index 0000000..eee84c5 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java @@ -0,0 +1,34 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo.table; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + + +@Schema(description = "管理后台 - 表定义分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CodegenTablePageReqVO extends PageParam { + + @Schema(description = "表名称,模糊匹配", example = "yudao") + private String tableName; + + @Schema(description = "表描述,模糊匹配", example = "芋道") + private String tableComment; + + @Schema(description = "实体,模糊匹配", example = "Yudao") + private String className; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java new file mode 100644 index 0000000..604420e --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java @@ -0,0 +1,72 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo.table; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 代码生成表定义 Response VO") +@Data +public class CodegenTableRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer scene; + + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String tableName; + + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String tableComment; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system") + private String moduleName; + + @Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen") + private String businessName; + + @Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable") + private String className; + + @Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义") + private String classComment; + + @Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String author; + + @Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer templateType; + + @Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer frontType; + + @Schema(description = "父菜单编号", example = "1024") + private Long parentMenuId; + + @Schema(description = "主表的编号", example = "2048") + private Long masterTableId; + @Schema(description = "子表关联主表的字段编号", example = "4096") + private Long subJoinColumnId; + @Schema(description = "主表与子表是否一对多", example = "4096") + private Boolean subJoinMany; + + @Schema(description = "树表的父字段编号", example = "8192") + private Long treeParentColumnId; + @Schema(description = "树表的名字字段编号", example = "16384") + private Long treeNameColumnId; + + @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer dataSourceConfigId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java new file mode 100644 index 0000000..2204ab0 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java @@ -0,0 +1,104 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo.table; + +import cn.hutool.core.util.ObjectUtil; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 代码生成表定义创建/修改 Response VO") +@Data +public class CodegenTableSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "导入类型不能为空") + private Integer scene; + + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "表名称不能为空") + private String tableName; + + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "表描述不能为空") + private String tableComment; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system") + @NotNull(message = "模块名不能为空") + private String moduleName; + + @Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen") + @NotNull(message = "业务名不能为空") + private String businessName; + + @Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable") + @NotNull(message = "类名称不能为空") + private String className; + + @Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义") + @NotNull(message = "类描述不能为空") + private String classComment; + + @Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotNull(message = "作者不能为空") + private String author; + + @Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "模板类型不能为空") + private Integer templateType; + + @Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + @NotNull(message = "前端类型不能为空") + private Integer frontType; + + @Schema(description = "父菜单编号", example = "1024") + private Long parentMenuId; + + @Schema(description = "主表的编号", example = "2048") + private Long masterTableId; + @Schema(description = "子表关联主表的字段编号", example = "4096") + private Long subJoinColumnId; + @Schema(description = "主表与子表是否一对多", example = "4096") + private Boolean subJoinMany; + + @Schema(description = "树表的父字段编号", example = "8192") + private Long treeParentColumnId; + @Schema(description = "树表的名字字段编号", example = "16384") + private Long treeNameColumnId; + + @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段") + @JsonIgnore + public boolean isParentMenuIdValid() { + // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的 + return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene()) + || getParentMenuId() != null; + } + + @AssertTrue(message = "关联的父表信息不全") + @JsonIgnore + public boolean isSubValid() { + return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB) + || (ObjectUtil.isAllNotEmpty(masterTableId, subJoinColumnId, subJoinMany)); + } + + @AssertTrue(message = "关联的树表信息不全") + @JsonIgnore + public boolean isTreeValid() { + return ObjectUtil.notEqual(templateType, CodegenTemplateTypeEnum.TREE) + || (ObjectUtil.isAllNotEmpty(treeParentColumnId, treeNameColumnId)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/DatabaseTableRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/DatabaseTableRespVO.java new file mode 100644 index 0000000..8020306 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/codegen/vo/table/DatabaseTableRespVO.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.infra.controller.admin.codegen.vo.table; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 数据库的表定义 Response VO") +@Data +public class DatabaseTableRespVO { + + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yuanma") + private String name; + + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String comment; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/ConfigController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/ConfigController.java new file mode 100644 index 0000000..f72c8b6 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/ConfigController.java @@ -0,0 +1,109 @@ +package com.tashow.cloud.infra.controller.admin.config; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigPageReqVO; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigRespVO; +import com.tashow.cloud.infra.convert.config.ConfigConvert; +import com.tashow.cloud.infra.dal.dataobject.config.ConfigDO; +import com.tashow.cloud.infra.service.config.ConfigService; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigSaveReqVO; +import com.tashow.cloud.infraapi.enums.ErrorCodeConstants; +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; + + +@Tag(name = "管理后台 - 参数配置") +@RestController +@RequestMapping("/infra/config") +@Validated +public class ConfigController { + + @Resource + private ConfigService configService; + + @PostMapping("/create") + @Operation(summary = "创建参数配置") + @PreAuthorize("@ss.hasPermission('infra:config:create')") + public CommonResult createConfig(@Valid @RequestBody ConfigSaveReqVO createReqVO) { + return success(configService.createConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改参数配置") + @PreAuthorize("@ss.hasPermission('infra:config:update')") + public CommonResult updateConfig(@Valid @RequestBody ConfigSaveReqVO updateReqVO) { + configService.updateConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除参数配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:config:delete')") + public CommonResult deleteConfig(@RequestParam("id") Long id) { + configService.deleteConfig(id); + return success(true); + } + + @GetMapping(value = "/get") + @Operation(summary = "获得参数配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:config:query')") + public CommonResult getConfig(@RequestParam("id") Long id) { + return success(ConfigConvert.INSTANCE.convert(configService.getConfig(id))); + } + + @GetMapping(value = "/get-value-by-key") + @Operation(summary = "根据参数键名查询参数值", description = "不可见的配置,不允许返回给前端") + @Parameter(name = "key", description = "参数键", required = true, example = "yunai.biz.username") + public CommonResult getConfigKey(@RequestParam("key") String key) { + ConfigDO config = configService.getConfigByKey(key); + if (config == null) { + return success(null); + } + if (!config.getVisible()) { + throw exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_VISIBLE); + } + return success(config.getValue()); + } + + @GetMapping("/page") + @Operation(summary = "获取参数配置分页") + @PreAuthorize("@ss.hasPermission('infra:config:query')") + public CommonResult> getConfigPage(@Valid ConfigPageReqVO pageReqVO) { + PageResult page = configService.getConfigPage(pageReqVO); + return success(ConfigConvert.INSTANCE.convertPage(page)); + } + + @GetMapping("/export") + @Operation(summary = "导出参数配置") + @PreAuthorize("@ss.hasPermission('infra:config:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportConfig(ConfigPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = configService.getConfigPage(exportReqVO).getList(); + // 输出 + ExcelUtils.write(response, "参数配置.xls", "数据", ConfigRespVO.class, + ConfigConvert.INSTANCE.convertList(list)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigPageReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigPageReqVO.java new file mode 100644 index 0000000..c3994a1 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigPageReqVO.java @@ -0,0 +1,34 @@ +package com.tashow.cloud.infra.controller.admin.config.vo; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + + +@Schema(description = "管理后台 - 参数配置分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ConfigPageReqVO extends PageParam { + + @Schema(description = "数据源名称,模糊匹配", example = "名称") + private String name; + + @Schema(description = "参数键名,模糊匹配", example = "yunai.db.username") + private String key; + + @Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", example = "1") + private Integer type; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigRespVO.java new file mode 100644 index 0000000..42dc916 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigRespVO.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.infra.controller.admin.config.vo; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.infraapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 参数配置信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ConfigRespVO { + + @Schema(description = "参数配置序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("参数配置序号") + private Long id; + + @Schema(description = "参数分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "biz") + @ExcelProperty("参数分类") + private String category; + + @Schema(description = "参数名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "数据库名") + @ExcelProperty("参数名称") + private String name; + + @Schema(description = "参数键名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yunai.db.username") + @ExcelProperty("参数键名") + private String key; + + @Schema(description = "参数键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("参数键值") + private String value; + + @Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "参数类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.CONFIG_TYPE) + private Integer type; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否可见", converter = DictConvert.class) + @DictFormat(DictTypeConstants.BOOLEAN_STRING) + private Boolean visible; + + @Schema(description = "备注", example = "备注一下很帅气!") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigSaveReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigSaveReqVO.java new file mode 100644 index 0000000..dfc0cdc --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/config/vo/ConfigSaveReqVO.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.infra.controller.admin.config.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +@Schema(description = "管理后台 - 参数配置创建/修改 Request VO") +@Data +public class ConfigSaveReqVO { + + @Schema(description = "参数配置序号", example = "1024") + private Long id; + + @Schema(description = "参数分组", requiredMode = Schema.RequiredMode.REQUIRED, example = "biz") + @NotEmpty(message = "参数分组不能为空") + @Size(max = 50, message = "参数名称不能超过 50 个字符") + private String category; + + @Schema(description = "参数名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "数据库名") + @NotBlank(message = "参数名称不能为空") + @Size(max = 100, message = "参数名称不能超过 100 个字符") + private String name; + + @Schema(description = "参数键名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yunai.db.username") + @NotBlank(message = "参数键名长度不能为空") + @Size(max = 100, message = "参数键名长度不能超过 100 个字符") + private String key; + + @Schema(description = "参数键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotBlank(message = "参数键值不能为空") + @Size(max = 500, message = "参数键值长度不能超过 500 个字符") + private String value; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否可见不能为空") + private Boolean visible; + + @Schema(description = "备注", example = "备注一下很帅气!") + private String remark; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/DataSourceConfigController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/DataSourceConfigController.java new file mode 100644 index 0000000..251bf72 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/DataSourceConfigController.java @@ -0,0 +1,73 @@ +package com.tashow.cloud.infra.controller.admin.db; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.db.vo.DataSourceConfigRespVO; +import com.tashow.cloud.infra.controller.admin.db.vo.DataSourceConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.db.DataSourceConfigDO; +import com.tashow.cloud.infra.service.db.DataSourceConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + + +@Tag(name = "管理后台 - 数据源配置") +@RestController +@RequestMapping("/infra/data-source-config") +@Validated +public class DataSourceConfigController { + + @Resource + private DataSourceConfigService dataSourceConfigService; + + @PostMapping("/create") + @Operation(summary = "创建数据源配置") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:create')") + public CommonResult createDataSourceConfig(@Valid @RequestBody DataSourceConfigSaveReqVO createReqVO) { + return success(dataSourceConfigService.createDataSourceConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新数据源配置") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:update')") + public CommonResult updateDataSourceConfig(@Valid @RequestBody DataSourceConfigSaveReqVO updateReqVO) { + dataSourceConfigService.updateDataSourceConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除数据源配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:data-source-config:delete')") + public CommonResult deleteDataSourceConfig(@RequestParam("id") Long id) { + dataSourceConfigService.deleteDataSourceConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得数据源配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:query')") + public CommonResult getDataSourceConfig(@RequestParam("id") Long id) { + DataSourceConfigDO config = dataSourceConfigService.getDataSourceConfig(id); + return success(BeanUtils.toBean(config, DataSourceConfigRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得数据源配置列表") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:query')") + public CommonResult> getDataSourceConfigList() { + List list = dataSourceConfigService.getDataSourceConfigList(); + return success(BeanUtils.toBean(list, DataSourceConfigRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/vo/DataSourceConfigRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/vo/DataSourceConfigRespVO.java new file mode 100644 index 0000000..7e482d2 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/vo/DataSourceConfigRespVO.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.infra.controller.admin.db.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 数据源配置 Response VO") +@Data +public class DataSourceConfigRespVO { + + @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer id; + + @Schema(description = "数据源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + private String name; + + @Schema(description = "数据源连接", requiredMode = Schema.RequiredMode.REQUIRED, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro") + private String url; + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root") + private String username; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/vo/DataSourceConfigSaveReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/vo/DataSourceConfigSaveReqVO.java new file mode 100644 index 0000000..9948155 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/db/vo/DataSourceConfigSaveReqVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.infra.controller.admin.db.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 数据源配置创建/修改 Request VO") +@Data +public class DataSourceConfigSaveReqVO { + + @Schema(description = "主键编号", example = "1024") + private Long id; + + @Schema(description = "数据源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + @NotNull(message = "数据源名称不能为空") + private String name; + + @Schema(description = "数据源连接", requiredMode = Schema.RequiredMode.REQUIRED, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro") + @NotNull(message = "数据源连接不能为空") + private String url; + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root") + @NotNull(message = "用户名不能为空") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotNull(message = "密码不能为空") + private String password; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/Demo01ContactController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/Demo01ContactController.java new file mode 100644 index 0000000..d33b5e4 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/Demo01ContactController.java @@ -0,0 +1,93 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo01; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo01.vo.Demo01ContactRespVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo01.Demo01ContactDO; +import com.tashow.cloud.infra.service.demo.demo01.Demo01ContactService; +import com.tashow.cloud.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO; +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - 示例联系人") +@RestController +@RequestMapping("/infra/demo01-contact") +@Validated +public class Demo01ContactController { + + @Resource + private Demo01ContactService demo01ContactService; + + @PostMapping("/create") + @Operation(summary = "创建示例联系人") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:create')") + public CommonResult createDemo01Contact(@Valid @RequestBody Demo01ContactSaveReqVO createReqVO) { + return success(demo01ContactService.createDemo01Contact(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新示例联系人") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:update')") + public CommonResult updateDemo01Contact(@Valid @RequestBody Demo01ContactSaveReqVO updateReqVO) { + demo01ContactService.updateDemo01Contact(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除示例联系人") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:delete')") + public CommonResult deleteDemo01Contact(@RequestParam("id") Long id) { + demo01ContactService.deleteDemo01Contact(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得示例联系人") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:query')") + public CommonResult getDemo01Contact(@RequestParam("id") Long id) { + Demo01ContactDO demo01Contact = demo01ContactService.getDemo01Contact(id); + return success(BeanUtils.toBean(demo01Contact, Demo01ContactRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得示例联系人分页") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:query')") + public CommonResult> getDemo01ContactPage(@Valid Demo01ContactPageReqVO pageReqVO) { + PageResult pageResult = demo01ContactService.getDemo01ContactPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, Demo01ContactRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出示例联系人 Excel") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDemo01ContactExcel(@Valid Demo01ContactPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = demo01ContactService.getDemo01ContactPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "示例联系人.xls", "数据", Demo01ContactRespVO.class, + BeanUtils.toBean(list, Demo01ContactRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactPageReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactPageReqVO.java new file mode 100644 index 0000000..f063d14 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactPageReqVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo01.vo; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + + +@Schema(description = "管理后台 - 示例联系人分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class Demo01ContactPageReqVO extends PageParam { + + @Schema(description = "名字", example = "张三") + private String name; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactRespVO.java new file mode 100644 index 0000000..db1683b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactRespVO.java @@ -0,0 +1,46 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo01.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 示例联系人 Response VO") +@Data +@ExcelIgnoreUnannotated +public class Demo01ContactRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21555") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @ExcelProperty("名字") + private String name; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "出生年", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生年") + private LocalDateTime birthday; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") + @ExcelProperty("简介") + private String description; + + @Schema(description = "头像") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactSaveReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactSaveReqVO.java new file mode 100644 index 0000000..0e6e639 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo01/vo/Demo01ContactSaveReqVO.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo01.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 示例联系人新增/修改 Request VO") +@Data +public class Demo01ContactSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21555") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "出生年", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生年不能为空") + private LocalDateTime birthday; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "头像") + private String avatar; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/Demo02CategoryController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/Demo02CategoryController.java new file mode 100644 index 0000000..642f767 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/Demo02CategoryController.java @@ -0,0 +1,90 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo02; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.infra.dal.dataobject.demo.demo02.Demo02CategoryDO; +import com.tashow.cloud.infra.service.demo.demo02.Demo02CategoryService; +import com.tashow.cloud.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo02.vo.Demo02CategoryRespVO; +import com.tashow.cloud.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO; +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 示例分类") +@RestController +@RequestMapping("/infra/demo02-category") +@Validated +public class Demo02CategoryController { + + @Resource + private Demo02CategoryService demo02CategoryService; + + @PostMapping("/create") + @Operation(summary = "创建示例分类") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:create')") + public CommonResult createDemo02Category(@Valid @RequestBody Demo02CategorySaveReqVO createReqVO) { + return success(demo02CategoryService.createDemo02Category(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新示例分类") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:update')") + public CommonResult updateDemo02Category(@Valid @RequestBody Demo02CategorySaveReqVO updateReqVO) { + demo02CategoryService.updateDemo02Category(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除示例分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo02-category:delete')") + public CommonResult deleteDemo02Category(@RequestParam("id") Long id) { + demo02CategoryService.deleteDemo02Category(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得示例分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:query')") + public CommonResult getDemo02Category(@RequestParam("id") Long id) { + Demo02CategoryDO demo02Category = demo02CategoryService.getDemo02Category(id); + return success(BeanUtils.toBean(demo02Category, Demo02CategoryRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得示例分类列表") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:query')") + public CommonResult> getDemo02CategoryList(@Valid Demo02CategoryListReqVO listReqVO) { + List list = demo02CategoryService.getDemo02CategoryList(listReqVO); + return success(BeanUtils.toBean(list, Demo02CategoryRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出示例分类 Excel") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDemo02CategoryExcel(@Valid Demo02CategoryListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List list = demo02CategoryService.getDemo02CategoryList(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "示例分类.xls", "数据", Demo02CategoryRespVO.class, + BeanUtils.toBean(list, Demo02CategoryRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategoryListReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategoryListReqVO.java new file mode 100644 index 0000000..4e532d7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategoryListReqVO.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo02.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 示例分类列表 Request VO") +@Data +public class Demo02CategoryListReqVO { + + @Schema(description = "名字", example = "芋艿") + private String name; + + @Schema(description = "父级编号", example = "6080") + private Long parentId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategoryRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategoryRespVO.java new file mode 100644 index 0000000..5a623e5 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategoryRespVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo02.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 示例分类 Response VO") +@Data +@ExcelIgnoreUnannotated +public class Demo02CategoryRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10304") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("名字") + private String name; + + @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6080") + @ExcelProperty("父级编号") + private Long parentId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategorySaveReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategorySaveReqVO.java new file mode 100644 index 0000000..02cfe29 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo02/vo/Demo02CategorySaveReqVO.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo02.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 示例分类新增/修改 Request VO") +@Data +public class Demo02CategorySaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10304") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6080") + @NotNull(message = "父级编号不能为空") + private Long parentId; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/Demo03StudentController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/Demo03StudentController.java new file mode 100644 index 0000000..5b3ae53 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/Demo03StudentController.java @@ -0,0 +1,211 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo03; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentRespVO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import com.tashow.cloud.infra.service.demo.demo03.Demo03StudentService; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentRespVO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import com.tashow.cloud.infra.service.demo.demo03.Demo03StudentService; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentRespVO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import com.tashow.cloud.infra.service.demo.demo03.Demo03StudentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/demo03-student") +@Validated +public class Demo03StudentController { + + @Resource + private Demo03StudentService demo03StudentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')") + public CommonResult createDemo03Student(@Valid @RequestBody Demo03StudentSaveReqVO createReqVO) { + return success(demo03StudentService.createDemo03Student(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')") + public CommonResult updateDemo03Student(@Valid @RequestBody Demo03StudentSaveReqVO updateReqVO) { + demo03StudentService.updateDemo03Student(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')") + public CommonResult deleteDemo03Student(@RequestParam("id") Long id) { + demo03StudentService.deleteDemo03Student(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult getDemo03Student(@RequestParam("id") Long id) { + Demo03StudentDO demo03Student = demo03StudentService.getDemo03Student(id); + return success(BeanUtils.toBean(demo03Student, Demo03StudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult> getDemo03StudentPage(@Valid Demo03StudentPageReqVO pageReqVO) { + PageResult pageResult = demo03StudentService.getDemo03StudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, Demo03StudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDemo03StudentExcel(@Valid Demo03StudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = demo03StudentService.getDemo03StudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", Demo03StudentRespVO.class, + BeanUtils.toBean(list, Demo03StudentRespVO.class)); + } + + // ==================== 子表(学生课程) ==================== + + @GetMapping("/demo03-course/page") + @Operation(summary = "获得学生课程分页") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult> getDemo03CoursePage(PageParam pageReqVO, + @RequestParam("studentId") Long studentId) { + return success(demo03StudentService.getDemo03CoursePage(pageReqVO, studentId)); + } + + @PostMapping("/demo03-course/create") + @Operation(summary = "创建学生课程") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')") + public CommonResult createDemo03Course(@Valid @RequestBody Demo03CourseDO demo03Course) { + return success(demo03StudentService.createDemo03Course(demo03Course)); + } + + @PutMapping("/demo03-course/update") + @Operation(summary = "更新学生课程") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')") + public CommonResult updateDemo03Course(@Valid @RequestBody Demo03CourseDO demo03Course) { + demo03StudentService.updateDemo03Course(demo03Course); + return success(true); + } + + @DeleteMapping("/demo03-course/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除学生课程") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')") + public CommonResult deleteDemo03Course(@RequestParam("id") Long id) { + demo03StudentService.deleteDemo03Course(id); + return success(true); + } + + @GetMapping("/demo03-course/get") + @Operation(summary = "获得学生课程") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult getDemo03Course(@RequestParam("id") Long id) { + return success(demo03StudentService.getDemo03Course(id)); + } + + @GetMapping("/demo03-course/list-by-student-id") + @Operation(summary = "获得学生课程列表") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult> getDemo03CourseListByStudentId(@RequestParam("studentId") Long studentId) { + return success(demo03StudentService.getDemo03CourseListByStudentId(studentId)); + } + + // ==================== 子表(学生班级) ==================== + + @GetMapping("/demo03-grade/page") + @Operation(summary = "获得学生班级分页") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult> getDemo03GradePage(PageParam pageReqVO, + @RequestParam("studentId") Long studentId) { + return success(demo03StudentService.getDemo03GradePage(pageReqVO, studentId)); + } + + @PostMapping("/demo03-grade/create") + @Operation(summary = "创建学生班级") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')") + public CommonResult createDemo03Grade(@Valid @RequestBody Demo03GradeDO demo03Grade) { + return success(demo03StudentService.createDemo03Grade(demo03Grade)); + } + + @PutMapping("/demo03-grade/update") + @Operation(summary = "更新学生班级") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')") + public CommonResult updateDemo03Grade(@Valid @RequestBody Demo03GradeDO demo03Grade) { + demo03StudentService.updateDemo03Grade(demo03Grade); + return success(true); + } + + @DeleteMapping("/demo03-grade/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除学生班级") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')") + public CommonResult deleteDemo03Grade(@RequestParam("id") Long id) { + demo03StudentService.deleteDemo03Grade(id); + return success(true); + } + + @GetMapping("/demo03-grade/get") + @Operation(summary = "获得学生班级") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult getDemo03Grade(@RequestParam("id") Long id) { + return success(demo03StudentService.getDemo03Grade(id)); + } + + @GetMapping("/demo03-grade/get-by-student-id") + @Operation(summary = "获得学生班级") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult getDemo03GradeByStudentId(@RequestParam("studentId") Long studentId) { + return success(demo03StudentService.getDemo03GradeByStudentId(studentId)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/package-info.java new file mode 100644 index 0000000..73e213f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/package-info.java @@ -0,0 +1 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo03; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentPageReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentPageReqVO.java new file mode 100644 index 0000000..3bebca6 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentPageReqVO.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo03.vo; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class Demo03StudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋艿") + private String name; + + @Schema(description = "性别") + private Integer sex; + + @Schema(description = "简介", example = "随便") + private String description; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentRespVO.java new file mode 100644 index 0000000..c0c6007 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentRespVO.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo03.vo; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class Demo03StudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8525") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("名字") + private String name; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "随便") + @ExcelProperty("简介") + private String description; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentSaveReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentSaveReqVO.java new file mode 100644 index 0000000..03cb151 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/demo03/vo/Demo03StudentSaveReqVO.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.infra.controller.admin.demo.demo03.vo; + +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class Demo03StudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8525") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "随便") + @NotEmpty(message = "简介不能为空") + private String description; + + + private List demo03Courses; + + private Demo03GradeDO demo03Grade; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/package-info.java new file mode 100644 index 0000000..0afb225 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/demo/package-info.java @@ -0,0 +1,8 @@ +/** + * 代码生成示例 + * + * 1. demo01:单表(增删改查) + * 2. demo02:单表(树形结构) + * 3. demo03:主子表(标准模式)+ 主子表(ERP 模式)+ 主子表(内嵌模式) + */ +package com.tashow.cloud.infra.controller.admin.demo; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileConfigController.http b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileConfigController.http new file mode 100644 index 0000000..14b6228 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileConfigController.http @@ -0,0 +1,45 @@ +### 请求 /infra/file-config/create 接口 => 成功 +POST {{baseUrl}}/infra/file-config/create +Content-Type: application/json +tenant-id: {{adminTenantId}} +Authorization: Bearer {{token}} + +{ + "name": "S3 - 七牛云", + "remark": "", + "storage": 20, + "config": { + "accessKey": "b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8", + "accessSecret": "kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP", + "bucket": "ruoyi-vue-pro", + "endpoint": "s3-cn-south-1.qiniucs.com", + "domain": "http://test.yudao.iocoder.cn", + "region": "oss-cn-beijing" + } +} + +### 请求 /infra/file-config/update 接口 => 成功 +PUT {{baseUrl}}/infra/file-config/update +Content-Type: application/json +tenant-id: {{adminTenantId}} +Authorization: Bearer {{token}} + +{ + "id": 2, + "name": "S3 - 七牛云", + "remark": "", + "config": { + "accessKey": "b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8", + "accessSecret": "kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP", + "bucket": "ruoyi-vue-pro", + "endpoint": "s3-cn-south-1.qiniucs.com", + "domain": "http://test.yudao.iocoder.cn", + "region": "oss-cn-beijing" + } +} + +### 请求 /infra/file-config/test 接口 => 成功 +GET {{baseUrl}}/infra/file-config/test?id=2 +Content-Type: application/json +tenant-id: {{adminTenantId}} +Authorization: Bearer {{token}} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileConfigController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileConfigController.java new file mode 100644 index 0000000..f0efff1 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileConfigController.java @@ -0,0 +1,92 @@ +package com.tashow.cloud.infra.controller.admin.file; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; +import com.tashow.cloud.infra.service.file.FileConfigService; +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigRespVO; +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; +import com.tashow.cloud.infra.service.file.FileConfigService; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; +import com.tashow.cloud.infra.service.file.FileConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 文件配置") +@RestController +@RequestMapping("/infra/file-config") +@Validated +public class FileConfigController { + + @Resource + private FileConfigService fileConfigService; + + @PostMapping("/create") + @Operation(summary = "创建文件配置") + @PreAuthorize("@ss.hasPermission('infra:file-config:create')") + public CommonResult createFileConfig(@Valid @RequestBody FileConfigSaveReqVO createReqVO) { + return success(fileConfigService.createFileConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新文件配置") + @PreAuthorize("@ss.hasPermission('infra:file-config:update')") + public CommonResult updateFileConfig(@Valid @RequestBody FileConfigSaveReqVO updateReqVO) { + fileConfigService.updateFileConfig(updateReqVO); + return success(true); + } + + @PutMapping("/update-master") + @Operation(summary = "更新文件配置为 Master") + @PreAuthorize("@ss.hasPermission('infra:file-config:update')") + public CommonResult updateFileConfigMaster(@RequestParam("id") Long id) { + fileConfigService.updateFileConfigMaster(id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除文件配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:file-config:delete')") + public CommonResult deleteFileConfig(@RequestParam("id") Long id) { + fileConfigService.deleteFileConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得文件配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") + public CommonResult getFileConfig(@RequestParam("id") Long id) { + FileConfigDO config = fileConfigService.getFileConfig(id); + return success(BeanUtils.toBean(config, FileConfigRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得文件配置分页") + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") + public CommonResult> getFileConfigPage(@Valid FileConfigPageReqVO pageVO) { + PageResult pageResult = fileConfigService.getFileConfigPage(pageVO); + return success(BeanUtils.toBean(pageResult, FileConfigRespVO.class)); + } + + @GetMapping("/test") + @Operation(summary = "测试文件配置是否正确") + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") + public CommonResult testFileConfig(@RequestParam("id") Long id) throws Exception { + String url = fileConfigService.testFileConfig(id); + return success(url); + } +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileController.java new file mode 100644 index 0000000..94a68e5 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/FileController.java @@ -0,0 +1,102 @@ +package com.tashow.cloud.infra.controller.admin.file; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.file.vo.file.*; +import com.tashow.cloud.infra.dal.dataobject.file.FileDO; +import com.tashow.cloud.infra.service.file.FileService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.infra.framework.file.core.utils.FileTypeUtils.writeAttachment; + +@Tag(name = "管理后台 - 文件存储") +@RestController +@RequestMapping("/infra/file") +@Validated +@Slf4j +public class FileController { + + @Resource + private FileService fileService; + + @PostMapping("/upload") + @Operation(summary = "上传文件", description = "模式一:后端上传文件") + public CommonResult uploadFile(FileUploadReqVO uploadReqVO) throws Exception { + MultipartFile file = uploadReqVO.getFile(); + String path = uploadReqVO.getPath(); + return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream()))); + } + + @GetMapping("/presigned-url") + @Operation(summary = "获取文件预签名地址", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器") + public CommonResult getFilePresignedUrl(@RequestParam("path") String path) throws Exception { + return success(fileService.getFilePresignedUrl(path)); + } + + @PostMapping("/create") + @Operation(summary = "创建文件", description = "模式二:前端上传文件:配合 presigned-url 接口,记录上传了上传的文件") + public CommonResult createFile(@Valid @RequestBody FileCreateReqVO createReqVO) { + return success(fileService.createFile(createReqVO)); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除文件") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:file:delete')") + public CommonResult deleteFile(@RequestParam("id") Long id) throws Exception { + fileService.deleteFile(id); + return success(true); + } + + @GetMapping("/{configId}/get/**") + @PermitAll + @Operation(summary = "下载文件") + @Parameter(name = "configId", description = "配置编号", required = true) + public void getFileContent(HttpServletRequest request, + HttpServletResponse response, + @PathVariable("configId") Long configId) throws Exception { + // 获取请求的路径 + String path = StrUtil.subAfter(request.getRequestURI(), "/get/", false); + if (StrUtil.isEmpty(path)) { + throw new IllegalArgumentException("结尾的 path 路径必须传递"); + } + // 解码,解决中文路径的问题 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/ + path = URLUtil.decode(path); + + // 读取内容 + byte[] content = fileService.getFileContent(configId, path); + if (content == null) { + log.warn("[getFileContent][configId({}) path({}) 文件不存在]", configId, path); + response.setStatus(HttpStatus.NOT_FOUND.value()); + return; + } + writeAttachment(response, path, content); + } + + @GetMapping("/page") + @Operation(summary = "获得文件分页") + @PreAuthorize("@ss.hasPermission('infra:file:query')") + public CommonResult> getFilePage(@Valid FilePageReqVO pageVO) { + PageResult pageResult = fileService.getFilePage(pageVO); + return success(BeanUtils.toBean(pageResult, FileRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java new file mode 100644 index 0000000..cd841b7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.infra.controller.admin.file.vo.config; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 文件配置分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class FileConfigPageReqVO extends PageParam { + + @Schema(description = "配置名", example = "S3 - 阿里云") + private String name; + + @Schema(description = "存储器", example = "1") + private Integer storage; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigRespVO.java new file mode 100644 index 0000000..430b844 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigRespVO.java @@ -0,0 +1,34 @@ +package com.tashow.cloud.infra.controller.admin.file.vo.config; + +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 文件配置 Response VO") +@Data +public class FileConfigRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云") + private String name; + + @Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer storage; + + @Schema(description = "是否为主配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean master; + + @Schema(description = "存储配置", requiredMode = Schema.RequiredMode.REQUIRED) + private FileClientConfig config; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigSaveReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigSaveReqVO.java new file mode 100644 index 0000000..1fdd35d --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/config/FileConfigSaveReqVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.infra.controller.admin.file.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 文件配置创建/修改 Request VO") +@Data +public class FileConfigSaveReqVO { + + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云") + @NotNull(message = "配置名不能为空") + private String name; + + @Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "存储器不能为空") + private Integer storage; + + @Schema(description = "存储配置,配置是动态参数,所以使用 Map 接收", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "存储配置不能为空") + private Map config; + + @Schema(description = "备注", example = "我是备注") + private String remark; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileCreateReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileCreateReqVO.java new file mode 100644 index 0000000..138140f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileCreateReqVO.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - 文件创建 Request VO") +@Data +public class FileCreateReqVO { + + @NotNull(message = "文件配置编号不能为空") + @Schema(description = "文件配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11") + private Long configId; + + @NotNull(message = "文件路径不能为空") + @Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg") + private String path; + + @NotNull(message = "原文件名不能为空") + @Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg") + private String name; + + @NotNull(message = "文件 URL不能为空") + @Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg") + private String url; + + @Schema(description = "文件 MIME 类型", example = "application/octet-stream") + private String type; + + @Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer size; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FilePageReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FilePageReqVO.java new file mode 100644 index 0000000..9abc3e5 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FilePageReqVO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.infra.controller.admin.file.vo.file; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 文件分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class FilePageReqVO extends PageParam { + + @Schema(description = "文件路径,模糊匹配", example = "yudao") + private String path; + + @Schema(description = "文件类型,模糊匹配", example = "jpg") + private String type; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FilePresignedUrlRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FilePresignedUrlRespVO.java new file mode 100644 index 0000000..866da64 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FilePresignedUrlRespVO.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "管理后台 - 文件预签名地址 Response VO") +@Data +public class FilePresignedUrlRespVO { + + @Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11") + private Long configId; + + @Schema(description = "文件上传 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://s3.cn-south-1.qiniucs.com/ruoyi-vue-pro/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS%2F20240217%2Fcn-south-1%2Fs3%2Faws4_request&X-Amz-Date=20240217T123222Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=a29f33770ab79bf523ccd4034d0752ac545f3c2a3b17baa1eb4e280cfdccfda5") + private String uploadUrl; + + /** + * 为什么要返回 url 字段? + * + * 前端上传完文件后,需要使用该 URL 进行访问 + */ + @Schema(description = "文件访问 URL", requiredMode = Schema.RequiredMode.REQUIRED, + example = "https://test.yudao.iocoder.cn/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png") + private String url; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileRespVO.java new file mode 100644 index 0000000..24a09ec --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileRespVO.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 文件 Response VO,不返回 content 字段,太大") +@Data +public class FileRespVO { + + @Schema(description = "文件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11") + private Long configId; + + @Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg") + private String path; + + @Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg") + private String name; + + @Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg") + private String url; + + @Schema(description = "文件MIME类型", example = "application/octet-stream") + private String type; + + @Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer size; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileUploadReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileUploadReqVO.java new file mode 100644 index 0000000..71e21a9 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/file/vo/file/FileUploadReqVO.java @@ -0,0 +1,20 @@ +package com.tashow.cloud.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 上传文件 Request VO") +@Data +public class FileUploadReqVO { + + @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "文件附件不能为空") + private MultipartFile file; + + @Schema(description = "文件附件", example = "yudaoyuanma.png") + private String path; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/job/JobController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/job/JobController.java new file mode 100644 index 0000000..6af6118 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/job/JobController.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.infra.controller.admin.job; + +import com.tashow.cloud.common.pojo.CommonResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static com.tashow.cloud.common.pojo.CommonResult.error; + + +@Tag(name = "管理后台 - 定时任务") +@RestController +@RequestMapping("/infra/job") +@Validated +public class JobController { + + @GetMapping("/page") + @Operation(summary = "获得定时任务分页") + @PreAuthorize("@ss.hasPermission('infra:job:query')") + public CommonResult getJobPage() { + return error(-1, "Cloud 版本使用 XXL-Job 作为定时任务!请参考 https://cloud.iocoder.cn/job/ 文档操作"); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/ApiAccessLogController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/ApiAccessLogController.java new file mode 100644 index 0000000..17096d7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/ApiAccessLogController.java @@ -0,0 +1,68 @@ +package com.tashow.cloud.infra.controller.admin.logger; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import com.tashow.cloud.infra.service.logger.ApiAccessLogService; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import com.tashow.cloud.infra.service.logger.ApiAccessLogService; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import com.tashow.cloud.infra.service.logger.ApiAccessLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - API 访问日志") +@RestController +@RequestMapping("/infra/api-access-log") +@Validated +public class ApiAccessLogController { + + @Resource + private ApiAccessLogService apiAccessLogService; + + @GetMapping("/page") + @Operation(summary = "获得API 访问日志分页") + @PreAuthorize("@ss.hasPermission('infra:api-access-log:query')") + public CommonResult> getApiAccessLogPage(@Valid ApiAccessLogPageReqVO pageReqVO) { + PageResult pageResult = apiAccessLogService.getApiAccessLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ApiAccessLogRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出API 访问日志 Excel") + @PreAuthorize("@ss.hasPermission('infra:api-access-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportApiAccessLogExcel(@Valid ApiAccessLogPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = apiAccessLogService.getApiAccessLogPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "API 访问日志.xls", "数据", ApiAccessLogRespVO.class, + BeanUtils.toBean(list, ApiAccessLogRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/ApiErrorLogController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/ApiErrorLogController.java new file mode 100644 index 0000000..b0e0929 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/ApiErrorLogController.java @@ -0,0 +1,74 @@ +package com.tashow.cloud.infra.controller.admin.logger; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiErrorLogDO; +import com.tashow.cloud.infra.service.logger.ApiErrorLogService; +import com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - API 错误日志") +@RestController +@RequestMapping("/infra/api-error-log") +@Validated +public class ApiErrorLogController { + + @Resource + private ApiErrorLogService apiErrorLogService; + + @PutMapping("/update-status") + @Operation(summary = "更新 API 错误日志的状态") + @Parameters({ + @Parameter(name = "id", description = "编号", required = true, example = "1024"), + @Parameter(name = "processStatus", description = "处理状态", required = true, example = "1") + }) + @PreAuthorize("@ss.hasPermission('infra:api-error-log:update-status')") + public CommonResult updateApiErrorLogProcess(@RequestParam("id") Long id, + @RequestParam("processStatus") Integer processStatus) { + apiErrorLogService.updateApiErrorLogProcess(id, processStatus, getLoginUserId()); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得 API 错误日志分页") + @PreAuthorize("@ss.hasPermission('infra:api-error-log:query')") + public CommonResult> getApiErrorLogPage(@Valid ApiErrorLogPageReqVO pageReqVO) { + PageResult pageResult = apiErrorLogService.getApiErrorLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ApiErrorLogRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出 API 错误日志 Excel") + @PreAuthorize("@ss.hasPermission('infra:api-error-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportApiErrorLogExcel(@Valid ApiErrorLogPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = apiErrorLogService.getApiErrorLogPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "API 错误日志.xls", "数据", ApiErrorLogRespVO.class, + BeanUtils.toBean(list, ApiErrorLogRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java new file mode 100644 index 0000000..db048bf --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - API 访问日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ApiAccessLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "666") + private Long userId; + + @Schema(description = "用户类型", example = "2") + private Integer userType; + + @Schema(description = "应用名", example = "dashboard") + private String applicationName; + + @Schema(description = "请求地址,模糊匹配", example = "/xxx/yyy") + private String requestUrl; + + @Schema(description = "开始时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] beginTime; + + @Schema(description = "执行时长,大于等于,单位:毫秒", example = "100") + private Integer duration; + + @Schema(description = "结果码", example = "0") + private Integer resultCode; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogRespVO.java new file mode 100644 index 0000000..3dd8752 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogRespVO.java @@ -0,0 +1,99 @@ +package com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - API 访问日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ApiAccessLogRespVO { + + @Schema(description = "日志主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("日志主键") + private Long id; + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "66600cb6-7852-11eb-9439-0242ac130002") + @ExcelProperty("链路追踪编号") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + @ExcelProperty("用户编号") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty(value = "用户类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.USER_TYPE) + private Integer userType; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard") + @ExcelProperty("应用名") + private String applicationName; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @ExcelProperty("请求方法名") + private String requestMethod; + + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy") + @ExcelProperty("请求地址") + private String requestUrl; + + @Schema(description = "请求参数") + @ExcelProperty("请求参数") + private String requestParams; + + @Schema(description = "响应结果") + @ExcelProperty("响应结果") + private String responseBody; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @ExcelProperty("用户 IP") + private String userIp; + + @Schema(description = "浏览器 UA", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + @ExcelProperty("浏览器 UA") + private String userAgent; + + @Schema(description = "操作模块", requiredMode = Schema.RequiredMode.REQUIRED, example = "商品模块") + @ExcelProperty("操作模块") + private String operateModule; + + @Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建商品") + @ExcelProperty("操作名") + private String operateName; + + @Schema(description = "操作分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "操作分类", converter = DictConvert.class) + @DictFormat(com.tashow.cloud.infraapi.enums.DictTypeConstants.OPERATE_TYPE) + private Integer operateType; + + @Schema(description = "开始请求时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("开始请求时间") + private LocalDateTime beginTime; + + @Schema(description = "结束请求时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("结束请求时间") + private LocalDateTime endTime; + + @Schema(description = "执行时长", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @ExcelProperty("执行时长") + private Integer duration; + + @Schema(description = "结果码", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty("结果码") + private Integer resultCode; + + @Schema(description = "结果提示", example = "芋道源码,牛逼!") + @ExcelProperty("结果提示") + private String resultMsg; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java new file mode 100644 index 0000000..fbb7376 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - API 错误日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ApiErrorLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "666") + private Long userId; + + @Schema(description = "用户类型", example = "1") + private Integer userType; + + @Schema(description = "应用名", example = "dashboard") + private String applicationName; + + @Schema(description = "请求地址", example = "/xx/yy") + private String requestUrl; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "异常发生时间") + private LocalDateTime[] exceptionTime; + + @Schema(description = "处理状态", example = "0") + private Integer processStatus; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogRespVO.java new file mode 100644 index 0000000..1796a72 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogRespVO.java @@ -0,0 +1,113 @@ +package com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.infraapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.infraapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - API 错误日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ApiErrorLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "66600cb6-7852-11eb-9439-0242ac130002") + @ExcelProperty("链路追踪编号") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + @ExcelProperty("用户编号") + private Long userId; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "用户类型", converter = DictConvert.class) + @DictFormat(com.tashow.cloud.systemapi.enums.DictTypeConstants.USER_TYPE) + private Integer userType; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard") + @ExcelProperty("应用名") + private String applicationName; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @ExcelProperty("请求方法名") + private String requestMethod; + + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xx/yy") + @ExcelProperty("请求地址") + private String requestUrl; + + @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("请求参数") + private String requestParams; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @ExcelProperty("用户 IP") + private String userIp; + + @Schema(description = "浏览器 UA", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + @ExcelProperty("浏览器 UA") + private String userAgent; + + @Schema(description = "异常发生时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生时间") + private LocalDateTime exceptionTime; + + @Schema(description = "异常名", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常名") + private String exceptionName; + + @Schema(description = "异常导致的消息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常导致的消息") + private String exceptionMessage; + + @Schema(description = "异常导致的根消息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常导致的根消息") + private String exceptionRootCauseMessage; + + @Schema(description = "异常的栈轨迹", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常的栈轨迹") + private String exceptionStackTrace; + + @Schema(description = "异常发生的类全名", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生的类全名") + private String exceptionClassName; + + @Schema(description = "异常发生的类文件", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生的类文件") + private String exceptionFileName; + + @Schema(description = "异常发生的方法名", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生的方法名") + private String exceptionMethodName; + + @Schema(description = "异常发生的方法所在行", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生的方法所在行") + private Integer exceptionLineNumber; + + @Schema(description = "处理状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty(value = "处理状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.API_ERROR_LOG_PROCESS_STATUS) + private Integer processStatus; + + @Schema(description = "处理时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("处理时间") + private LocalDateTime processTime; + + @Schema(description = "处理用户编号", example = "233") + @ExcelProperty("处理用户编号") + private Integer processUserId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/RedisController.http b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/RedisController.http new file mode 100644 index 0000000..68b5487 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/RedisController.http @@ -0,0 +1,4 @@ +### 请求 /infra/redis/get-monitor-info 接口 => 成功 +GET {{baseUrl}}/infra/redis/get-monitor-info +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/RedisController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/RedisController.java new file mode 100644 index 0000000..5cb9b31 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/RedisController.java @@ -0,0 +1,47 @@ +package com.tashow.cloud.infra.controller.admin.redis; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infra.controller.admin.redis.vo.RedisMonitorRespVO; +import com.tashow.cloud.infra.convert.redis.RedisConvert; +import com.tashow.cloud.infra.controller.admin.redis.vo.RedisMonitorRespVO; +import com.tashow.cloud.infra.convert.redis.RedisConvert; +import com.tashow.cloud.infra.controller.admin.redis.vo.RedisMonitorRespVO; +import com.tashow.cloud.infra.convert.redis.RedisConvert; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.data.redis.connection.RedisServerCommands; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import java.util.Properties; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - Redis 监控") +@RestController +@RequestMapping("/infra/redis") +public class RedisController { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + @GetMapping("/get-monitor-info") + @Operation(summary = "获得 Redis 监控信息") + @PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')") + public CommonResult getRedisMonitorInfo() { + // 获得 Redis 统计信息 + Properties info = stringRedisTemplate.execute((RedisCallback) RedisServerCommands::info); + Long dbSize = stringRedisTemplate.execute(RedisServerCommands::dbSize); + Properties commandStats = stringRedisTemplate.execute(( + RedisCallback) connection -> connection.serverCommands().info("commandstats")); + assert commandStats != null; // 断言,避免警告 + // 拼接结果返回 + return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/vo/RedisMonitorRespVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/vo/RedisMonitorRespVO.java new file mode 100644 index 0000000..802d374 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/admin/redis/vo/RedisMonitorRespVO.java @@ -0,0 +1,43 @@ +package com.tashow.cloud.infra.controller.admin.redis.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Properties; + +@Schema(description = "管理后台 - Redis 监控信息 Response VO") +@Data +@Builder +@AllArgsConstructor +public class RedisMonitorRespVO { + + @Schema(description = "Redis info 指令结果,具体字段,查看 Redis 文档", requiredMode = Schema.RequiredMode.REQUIRED) + private Properties info; + + @Schema(description = "Redis key 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long dbSize; + + @Schema(description = "CommandStat 数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List commandStats; + + @Schema(description = "Redis 命令统计结果") + @Data + @Builder + @AllArgsConstructor + public static class CommandStat { + + @Schema(description = "Redis 命令", requiredMode = Schema.RequiredMode.REQUIRED, example = "get") + private String command; + + @Schema(description = "调用次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long calls; + + @Schema(description = "消耗 CPU 秒数", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Long usec; + + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/file/AppFileController.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/file/AppFileController.java new file mode 100644 index 0000000..6fada29 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/file/AppFileController.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.infra.controller.app.file; + +import cn.hutool.core.io.IoUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.infra.service.file.FileService; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FileCreateReqVO; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO; +import com.tashow.cloud.infra.controller.app.file.vo.AppFileUploadReqVO; +import com.tashow.cloud.infra.service.file.FileService; +import com.tashow.cloud.infra.service.file.FileService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 文件存储") +@RestController +@RequestMapping("/infra/file") +@Validated +@Slf4j +public class AppFileController { + + @Resource + private FileService fileService; + + @PostMapping("/upload") + @Operation(summary = "上传文件") + @PermitAll + public CommonResult uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception { + MultipartFile file = uploadReqVO.getFile(); + String path = uploadReqVO.getPath(); + return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream()))); + } + + @GetMapping("/presigned-url") + @Operation(summary = "获取文件预签名地址", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器") + @PermitAll + public CommonResult getFilePresignedUrl(@RequestParam("path") String path) throws Exception { + return success(fileService.getFilePresignedUrl(path)); + } + + @PostMapping("/create") + @Operation(summary = "创建文件", description = "模式二:前端上传文件:配合 presigned-url 接口,记录上传了上传的文件") + @PermitAll + public CommonResult createFile(@Valid @RequestBody FileCreateReqVO createReqVO) { + return success(fileService.createFile(createReqVO)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/file/vo/AppFileUploadReqVO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/file/vo/AppFileUploadReqVO.java new file mode 100644 index 0000000..5a8f788 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/file/vo/AppFileUploadReqVO.java @@ -0,0 +1,20 @@ +package com.tashow.cloud.infra.controller.app.file.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.validation.constraints.NotNull; + +@Schema(description = "用户 App - 上传文件 Request VO") +@Data +public class AppFileUploadReqVO { + + @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "文件附件不能为空") + private MultipartFile file; + + @Schema(description = "文件附件", example = "yudaoyuanma.png") + private String path; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/package-info.java new file mode 100644 index 0000000..e3cb81c --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/app/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package com.tashow.cloud.infra.controller.app; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/package-info.java new file mode 100644 index 0000000..149a690 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package com.tashow.cloud.infra.controller; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/codegen/CodegenConvert.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/codegen/CodegenConvert.java new file mode 100644 index 0000000..c8d8285 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/codegen/CodegenConvert.java @@ -0,0 +1,68 @@ +package com.tashow.cloud.infra.convert.codegen; + +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenDetailRespVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenPreviewRespVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTableRespVO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import org.apache.ibatis.type.JdbcType; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface CodegenConvert { + + CodegenConvert INSTANCE = Mappers.getMapper(CodegenConvert.class); + + // ========== TableInfo 相关 ========== + + @Mappings({ + @Mapping(source = "name", target = "tableName"), + @Mapping(source = "comment", target = "tableComment"), + }) + CodegenTableDO convert(TableInfo bean); + + List convertList(List list); + + @Mappings({ + @Mapping(source = "name", target = "columnName"), + @Mapping(source = "metaInfo.jdbcType", target = "dataType", qualifiedByName = "getDataType"), + @Mapping(source = "comment", target = "columnComment"), + @Mapping(source = "metaInfo.nullable", target = "nullable"), + @Mapping(source = "keyFlag", target = "primaryKey"), + @Mapping(source = "columnType.type", target = "javaType"), + @Mapping(source = "propertyName", target = "javaField"), + }) + CodegenColumnDO convert(TableField bean); + + @Named("getDataType") + default String getDataType(JdbcType jdbcType) { + return jdbcType.name(); + } + + // ========== 其它 ========== + + default CodegenDetailRespVO convert(CodegenTableDO table, List columns) { + CodegenDetailRespVO respVO = new CodegenDetailRespVO(); + respVO.setTable(BeanUtils.toBean(table, CodegenTableRespVO.class)); + respVO.setColumns(BeanUtils.toBean(columns, CodegenColumnRespVO.class)); + return respVO; + } + + default List convert(Map codes) { + return CollectionUtils.convertList(codes.entrySet(), + entry -> new CodegenPreviewRespVO().setFilePath(entry.getKey()).setCode(entry.getValue())); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/config/ConfigConvert.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/config/ConfigConvert.java new file mode 100644 index 0000000..8548296 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/config/ConfigConvert.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.infra.convert.config; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigRespVO; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.config.ConfigDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface ConfigConvert { + + ConfigConvert INSTANCE = Mappers.getMapper(ConfigConvert.class); + + PageResult convertPage(PageResult page); + + List convertList(List list); + + @Mapping(source = "configKey", target = "key") + ConfigRespVO convert(ConfigDO bean); + + @Mapping(source = "key", target = "configKey") + ConfigDO convert(ConfigSaveReqVO bean); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/file/FileConfigConvert.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/file/FileConfigConvert.java new file mode 100644 index 0000000..ed141ec --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/file/FileConfigConvert.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.infra.convert.file; + +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * 文件配置 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface FileConfigConvert { + + FileConfigConvert INSTANCE = Mappers.getMapper(FileConfigConvert.class); + + @Mapping(target = "config", ignore = true) + FileConfigDO convert(FileConfigSaveReqVO bean); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/package-info.java new file mode 100644 index 0000000..dc3d339 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package com.tashow.cloud.infra.convert; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/redis/RedisConvert.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/redis/RedisConvert.java new file mode 100644 index 0000000..00cc775 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/redis/RedisConvert.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.infra.convert.redis; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.infra.controller.admin.redis.vo.RedisMonitorRespVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.Properties; + +@Mapper +public interface RedisConvert { + + RedisConvert INSTANCE = Mappers.getMapper(RedisConvert.class); + + default RedisMonitorRespVO build(Properties info, Long dbSize, Properties commandStats) { + RedisMonitorRespVO respVO = RedisMonitorRespVO.builder().info(info).dbSize(dbSize) + .commandStats(new ArrayList<>(commandStats.size())).build(); + commandStats.forEach((key, value) -> { + respVO.getCommandStats().add(RedisMonitorRespVO.CommandStat.builder() + .command(StrUtil.subAfter((String) key, "cmdstat_", false)) + .calls(Long.valueOf(StrUtil.subBetween((String) value, "calls=", ","))) + .usec(Long.valueOf(StrUtil.subBetween((String) value, "usec=", ","))) + .build()); + }); + return respVO; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 0000000..8153487 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/codegen/CodegenColumnDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/codegen/CodegenColumnDO.java new file mode 100644 index 0000000..1b0b322 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/codegen/CodegenColumnDO.java @@ -0,0 +1,140 @@ +package com.tashow.cloud.infra.dal.dataobject.codegen; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnHtmlTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnListConditionEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnHtmlTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnListConditionEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnHtmlTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnListConditionEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 代码生成 column 字段定义 + * + * @author 芋道源码 + */ +@TableName(value = "infra_codegen_column", autoResultMap = true) +@KeySequence("infra_codegen_column_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class CodegenColumnDO extends BaseDO { + + /** + * ID 编号 + */ + @TableId + private Long id; + /** + * 表编号 + *

+ * 关联 {@link CodegenTableDO#getId()} + */ + private Long tableId; + + // ========== 表相关字段 ========== + + /** + * 字段名 + * + * 关联 {@link TableField#getName()} + */ + private String columnName; + /** + * 数据库字段类型 + * + * 关联 {@link TableField.MetaInfo#getJdbcType()} + */ + private String dataType; + /** + * 字段描述 + * + * 关联 {@link TableField#getComment()} + */ + private String columnComment; + /** + * 是否允许为空 + * + * 关联 {@link TableField.MetaInfo#isNullable()} + */ + private Boolean nullable; + /** + * 是否主键 + * + * 关联 {@link TableField#isKeyFlag()} + */ + private Boolean primaryKey; + /** + * 排序 + */ + private Integer ordinalPosition; + + // ========== Java 相关字段 ========== + + /** + * Java 属性类型 + * + * 例如说 String、Boolean 等等 + * + * 关联 {@link TableField#getColumnType()} + */ + private String javaType; + /** + * Java 属性名 + * + * 关联 {@link TableField#getPropertyName()} + */ + private String javaField; + /** + * 字典类型 + *

+ * 关联 DictTypeDO 的 type 属性 + */ + private String dictType; + /** + * 数据示例,主要用于生成 Swagger 注解的 example 字段 + */ + private String example; + + // ========== CRUD 相关字段 ========== + + /** + * 是否为 Create 创建操作的字段 + */ + private Boolean createOperation; + /** + * 是否为 Update 更新操作的字段 + */ + private Boolean updateOperation; + /** + * 是否为 List 查询操作的字段 + */ + private Boolean listOperation; + /** + * List 查询操作的条件类型 + *

+ * 枚举 {@link CodegenColumnListConditionEnum} + */ + private String listOperationCondition; + /** + * 是否为 List 查询操作的返回字段 + */ + private Boolean listOperationResult; + + // ========== UI 相关字段 ========== + + /** + * 显示类型 + *

+ * 枚举 {@link CodegenColumnHtmlTypeEnum} + */ + private String htmlType; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/codegen/CodegenTableDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/codegen/CodegenTableDO.java new file mode 100644 index 0000000..416258f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/codegen/CodegenTableDO.java @@ -0,0 +1,164 @@ +package com.tashow.cloud.infra.dal.dataobject.codegen; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.infra.enums.codegen.CodegenFrontTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.tashow.cloud.infra.dal.dataobject.db.DataSourceConfigDO; +import com.tashow.cloud.infra.enums.codegen.CodegenFrontTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.tashow.cloud.infra.enums.codegen.CodegenFrontTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 代码生成 table 表定义 + * + * @author 芋道源码 + */ +@TableName(value = "infra_codegen_table", autoResultMap = true) +@KeySequence("infra_codegen_table_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class CodegenTableDO extends BaseDO { + + /** + * ID 编号 + */ + @TableId + private Long id; + + /** + * 数据源编号 + * + * 关联 {@link DataSourceConfigDO#getId()} + */ + private Long dataSourceConfigId; + /** + * 生成场景 + * + * 枚举 {@link CodegenSceneEnum} + */ + private Integer scene; + + // ========== 表相关字段 ========== + + /** + * 表名称 + * + * 关联 {@link TableInfo#getName()} + */ + private String tableName; + /** + * 表描述 + * + * 关联 {@link TableInfo#getComment()} + */ + private String tableComment; + /** + * 备注 + */ + private String remark; + + // ========== 类相关字段 ========== + + /** + * 模块名,即一级目录 + * + * 例如说,system、infra、tool 等等 + */ + private String moduleName; + /** + * 业务名,即二级目录 + * + * 例如说,user、permission、dict 等等 + */ + private String businessName; + /** + * 类名称(首字母大写) + * + * 例如说,SysUser、SysMenu、SysDictData 等等 + */ + private String className; + /** + * 类描述 + */ + private String classComment; + /** + * 作者 + */ + private String author; + + // ========== 生成相关字段 ========== + + /** + * 模板类型 + * + * 枚举 {@link CodegenTemplateTypeEnum} + */ + private Integer templateType; + /** + * 代码生成的前端类型 + * + * 枚举 {@link CodegenFrontTypeEnum} + */ + private Integer frontType; + + // ========== 菜单相关字段 ========== + + /** + * 父菜单编号 + * + * 关联 MenuDO 的 id 属性 + */ + private Long parentMenuId; + + // ========== 主子表相关字段 ========== + + /** + * 主表的编号 + * + * 关联 {@link CodegenTableDO#getId()} + */ + private Long masterTableId; + /** + * 【自己】子表关联主表的字段编号 + * + * 关联 {@link CodegenColumnDO#getId()} + */ + private Long subJoinColumnId; + /** + * 主表与子表是否一对多 + * + * true:一对多 + * false:一对一 + */ + private Boolean subJoinMany; + + // ========== 树表相关字段 ========== + + /** + * 树表的父字段编号 + * + * 关联 {@link CodegenColumnDO#getId()} + */ + private Long treeParentColumnId; + /** + * 树表的名字字段编号 + * + * 名字的用途:新增或修改时,select 框展示的字段 + * + * 关联 {@link CodegenColumnDO#getId()} + */ + private Long treeNameColumnId; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/config/ConfigDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/config/ConfigDO.java new file mode 100644 index 0000000..1834f48 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/config/ConfigDO.java @@ -0,0 +1,66 @@ +package com.tashow.cloud.infra.dal.dataobject.config; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.infra.enums.config.ConfigTypeEnum; +import com.tashow.cloud.infra.enums.config.ConfigTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.infra.enums.config.ConfigTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 参数配置表 + * + * @author 芋道源码 + */ +@TableName("infra_config") +@KeySequence("infra_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ConfigDO extends BaseDO { + + /** + * 参数主键 + */ + @TableId + private Long id; + /** + * 参数分类 + */ + private String category; + /** + * 参数名称 + */ + private String name; + /** + * 参数键名 + * + * 支持多 DB 类型时,无法直接使用 key + @TableField("config_key") 来实现转换,原因是 "config_key" AS key 而存在报错 + */ + private String configKey; + /** + * 参数键值 + */ + private String value; + /** + * 参数类型 + * + * 枚举 {@link ConfigTypeEnum} + */ + private Integer type; + /** + * 是否可见 + * + * 不可见的参数,一般是敏感参数,前端不可获取 + */ + private Boolean visible; + /** + * 备注 + */ + private String remark; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/db/DataSourceConfigDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/db/DataSourceConfigDO.java new file mode 100644 index 0000000..39dfa3d --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/db/DataSourceConfigDO.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.infra.dal.dataobject.db; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.mybatis.mybatis.core.type.EncryptTypeHandler; +import lombok.Data; + +/** + * 数据源配置 + * + * @author 芋道源码 + */ +@TableName(value = "infra_data_source_config", autoResultMap = true) +@KeySequence("infra_data_source_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class DataSourceConfigDO extends BaseDO { + + /** + * 主键编号 - Master 数据源 + */ + public static final Long ID_MASTER = 0L; + + /** + * 主键编号 + */ + private Long id; + /** + * 连接名 + */ + private String name; + + /** + * 数据源连接 + */ + private String url; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + @TableField(typeHandler = EncryptTypeHandler.class) + private String password; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo01/Demo01ContactDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo01/Demo01ContactDO.java new file mode 100644 index 0000000..35d72c1 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo01/Demo01ContactDO.java @@ -0,0 +1,54 @@ +package com.tashow.cloud.infra.dal.dataobject.demo.demo01; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 示例联系人 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo01_contact") +@KeySequence("yudao_demo01_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo01ContactDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 出生年 + */ + private LocalDateTime birthday; + /** + * 简介 + */ + private String description; + /** + * 头像 + */ + private String avatar; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo02/Demo02CategoryDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo02/Demo02CategoryDO.java new file mode 100644 index 0000000..1b6bb2b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo02/Demo02CategoryDO.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.infra.dal.dataobject.demo.demo02; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 示例分类 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo02_category") +@KeySequence("yudao_demo02_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo02CategoryDO extends BaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 父级编号 + */ + private Long parentId; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03CourseDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03CourseDO.java new file mode 100644 index 0000000..488cba5 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03CourseDO.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.infra.dal.dataobject.demo.demo03; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 学生课程 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo03_course") +@KeySequence("yudao_demo03_course_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo03CourseDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 分数 + */ + private Integer score; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03GradeDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03GradeDO.java new file mode 100644 index 0000000..3254e22 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03GradeDO.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.infra.dal.dataobject.demo.demo03; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 学生班级 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo03_grade") +@KeySequence("yudao_demo03_grade_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo03GradeDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 班主任 + */ + private String teacher; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03StudentDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03StudentDO.java new file mode 100644 index 0000000..b3397a1 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/demo/demo03/Demo03StudentDO.java @@ -0,0 +1,50 @@ +package com.tashow.cloud.infra.dal.dataobject.demo.demo03; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo03_student") +@KeySequence("yudao_demo03_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo03StudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 简介 + */ + private String description; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileConfigDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileConfigDO.java new file mode 100644 index 0000000..e18b8ca --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileConfigDO.java @@ -0,0 +1,111 @@ +package com.tashow.cloud.infra.dal.dataobject.file; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.db.DBFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.ftp.FtpFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.local.LocalFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.s3.S3FileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.sftp.SftpFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.enums.FileStorageEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.*; + +import java.lang.reflect.Field; + +/** + * 文件配置表 + * + * @author 芋道源码 + */ +@TableName(value = "infra_file_config", autoResultMap = true) +@KeySequence("infra_file_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FileConfigDO extends BaseDO { + + /** + * 配置编号,数据库自增 + */ + private Long id; + /** + * 配置名 + */ + private String name; + /** + * 存储器 + * + * 枚举 {@link FileStorageEnum} + */ + private Integer storage; + /** + * 备注 + */ + private String remark; + /** + * 是否为主配置 + * + * 由于我们可以配置多个文件配置,默认情况下,使用主配置进行文件的上传 + */ + private Boolean master; + + /** + * 支付渠道配置 + */ + @TableField(typeHandler = FileClientConfigTypeHandler.class) + private FileClientConfig config; + + public static class FileClientConfigTypeHandler extends AbstractJsonTypeHandler { + + public FileClientConfigTypeHandler(Class type) { + super(type); + } + + public FileClientConfigTypeHandler(Class type, Field field) { + super(type, field); + } + + @Override + public Object parse(String json) { + FileClientConfig config = JsonUtils.parseObjectQuietly(json, new TypeReference<>() {}); + if (config != null) { + return config; + } + + // 兼容老版本的包路径 + String className = JsonUtils.parseObject(json, "@class", String.class); + className = StrUtil.subAfter(className, ".", true); + switch (className) { + case "DBFileClientConfig": + return JsonUtils.parseObject2(json, DBFileClientConfig.class); + case "FtpFileClientConfig": + return JsonUtils.parseObject2(json, FtpFileClientConfig.class); + case "LocalFileClientConfig": + return JsonUtils.parseObject2(json, LocalFileClientConfig.class); + case "SftpFileClientConfig": + return JsonUtils.parseObject2(json, SftpFileClientConfig.class); + case "S3FileClientConfig": + return JsonUtils.parseObject2(json, S3FileClientConfig.class); + default: + throw new IllegalArgumentException("未知的 FileClientConfig 类型:" + json); + } + } + + @Override + public String toJson(Object obj) { + return JsonUtils.toJsonString(obj); + } + + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileContentDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileContentDO.java new file mode 100644 index 0000000..23b8117 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileContentDO.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.infra.dal.dataobject.file; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.infra.framework.file.core.client.db.DBFileClient; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 文件内容表 + * + * 专门用于存储 {@link DBFileClient} 的文件内容 + * + * @author 芋道源码 + */ +@TableName("infra_file_content") +@KeySequence("infra_file_content_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FileContentDO extends BaseDO { + + /** + * 编号,数据库自增 + */ + @TableId + private Long id; + /** + * 配置编号 + * + * 关联 {@link FileConfigDO#getId()} + */ + private Long configId; + /** + * 路径,即文件名 + */ + private String path; + /** + * 文件内容 + */ + private byte[] content; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileDO.java new file mode 100644 index 0000000..60213ac --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/file/FileDO.java @@ -0,0 +1,55 @@ +package com.tashow.cloud.infra.dal.dataobject.file; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 文件表 + * 每次文件上传,都会记录一条记录到该表中 + * + * @author 芋道源码 + */ +@TableName("infra_file") +@KeySequence("infra_file_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FileDO extends BaseDO { + + /** + * 编号,数据库自增 + */ + private Long id; + /** + * 配置编号 + * + * 关联 {@link FileConfigDO#getId()} + */ + private Long configId; + /** + * 原文件名 + */ + private String name; + /** + * 路径,即文件名 + */ + private String path; + /** + * 访问地址 + */ + private String url; + /** + * 文件的 MIME 类型,例如 "application/octet-stream" + */ + private String type; + /** + * 文件大小 + */ + private Integer size; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/logger/ApiAccessLogDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/logger/ApiAccessLogDO.java new file mode 100644 index 0000000..6d2221b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/logger/ApiAccessLogDO.java @@ -0,0 +1,140 @@ +package com.tashow.cloud.infra.dal.dataobject.logger; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * API 访问日志 + * + * @author 芋道源码 + */ +@TableName("infra_api_access_log") +@KeySequence(value = "infra_api_access_log_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ApiAccessLogDO extends BaseDO { + + /** + * {@link #requestParams} 的最大长度 + */ + public static final Integer REQUEST_PARAMS_MAX_LENGTH = 8000; + + /** + * {@link #resultMsg} 的最大长度 + */ + public static final Integer RESULT_MSG_MAX_LENGTH = 512; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 + */ + private String traceId; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 应用名 + * + * 目前读取 `spring.application.name` 配置项 + */ + private String applicationName; + + // ========== 请求相关字段 ========== + + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 访问地址 + */ + private String requestUrl; + /** + * 请求参数 + * + * query: Query String + * body: Quest Body + */ + private String requestParams; + /** + * 响应结果 + */ + private String responseBody; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + + // ========== 执行相关字段 ========== + + /** + * 操作模块 + */ + private String operateModule; + /** + * 操作名 + */ + private String operateName; + /** + * 操作分类 + * + * 枚举 {@link OperateTypeEnum} + */ + private Integer operateType; + + /** + * 开始请求时间 + */ + private LocalDateTime beginTime; + /** + * 结束请求时间 + */ + private LocalDateTime endTime; + /** + * 执行时长,单位:毫秒 + */ + private Integer duration; + + /** + * 结果码 + * + * 目前使用的 {@link CommonResult#getCode()} 属性 + */ + private Integer resultCode; + /** + * 结果提示 + * + * 目前使用的 {@link CommonResult#getMsg()} 属性 + */ + private String resultMsg; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/logger/ApiErrorLogDO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/logger/ApiErrorLogDO.java new file mode 100644 index 0000000..ad3b299 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/dataobject/logger/ApiErrorLogDO.java @@ -0,0 +1,163 @@ +package com.tashow.cloud.infra.dal.dataobject.logger; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.infra.enums.logger.ApiErrorLogProcessStatusEnum; +import com.tashow.cloud.infra.enums.logger.ApiErrorLogProcessStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.infra.enums.logger.ApiErrorLogProcessStatusEnum; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * API 异常数据 + * + * @author 芋道源码 + */ +@TableName("infra_api_error_log") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@KeySequence(value = "infra_api_error_log_seq") +public class ApiErrorLogDO extends BaseDO { + + /** + * {@link #requestParams} 的最大长度 + */ + public static final Integer REQUEST_PARAMS_MAX_LENGTH = 8000; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + */ + private Long userId; + /** + * 链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 + */ + private String traceId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 应用名 + * + * 目前读取 spring.application.name + */ + private String applicationName; + + // ========== 请求相关字段 ========== + + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 访问地址 + */ + private String requestUrl; + /** + * 请求参数 + * + * query: Query String + * body: Quest Body + */ + private String requestParams; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + + // ========== 异常相关字段 ========== + + /** + * 异常发生时间 + */ + private LocalDateTime exceptionTime; + /** + * 异常名 + * + * {@link Throwable#getClass()} 的类全名 + */ + private String exceptionName; + /** + * 异常导致的消息 + * + * {@link cn.hutool.core.exceptions.ExceptionUtil#getMessage(Throwable)} + */ + private String exceptionMessage; + /** + * 异常导致的根消息 + * + * {@link cn.hutool.core.exceptions.ExceptionUtil#getRootCauseMessage(Throwable)} + */ + private String exceptionRootCauseMessage; + /** + * 异常的栈轨迹 + * + * {@link org.apache.commons.lang3.exception.ExceptionUtils#getStackTrace(Throwable)} + */ + private String exceptionStackTrace; + /** + * 异常发生的类全名 + * + * {@link StackTraceElement#getClassName()} + */ + private String exceptionClassName; + /** + * 异常发生的类文件 + * + * {@link StackTraceElement#getFileName()} + */ + private String exceptionFileName; + /** + * 异常发生的方法名 + * + * {@link StackTraceElement#getMethodName()} + */ + private String exceptionMethodName; + /** + * 异常发生的方法所在行 + * + * {@link StackTraceElement#getLineNumber()} + */ + private Integer exceptionLineNumber; + + // ========== 处理相关字段 ========== + + /** + * 处理状态 + * + * 枚举 {@link ApiErrorLogProcessStatusEnum} + */ + private Integer processStatus; + /** + * 处理时间 + */ + private LocalDateTime processTime; + /** + * 处理用户编号 + * + * 关联 cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO.SysUserDO#getId() + */ + private Long processUserId; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/codegen/CodegenColumnMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/codegen/CodegenColumnMapper.java new file mode 100644 index 0000000..556fd87 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/codegen/CodegenColumnMapper.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.infra.dal.mysql.codegen; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface CodegenColumnMapper extends BaseMapperX { + + default List selectListByTableId(Long tableId) { + return selectList(new LambdaQueryWrapperX() + .eq(CodegenColumnDO::getTableId, tableId) + .orderByAsc(CodegenColumnDO::getOrdinalPosition)); + } + + default void deleteListByTableId(Long tableId) { + delete(new LambdaQueryWrapperX() + .eq(CodegenColumnDO::getTableId, tableId)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/codegen/CodegenTableMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/codegen/CodegenTableMapper.java new file mode 100644 index 0000000..8d810e7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/codegen/CodegenTableMapper.java @@ -0,0 +1,43 @@ +package com.tashow.cloud.infra.dal.mysql.codegen; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface CodegenTableMapper extends BaseMapperX { + + default CodegenTableDO selectByTableNameAndDataSourceConfigId(String tableName, Long dataSourceConfigId) { + return selectOne(CodegenTableDO::getTableName, tableName, + CodegenTableDO::getDataSourceConfigId, dataSourceConfigId); + } + + default PageResult selectPage(CodegenTablePageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .likeIfPresent(CodegenTableDO::getTableName, pageReqVO.getTableName()) + .likeIfPresent(CodegenTableDO::getTableComment, pageReqVO.getTableComment()) + .likeIfPresent(CodegenTableDO::getClassName, pageReqVO.getClassName()) + .betweenIfPresent(CodegenTableDO::getCreateTime, pageReqVO.getCreateTime()) + .orderByDesc(CodegenTableDO::getUpdateTime) + ); + } + + default List selectListByDataSourceConfigId(Long dataSourceConfigId) { + return selectList(CodegenTableDO::getDataSourceConfigId, dataSourceConfigId); + } + + default List selectListByTemplateTypeAndMasterTableId(Integer templateType, Long masterTableId) { + return selectList(CodegenTableDO::getTemplateType, templateType, + CodegenTableDO::getMasterTableId, masterTableId); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/config/ConfigMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/config/ConfigMapper.java new file mode 100644 index 0000000..c877329 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/config/ConfigMapper.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.infra.dal.mysql.config; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.dal.dataobject.config.ConfigDO; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.config.ConfigDO; +import com.tashow.cloud.infra.dal.dataobject.config.ConfigDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ConfigMapper extends BaseMapperX { + + default ConfigDO selectByKey(String key) { + return selectOne(ConfigDO::getConfigKey, key); + } + + default PageResult selectPage(ConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ConfigDO::getName, reqVO.getName()) + .likeIfPresent(ConfigDO::getConfigKey, reqVO.getKey()) + .eqIfPresent(ConfigDO::getType, reqVO.getType()) + .betweenIfPresent(ConfigDO::getCreateTime, reqVO.getCreateTime())); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/db/DataSourceConfigMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/db/DataSourceConfigMapper.java new file mode 100644 index 0000000..32c7ce9 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/db/DataSourceConfigMapper.java @@ -0,0 +1,14 @@ +package com.tashow.cloud.infra.dal.mysql.db; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.infra.dal.dataobject.db.DataSourceConfigDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 数据源配置 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface DataSourceConfigMapper extends BaseMapperX { +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo01/Demo01ContactMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo01/Demo01ContactMapper.java new file mode 100644 index 0000000..556f72a --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo01/Demo01ContactMapper.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.infra.dal.mysql.demo.demo01; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo01.Demo01ContactDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 示例联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo01ContactMapper extends BaseMapperX { + + default PageResult selectPage(Demo01ContactPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(Demo01ContactDO::getName, reqVO.getName()) + .eqIfPresent(Demo01ContactDO::getSex, reqVO.getSex()) + .betweenIfPresent(Demo01ContactDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(Demo01ContactDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo02/Demo02CategoryMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo02/Demo02CategoryMapper.java new file mode 100644 index 0000000..b6c466b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo02/Demo02CategoryMapper.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.infra.dal.mysql.demo.demo02; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo02.Demo02CategoryDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 示例分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo02CategoryMapper extends BaseMapperX { + + default List selectList(Demo02CategoryListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(Demo02CategoryDO::getName, reqVO.getName()) + .eqIfPresent(Demo02CategoryDO::getParentId, reqVO.getParentId()) + .betweenIfPresent(Demo02CategoryDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(Demo02CategoryDO::getId)); + } + + default Demo02CategoryDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(Demo02CategoryDO::getParentId, parentId, Demo02CategoryDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(Demo02CategoryDO::getParentId, parentId); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03CourseMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03CourseMapper.java new file mode 100644 index 0000000..dd943de --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03CourseMapper.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.infra.dal.mysql.demo.demo03; + +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 学生课程 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo03CourseMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long studentId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(Demo03CourseDO::getStudentId, studentId) + .orderByDesc(Demo03CourseDO::getId)); + } + + default List selectListByStudentId(Long studentId) { + return selectList(Demo03CourseDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(Demo03CourseDO::getStudentId, studentId); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03GradeMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03GradeMapper.java new file mode 100644 index 0000000..19548ed --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03GradeMapper.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.infra.dal.mysql.demo.demo03; + +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生班级 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo03GradeMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long studentId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(Demo03GradeDO::getStudentId, studentId) + .orderByDesc(Demo03GradeDO::getId)); + } + + default Demo03GradeDO selectByStudentId(Long studentId) { + return selectOne(Demo03GradeDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(Demo03GradeDO::getStudentId, studentId); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03StudentMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03StudentMapper.java new file mode 100644 index 0000000..e5152be --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/demo/demo03/Demo03StudentMapper.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.infra.dal.mysql.demo.demo03; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo03StudentMapper extends BaseMapperX { + + default PageResult selectPage(Demo03StudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(Demo03StudentDO::getName, reqVO.getName()) + .eqIfPresent(Demo03StudentDO::getSex, reqVO.getSex()) + .eqIfPresent(Demo03StudentDO::getDescription, reqVO.getDescription()) + .betweenIfPresent(Demo03StudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(Demo03StudentDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileConfigMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileConfigMapper.java new file mode 100644 index 0000000..889fd72 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileConfigMapper.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.infra.dal.mysql.file; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface FileConfigMapper extends BaseMapperX { + + default PageResult selectPage(FileConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(FileConfigDO::getName, reqVO.getName()) + .eqIfPresent(FileConfigDO::getStorage, reqVO.getStorage()) + .betweenIfPresent(FileConfigDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(FileConfigDO::getId)); + } + + default FileConfigDO selectByMaster() { + return selectOne(FileConfigDO::getMaster, true); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileContentMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileContentMapper.java new file mode 100644 index 0000000..c2062fe --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileContentMapper.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.infra.dal.mysql.file; + +import com.tashow.cloud.infra.dal.dataobject.file.FileContentDO; +import com.tashow.cloud.infra.dal.dataobject.file.FileContentDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.tashow.cloud.infra.dal.dataobject.file.FileContentDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface FileContentMapper extends BaseMapper { + + default void deleteByConfigIdAndPath(Long configId, String path) { + this.delete(new LambdaQueryWrapper() + .eq(FileContentDO::getConfigId, configId) + .eq(FileContentDO::getPath, path)); + } + + default List selectListByConfigIdAndPath(Long configId, String path) { + return selectList(new LambdaQueryWrapper() + .eq(FileContentDO::getConfigId, configId) + .eq(FileContentDO::getPath, path)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileMapper.java new file mode 100644 index 0000000..72f4bbd --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/file/FileMapper.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.infra.dal.mysql.file; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.dal.dataobject.file.FileDO; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FilePageReqVO; +import com.tashow.cloud.infra.dal.dataobject.file.FileDO; +import com.tashow.cloud.infra.dal.dataobject.file.FileDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 文件操作 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface FileMapper extends BaseMapperX { + + default PageResult selectPage(FilePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(FileDO::getPath, reqVO.getPath()) + .likeIfPresent(FileDO::getType, reqVO.getType()) + .betweenIfPresent(FileDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(FileDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/logger/ApiAccessLogMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/logger/ApiAccessLogMapper.java new file mode 100644 index 0000000..9a7e6ee --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/logger/ApiAccessLogMapper.java @@ -0,0 +1,49 @@ +package com.tashow.cloud.infra.dal.mysql.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +/** + * API 访问日志 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ApiAccessLogMapper extends BaseMapperX { + + default PageResult selectPage(ApiAccessLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ApiAccessLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ApiAccessLogDO::getUserType, reqVO.getUserType()) + .eqIfPresent(ApiAccessLogDO::getApplicationName, reqVO.getApplicationName()) + .likeIfPresent(ApiAccessLogDO::getRequestUrl, reqVO.getRequestUrl()) + .betweenIfPresent(ApiAccessLogDO::getBeginTime, reqVO.getBeginTime()) + .geIfPresent(ApiAccessLogDO::getDuration, reqVO.getDuration()) + .eqIfPresent(ApiAccessLogDO::getResultCode, reqVO.getResultCode()) + .orderByDesc(ApiAccessLogDO::getId) + ); + } + + /** + * 物理删除指定时间之前的日志 + * + * @param createTime 最大时间 + * @param limit 删除条数,防止一次删除太多 + * @return 删除条数 + */ + @Delete("DELETE FROM infra_api_access_log WHERE create_time < #{createTime} LIMIT #{limit}") + Integer deleteByCreateTimeLt(@Param("createTime") LocalDateTime createTime, @Param("limit") Integer limit); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/logger/ApiErrorLogMapper.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/logger/ApiErrorLogMapper.java new file mode 100644 index 0000000..2b16482 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/dal/mysql/logger/ApiErrorLogMapper.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.infra.dal.mysql.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiErrorLogDO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiErrorLogDO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiErrorLogDO; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +/** + * API 错误日志 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ApiErrorLogMapper extends BaseMapperX { + + default PageResult selectPage(ApiErrorLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ApiErrorLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ApiErrorLogDO::getUserType, reqVO.getUserType()) + .eqIfPresent(ApiErrorLogDO::getApplicationName, reqVO.getApplicationName()) + .likeIfPresent(ApiErrorLogDO::getRequestUrl, reqVO.getRequestUrl()) + .betweenIfPresent(ApiErrorLogDO::getExceptionTime, reqVO.getExceptionTime()) + .eqIfPresent(ApiErrorLogDO::getProcessStatus, reqVO.getProcessStatus()) + .orderByDesc(ApiErrorLogDO::getId) + ); + } + + /** + * 物理删除指定时间之前的日志 + * + * @param createTime 最大时间 + * @param limit 删除条数,防止一次删除太多 + * @return 删除条数 + */ + @Delete("DELETE FROM infra_api_error_log WHERE create_time < #{createTime} LIMIT #{limit}") + Integer deleteByCreateTimeLt(@Param("createTime") LocalDateTime createTime, @Param("limit")Integer limit); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenColumnHtmlTypeEnum.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenColumnHtmlTypeEnum.java new file mode 100644 index 0000000..7b8e9c6 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenColumnHtmlTypeEnum.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.infra.enums.codegen; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 代码生成器的字段 HTML 展示枚举 + */ +@AllArgsConstructor +@Getter +public enum CodegenColumnHtmlTypeEnum { + + INPUT("input"), // 文本框 + TEXTAREA("textarea"), // 文本域 + SELECT("select"), // 下拉框 + RADIO("radio"), // 单选框 + CHECKBOX("checkbox"), // 复选框 + DATETIME("datetime"), // 日期控件 + IMAGE_UPLOAD("imageUpload"), // 上传图片 + FILE_UPLOAD("fileUpload"), // 上传文件 + EDITOR("editor"), // 富文本控件 + ; + + /** + * 条件 + */ + private final String type; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenColumnListConditionEnum.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenColumnListConditionEnum.java new file mode 100644 index 0000000..67b6e41 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenColumnListConditionEnum.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.infra.enums.codegen; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 代码生成器的字段过滤条件枚举 + */ +@AllArgsConstructor +@Getter +public enum CodegenColumnListConditionEnum { + + EQ("="), + NE("!="), + GT(">"), + GTE(">="), + LT("<"), + LTE("<="), + LIKE("LIKE"), + BETWEEN("BETWEEN"); + + /** + * 条件 + */ + private final String condition; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenFrontTypeEnum.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenFrontTypeEnum.java new file mode 100644 index 0000000..1425142 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenFrontTypeEnum.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.infra.enums.codegen; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 代码生成的前端类型枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CodegenFrontTypeEnum { + + VUE2(10), // Vue2 Element UI 标准模版 + VUE3(20), // Vue3 Element Plus 标准模版 + VUE3_VBEN(30), // Vue3 VBEN 模版 + ; + + /** + * 类型 + */ + private final Integer type; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenSceneEnum.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenSceneEnum.java new file mode 100644 index 0000000..f60cfb7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenSceneEnum.java @@ -0,0 +1,41 @@ +package com.tashow.cloud.infra.enums.codegen; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import static cn.hutool.core.util.ArrayUtil.*; + +/** + * 代码生成的场景枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CodegenSceneEnum { + + ADMIN(1, "管理后台", "admin", ""), + APP(2, "用户 APP", "app", "App"); + + /** + * 场景 + */ + private final Integer scene; + /** + * 场景名 + */ + private final String name; + /** + * 基础包名 + */ + private final String basePackage; + /** + * Controller 和 VO 类的前缀 + */ + private final String prefixClass; + + public static CodegenSceneEnum valueOf(Integer scene) { + return firstMatch(sceneEnum -> sceneEnum.getScene().equals(scene), values()); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenTemplateTypeEnum.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenTemplateTypeEnum.java new file mode 100644 index 0000000..acecac4 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/codegen/CodegenTemplateTypeEnum.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.infra.enums.codegen; + +import com.tashow.cloud.common.util.object.ObjectUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 代码生成模板类型 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CodegenTemplateTypeEnum { + + ONE(1), // 单表(增删改查) + TREE(2), // 树表(增删改查) + + MASTER_NORMAL(10), // 主子表 - 主表 - 普通模式 + MASTER_ERP(11), // 主子表 - 主表 - ERP 模式 + MASTER_INNER(12), // 主子表 - 主表 - 内嵌模式 + SUB(15), // 主子表 - 子表 + ; + + /** + * 类型 + */ + private final Integer type; + + /** + * 是否为主表 + * + * @param type 类型 + * @return 是否主表 + */ + public static boolean isMaster(Integer type) { + return ObjectUtils.equalsAny(type, + MASTER_NORMAL.type, MASTER_ERP.type, MASTER_INNER.type); + } + + /** + * 是否为树表 + * + * @param type 类型 + * @return 是否树表 + */ + public static boolean isTree(Integer type) { + return Objects.equals(type, TREE.type); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/config/ConfigTypeEnum.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/config/ConfigTypeEnum.java new file mode 100644 index 0000000..b20b430 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/config/ConfigTypeEnum.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.infra.enums.config; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ConfigTypeEnum { + + /** + * 系统配置 + */ + SYSTEM(1), + /** + * 自定义配置 + */ + CUSTOM(2); + + private final Integer type; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/logger/ApiErrorLogProcessStatusEnum.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/logger/ApiErrorLogProcessStatusEnum.java new file mode 100644 index 0000000..7487cba --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/logger/ApiErrorLogProcessStatusEnum.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.infra.enums.logger; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * API 异常数据的处理状态 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum ApiErrorLogProcessStatusEnum { + + INIT(0, "未处理"), + DONE(1, "已处理"), + IGNORE(2, "已忽略"); + + /** + * 状态 + */ + private final Integer status; + /** + * 资源类型名 + */ + private final String name; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/package-info.java new file mode 100644 index 0000000..41c4aea --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/enums/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package com.tashow.cloud.infra.enums; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/config/CodegenConfiguration.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/config/CodegenConfiguration.java new file mode 100644 index 0000000..e94e109 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/config/CodegenConfiguration.java @@ -0,0 +1,9 @@ +package com.tashow.cloud.infra.framework.codegen.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(CodegenProperties.class) +public class CodegenConfiguration { +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/config/CodegenProperties.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/config/CodegenProperties.java new file mode 100644 index 0000000..7998129 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/config/CodegenProperties.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.infra.framework.codegen.config; + +import com.tashow.cloud.infra.enums.codegen.CodegenFrontTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenFrontTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenFrontTypeEnum; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.Collection; + +@ConfigurationProperties(prefix = "yudao.codegen") +@Validated +@Data +public class CodegenProperties { + + /** + * 生成的 Java 代码的基础包 + */ + @NotNull(message = "Java 代码的基础包不能为空") + private String basePackage; + + /** + * 数据库名数组 + */ + @NotEmpty(message = "数据库不能为空") + private Collection dbSchemas; + + /** + * 代码生成的前端类型(默认) + * + * 枚举 {@link CodegenFrontTypeEnum#getType()} + */ + @NotNull(message = "代码生成的前端类型不能为空") + private Integer frontType; + + /** + * 是否生成单元测试 + */ + @NotNull(message = "是否生成单元测试不能为空") + private Boolean unitTestEnable; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/package-info.java new file mode 100644 index 0000000..c309215 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/codegen/package-info.java @@ -0,0 +1,4 @@ +/** + * 代码生成器 + */ +package com.tashow.cloud.infra.framework.codegen; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/config/YudaoFileAutoConfiguration.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/config/YudaoFileAutoConfiguration.java new file mode 100644 index 0000000..68ba8e7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/config/YudaoFileAutoConfiguration.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.infra.framework.file.config; + +import com.tashow.cloud.infra.framework.file.core.client.FileClientFactory; +import com.tashow.cloud.infra.framework.file.core.client.FileClientFactoryImpl; +import com.tashow.cloud.infra.framework.file.core.client.FileClientFactory; +import com.tashow.cloud.infra.framework.file.core.client.FileClientFactoryImpl; +import com.tashow.cloud.infra.framework.file.core.client.FileClientFactory; +import com.tashow.cloud.infra.framework.file.core.client.FileClientFactoryImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 文件配置类 + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class YudaoFileAutoConfiguration { + + @Bean + public FileClientFactory fileClientFactory() { + return new FileClientFactoryImpl(); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/AbstractFileClient.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/AbstractFileClient.java new file mode 100644 index 0000000..a35851f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/AbstractFileClient.java @@ -0,0 +1,69 @@ +package com.tashow.cloud.infra.framework.file.core.client; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * 文件客户端的抽象类,提供模板方法,减少子类的冗余代码 + * + * @author 芋道源码 + */ +@Slf4j +public abstract class AbstractFileClient implements FileClient { + + /** + * 配置编号 + */ + private final Long id; + /** + * 文件配置 + */ + protected Config config; + + public AbstractFileClient(Long id, Config config) { + this.id = id; + this.config = config; + } + + /** + * 初始化 + */ + public final void init() { + doInit(); + log.debug("[init][配置({}) 初始化完成]", config); + } + + /** + * 自定义初始化 + */ + protected abstract void doInit(); + + public final void refresh(Config config) { + // 判断是否更新 + if (config.equals(this.config)) { + return; + } + log.info("[refresh][配置({})发生变化,重新初始化]", config); + this.config = config; + // 初始化 + this.init(); + } + + @Override + public Long getId() { + return id; + } + + /** + * 格式化文件的 URL 访问地址 + * 使用场景:local、ftp、db,通过 FileController 的 getFile 来获取文件内容 + * + * @param domain 自定义域名 + * @param path 文件路径 + * @return URL 访问地址 + */ + protected String formatFileUrl(String domain, String path) { + return StrUtil.format("{}/admin-api/infra/file/{}/get/{}", domain, getId(), path); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClient.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClient.java new file mode 100644 index 0000000..c386fc5 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClient.java @@ -0,0 +1,57 @@ +package com.tashow.cloud.infra.framework.file.core.client; + +import com.tashow.cloud.infra.framework.file.core.client.s3.FilePresignedUrlRespDTO; +import com.tashow.cloud.infra.framework.file.core.client.s3.FilePresignedUrlRespDTO; +import com.tashow.cloud.infra.framework.file.core.client.s3.FilePresignedUrlRespDTO; + +/** + * 文件客户端 + * + * @author 芋道源码 + */ +public interface FileClient { + + /** + * 获得客户端编号 + * + * @return 客户端编号 + */ + Long getId(); + + /** + * 上传文件 + * + * @param content 文件流 + * @param path 相对路径 + * @return 完整路径,即 HTTP 访问地址 + * @throws Exception 上传文件时,抛出 Exception 异常 + */ + String upload(byte[] content, String path, String type) throws Exception; + + /** + * 删除文件 + * + * @param path 相对路径 + * @throws Exception 删除文件时,抛出 Exception 异常 + */ + void delete(String path) throws Exception; + + /** + * 获得文件的内容 + * + * @param path 相对路径 + * @return 文件的内容 + */ + byte[] getContent(String path) throws Exception; + + /** + * 获得文件预签名地址 + * + * @param path 相对路径 + * @return 文件预签名地址 + */ + default FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception { + throw new UnsupportedOperationException("不支持的操作"); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientConfig.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientConfig.java new file mode 100644 index 0000000..c2f7c6d --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientConfig.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.infra.framework.file.core.client; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +/** + * 文件客户端的配置 + * 不同实现的客户端,需要不同的配置,通过子类来定义 + * + * @author 芋道源码 + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +// @JsonTypeInfo 注解的作用,Jackson 多态 +// 1. 序列化到时数据库时,增加 @class 属性。 +// 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 +public interface FileClientConfig { +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientFactory.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientFactory.java new file mode 100644 index 0000000..8361e73 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientFactory.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.infra.framework.file.core.client; + +import com.tashow.cloud.infra.framework.file.core.enums.FileStorageEnum; +import com.tashow.cloud.infra.framework.file.core.enums.FileStorageEnum; +import com.tashow.cloud.infra.framework.file.core.enums.FileStorageEnum; + +public interface FileClientFactory { + + /** + * 获得文件客户端 + * + * @param configId 配置编号 + * @return 文件客户端 + */ + FileClient getFileClient(Long configId); + + /** + * 创建文件客户端 + * + * @param configId 配置编号 + * @param storage 存储器的枚举 {@link FileStorageEnum} + * @param config 文件配置 + */ + void createOrUpdateFileClient(Long configId, Integer storage, Config config); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientFactoryImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientFactoryImpl.java new file mode 100644 index 0000000..6eee5e3 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/FileClientFactoryImpl.java @@ -0,0 +1,58 @@ +package com.tashow.cloud.infra.framework.file.core.client; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ReflectUtil; +import com.tashow.cloud.infra.framework.file.core.enums.FileStorageEnum; +import com.tashow.cloud.infra.framework.file.core.enums.FileStorageEnum; +import com.tashow.cloud.infra.framework.file.core.enums.FileStorageEnum; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 文件客户端的工厂实现类 + * + * @author 芋道源码 + */ +@Slf4j +public class FileClientFactoryImpl implements FileClientFactory { + + /** + * 文件客户端 Map + * key:配置编号 + */ + private final ConcurrentMap> clients = new ConcurrentHashMap<>(); + + @Override + public FileClient getFileClient(Long configId) { + AbstractFileClient client = clients.get(configId); + if (client == null) { + log.error("[getFileClient][配置编号({}) 找不到客户端]", configId); + } + return client; + } + + @Override + @SuppressWarnings("unchecked") + public void createOrUpdateFileClient(Long configId, Integer storage, Config config) { + AbstractFileClient client = (AbstractFileClient) clients.get(configId); + if (client == null) { + client = this.createFileClient(configId, storage, config); + client.init(); + clients.put(client.getId(), client); + } else { + client.refresh(config); + } + } + + @SuppressWarnings("unchecked") + private AbstractFileClient createFileClient( + Long configId, Integer storage, Config config) { + FileStorageEnum storageEnum = FileStorageEnum.getByStorage(storage); + Assert.notNull(storageEnum, String.format("文件配置(%s) 为空", storageEnum)); + // 创建客户端 + return (AbstractFileClient) ReflectUtil.newInstance(storageEnum.getClientClass(), configId, config); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/db/DBFileClient.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/db/DBFileClient.java new file mode 100644 index 0000000..c4bc920 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/db/DBFileClient.java @@ -0,0 +1,59 @@ +package com.tashow.cloud.infra.framework.file.core.client.db; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.tashow.cloud.infra.dal.dataobject.file.FileContentDO; +import com.tashow.cloud.infra.dal.mysql.file.FileContentMapper; +import com.tashow.cloud.infra.dal.dataobject.file.FileContentDO; +import com.tashow.cloud.infra.dal.mysql.file.FileContentMapper; +import com.tashow.cloud.infra.framework.file.core.client.AbstractFileClient; +import com.tashow.cloud.infra.dal.dataobject.file.FileContentDO; +import com.tashow.cloud.infra.dal.mysql.file.FileContentMapper; + +import java.util.Comparator; +import java.util.List; + +/** + * 基于 DB 存储的文件客户端的配置类 + * + * @author 芋道源码 + */ +public class DBFileClient extends AbstractFileClient { + + private FileContentMapper fileContentMapper; + + public DBFileClient(Long id, DBFileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + fileContentMapper = SpringUtil.getBean(FileContentMapper.class); + } + + @Override + public String upload(byte[] content, String path, String type) { + FileContentDO contentDO = new FileContentDO().setConfigId(getId()) + .setPath(path).setContent(content); + fileContentMapper.insert(contentDO); + // 拼接返回路径 + return super.formatFileUrl(config.getDomain(), path); + } + + @Override + public void delete(String path) { + fileContentMapper.deleteByConfigIdAndPath(getId(), path); + } + + @Override + public byte[] getContent(String path) { + List list = fileContentMapper.selectListByConfigIdAndPath(getId(), path); + if (CollUtil.isEmpty(list)) { + return null; + } + // 排序后,拿 id 最大的,即最后上传的 + list.sort(Comparator.comparing(FileContentDO::getId)); + return CollUtil.getLast(list).getContent(); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/db/DBFileClientConfig.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/db/DBFileClientConfig.java new file mode 100644 index 0000000..512b02f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/db/DBFileClientConfig.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.infra.framework.file.core.client.db; + +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +/** + * 基于 DB 存储的文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class DBFileClientConfig implements FileClientConfig { + + /** + * 自定义域名 + */ + @NotEmpty(message = "domain 不能为空") + @URL(message = "domain 必须是 URL 格式") + private String domain; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/ftp/FtpFileClient.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/ftp/FtpFileClient.java new file mode 100644 index 0000000..07cabf5 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/ftp/FtpFileClient.java @@ -0,0 +1,77 @@ +package com.tashow.cloud.infra.framework.file.core.client.ftp; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.ftp.Ftp; +import cn.hutool.extra.ftp.FtpException; +import cn.hutool.extra.ftp.FtpMode; +import com.tashow.cloud.infra.framework.file.core.client.AbstractFileClient; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +/** + * Ftp 文件客户端 + * + * @author 芋道源码 + */ +public class FtpFileClient extends AbstractFileClient { + + private Ftp ftp; + + public FtpFileClient(Long id, FtpFileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + // 把配置的 \ 替换成 /, 如果路径配置 \a\test, 替换成 /a/test, 替换方法已经处理 null 情况 + config.setBasePath(StrUtil.replace(config.getBasePath(), StrUtil.BACKSLASH, StrUtil.SLASH)); + // ftp的路径是 / 结尾 + if (!config.getBasePath().endsWith(StrUtil.SLASH)) { + config.setBasePath(config.getBasePath() + StrUtil.SLASH); + } + // 初始化 Ftp 对象 + this.ftp = new Ftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword(), + CharsetUtil.CHARSET_UTF_8, null, null, FtpMode.valueOf(config.getMode())); + } + + @Override + public String upload(byte[] content, String path, String type) { + // 执行写入 + String filePath = getFilePath(path); + String fileName = FileUtil.getName(filePath); + String dir = StrUtil.removeSuffix(filePath, fileName); + ftp.reconnectIfTimeout(); + boolean success = ftp.upload(dir, fileName, new ByteArrayInputStream(content)); + if (!success) { + throw new FtpException(StrUtil.format("上传文件到目标目录 ({}) 失败", filePath)); + } + // 拼接返回路径 + return super.formatFileUrl(config.getDomain(), path); + } + + @Override + public void delete(String path) { + String filePath = getFilePath(path); + ftp.reconnectIfTimeout(); + ftp.delFile(filePath); + } + + @Override + public byte[] getContent(String path) { + String filePath = getFilePath(path); + String fileName = FileUtil.getName(filePath); + String dir = StrUtil.removeSuffix(filePath, fileName); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ftp.reconnectIfTimeout(); + ftp.download(dir, fileName, out); + return out.toByteArray(); + } + + private String getFilePath(String path) { + return config.getBasePath() + path; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/ftp/FtpFileClientConfig.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/ftp/FtpFileClientConfig.java new file mode 100644 index 0000000..c8c5ad6 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/ftp/FtpFileClientConfig.java @@ -0,0 +1,58 @@ +package com.tashow.cloud.infra.framework.file.core.client.ftp; + +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +/** + * Ftp 文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class FtpFileClientConfig implements FileClientConfig { + + /** + * 基础路径 + */ + @NotEmpty(message = "基础路径不能为空") + private String basePath; + + /** + * 自定义域名 + */ + @NotEmpty(message = "domain 不能为空") + @URL(message = "domain 必须是 URL 格式") + private String domain; + + /** + * 主机地址 + */ + @NotEmpty(message = "host 不能为空") + private String host; + /** + * 主机端口 + */ + @NotNull(message = "port 不能为空") + private Integer port; + /** + * 用户名 + */ + @NotEmpty(message = "用户名不能为空") + private String username; + /** + * 密码 + */ + @NotEmpty(message = "密码不能为空") + private String password; + /** + * 连接模式 + * + * 使用 {@link cn.hutool.extra.ftp.FtpMode} 对应的字符串 + */ + @NotEmpty(message = "连接模式不能为空") + private String mode; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/local/LocalFileClient.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/local/LocalFileClient.java new file mode 100644 index 0000000..aa99e0a --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/local/LocalFileClient.java @@ -0,0 +1,52 @@ +package com.tashow.cloud.infra.framework.file.core.client.local; + +import cn.hutool.core.io.FileUtil; +import com.tashow.cloud.infra.framework.file.core.client.AbstractFileClient; + +import java.io.File; + +/** + * 本地文件客户端 + * + * @author 芋道源码 + */ +public class LocalFileClient extends AbstractFileClient { + + public LocalFileClient(Long id, LocalFileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + // 补全风格。例如说 Linux 是 /,Windows 是 \ + if (!config.getBasePath().endsWith(File.separator)) { + config.setBasePath(config.getBasePath() + File.separator); + } + } + + @Override + public String upload(byte[] content, String path, String type) { + // 执行写入 + String filePath = getFilePath(path); + FileUtil.writeBytes(content, filePath); + // 拼接返回路径 + return super.formatFileUrl(config.getDomain(), path); + } + + @Override + public void delete(String path) { + String filePath = getFilePath(path); + FileUtil.del(filePath); + } + + @Override + public byte[] getContent(String path) { + String filePath = getFilePath(path); + return FileUtil.readBytes(filePath); + } + + private String getFilePath(String path) { + return config.getBasePath() + path; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/local/LocalFileClientConfig.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/local/LocalFileClientConfig.java new file mode 100644 index 0000000..375dad6 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/local/LocalFileClientConfig.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.infra.framework.file.core.client.local; + +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +/** + * 本地文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class LocalFileClientConfig implements FileClientConfig { + + /** + * 基础路径 + */ + @NotEmpty(message = "基础路径不能为空") + private String basePath; + + /** + * 自定义域名 + */ + @NotEmpty(message = "domain 不能为空") + @URL(message = "domain 必须是 URL 格式") + private String domain; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/FilePresignedUrlRespDTO.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/FilePresignedUrlRespDTO.java new file mode 100644 index 0000000..3af8231 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/FilePresignedUrlRespDTO.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.infra.framework.file.core.client.s3; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 文件预签名地址 Response DTO + * + * @author owen + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class FilePresignedUrlRespDTO { + + /** + * 文件上传 URL(用于上传) + * + * 例如说: + */ + private String uploadUrl; + + /** + * 文件 URL(用于读取、下载等) + */ + private String url; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/S3FileClient.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/S3FileClient.java new file mode 100644 index 0000000..d3990fb --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/S3FileClient.java @@ -0,0 +1,118 @@ +package com.tashow.cloud.infra.framework.file.core.client.s3; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.tashow.cloud.infra.framework.file.core.client.AbstractFileClient; +import com.amazonaws.HttpMethod; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.S3Object; + +import java.io.ByteArrayInputStream; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 + *

+ * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库 + * + * @author 芋道源码 + */ +public class S3FileClient extends AbstractFileClient { + + private AmazonS3Client client; + + public S3FileClient(Long id, S3FileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + // 补全 domain + if (StrUtil.isEmpty(config.getDomain())) { + config.setDomain(buildDomain()); + } + // 初始化客户端 + client = (AmazonS3Client)AmazonS3ClientBuilder.standard() + .withCredentials(buildCredentials()) + .withEndpointConfiguration(buildEndpointConfiguration()) + .build(); + } + + /** + * 基于 config 秘钥,构建 S3 客户端的认证信息 + * + * @return S3 客户端的认证信息 + */ + private AWSStaticCredentialsProvider buildCredentials() { + return new AWSStaticCredentialsProvider( + new BasicAWSCredentials(config.getAccessKey(), config.getAccessSecret())); + } + + /** + * 构建 S3 客户端的 Endpoint 配置,包括 region、endpoint + * + * @return S3 客户端的 EndpointConfiguration 配置 + */ + private AwsClientBuilder.EndpointConfiguration buildEndpointConfiguration() { + return new AwsClientBuilder.EndpointConfiguration(config.getEndpoint(), + null); // 无需设置 region + } + + /** + * 基于 bucket + endpoint 构建访问的 Domain 地址 + * + * @return Domain 地址 + */ + private String buildDomain() { + // 如果已经是 http 或者 https,则不进行拼接.主要适配 MinIO + if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) { + return StrUtil.format("{}/{}", config.getEndpoint(), config.getBucket()); + } + // 阿里云、腾讯云、华为云都适合。七牛云比较特殊,必须有自定义域名 + return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint()); + } + + @Override + public String upload(byte[] content, String path, String type) throws Exception { + // 元数据,主要用于设置文件类型 + ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentType(type); + objectMetadata.setContentLength(content.length); // 如果不设置,会有 “ No content length specified for stream data” 警告日志 + // 执行上传 + client.putObject(config.getBucket(), + path, // 相对路径 + new ByteArrayInputStream(content), // 文件内容 + objectMetadata); + + // 拼接返回路径 + return config.getDomain() + "/" + path; + } + + @Override + public void delete(String path) throws Exception { + client.deleteObject(config.getBucket(), path); + } + + @Override + public byte[] getContent(String path) throws Exception { + S3Object tempS3Object = client.getObject(config.getBucket(), path); + return IoUtil.readBytes(tempS3Object.getObjectContent()); + } + + @Override + public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception { + // 设定过期时间为 10 分钟。取值范围:1 秒 ~ 7 天 + Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10)); + // 生成上传 URL + String uploadUrl = String.valueOf(client.generatePresignedUrl(config.getBucket(), path, expiration , HttpMethod.PUT)); + return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/S3FileClientConfig.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/S3FileClientConfig.java new file mode 100644 index 0000000..9a3cf07 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/s3/S3FileClientConfig.java @@ -0,0 +1,80 @@ +package com.tashow.cloud.infra.framework.file.core.client.s3; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +/** + * S3 文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class S3FileClientConfig implements FileClientConfig { + + public static final String ENDPOINT_QINIU = "qiniucs.com"; + public static final String ENDPOINT_ALIYUN = "aliyuncs.com"; + public static final String ENDPOINT_TENCENT = "myqcloud.com"; + public static final String ENDPOINT_VOLCES = "volces.com"; // 火山云(字节) + + /** + * 节点地址 + * 1. MinIO:https://www.iocoder.cn/Spring-Boot/MinIO 。例如说,http://127.0.0.1:9000 + * 2. 阿里云:https://help.aliyun.com/document_detail/31837.html + * 3. 腾讯云:https://cloud.tencent.com/document/product/436/6224 + * 4. 七牛云:https://developer.qiniu.com/kodo/4088/s3-access-domainname + * 5. 华为云:https://console.huaweicloud.com/apiexplorer/#/endpoint/OBS + * 6. 火山云:https://www.volcengine.com/docs/6349/107356 + */ + @NotNull(message = "endpoint 不能为空") + private String endpoint; + /** + * 自定义域名 + * 1. MinIO:通过 Nginx 配置 + * 2. 阿里云:https://help.aliyun.com/document_detail/31836.html + * 3. 腾讯云:https://cloud.tencent.com/document/product/436/11142 + * 4. 七牛云:https://developer.qiniu.com/kodo/8556/set-the-custom-source-domain-name + * 5. 华为云:https://support.huaweicloud.com/usermanual-obs/obs_03_0032.html + * 6. 火山云:https://www.volcengine.com/docs/6349/128983 + */ + @URL(message = "domain 必须是 URL 格式") + private String domain; + /** + * 存储 Bucket + */ + @NotNull(message = "bucket 不能为空") + private String bucket; + + /** + * 访问 Key + * 1. MinIO:https://www.iocoder.cn/Spring-Boot/MinIO + * 2. 阿里云:https://ram.console.aliyun.com/manage/ak + * 3. 腾讯云:https://console.cloud.tencent.com/cam/capi + * 4. 七牛云:https://portal.qiniu.com/user/key + * 5. 华为云:https://support.huaweicloud.com/qs-obs/obs_qs_0005.html + * 6. 火山云:https://console.volcengine.com/iam/keymanage/ + */ + @NotNull(message = "accessKey 不能为空") + private String accessKey; + /** + * 访问 Secret + */ + @NotNull(message = "accessSecret 不能为空") + private String accessSecret; + + @SuppressWarnings("RedundantIfStatement") + @AssertTrue(message = "domain 不能为空") + @JsonIgnore + public boolean isDomainValid() { + // 如果是七牛,必须带有 domain + if (StrUtil.contains(endpoint, ENDPOINT_QINIU) && StrUtil.isEmpty(domain)) { + return false; + } + return true; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/sftp/SftpFileClient.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/sftp/SftpFileClient.java new file mode 100644 index 0000000..383a2df --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/sftp/SftpFileClient.java @@ -0,0 +1,61 @@ +package com.tashow.cloud.infra.framework.file.core.client.sftp; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.extra.ssh.Sftp; +import com.tashow.cloud.common.util.io.FileUtils; +import com.tashow.cloud.infra.framework.file.core.client.AbstractFileClient; + +import java.io.File; + +/** + * Sftp 文件客户端 + * + * @author 芋道源码 + */ +public class SftpFileClient extends AbstractFileClient { + + private Sftp sftp; + + public SftpFileClient(Long id, SftpFileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + // 补全风格。例如说 Linux 是 /,Windows 是 \ + if (!config.getBasePath().endsWith(File.separator)) { + config.setBasePath(config.getBasePath() + File.separator); + } + // 初始化 Ftp 对象 + this.sftp = new Sftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword()); + } + + @Override + public String upload(byte[] content, String path, String type) { + // 执行写入 + String filePath = getFilePath(path); + File file = FileUtils.createTempFile(content); + sftp.upload(filePath, file); + // 拼接返回路径 + return super.formatFileUrl(config.getDomain(), path); + } + + @Override + public void delete(String path) { + String filePath = getFilePath(path); + sftp.delFile(filePath); + } + + @Override + public byte[] getContent(String path) { + String filePath = getFilePath(path); + File destFile = FileUtils.createTempFile(); + sftp.download(filePath, destFile); + return FileUtil.readBytes(destFile); + } + + private String getFilePath(String path) { + return config.getBasePath() + path; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/sftp/SftpFileClientConfig.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/sftp/SftpFileClientConfig.java new file mode 100644 index 0000000..300feff --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/client/sftp/SftpFileClientConfig.java @@ -0,0 +1,51 @@ +package com.tashow.cloud.infra.framework.file.core.client.sftp; + +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +/** + * Sftp 文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class SftpFileClientConfig implements FileClientConfig { + + /** + * 基础路径 + */ + @NotEmpty(message = "基础路径不能为空") + private String basePath; + + /** + * 自定义域名 + */ + @NotEmpty(message = "domain 不能为空") + @URL(message = "domain 必须是 URL 格式") + private String domain; + + /** + * 主机地址 + */ + @NotEmpty(message = "host 不能为空") + private String host; + /** + * 主机端口 + */ + @NotNull(message = "port 不能为空") + private Integer port; + /** + * 用户名 + */ + @NotEmpty(message = "用户名不能为空") + private String username; + /** + * 密码 + */ + @NotEmpty(message = "密码不能为空") + private String password; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/enums/FileStorageEnum.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/enums/FileStorageEnum.java new file mode 100644 index 0000000..d51b847 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/enums/FileStorageEnum.java @@ -0,0 +1,73 @@ +package com.tashow.cloud.infra.framework.file.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import com.tashow.cloud.infra.framework.file.core.client.db.DBFileClient; +import com.tashow.cloud.infra.framework.file.core.client.db.DBFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.ftp.FtpFileClient; +import com.tashow.cloud.infra.framework.file.core.client.ftp.FtpFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.local.LocalFileClient; +import com.tashow.cloud.infra.framework.file.core.client.s3.S3FileClient; +import com.tashow.cloud.infra.framework.file.core.client.s3.S3FileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.sftp.SftpFileClient; +import com.tashow.cloud.infra.framework.file.core.client.sftp.SftpFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.FileClient; +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.db.DBFileClient; +import com.tashow.cloud.infra.framework.file.core.client.db.DBFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.ftp.FtpFileClient; +import com.tashow.cloud.infra.framework.file.core.client.ftp.FtpFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.local.LocalFileClient; +import com.tashow.cloud.infra.framework.file.core.client.local.LocalFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.s3.S3FileClient; +import com.tashow.cloud.infra.framework.file.core.client.s3.S3FileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.sftp.SftpFileClient; +import com.tashow.cloud.infra.framework.file.core.client.sftp.SftpFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.db.DBFileClient; +import com.tashow.cloud.infra.framework.file.core.client.db.DBFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.ftp.FtpFileClient; +import com.tashow.cloud.infra.framework.file.core.client.ftp.FtpFileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.local.LocalFileClient; +import com.tashow.cloud.infra.framework.file.core.client.s3.S3FileClient; +import com.tashow.cloud.infra.framework.file.core.client.s3.S3FileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.sftp.SftpFileClient; +import com.tashow.cloud.infra.framework.file.core.client.sftp.SftpFileClientConfig; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 文件存储器枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum FileStorageEnum { + + DB(1, DBFileClientConfig.class, DBFileClient.class), + + LOCAL(10, LocalFileClientConfig.class, LocalFileClient.class), + FTP(11, FtpFileClientConfig.class, FtpFileClient.class), + SFTP(12, SftpFileClientConfig.class, SftpFileClient.class), + + S3(20, S3FileClientConfig.class, S3FileClient.class), + ; + + /** + * 存储器 + */ + private final Integer storage; + + /** + * 配置类 + */ + private final Class configClass; + /** + * 客户端类 + */ + private final Class clientClass; + + public static FileStorageEnum getByStorage(Integer storage) { + return ArrayUtil.firstMatch(o -> o.getStorage().equals(storage), values()); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/utils/FileTypeUtils.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/utils/FileTypeUtils.java new file mode 100644 index 0000000..92d1483 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/core/utils/FileTypeUtils.java @@ -0,0 +1,76 @@ +package com.tashow.cloud.infra.framework.file.core.utils; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.ttl.TransmittableThreadLocal; +import jakarta.servlet.http.HttpServletResponse; +import lombok.SneakyThrows; +import org.apache.tika.Tika; + +import java.io.IOException; +import java.net.URLEncoder; + +/** + * 文件类型 Utils + * + * @author 芋道源码 + */ +public class FileTypeUtils { + + private static final ThreadLocal TIKA = TransmittableThreadLocal.withInitial(Tika::new); + + /** + * 获得文件的 mineType,对于doc,jar等文件会有误差 + * + * @param data 文件内容 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + @SneakyThrows + public static String getMineType(byte[] data) { + return TIKA.get().detect(data); + } + + /** + * 已知文件名,获取文件类型,在某些情况下比通过字节数组准确,例如使用jar文件时,通过名字更为准确 + * + * @param name 文件名 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + public static String getMineType(String name) { + return TIKA.get().detect(name); + } + + /** + * 在拥有文件和数据的情况下,最好使用此方法,最为准确 + * + * @param data 文件内容 + * @param name 文件名 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + public static String getMineType(byte[] data, String name) { + return TIKA.get().detect(data, name); + } + + /** + * 返回附件 + * + * @param response 响应 + * @param filename 文件名 + * @param content 附件内容 + */ + public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { + // 设置 header 和 contentType + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); + String contentType = getMineType(content, filename); + response.setContentType(contentType); + // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题 + if (StrUtil.containsIgnoreCase(contentType, "video")) { + response.setHeader("Content-Length", String.valueOf(content.length - 1)); + response.setHeader("Content-Range", String.valueOf(content.length - 1)); + response.setHeader("Accept-Ranges", "bytes"); + } + // 输出附件 + IoUtil.write(response.getOutputStream(), false, content); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/package-info.java new file mode 100644 index 0000000..bd5ad3f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/file/package-info.java @@ -0,0 +1,12 @@ +/** + * 文件客户端,支持多种存储器 + * + * 1. local:本地磁盘 + * 2. ftp:FTP 服务器 + * 3. sftp:SFTP 服务器 + * 4. db:数据库 + * 5. s3:支持 S3 协议的云存储服务,例如说 MinIO、阿里云、华为云、腾讯云、七牛云等等 + * + * @author 芋道源码 + */ +package com.tashow.cloud.infra.framework.file; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/config/AdminServerConfiguration.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/config/AdminServerConfiguration.java new file mode 100644 index 0000000..3035b30 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/config/AdminServerConfiguration.java @@ -0,0 +1,9 @@ +package com.tashow.cloud.infra.framework.monitor.config; + +import de.codecentric.boot.admin.server.config.EnableAdminServer; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@EnableAdminServer +public class AdminServerConfiguration { +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/package-info.java new file mode 100644 index 0000000..2149935 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/package-info.java @@ -0,0 +1,4 @@ +/** + * 使用 Spring Boot Admin 实现简单的监控平台 + */ +package com.tashow.cloud.infra.framework.monitor; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md new file mode 100644 index 0000000..a1e3676 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md @@ -0,0 +1 @@ + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/package-info.java new file mode 100644 index 0000000..18de46f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 infra 模块的 framework 封装 + * + * @author 芋道源码 + */ +package com.tashow.cloud.infra.framework; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/rpc/config/RpcConfiguration.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/rpc/config/RpcConfiguration.java new file mode 100644 index 0000000..b1e9a50 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/rpc/config/RpcConfiguration.java @@ -0,0 +1,10 @@ +package com.tashow.cloud.infra.framework.rpc.config; + +import com.tashow.cloud.systemapi.api.user.AdminUserApi; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@EnableFeignClients(clients = AdminUserApi.class) +public class RpcConfiguration { +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/rpc/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/rpc/package-info.java new file mode 100644 index 0000000..2b839c9 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/rpc/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package com.tashow.cloud.infra.framework.rpc; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/security/config/SecurityConfiguration.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/security/config/SecurityConfiguration.java new file mode 100644 index 0000000..03ab38b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/security/config/SecurityConfiguration.java @@ -0,0 +1,50 @@ +package com.tashow.cloud.infra.framework.security.config; + +import com.tashow.cloud.infraapi.enums.ApiConstants; +import com.tashow.cloud.security.security.config.AuthorizeRequestsCustomizer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; + +/** + * Infra 模块的 Security 配置 + */ +@Configuration(proxyBeanMethods = false, value = "infraSecurityConfiguration") +public class SecurityConfiguration { + + @Value("${spring.boot.admin.context-path:''}") + private String adminSeverContextPath; + + @Bean("infraAuthorizeRequestsCustomizer") + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { + return new AuthorizeRequestsCustomizer() { + + @Override + public void customize(AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry registry) { + // Swagger 接口文档 + registry.requestMatchers("/v3/api-docs/**").permitAll() + .requestMatchers("/webjars/**").permitAll() + .requestMatchers("/swagger-ui").permitAll() + .requestMatchers("/swagger-ui/**").permitAll(); + // Spring Boot Actuator 的安全配置 + registry.requestMatchers("/actuator").permitAll() + .requestMatchers("/actuator/**").permitAll(); + // Druid 监控 + registry.requestMatchers("/druid/**").permitAll(); + // Spring Boot Admin Server 的安全配置 + registry.requestMatchers(adminSeverContextPath).permitAll() + .requestMatchers(adminSeverContextPath + "/**").permitAll(); + // 文件读取 + registry.requestMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll(); + + // TODO 芋艿:这个每个项目都需要重复配置,得捉摸有没通用的方案 + // RPC 服务的安全配置 + registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); + } + + }; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/security/core/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/security/core/package-info.java new file mode 100644 index 0000000..01e0ad8 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/framework/security/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package com.tashow.cloud.infra.framework.security.core; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/logger/AccessLogCleanJob.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/logger/AccessLogCleanJob.java new file mode 100644 index 0000000..7f6c5d7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/logger/AccessLogCleanJob.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.infra.job.logger; + +import com.tashow.cloud.infra.service.logger.ApiAccessLogService; +import com.tashow.cloud.tenant.core.aop.TenantIgnore; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +/** + * 物理删除 N 天前的访问日志的 Job + * + * @author j-sentinel + */ +@Component +@Slf4j +public class AccessLogCleanJob { + + @Resource + private ApiAccessLogService apiAccessLogService; + + /** + * 清理超过(14)天的日志 + */ + private static final Integer JOB_CLEAN_RETAIN_DAY = 14; + + /** + * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 + */ + private static final Integer DELETE_LIMIT = 100; + + @XxlJob("accessLogCleanJob") + @TenantIgnore + public void execute() { + Integer count = apiAccessLogService.cleanAccessLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT); + log.info("[execute][定时执行清理访问日志数量 ({}) 个]", count); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/logger/ErrorLogCleanJob.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/logger/ErrorLogCleanJob.java new file mode 100644 index 0000000..b84fc48 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/logger/ErrorLogCleanJob.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.infra.job.logger; + +import com.tashow.cloud.infra.service.logger.ApiErrorLogService; +import com.tashow.cloud.tenant.core.aop.TenantIgnore; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +/** + * 物理删除 N 天前的错误日志的 Job + * + * @author j-sentinel + */ +@Slf4j +@Component +public class ErrorLogCleanJob { + + @Resource + private ApiErrorLogService apiErrorLogService; + + /** + * 清理超过(14)天的日志 + */ + private static final Integer JOB_CLEAN_RETAIN_DAY = 14; + + /** + * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 + */ + private static final Integer DELETE_LIMIT = 100; + + @XxlJob("errorLogCleanJob") + @TenantIgnore + public void execute() { + Integer count = apiErrorLogService.cleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT); + log.info("[execute][定时执行清理错误日志数量 ({}) 个]", count); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/package-info.java new file mode 100644 index 0000000..855452b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/job/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位,无特殊含义 + */ +package com.tashow.cloud.infra.job; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/consumer/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/consumer/package-info.java new file mode 100644 index 0000000..c0d8cb3 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/consumer/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消费者 + */ +package com.tashow.cloud.infra.mq.consumer; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/message/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/message/package-info.java new file mode 100644 index 0000000..a0e2c93 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/message/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消息 + */ +package com.tashow.cloud.infra.mq.message; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/producer/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/producer/package-info.java new file mode 100644 index 0000000..21dd3f3 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/mq/producer/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的生产者 + */ +package com.tashow.cloud.infra.mq.producer; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/package-info.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/package-info.java new file mode 100644 index 0000000..a164141 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/package-info.java @@ -0,0 +1,9 @@ +/** + * infra 模块,主要提供两块能力: + * 1. 我们放基础设施的运维与管理,支撑上层的通用与核心业务。 例如说:定时任务的管理、服务器的信息等等 + * 2. 研发工具,提升研发效率与质量。 例如说:代码生成器、接口文档等等 + * + * 1. Controller URL:以 /infra/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 infra_ 开头,方便在数据库中区分 + */ +package com.tashow.cloud.infra; diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/CodegenService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/CodegenService.java new file mode 100644 index 0000000..207d449 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/CodegenService.java @@ -0,0 +1,101 @@ +package com.tashow.cloud.infra.service.codegen; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; + +import java.util.List; +import java.util.Map; + +/** + * 代码生成 Service 接口 + * + * @author 芋道源码 + */ +public interface CodegenService { + + /** + * 基于数据库的表结构,创建代码生成器的表定义 + * + * @param userId 用户编号 + * @param reqVO 表信息 + * @return 创建的表定义的编号数组 + */ + List createCodegenList(Long userId, CodegenCreateListReqVO reqVO); + + /** + * 更新数据库的表和字段定义 + * + * @param updateReqVO 更新信息 + */ + void updateCodegen(CodegenUpdateReqVO updateReqVO); + + /** + * 基于数据库的表结构,同步数据库的表和字段定义 + * + * @param tableId 表编号 + */ + void syncCodegenFromDB(Long tableId); + + /** + * 删除数据库的表和字段定义 + * + * @param tableId 数据编号 + */ + void deleteCodegen(Long tableId); + + /** + * 获得表定义列表 + * + * @param dataSourceConfigId 数据源配置的编号 + * @return 表定义列表 + */ + List getCodegenTableList(Long dataSourceConfigId); + + /** + * 获得表定义分页 + * + * @param pageReqVO 分页条件 + * @return 表定义分页 + */ + PageResult getCodegenTablePage(CodegenTablePageReqVO pageReqVO); + + /** + * 获得表定义 + * + * @param id 表编号 + * @return 表定义 + */ + CodegenTableDO getCodegenTable(Long id); + + /** + * 获得指定表的字段定义数组 + * + * @param tableId 表编号 + * @return 字段定义数组 + */ + List getCodegenColumnListByTableId(Long tableId); + + /** + * 执行指定表的代码生成 + * + * @param tableId 表编号 + * @return 生成结果。key 为文件路径,value 为对应的代码内容 + */ + Map generationCodes(Long tableId); + + /** + * 获得数据库自带的表定义列表 + * + * @param dataSourceConfigId 数据源的配置编号 + * @param name 表名称 + * @param comment 表描述 + * @return 表定义列表 + */ + List getDatabaseTableList(Long dataSourceConfigId, String name, String comment); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/CodegenServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/CodegenServiceImpl.java new file mode 100644 index 0000000..d5fd8d1 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/CodegenServiceImpl.java @@ -0,0 +1,322 @@ +package com.tashow.cloud.infra.service.codegen; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.dal.mysql.codegen.CodegenColumnMapper; +import com.tashow.cloud.infra.dal.mysql.codegen.CodegenTableMapper; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.tashow.cloud.infra.service.codegen.inner.CodegenBuilder; +import com.tashow.cloud.infra.service.codegen.inner.CodegenEngine; +import com.tashow.cloud.infra.service.db.DatabaseTableService; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.dal.mysql.codegen.CodegenColumnMapper; +import com.tashow.cloud.infra.dal.mysql.codegen.CodegenTableMapper; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.tashow.cloud.infra.framework.codegen.config.CodegenProperties; +import com.tashow.cloud.infra.service.codegen.inner.CodegenBuilder; +import com.tashow.cloud.infra.service.codegen.inner.CodegenEngine; +import com.tashow.cloud.infra.service.db.DatabaseTableService; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import com.tashow.cloud.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.dal.mysql.codegen.CodegenColumnMapper; +import com.tashow.cloud.infra.dal.mysql.codegen.CodegenTableMapper; +import com.tashow.cloud.infraapi.enums.ErrorCodeConstants; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.tashow.cloud.infra.service.codegen.inner.CodegenBuilder; +import com.tashow.cloud.infra.service.codegen.inner.CodegenEngine; +import com.tashow.cloud.infra.service.db.DatabaseTableService; +import com.tashow.cloud.systemapi.api.user.AdminUserApi; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.google.common.annotations.VisibleForTesting; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertMap; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; + +/** + * 代码生成 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class CodegenServiceImpl implements CodegenService { + + @Resource + private DatabaseTableService databaseTableService; + + @Resource + private CodegenTableMapper codegenTableMapper; + @Resource + private CodegenColumnMapper codegenColumnMapper; + + @Resource + private AdminUserApi userApi; + + @Resource + private CodegenBuilder codegenBuilder; + @Resource + private CodegenEngine codegenEngine; + + @Resource + private CodegenProperties codegenProperties; + + @Override + @Transactional(rollbackFor = Exception.class) + public List createCodegenList(Long userId, CodegenCreateListReqVO reqVO) { + List ids = new ArrayList<>(reqVO.getTableNames().size()); + // 遍历添加。虽然效率会低一点,但是没必要做成完全批量,因为不会这么大量 + reqVO.getTableNames().forEach(tableName -> ids.add(createCodegen(userId, reqVO.getDataSourceConfigId(), tableName))); + return ids; + } + + private Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) { + // 从数据库中,获得数据库表结构 + TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName); + // 导入 + return createCodegen0(userId, dataSourceConfigId, tableInfo); + } + + private Long createCodegen0(Long userId, Long dataSourceConfigId, TableInfo tableInfo) { + // 校验导入的表和字段非空 + validateTableInfo(tableInfo); + // 校验是否已经存在 + if (codegenTableMapper.selectByTableNameAndDataSourceConfigId(tableInfo.getName(), + dataSourceConfigId) != null) { + throw exception(ErrorCodeConstants.CODEGEN_TABLE_EXISTS); + } + + // 构建 CodegenTableDO 对象,插入到 DB 中 + CodegenTableDO table = codegenBuilder.buildTable(tableInfo); + table.setDataSourceConfigId(dataSourceConfigId); + table.setScene(CodegenSceneEnum.ADMIN.getScene()); // 默认配置下,使用管理后台的模板 + table.setFrontType(codegenProperties.getFrontType()); + table.setAuthor(userApi.getUser(userId).getCheckedData().getNickname()); + codegenTableMapper.insert(table); + + // 构建 CodegenColumnDO 数组,插入到 DB 中 + List columns = codegenBuilder.buildColumns(table.getId(), tableInfo.getFields()); + // 如果没有主键,则使用第一个字段作为主键 + if (!tableInfo.isHavePrimaryKey()) { + columns.get(0).setPrimaryKey(true); + } + codegenColumnMapper.insertBatch(columns); + return table.getId(); + } + + @VisibleForTesting + void validateTableInfo(TableInfo tableInfo) { + if (tableInfo == null) { + throw exception(ErrorCodeConstants.CODEGEN_IMPORT_TABLE_NULL); + } + if (StrUtil.isEmpty(tableInfo.getComment())) { + throw exception(ErrorCodeConstants.CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL); + } + if (CollUtil.isEmpty(tableInfo.getFields())) { + throw exception(ErrorCodeConstants.CODEGEN_IMPORT_COLUMNS_NULL); + } + tableInfo.getFields().forEach(field -> { + if (StrUtil.isEmpty(field.getComment())) { + throw exception(ErrorCodeConstants.CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName()); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateCodegen(CodegenUpdateReqVO updateReqVO) { + // 校验是否已经存在 + if (codegenTableMapper.selectById(updateReqVO.getTable().getId()) == null) { + throw exception(ErrorCodeConstants.CODEGEN_TABLE_NOT_EXISTS); + } + // 校验主表字段存在 + if (Objects.equals(updateReqVO.getTable().getTemplateType(), CodegenTemplateTypeEnum.SUB.getType())) { + if (codegenTableMapper.selectById(updateReqVO.getTable().getMasterTableId()) == null) { + throw exception(ErrorCodeConstants.CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId()); + } + if (CollUtil.findOne(updateReqVO.getColumns(), // 关联主表的字段不存在 + column -> column.getId().equals(updateReqVO.getTable().getSubJoinColumnId())) == null) { + throw exception(ErrorCodeConstants.CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId()); + } + } + + // 更新 table 表定义 + CodegenTableDO updateTableObj = BeanUtils.toBean(updateReqVO.getTable(), CodegenTableDO.class); + codegenTableMapper.updateById(updateTableObj); + // 更新 column 字段定义 + List updateColumnObjs = BeanUtils.toBean(updateReqVO.getColumns(), CodegenColumnDO.class); + updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncCodegenFromDB(Long tableId) { + // 校验是否已经存在 + CodegenTableDO table = codegenTableMapper.selectById(tableId); + if (table == null) { + throw exception(ErrorCodeConstants.CODEGEN_TABLE_NOT_EXISTS); + } + // 从数据库中,获得数据库表结构 + TableInfo tableInfo = databaseTableService.getTable(table.getDataSourceConfigId(), table.getTableName()); + // 执行同步 + syncCodegen0(tableId, tableInfo); + } + + private void syncCodegen0(Long tableId, TableInfo tableInfo) { + // 1. 校验导入的表和字段非空 + validateTableInfo(tableInfo); + List tableFields = tableInfo.getFields(); + + // 2. 构建 CodegenColumnDO 数组,只同步新增的字段 + List codegenColumns = codegenColumnMapper.selectListByTableId(tableId); + Set codegenColumnNames = convertSet(codegenColumns, CodegenColumnDO::getColumnName); + + // 3.1 计算需要【修改】的字段,插入时重新插入,删除时将原来的删除 + Map codegenColumnDOMap = convertMap(codegenColumns, CodegenColumnDO::getColumnName); + BiPredicate primaryKeyPredicate = + (tableField, codegenColumn) -> tableField.getMetaInfo().getJdbcType().name().equals(codegenColumn.getDataType()) + && tableField.getMetaInfo().isNullable() == codegenColumn.getNullable() + && tableField.isKeyFlag() == codegenColumn.getPrimaryKey() + && tableField.getComment().equals(codegenColumn.getColumnComment()); + Set modifyFieldNames = IntStream.range(0, tableFields.size()).mapToObj(index -> { + TableField tableField = tableFields.get(index); + String columnName = tableField.getColumnName(); + CodegenColumnDO codegenColumn = codegenColumnDOMap.get(columnName); + if (codegenColumn == null) { + return null; + } + if (!primaryKeyPredicate.test(tableField, codegenColumn) || codegenColumn.getOrdinalPosition() != index) { + return columnName; + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toSet()); + // 3.2 计算需要【删除】的字段 + Set tableFieldNames = convertSet(tableFields, TableField::getName); + Set deleteColumnIds = codegenColumns.stream() + .filter(column -> (!tableFieldNames.contains(column.getColumnName())) || modifyFieldNames.contains(column.getColumnName())) + .map(CodegenColumnDO::getId).collect(Collectors.toSet()); + // 移除已经存在的字段 + tableFields.removeIf(column -> codegenColumnNames.contains(column.getColumnName()) && (!modifyFieldNames.contains(column.getColumnName()))); + if (CollUtil.isEmpty(tableFields) && CollUtil.isEmpty(deleteColumnIds)) { + throw exception(ErrorCodeConstants.CODEGEN_SYNC_NONE_CHANGE); + } + + // 4.1 插入新增的字段 + List columns = codegenBuilder.buildColumns(tableId, tableFields); + codegenColumnMapper.insertBatch(columns); + // 4.2 删除不存在的字段 + if (CollUtil.isNotEmpty(deleteColumnIds)) { + codegenColumnMapper.deleteBatchIds(deleteColumnIds); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteCodegen(Long tableId) { + // 校验是否已经存在 + if (codegenTableMapper.selectById(tableId) == null) { + throw exception(ErrorCodeConstants.CODEGEN_TABLE_NOT_EXISTS); + } + + // 删除 table 表定义 + codegenTableMapper.deleteById(tableId); + // 删除 column 字段定义 + codegenColumnMapper.deleteListByTableId(tableId); + } + + @Override + public List getCodegenTableList(Long dataSourceConfigId) { + return codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId); + } + + @Override + public PageResult getCodegenTablePage(CodegenTablePageReqVO pageReqVO) { + return codegenTableMapper.selectPage(pageReqVO); + } + + @Override + public CodegenTableDO getCodegenTable(Long id) { + return codegenTableMapper.selectById(id); + } + + @Override + public List getCodegenColumnListByTableId(Long tableId) { + return codegenColumnMapper.selectListByTableId(tableId); + } + + @Override + public Map generationCodes(Long tableId) { + // 校验是否已经存在 + CodegenTableDO table = codegenTableMapper.selectById(tableId); + if (table == null) { + throw exception(ErrorCodeConstants.CODEGEN_TABLE_NOT_EXISTS); + } + List columns = codegenColumnMapper.selectListByTableId(tableId); + if (CollUtil.isEmpty(columns)) { + throw exception(ErrorCodeConstants.CODEGEN_COLUMN_NOT_EXISTS); + } + + // 如果是主子表,则加载对应的子表信息 + List subTables = null; + List> subColumnsList = null; + if (CodegenTemplateTypeEnum.isMaster(table.getTemplateType())) { + // 校验子表存在 + subTables = codegenTableMapper.selectListByTemplateTypeAndMasterTableId( + CodegenTemplateTypeEnum.SUB.getType(), tableId); + if (CollUtil.isEmpty(subTables)) { + throw exception(ErrorCodeConstants.CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE); + } + // 校验子表的关联字段存在 + subColumnsList = new ArrayList<>(); + for (CodegenTableDO subTable : subTables) { + List subColumns = codegenColumnMapper.selectListByTableId(subTable.getId()); + if (CollUtil.findOne(subColumns, column -> column.getId().equals(subTable.getSubJoinColumnId())) == null) { + throw exception(ErrorCodeConstants.CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId()); + } + subColumnsList.add(subColumns); + } + } + + // 执行生成 + return codegenEngine.execute(table, columns, subTables, subColumnsList); + } + + @Override + public List getDatabaseTableList(Long dataSourceConfigId, String name, String comment) { + List tables = databaseTableService.getTableList(dataSourceConfigId, name, comment); + // 移除在 Codegen 中,已经存在的 + Set existsTables = convertSet( + codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName); + tables.removeIf(table -> existsTables.contains(table.getName())); + return BeanUtils.toBean(tables, DatabaseTableRespVO.class); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/inner/CodegenBuilder.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/inner/CodegenBuilder.java new file mode 100644 index 0000000..46158b0 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/inner/CodegenBuilder.java @@ -0,0 +1,233 @@ +package com.tashow.cloud.infra.service.codegen.inner; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.infra.convert.codegen.CodegenConvert; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnHtmlTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnListConditionEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.tashow.cloud.infra.convert.codegen.CodegenConvert; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnHtmlTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnListConditionEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.google.common.collect.Sets; +import com.tashow.cloud.infra.convert.codegen.CodegenConvert; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnHtmlTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenColumnListConditionEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.*; + +import static cn.hutool.core.text.CharSequenceUtil.*; +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.hutool.core.util.RandomUtil.randomInt; + +/** + * 代码生成器的 Builder,负责: + * 1. 将数据库的表 {@link TableInfo} 定义,构建成 {@link CodegenTableDO} + * 2. 将数据库的列 {@link TableField} 构定义,建成 {@link CodegenColumnDO} + */ +@Component +public class CodegenBuilder { + + /** + * 字段名与 {@link CodegenColumnListConditionEnum} 的默认映射 + * 注意,字段的匹配以后缀的方式 + */ + private static final Map COLUMN_LIST_OPERATION_CONDITION_MAPPINGS = + MapUtil.builder() + .put("name", CodegenColumnListConditionEnum.LIKE) + .put("time", CodegenColumnListConditionEnum.BETWEEN) + .put("date", CodegenColumnListConditionEnum.BETWEEN) + .build(); + + /** + * 字段名与 {@link CodegenColumnHtmlTypeEnum} 的默认映射 + * 注意,字段的匹配以后缀的方式 + */ + private static final Map COLUMN_HTML_TYPE_MAPPINGS = + MapUtil.builder() + .put("status", CodegenColumnHtmlTypeEnum.RADIO) + .put("sex", CodegenColumnHtmlTypeEnum.RADIO) + .put("type", CodegenColumnHtmlTypeEnum.SELECT) + .put("image", CodegenColumnHtmlTypeEnum.IMAGE_UPLOAD) + .put("file", CodegenColumnHtmlTypeEnum.FILE_UPLOAD) + .put("content", CodegenColumnHtmlTypeEnum.EDITOR) + .put("description", CodegenColumnHtmlTypeEnum.EDITOR) + .put("demo", CodegenColumnHtmlTypeEnum.EDITOR) + .put("time", CodegenColumnHtmlTypeEnum.DATETIME) + .put("date", CodegenColumnHtmlTypeEnum.DATETIME) + .build(); + + /** + * 多租户编号的字段名 + */ + public static final String TENANT_ID_FIELD = "tenantId"; + /** + * {@link BaseDO} 的字段 + */ + public static final Set BASE_DO_FIELDS = new HashSet<>(); + /** + * 新增操作,不需要传递的字段 + */ + private static final Set CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id"); + /** + * 修改操作,不需要传递的字段 + */ + private static final Set UPDATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet(); + /** + * 列表操作的条件,不需要传递的字段 + */ + private static final Set LIST_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id"); + /** + * 列表操作的结果,不需要返回的字段 + */ + private static final Set LIST_OPERATION_RESULT_EXCLUDE_COLUMN = Sets.newHashSet(); + + static { + Arrays.stream(ReflectUtil.getFields(BaseDO.class)).forEach(field -> BASE_DO_FIELDS.add(field.getName())); + BASE_DO_FIELDS.add(TENANT_ID_FIELD); + // 处理 OPERATION 相关的字段 + CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); + UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); + LIST_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); + LIST_OPERATION_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是可能需要传递的 + LIST_OPERATION_RESULT_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); + LIST_OPERATION_RESULT_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是需要返回的 + } + + public CodegenTableDO buildTable(TableInfo tableInfo) { + CodegenTableDO table = CodegenConvert.INSTANCE.convert(tableInfo); + initTableDefault(table); + return table; + } + + /** + * 初始化 Table 表的默认字段 + * + * @param table 表定义 + */ + private void initTableDefault(CodegenTableDO table) { + // 以 system_dept 举例子。moduleName 为 system、businessName 为 dept、className 为 Dept + // 如果希望以 System 前缀,则可以手动在【代码生成 - 修改生成配置 - 基本信息】,将实体类名称改为 SystemDept 即可 + String tableName = table.getTableName().toLowerCase(); + // 第一步,_ 前缀的前面,作为 module 名字;第二步,moduleName 必须小写; + table.setModuleName(subBefore(tableName, '_', false).toLowerCase()); + // 第一步,第一个 _ 前缀的后面,作为 module 名字; 第二步,可能存在多个 _ 的情况,转换成驼峰; 第三步,businessName 必须小写; + table.setBusinessName(toCamelCase(subAfter(tableName, '_', false)).toLowerCase()); + // 驼峰 + 首字母大写;第一步,第一个 _ 前缀的后面,作为 class 名字;第二步,驼峰命名 + table.setClassName(upperFirst(toCamelCase(subAfter(tableName, '_', false)))); + // 去除结尾的表,作为类描述 + table.setClassComment(StrUtil.removeSuffixIgnoreCase(table.getTableComment(), "表")); + table.setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); + } + + public List buildColumns(Long tableId, List tableFields) { + List columns = CodegenConvert.INSTANCE.convertList(tableFields); + int index = 1; + for (CodegenColumnDO column : columns) { + column.setTableId(tableId); + column.setOrdinalPosition(index++); + // 特殊处理:Byte => Integer + if (Byte.class.getSimpleName().equals(column.getJavaType())) { + column.setJavaType(Integer.class.getSimpleName()); + } + // 初始化 Column 列的默认字段 + processColumnOperation(column); // 处理 CRUD 相关的字段的默认值 + processColumnUI(column); // 处理 UI 相关的字段的默认值 + processColumnExample(column); // 处理字段的 swagger example 示例 + } + return columns; + } + + private void processColumnOperation(CodegenColumnDO column) { + // 处理 createOperation 字段 + column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField()) + && !column.getPrimaryKey()); // 对于主键,创建时无需传递 + // 处理 updateOperation 字段 + column.setUpdateOperation(!UPDATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField()) + || column.getPrimaryKey()); // 对于主键,更新时需要传递 + // 处理 listOperation 字段 + column.setListOperation(!LIST_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField()) + && !column.getPrimaryKey()); // 对于主键,列表过滤不需要传递 + // 处理 listOperationCondition 字段 + COLUMN_LIST_OPERATION_CONDITION_MAPPINGS.entrySet().stream() + .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey())) + .findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition())); + if (column.getListOperationCondition() == null) { + column.setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition()); + } + // 处理 listOperationResult 字段 + column.setListOperationResult(!LIST_OPERATION_RESULT_EXCLUDE_COLUMN.contains(column.getJavaField())); + } + + private void processColumnUI(CodegenColumnDO column) { + // 基于后缀进行匹配 + COLUMN_HTML_TYPE_MAPPINGS.entrySet().stream() + .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey())) + .findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType())); + // 如果是 Boolean 类型时,设置为 radio 类型. + if (Boolean.class.getSimpleName().equals(column.getJavaType())) { + column.setHtmlType(CodegenColumnHtmlTypeEnum.RADIO.getType()); + } + // 如果是 LocalDateTime 类型,则设置为 datetime 类型 + if (LocalDateTime.class.getSimpleName().equals(column.getJavaType())) { + column.setHtmlType(CodegenColumnHtmlTypeEnum.DATETIME.getType()); + } + // 兜底,设置默认为 input 类型 + if (column.getHtmlType() == null) { + column.setHtmlType(CodegenColumnHtmlTypeEnum.INPUT.getType()); + } + } + + /** + * 处理字段的 swagger example 示例 + * + * @param column 字段 + */ + private void processColumnExample(CodegenColumnDO column) { + // id、price、count 等可能是整数的后缀 + if (StrUtil.endWithAnyIgnoreCase(column.getJavaField(), "id", "price", "count")) { + column.setExample(String.valueOf(randomInt(1, Short.MAX_VALUE))); + return; + } + // name + if (StrUtil.endWithIgnoreCase(column.getJavaField(), "name")) { + column.setExample(randomEle(new String[]{"张三", "李四", "王五", "赵六", "芋艿"})); + return; + } + // status + if (StrUtil.endWithAnyIgnoreCase(column.getJavaField(), "status", "type")) { + column.setExample(randomEle(new String[]{"1", "2"})); + return; + } + // url + if (StrUtil.endWithIgnoreCase(column.getColumnName(), "url")) { + column.setExample("https://www.iocoder.cn"); + return; + } + // reason + if (StrUtil.endWithIgnoreCase(column.getColumnName(), "reason")) { + column.setExample(randomEle(new String[]{"不喜欢", "不对", "不好", "不香"})); + return; + } + // description、memo、remark + if (StrUtil.endWithAnyIgnoreCase(column.getColumnName(), "description", "memo", "remark")) { + column.setExample(randomEle(new String[]{"你猜", "随便", "你说的对"})); + return; + } + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/inner/CodegenEngine.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/inner/CodegenEngine.java new file mode 100644 index 0000000..2757cfb --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/codegen/inner/CodegenEngine.java @@ -0,0 +1,511 @@ +package com.tashow.cloud.infra.service.codegen.inner; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.template.TemplateConfig; +import cn.hutool.extra.template.TemplateEngine; +import cn.hutool.extra.template.engine.velocity.VelocityEngine; +import cn.hutool.system.SystemUtil; +import com.tashow.cloud.common.exception.util.ServiceExceptionUtil; +import com.tashow.cloud.common.util.date.LocalDateTimeUtils; +import com.tashow.cloud.common.util.object.ObjectUtils; +import com.tashow.cloud.common.util.string.StrUtils; +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.date.DateUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenColumnDO; +import com.tashow.cloud.infra.dal.dataobject.codegen.CodegenTableDO; +import com.tashow.cloud.infra.enums.codegen.CodegenFrontTypeEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenSceneEnum; +import com.tashow.cloud.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.tashow.cloud.infra.framework.codegen.config.CodegenProperties; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Maps; +import com.google.common.collect.Table; +import com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.Setter; +import org.springframework.stereotype.Component; + +import java.util.*; + +import static cn.hutool.core.map.MapUtil.getStr; +import static cn.hutool.core.text.CharSequenceUtil.*; + +/** + * 代码生成的引擎,用于具体生成代码 + * 目前基于 {@link org.apache.velocity.app.Velocity} 模板引擎实现 + * + * 考虑到 Java 模板引擎的框架非常多,Freemarker、Velocity、Thymeleaf 等等,所以我们采用 hutool 封装的 {@link cn.hutool.extra.template.Template} 抽象 + * + * @author 芋道源码 + */ +@Component +public class CodegenEngine { + + /** + * 后端的模板配置 + * + * key:模板在 resources 的地址 + * value:生成的路径 + */ + private static final Map SERVER_TEMPLATES = MapUtil.builder(new LinkedHashMap<>()) // 有序 + // Java module-biz Main + .put(javaTemplatePath("controller/vo/pageReqVO"), javaModuleImplVOFilePath("PageReqVO")) + .put(javaTemplatePath("controller/vo/listReqVO"), javaModuleImplVOFilePath("ListReqVO")) + .put(javaTemplatePath("controller/vo/respVO"), javaModuleImplVOFilePath("RespVO")) + .put(javaTemplatePath("controller/vo/saveReqVO"), javaModuleImplVOFilePath("SaveReqVO")) + .put(javaTemplatePath("controller/controller"), javaModuleImplControllerFilePath()) + .put(javaTemplatePath("dal/do"), + javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${table.className}DO")) + .put(javaTemplatePath("dal/do_sub"), // 特殊:主子表专属逻辑 + javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${subTable.className}DO")) + .put(javaTemplatePath("dal/mapper"), + javaModuleImplMainFilePath("dal/mysql/${table.businessName}/${table.className}Mapper")) + .put(javaTemplatePath("dal/mapper_sub"), // 特殊:主子表专属逻辑 + javaModuleImplMainFilePath("dal/mysql/${table.businessName}/${subTable.className}Mapper")) + .put(javaTemplatePath("dal/mapper.xml"), mapperXmlFilePath()) + .put(javaTemplatePath("service/serviceImpl"), + javaModuleImplMainFilePath("service/${table.businessName}/${table.className}ServiceImpl")) + .put(javaTemplatePath("service/service"), + javaModuleImplMainFilePath("service/${table.businessName}/${table.className}Service")) + // Java module-biz Test + .put(javaTemplatePath("test/serviceTest"), + javaModuleImplTestFilePath("service/${table.businessName}/${table.className}ServiceImplTest")) + // Java module-api Main + .put(javaTemplatePath("enums/errorcode"), javaModuleApiMainFilePath("enums/ErrorCodeConstants_手动操作")) + // SQL + .put("codegen/sql/sql.vm", "sql/sql.sql") + .put("codegen/sql/h2.vm", "sql/h2.sql") + .build(); + + /** + * 后端的配置模版 + * + * key1:UI 模版的类型 {@link CodegenFrontTypeEnum#getType()} + * key2:模板在 resources 的地址 + * value:生成的路径 + */ + private static final Table FRONT_TEMPLATES = ImmutableTable.builder() + // Vue2 标准模版 + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/index.vue"), + vueFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("api/api.js"), + vueFilePath("api/${table.moduleName}/${table.businessName}/index.js")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/form.vue"), + vueFilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/form_sub_erp.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/list_sub_inner.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/list_sub_erp.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) + // Vue3 标准模版 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/index.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/form.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_erp.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_inner.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_erp.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("api/api.ts"), + vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts")) + // Vue3 vben 模版 + .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/data.ts"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/${classNameVar}.data.ts")) + .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/index.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) + .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/form.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Modal.vue")) + .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("api/api.ts"), + vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts")) + .build(); + + @Resource + private CodegenProperties codegenProperties; + + /** + * 是否使用 jakarta 包,用于解决 Spring Boot 2.X 和 3.X 的兼容性问题 + * + * true - 使用 jakarta.validation.constraints.* + * false - 使用 javax.validation.constraints.* + */ + @Setter // 允许设置的原因,是因为单测需要手动改变 + private Boolean jakartaEnable; + + /** + * 模板引擎,由 hutool 实现 + */ + private final TemplateEngine templateEngine; + /** + * 全局通用变量映射 + */ + private final Map globalBindingMap = new HashMap<>(); + + public CodegenEngine() { + // 初始化 TemplateEngine 属性 + TemplateConfig config = new TemplateConfig(); + config.setResourceMode(TemplateConfig.ResourceMode.CLASSPATH); + this.templateEngine = new VelocityEngine(config); + // 设置 javaxEnable,按照是否使用 JDK17 来判断 + this.jakartaEnable = SystemUtil.getJavaInfo().isJavaVersionAtLeast(1700); // 17.00 * 100 + } + + @PostConstruct + @VisibleForTesting + void initGlobalBindingMap() { + // 全局配置 + globalBindingMap.put("basePackage", codegenProperties.getBasePackage()); + globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage() + + '.' + "framework"); // 用于后续获取测试类的 package 地址 + globalBindingMap.put("jakartaPackage", jakartaEnable ? "jakarta" : "javax"); + // 全局 Java Bean + globalBindingMap.put("CommonResultClassName", CommonResult.class.getName()); + globalBindingMap.put("PageResultClassName", PageResult.class.getName()); + // VO 类,独有字段 + globalBindingMap.put("PageParamClassName", PageParam.class.getName()); + globalBindingMap.put("DictFormatClassName", DictFormat.class.getName()); + // DO 类,独有字段 + globalBindingMap.put("BaseDOClassName", BaseDO.class.getName()); + globalBindingMap.put("baseDOFields", CodegenBuilder.BASE_DO_FIELDS); + globalBindingMap.put("QueryWrapperClassName", LambdaQueryWrapperX.class.getName()); + globalBindingMap.put("BaseMapperClassName", BaseMapperX.class.getName()); + // Util 工具类 + globalBindingMap.put("ServiceExceptionUtilClassName", ServiceExceptionUtil.class.getName()); + globalBindingMap.put("DateUtilsClassName", DateUtils.class.getName()); + globalBindingMap.put("ExcelUtilsClassName", ExcelUtils.class.getName()); + globalBindingMap.put("LocalDateTimeUtilsClassName", LocalDateTimeUtils.class.getName()); + globalBindingMap.put("ObjectUtilsClassName", ObjectUtils.class.getName()); + globalBindingMap.put("DictConvertClassName", DictConvert.class.getName()); + globalBindingMap.put("ApiAccessLogClassName", ApiAccessLog.class.getName()); + globalBindingMap.put("OperateTypeEnumClassName", OperateTypeEnum.class.getName()); + globalBindingMap.put("BeanUtils", BeanUtils.class.getName()); + } + + /** + * 生成代码 + * + * @param table 表定义 + * @param columns table 的字段定义数组 + * @param subTables 子表数组,当且仅当主子表时使用 + * @param subColumnsList subTables 的字段定义数组 + * @return 生成的代码,key 是路径,value 是对应代码 + */ + public Map execute(CodegenTableDO table, List columns, + List subTables, List> subColumnsList) { + // 1.1 初始化 bindMap 上下文 + Map bindingMap = initBindingMap(table, columns, subTables, subColumnsList); + // 1.2 获得模版 + Map templates = getTemplates(table.getFrontType()); + + // 2. 执行生成 + Map result = Maps.newLinkedHashMapWithExpectedSize(templates.size()); // 有序 + templates.forEach((vmPath, filePath) -> { + // 2.1 特殊:主子表专属逻辑 + if (isSubTemplate(vmPath)) { + generateSubCode(table, subTables, result, vmPath, filePath, bindingMap); + return; + // 2.2 特殊:树表专属逻辑 + } else if (isPageReqVOTemplate(vmPath)) { + // 减少多余的类生成,例如说 PageVO.java 类 + if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { + return; + } + } else if (isListReqVOTemplate(vmPath)) { + // 减少多余的类生成,例如说 ListVO.java 类 + if (!CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { + return; + } + } + // 2.3 默认生成 + generateCode(result, vmPath, filePath, bindingMap); + }); + return result; + } + + private void generateCode(Map result, String vmPath, + String filePath, Map bindingMap) { + filePath = formatFilePath(filePath, bindingMap); + String content = templateEngine.getTemplate(vmPath).render(bindingMap); + // 格式化代码 + content = prettyCode(content); + result.put(filePath, content); + } + + private void generateSubCode(CodegenTableDO table, List subTables, + Map result, String vmPath, + String filePath, Map bindingMap) { + // 没有子表,所以不生成 + if (CollUtil.isEmpty(subTables)) { + return; + } + // 主子表的模式匹配。目的:过滤掉个性化的模版 + if (vmPath.contains("_normal") + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_NORMAL.getType())) { + return; + } + if (vmPath.contains("_erp") + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_ERP.getType())) { + return; + } + if (vmPath.contains("_inner") + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_INNER.getType())) { + return; + } + + // 逐个生成 + for (int i = 0; i < subTables.size(); i++) { + bindingMap.put("subIndex", i); + generateCode(result, vmPath, filePath, bindingMap); + } + bindingMap.remove("subIndex"); + } + + /** + * 格式化生成后的代码 + * + * 因为尽量让 vm 模版简单,所以统一的处理都在这个方法。 + * 如果不处理,Vue 的 Pretty 格式校验可能会报错 + * + * @param content 格式化前的代码 + * @return 格式化后的代码 + */ + private String prettyCode(String content) { + // Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错 + content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }"); + // Vue 界面:去除多的 dateFormatter,只有一个的情况下,说明没使用到 + if (StrUtil.count(content, "dateFormatter") == 1) { + content = StrUtils.removeLineContains(content, "dateFormatter"); + } + // Vue2 界面:修正 $refs + if (StrUtil.count(content, "this.refs") >= 1) { + content = content.replace("this.refs", "this.$refs"); + } + // Vue 界面:去除多的 dict 相关,只有一个的情况下,说明没使用到 + if (StrUtil.count(content, "getIntDictOptions") == 1) { + content = content.replace("getIntDictOptions, ", ""); + } + if (StrUtil.count(content, "getStrDictOptions") == 1) { + content = content.replace("getStrDictOptions, ", ""); + } + if (StrUtil.count(content, "getBoolDictOptions") == 1) { + content = content.replace("getBoolDictOptions, ", ""); + } + if (StrUtil.count(content, "DICT_TYPE.") == 0) { + content = StrUtils.removeLineContains(content, "DICT_TYPE"); + } + return content; + } + + private Map initBindingMap(CodegenTableDO table, List columns, + List subTables, List> subColumnsList) { + // 创建 bindingMap + Map bindingMap = new HashMap<>(globalBindingMap); + bindingMap.put("table", table); + bindingMap.put("columns", columns); + bindingMap.put("primaryColumn", CollectionUtils.findFirst(columns, CodegenColumnDO::getPrimaryKey)); // 主键字段 + bindingMap.put("sceneEnum", CodegenSceneEnum.valueOf(table.getScene())); + + // className 相关 + // 去掉指定前缀,将 TestDictType 转换成 DictType. 因为在 create 等方法后,不需要带上 Test 前缀 + String simpleClassName = equalsAnyIgnoreCase(table.getClassName(), table.getModuleName()) ? table.getClassName() + : removePrefix(table.getClassName(), upperFirst(table.getModuleName())); + bindingMap.put("simpleClassName", simpleClassName); + bindingMap.put("simpleClassName_underlineCase", toUnderlineCase(simpleClassName)); // 将 DictType 转换成 dict_type + bindingMap.put("classNameVar", lowerFirst(simpleClassName)); // 将 DictType 转换成 dictType,用于变量 + // 将 DictType 转换成 dict-type + String simpleClassNameStrikeCase = toSymbolCase(simpleClassName, '-'); + bindingMap.put("simpleClassName_strikeCase", simpleClassNameStrikeCase); + // permission 前缀 + bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase); + + // 特殊:树表专属逻辑 + if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { + CodegenColumnDO treeParentColumn = CollUtil.findOne(columns, + column -> Objects.equals(column.getId(), table.getTreeParentColumnId())); + bindingMap.put("treeParentColumn", treeParentColumn); + bindingMap.put("treeParentColumn_javaField_underlineCase", toUnderlineCase(treeParentColumn.getJavaField())); + CodegenColumnDO treeNameColumn = CollUtil.findOne(columns, + column -> Objects.equals(column.getId(), table.getTreeNameColumnId())); + bindingMap.put("treeNameColumn", treeNameColumn); + bindingMap.put("treeNameColumn_javaField_underlineCase", toUnderlineCase(treeNameColumn.getJavaField())); + } + + // 特殊:主子表专属逻辑 + if (CollUtil.isNotEmpty(subTables)) { + // 创建 bindingMap + bindingMap.put("subTables", subTables); + bindingMap.put("subColumnsList", subColumnsList); + List subPrimaryColumns = new ArrayList<>(); + List subJoinColumns = new ArrayList<>(); + List subJoinColumnStrikeCases = new ArrayList<>(); + List subSimpleClassNames = new ArrayList<>(); + List subClassNameVars = new ArrayList<>(); + List simpleClassNameUnderlineCases = new ArrayList<>(); + List subSimpleClassNameStrikeCases = new ArrayList<>(); + for (int i = 0; i < subTables.size(); i++) { + CodegenTableDO subTable = subTables.get(i); + List subColumns = subColumnsList.get(i); + subPrimaryColumns.add(CollectionUtils.findFirst(subColumns, CodegenColumnDO::getPrimaryKey)); // + CodegenColumnDO subColumn = CollectionUtils.findFirst(subColumns, // 关联的字段 + column -> Objects.equals(column.getId(), subTable.getSubJoinColumnId())); + subJoinColumns.add(subColumn); + subJoinColumnStrikeCases.add(toSymbolCase(subColumn.getJavaField(), '-')); // 将 DictType 转换成 dict-type + // className 相关 + String subSimpleClassName = removePrefix(subTable.getClassName(), upperFirst(subTable.getModuleName())); + subSimpleClassNames.add(subSimpleClassName); + simpleClassNameUnderlineCases.add(toUnderlineCase(subSimpleClassName)); // 将 DictType 转换成 dict_type + subClassNameVars.add(lowerFirst(subSimpleClassName)); // 将 DictType 转换成 dictType,用于变量 + subSimpleClassNameStrikeCases.add(toSymbolCase(subSimpleClassName, '-')); // 将 DictType 转换成 dict-type + } + bindingMap.put("subPrimaryColumns", subPrimaryColumns); + bindingMap.put("subJoinColumns", subJoinColumns); + bindingMap.put("subJoinColumn_strikeCases", subJoinColumnStrikeCases); + bindingMap.put("subSimpleClassNames", subSimpleClassNames); + bindingMap.put("simpleClassNameUnderlineCases", simpleClassNameUnderlineCases); + bindingMap.put("subClassNameVars", subClassNameVars); + bindingMap.put("subSimpleClassName_strikeCases", subSimpleClassNameStrikeCases); + } + return bindingMap; + } + + private Map getTemplates(Integer frontType) { + Map templates = new LinkedHashMap<>(); + templates.putAll(SERVER_TEMPLATES); + templates.putAll(FRONT_TEMPLATES.row(frontType)); + // 如果禁用单元测试,则移除对应的模版 + if (Boolean.FALSE.equals(codegenProperties.getUnitTestEnable())) { + templates.remove(javaTemplatePath("test/serviceTest")); + templates.remove("codegen/sql/h2.vm"); + } + return templates; + } + + @SuppressWarnings("unchecked") + private String formatFilePath(String filePath, Map bindingMap) { + filePath = StrUtil.replace(filePath, "${basePackage}", + getStr(bindingMap, "basePackage").replaceAll("\\.", "/")); + filePath = StrUtil.replace(filePath, "${classNameVar}", + getStr(bindingMap, "classNameVar")); + filePath = StrUtil.replace(filePath, "${simpleClassName}", + getStr(bindingMap, "simpleClassName")); + // sceneEnum 包含的字段 + CodegenSceneEnum sceneEnum = (CodegenSceneEnum) bindingMap.get("sceneEnum"); + filePath = StrUtil.replace(filePath, "${sceneEnum.prefixClass}", sceneEnum.getPrefixClass()); + filePath = StrUtil.replace(filePath, "${sceneEnum.basePackage}", sceneEnum.getBasePackage()); + // table 包含的字段 + CodegenTableDO table = (CodegenTableDO) bindingMap.get("table"); + filePath = StrUtil.replace(filePath, "${table.moduleName}", table.getModuleName()); + filePath = StrUtil.replace(filePath, "${table.businessName}", table.getBusinessName()); + filePath = StrUtil.replace(filePath, "${table.className}", table.getClassName()); + // 特殊:主子表专属逻辑 + Integer subIndex = (Integer) bindingMap.get("subIndex"); + if (subIndex != null) { + CodegenTableDO subTable = ((List) bindingMap.get("subTables")).get(subIndex); + filePath = StrUtil.replace(filePath, "${subTable.moduleName}", subTable.getModuleName()); + filePath = StrUtil.replace(filePath, "${subTable.businessName}", subTable.getBusinessName()); + filePath = StrUtil.replace(filePath, "${subTable.className}", subTable.getClassName()); + filePath = StrUtil.replace(filePath, "${subSimpleClassName}", + ((List) bindingMap.get("subSimpleClassNames")).get(subIndex)); + } + return filePath; + } + + private static String javaTemplatePath(String path) { + return "codegen/java/" + path + ".vm"; + } + + private static String javaModuleImplVOFilePath(String path) { + return javaModuleFilePath("controller/${sceneEnum.basePackage}/${table.businessName}/" + + "vo/${sceneEnum.prefixClass}${table.className}" + path, "biz", "main"); + } + + private static String javaModuleImplControllerFilePath() { + return javaModuleFilePath("controller/${sceneEnum.basePackage}/${table.businessName}/" + + "${sceneEnum.prefixClass}${table.className}Controller", "biz", "main"); + } + + private static String javaModuleImplMainFilePath(String path) { + return javaModuleFilePath(path, "biz", "main"); + } + + private static String javaModuleApiMainFilePath(String path) { + return javaModuleFilePath(path, "api", "main"); + } + + private static String javaModuleImplTestFilePath(String path) { + return javaModuleFilePath(path, "biz", "test"); + } + + private static String javaModuleFilePath(String path, String module, String src) { + return "yudao-module-${table.moduleName}/" + // 顶级模块 + "yudao-module-${table.moduleName}-" + module + "/" + // 子模块 + "src/" + src + "/java/${basePackage}/module/${table.moduleName}/" + path + ".java"; + } + + private static String mapperXmlFilePath() { + return "yudao-module-${table.moduleName}/" + // 顶级模块 + "yudao-module-${table.moduleName}-biz/" + // 子模块 + "src/main/resources/mapper/${table.businessName}/${table.className}Mapper.xml"; + } + + private static String vueTemplatePath(String path) { + return "codegen/vue/" + path + ".vm"; + } + + private static String vueFilePath(String path) { + return "yudao-ui-${sceneEnum.basePackage}-vue2/" + // 顶级目录 + "src/" + path; + } + + private static String vue3TemplatePath(String path) { + return "codegen/vue3/" + path + ".vm"; + } + + private static String vue3FilePath(String path) { + return "yudao-ui-${sceneEnum.basePackage}-vue3/" + // 顶级目录 + "src/" + path; + } + + private static String vue3VbenTemplatePath(String path) { + return "codegen/vue3_vben/" + path + ".vm"; + } + + private static boolean isSubTemplate(String path) { + return path.contains("_sub"); + } + + private static boolean isPageReqVOTemplate(String path) { + return path.contains("pageReqVO"); + } + + private static boolean isListReqVOTemplate(String path) { + return path.contains("listReqVO"); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/config/ConfigService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/config/ConfigService.java new file mode 100644 index 0000000..64f72c6 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/config/ConfigService.java @@ -0,0 +1,63 @@ +package com.tashow.cloud.infra.service.config; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigPageReqVO; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.config.ConfigDO; + +import jakarta.validation.Valid; + +/** + * 参数配置 Service 接口 + * + * @author 芋道源码 + */ +public interface ConfigService { + + /** + * 创建参数配置 + * + * @param createReqVO 创建信息 + * @return 配置编号 + */ + Long createConfig(@Valid ConfigSaveReqVO createReqVO); + + /** + * 更新参数配置 + * + * @param updateReqVO 更新信息 + */ + void updateConfig(@Valid ConfigSaveReqVO updateReqVO); + + /** + * 删除参数配置 + * + * @param id 配置编号 + */ + void deleteConfig(Long id); + + /** + * 获得参数配置 + * + * @param id 配置编号 + * @return 参数配置 + */ + ConfigDO getConfig(Long id); + + /** + * 根据参数键,获得参数配置 + * + * @param key 配置键 + * @return 参数配置 + */ + ConfigDO getConfigByKey(String key); + + /** + * 获得参数配置分页列表 + * + * @param reqVO 分页条件 + * @return 分页列表 + */ + PageResult getConfigPage(ConfigPageReqVO reqVO); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/config/ConfigServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/config/ConfigServiceImpl.java new file mode 100644 index 0000000..8696a7c --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/config/ConfigServiceImpl.java @@ -0,0 +1,109 @@ +package com.tashow.cloud.infra.service.config; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.convert.config.ConfigConvert; +import com.tashow.cloud.infra.enums.config.ConfigTypeEnum; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigPageReqVO; +import com.tashow.cloud.infra.controller.admin.config.vo.ConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.config.ConfigDO; +import com.tashow.cloud.infra.dal.mysql.config.ConfigMapper; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.*; + +/** + * 参数配置 Service 实现类 + */ +@Service +@Slf4j +@Validated +public class ConfigServiceImpl implements ConfigService { + + @Resource + private ConfigMapper configMapper; + + @Override + public Long createConfig(ConfigSaveReqVO createReqVO) { + // 校验参数配置 key 的唯一性 + validateConfigKeyUnique(null, createReqVO.getKey()); + + // 插入参数配置 + ConfigDO config = ConfigConvert.INSTANCE.convert(createReqVO); + config.setType(ConfigTypeEnum.CUSTOM.getType()); + configMapper.insert(config); + return config.getId(); + } + + @Override + public void updateConfig(ConfigSaveReqVO updateReqVO) { + // 校验自己存在 + validateConfigExists(updateReqVO.getId()); + // 校验参数配置 key 的唯一性 + validateConfigKeyUnique(updateReqVO.getId(), updateReqVO.getKey()); + + // 更新参数配置 + ConfigDO updateObj = ConfigConvert.INSTANCE.convert(updateReqVO); + configMapper.updateById(updateObj); + } + + @Override + public void deleteConfig(Long id) { + // 校验配置存在 + ConfigDO config = validateConfigExists(id); + // 内置配置,不允许删除 + if (ConfigTypeEnum.SYSTEM.getType().equals(config.getType())) { + throw exception(CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE); + } + // 删除 + configMapper.deleteById(id); + } + + @Override + public ConfigDO getConfig(Long id) { + return configMapper.selectById(id); + } + + @Override + public ConfigDO getConfigByKey(String key) { + return configMapper.selectByKey(key); + } + + @Override + public PageResult getConfigPage(ConfigPageReqVO pageReqVO) { + return configMapper.selectPage(pageReqVO); + } + + @VisibleForTesting + public ConfigDO validateConfigExists(Long id) { + if (id == null) { + return null; + } + ConfigDO config = configMapper.selectById(id); + if (config == null) { + throw exception(CONFIG_NOT_EXISTS); + } + return config; + } + + @VisibleForTesting + public void validateConfigKeyUnique(Long id, String key) { + ConfigDO config = configMapper.selectByKey(key); + if (config == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的参数配置 + if (id == null) { + throw exception(CONFIG_KEY_DUPLICATE); + } + if (!config.getId().equals(id)) { + throw exception(CONFIG_KEY_DUPLICATE); + } + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DataSourceConfigService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DataSourceConfigService.java new file mode 100644 index 0000000..42ca625 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DataSourceConfigService.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.infra.service.db; + +import com.tashow.cloud.infra.controller.admin.db.vo.DataSourceConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.db.DataSourceConfigDO; + +import jakarta.validation.Valid; +import java.util.List; + +/** + * 数据源配置 Service 接口 + * + * @author 芋道源码 + */ +public interface DataSourceConfigService { + + /** + * 创建数据源配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDataSourceConfig(@Valid DataSourceConfigSaveReqVO createReqVO); + + /** + * 更新数据源配置 + * + * @param updateReqVO 更新信息 + */ + void updateDataSourceConfig(@Valid DataSourceConfigSaveReqVO updateReqVO); + + /** + * 删除数据源配置 + * + * @param id 编号 + */ + void deleteDataSourceConfig(Long id); + + /** + * 获得数据源配置 + * + * @param id 编号 + * @return 数据源配置 + */ + DataSourceConfigDO getDataSourceConfig(Long id); + + /** + * 获得数据源配置列表 + * + * @return 数据源配置列表 + */ + List getDataSourceConfigList(); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DataSourceConfigServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DataSourceConfigServiceImpl.java new file mode 100644 index 0000000..104cc38 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DataSourceConfigServiceImpl.java @@ -0,0 +1,106 @@ +package com.tashow.cloud.infra.service.db; + +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.db.vo.DataSourceConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.db.DataSourceConfigDO; +import com.tashow.cloud.infra.dal.mysql.db.DataSourceConfigMapper; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; +import com.tashow.cloud.mybatis.mybatis.core.util.JdbcUtils; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.List; +import java.util.Objects; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_OK; + +/** + * 数据源配置 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class DataSourceConfigServiceImpl implements DataSourceConfigService { + + @Resource + private DataSourceConfigMapper dataSourceConfigMapper; + + @Resource + private DynamicDataSourceProperties dynamicDataSourceProperties; + + @Override + public Long createDataSourceConfig(DataSourceConfigSaveReqVO createReqVO) { + DataSourceConfigDO config = BeanUtils.toBean(createReqVO, DataSourceConfigDO.class); + validateConnectionOK(config); + + // 插入 + dataSourceConfigMapper.insert(config); + // 返回 + return config.getId(); + } + + @Override + public void updateDataSourceConfig(DataSourceConfigSaveReqVO updateReqVO) { + // 校验存在 + validateDataSourceConfigExists(updateReqVO.getId()); + DataSourceConfigDO updateObj = BeanUtils.toBean(updateReqVO, DataSourceConfigDO.class); + validateConnectionOK(updateObj); + + // 更新 + dataSourceConfigMapper.updateById(updateObj); + } + + @Override + public void deleteDataSourceConfig(Long id) { + // 校验存在 + validateDataSourceConfigExists(id); + // 删除 + dataSourceConfigMapper.deleteById(id); + } + + private void validateDataSourceConfigExists(Long id) { + if (dataSourceConfigMapper.selectById(id) == null) { + throw exception(DATA_SOURCE_CONFIG_NOT_EXISTS); + } + } + + @Override + public DataSourceConfigDO getDataSourceConfig(Long id) { + // 如果 id 为 0,默认为 master 的数据源 + if (Objects.equals(id, DataSourceConfigDO.ID_MASTER)) { + return buildMasterDataSourceConfig(); + } + // 从 DB 中读取 + return dataSourceConfigMapper.selectById(id); + } + + @Override + public List getDataSourceConfigList() { + List result = dataSourceConfigMapper.selectList(); + // 补充 master 数据源 + result.add(0, buildMasterDataSourceConfig()); + return result; + } + + private void validateConnectionOK(DataSourceConfigDO config) { + boolean success = JdbcUtils.isConnectionOK(config.getUrl(), config.getUsername(), config.getPassword()); + if (!success) { + throw exception(DATA_SOURCE_CONFIG_NOT_OK); + } + } + + private DataSourceConfigDO buildMasterDataSourceConfig() { + String primary = dynamicDataSourceProperties.getPrimary(); + DataSourceProperty dataSourceProperty = dynamicDataSourceProperties.getDatasource().get(primary); + return new DataSourceConfigDO().setId(DataSourceConfigDO.ID_MASTER).setName(primary) + .setUrl(dataSourceProperty.getUrl()) + .setUsername(dataSourceProperty.getUsername()) + .setPassword(dataSourceProperty.getPassword()); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DatabaseTableService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DatabaseTableService.java new file mode 100644 index 0000000..2f09552 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DatabaseTableService.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.infra.service.db; + +import com.baomidou.mybatisplus.generator.config.po.TableInfo; + +import java.util.List; + +/** + * 数据库表 Service + * + * @author 芋道源码 + */ +public interface DatabaseTableService { + + /** + * 获得表列表,基于表名称 + 表描述进行模糊匹配 + * + * @param dataSourceConfigId 数据源配置的编号 + * @param nameLike 表名称,模糊匹配 + * @param commentLike 表描述,模糊匹配 + * @return 表列表 + */ + List getTableList(Long dataSourceConfigId, String nameLike, String commentLike); + + /** + * 获得指定表名 + * + * @param dataSourceConfigId 数据源配置的编号 + * @param tableName 表名称 + * @return 表 + */ + TableInfo getTable(Long dataSourceConfigId, String tableName); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DatabaseTableServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DatabaseTableServiceImpl.java new file mode 100644 index 0000000..21c8a35 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/db/DatabaseTableServiceImpl.java @@ -0,0 +1,77 @@ +package com.tashow.cloud.infra.service.db; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.infra.dal.dataobject.db.DataSourceConfigDO; +import com.baomidou.mybatisplus.generator.config.DataSourceConfig; +import com.baomidou.mybatisplus.generator.config.GlobalConfig; +import com.baomidou.mybatisplus.generator.config.StrategyConfig; +import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.baomidou.mybatisplus.generator.config.rules.DateType; +import com.baomidou.mybatisplus.generator.query.SQLQuery; +import com.tashow.cloud.mybatis.mybatis.core.util.JdbcUtils; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 数据库表 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class DatabaseTableServiceImpl implements DatabaseTableService { + + @Resource + private DataSourceConfigService dataSourceConfigService; + + @Override + public List getTableList(Long dataSourceConfigId, String nameLike, String commentLike) { + List tables = getTableList0(dataSourceConfigId, null); + return tables.stream().filter(tableInfo -> (StrUtil.isEmpty(nameLike) || tableInfo.getName().contains(nameLike)) + && (StrUtil.isEmpty(commentLike) || tableInfo.getComment().contains(commentLike))) + .collect(Collectors.toList()); + } + + @Override + public TableInfo getTable(Long dataSourceConfigId, String name) { + return CollUtil.getFirst(getTableList0(dataSourceConfigId, name)); + } + + private List getTableList0(Long dataSourceConfigId, String name) { + // 获得数据源配置 + DataSourceConfigDO config = dataSourceConfigService.getDataSourceConfig(dataSourceConfigId); + Assert.notNull(config, "数据源({}) 不存在!", dataSourceConfigId); + + // 使用 MyBatis Plus Generator 解析表结构 + DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig.Builder(config.getUrl(), config.getUsername(), + config.getPassword()); + if (JdbcUtils.isSQLServer(config.getUrl())) { // 特殊:SQLServer jdbc 非标准,参见 https://github.com/baomidou/mybatis-plus/issues/5419 + dataSourceConfigBuilder.databaseQueryClass(SQLQuery.class); + } + StrategyConfig.Builder strategyConfig = new StrategyConfig.Builder().enableSkipView(); // 忽略视图,业务上一般用不到 + if (StrUtil.isNotEmpty(name)) { + strategyConfig.addInclude(name); + } else { + // 移除工作流和定时任务前缀的表名 + strategyConfig.addExclude("ACT_[\\S\\s]+|QRTZ_[\\S\\s]+|FLW_[\\S\\s]+"); + // 移除 ORACLE 相关的系统表 + strategyConfig.addExclude("IMPDP_[\\S\\s]+|ALL_[\\S\\s]+|HS_[\\S\\\\s]+"); + strategyConfig.addExclude("[\\S\\s]+\\$[\\S\\s]+|[\\S\\s]+\\$"); // 表里不能有 $,一般有都是系统的表 + } + + GlobalConfig globalConfig = new GlobalConfig.Builder().dateType(DateType.TIME_PACK).build(); // 只使用 LocalDateTime 类型,不使用 LocalDate + ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfigBuilder.build(), strategyConfig.build(), + null, globalConfig, null); + // 按照名字排序 + List tables = builder.getTableInfoList(); + tables.sort(Comparator.comparing(TableInfo::getName)); + return tables; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo01/Demo01ContactService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo01/Demo01ContactService.java new file mode 100644 index 0000000..5bceb7d --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo01/Demo01ContactService.java @@ -0,0 +1,55 @@ +package com.tashow.cloud.infra.service.demo.demo01; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo01.Demo01ContactDO; + +import jakarta.validation.Valid; + +/** + * 示例联系人 Service 接口 + * + * @author 芋道源码 + */ +public interface Demo01ContactService { + + /** + * 创建示例联系人 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDemo01Contact(@Valid Demo01ContactSaveReqVO createReqVO); + + /** + * 更新示例联系人 + * + * @param updateReqVO 更新信息 + */ + void updateDemo01Contact(@Valid Demo01ContactSaveReqVO updateReqVO); + + /** + * 删除示例联系人 + * + * @param id 编号 + */ + void deleteDemo01Contact(Long id); + + /** + * 获得示例联系人 + * + * @param id 编号 + * @return 示例联系人 + */ + Demo01ContactDO getDemo01Contact(Long id); + + /** + * 获得示例联系人分页 + * + * @param pageReqVO 分页查询 + * @return 示例联系人分页 + */ + PageResult getDemo01ContactPage(Demo01ContactPageReqVO pageReqVO); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo01/Demo01ContactServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo01/Demo01ContactServiceImpl.java new file mode 100644 index 0000000..15910b8 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo01/Demo01ContactServiceImpl.java @@ -0,0 +1,71 @@ +package com.tashow.cloud.infra.service.demo.demo01; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo01.Demo01ContactDO; +import com.tashow.cloud.infra.dal.mysql.demo.demo01.Demo01ContactMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.DEMO01_CONTACT_NOT_EXISTS; + +/** + * 示例联系人 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class Demo01ContactServiceImpl implements Demo01ContactService { + + @Resource + private Demo01ContactMapper demo01ContactMapper; + + @Override + public Long createDemo01Contact(Demo01ContactSaveReqVO createReqVO) { + // 插入 + Demo01ContactDO demo01Contact = BeanUtils.toBean(createReqVO, Demo01ContactDO.class); + demo01ContactMapper.insert(demo01Contact); + // 返回 + return demo01Contact.getId(); + } + + @Override + public void updateDemo01Contact(Demo01ContactSaveReqVO updateReqVO) { + // 校验存在 + validateDemo01ContactExists(updateReqVO.getId()); + // 更新 + Demo01ContactDO updateObj = BeanUtils.toBean(updateReqVO, Demo01ContactDO.class); + demo01ContactMapper.updateById(updateObj); + } + + @Override + public void deleteDemo01Contact(Long id) { + // 校验存在 + validateDemo01ContactExists(id); + // 删除 + demo01ContactMapper.deleteById(id); + } + + private void validateDemo01ContactExists(Long id) { + if (demo01ContactMapper.selectById(id) == null) { + throw exception(DEMO01_CONTACT_NOT_EXISTS); + } + } + + @Override + public Demo01ContactDO getDemo01Contact(Long id) { + return demo01ContactMapper.selectById(id); + } + + @Override + public PageResult getDemo01ContactPage(Demo01ContactPageReqVO pageReqVO) { + return demo01ContactMapper.selectPage(pageReqVO); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo02/Demo02CategoryService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo02/Demo02CategoryService.java new file mode 100644 index 0000000..8652fdb --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo02/Demo02CategoryService.java @@ -0,0 +1,55 @@ +package com.tashow.cloud.infra.service.demo.demo02; + +import com.tashow.cloud.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo02.Demo02CategoryDO; + +import jakarta.validation.Valid; +import java.util.List; + +/** + * 示例分类 Service 接口 + * + * @author 芋道源码 + */ +public interface Demo02CategoryService { + + /** + * 创建示例分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDemo02Category(@Valid Demo02CategorySaveReqVO createReqVO); + + /** + * 更新示例分类 + * + * @param updateReqVO 更新信息 + */ + void updateDemo02Category(@Valid Demo02CategorySaveReqVO updateReqVO); + + /** + * 删除示例分类 + * + * @param id 编号 + */ + void deleteDemo02Category(Long id); + + /** + * 获得示例分类 + * + * @param id 编号 + * @return 示例分类 + */ + Demo02CategoryDO getDemo02Category(Long id); + + /** + * 获得示例分类列表 + * + * @param listReqVO 查询条件 + * @return 示例分类列表 + */ + List getDemo02CategoryList(Demo02CategoryListReqVO listReqVO); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo02/Demo02CategoryServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo02/Demo02CategoryServiceImpl.java new file mode 100644 index 0000000..1f6a4fc --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo02/Demo02CategoryServiceImpl.java @@ -0,0 +1,134 @@ +package com.tashow.cloud.infra.service.demo.demo02; + +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo02.Demo02CategoryDO; +import com.tashow.cloud.infra.dal.mysql.demo.demo02.Demo02CategoryMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.List; +import java.util.Objects; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.*; + +/** + * 示例分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class Demo02CategoryServiceImpl implements Demo02CategoryService { + + @Resource + private Demo02CategoryMapper demo02CategoryMapper; + + @Override + public Long createDemo02Category(Demo02CategorySaveReqVO createReqVO) { + // 校验父级编号的有效性 + validateParentDemo02Category(null, createReqVO.getParentId()); + // 校验名字的唯一性 + validateDemo02CategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入 + Demo02CategoryDO demo02Category = BeanUtils.toBean(createReqVO, Demo02CategoryDO.class); + demo02CategoryMapper.insert(demo02Category); + // 返回 + return demo02Category.getId(); + } + + @Override + public void updateDemo02Category(Demo02CategorySaveReqVO updateReqVO) { + // 校验存在 + validateDemo02CategoryExists(updateReqVO.getId()); + // 校验父级编号的有效性 + validateParentDemo02Category(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验名字的唯一性 + validateDemo02CategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新 + Demo02CategoryDO updateObj = BeanUtils.toBean(updateReqVO, Demo02CategoryDO.class); + demo02CategoryMapper.updateById(updateObj); + } + + @Override + public void deleteDemo02Category(Long id) { + // 校验存在 + validateDemo02CategoryExists(id); + // 校验是否有子示例分类 + if (demo02CategoryMapper.selectCountByParentId(id) > 0) { + throw exception(DEMO02_CATEGORY_EXITS_CHILDREN); + } + // 删除 + demo02CategoryMapper.deleteById(id); + } + + private void validateDemo02CategoryExists(Long id) { + if (demo02CategoryMapper.selectById(id) == null) { + throw exception(DEMO02_CATEGORY_NOT_EXISTS); + } + } + + private void validateParentDemo02Category(Long id, Long parentId) { + if (parentId == null || Demo02CategoryDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父示例分类 + if (Objects.equals(id, parentId)) { + throw exception(DEMO02_CATEGORY_PARENT_ERROR); + } + // 2. 父示例分类不存在 + Demo02CategoryDO parentDemo02Category = demo02CategoryMapper.selectById(parentId); + if (parentDemo02Category == null) { + throw exception(DEMO02_CATEGORY_PARENT_NOT_EXITS); + } + // 3. 递归校验父示例分类,如果父示例分类是自己的子示例分类,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentDemo02Category.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(DEMO02_CATEGORY_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父示例分类 + if (parentId == null || Demo02CategoryDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentDemo02Category = demo02CategoryMapper.selectById(parentId); + if (parentDemo02Category == null) { + break; + } + } + } + + private void validateDemo02CategoryNameUnique(Long id, Long parentId, String name) { + Demo02CategoryDO demo02Category = demo02CategoryMapper.selectByParentIdAndName(parentId, name); + if (demo02Category == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的示例分类 + if (id == null) { + throw exception(DEMO02_CATEGORY_NAME_DUPLICATE); + } + if (!Objects.equals(demo02Category.getId(), id)) { + throw exception(DEMO02_CATEGORY_NAME_DUPLICATE); + } + } + + @Override + public Demo02CategoryDO getDemo02Category(Long id) { + return demo02CategoryMapper.selectById(id); + } + + @Override + public List getDemo02CategoryList(Demo02CategoryListReqVO listReqVO) { + return demo02CategoryMapper.selectList(listReqVO); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo03/Demo03StudentService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo03/Demo03StudentService.java new file mode 100644 index 0000000..e3c0407 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo03/Demo03StudentService.java @@ -0,0 +1,158 @@ +package com.tashow.cloud.infra.service.demo.demo03; + +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03StudentDO; + +import jakarta.validation.Valid; +import java.util.List; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface Demo03StudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDemo03Student(@Valid Demo03StudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateDemo03Student(@Valid Demo03StudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteDemo03Student(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + Demo03StudentDO getDemo03Student(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getDemo03StudentPage(Demo03StudentPageReqVO pageReqVO); + + + // ==================== 子表(学生课程) ==================== + + /** + * 获得学生课程列表 + * + * @param studentId 学生编号 + * @return 学生课程列表 + */ + List getDemo03CourseListByStudentId(Long studentId); + + /** + * 获得学生课程分页 + * + * @param pageReqVO 分页查询 + * @param studentId 学生编号 + * @return 学生课程分页 + */ + PageResult getDemo03CoursePage(PageParam pageReqVO, Long studentId); + + /** + * 创建学生课程 + * + * @param demo03Course 创建信息 + * @return 编号 + */ + Long createDemo03Course(@Valid Demo03CourseDO demo03Course); + + /** + * 更新学生课程 + * + * @param demo03Course 更新信息 + */ + void updateDemo03Course(@Valid Demo03CourseDO demo03Course); + + /** + * 删除学生课程 + * + * @param id 编号 + */ + void deleteDemo03Course(Long id); + + /** + * 获得学生课程 + * + * @param id 编号 + * @return 学生课程 + */ + Demo03CourseDO getDemo03Course(Long id); + + // ==================== 子表(学生班级) ==================== + + /** + * 获得学生班级 + * + * @param studentId 学生编号 + * @return 学生班级 + */ + Demo03GradeDO getDemo03GradeByStudentId(Long studentId); + + /** + * 获得学生班级分页 + * + * @param pageReqVO 分页查询 + * @param studentId 学生编号 + * @return 学生班级分页 + */ + PageResult getDemo03GradePage(PageParam pageReqVO, Long studentId); + + /** + * 创建学生班级 + * + * @param demo03Grade 创建信息 + * @return 编号 + */ + Long createDemo03Grade(@Valid Demo03GradeDO demo03Grade); + + /** + * 更新学生班级 + * + * @param demo03Grade 更新信息 + */ + void updateDemo03Grade(@Valid Demo03GradeDO demo03Grade); + + /** + * 删除学生班级 + * + * @param id 编号 + */ + void deleteDemo03Grade(Long id); + + /** + * 获得学生班级 + * + * @param id 编号 + * @return 学生班级 + */ + Demo03GradeDO getDemo03Grade(Long id); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo03/Demo03StudentServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo03/Demo03StudentServiceImpl.java new file mode 100644 index 0000000..e076c73 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/demo/demo03/Demo03StudentServiceImpl.java @@ -0,0 +1,217 @@ +package com.tashow.cloud.infra.service.demo.demo03; + +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import com.tashow.cloud.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import com.tashow.cloud.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import com.tashow.cloud.infra.dal.mysql.demo.demo03.Demo03CourseMapper; +import com.tashow.cloud.infra.dal.mysql.demo.demo03.Demo03GradeMapper; +import com.tashow.cloud.infra.dal.mysql.demo.demo03.Demo03StudentMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class Demo03StudentServiceImpl implements Demo03StudentService { + + @Resource + private Demo03StudentMapper demo03StudentMapper; + @Resource + private Demo03CourseMapper demo03CourseMapper; + @Resource + private Demo03GradeMapper demo03GradeMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createDemo03Student(Demo03StudentSaveReqVO createReqVO) { + // 插入 + Demo03StudentDO demo03Student = BeanUtils.toBean(createReqVO, Demo03StudentDO.class); + demo03StudentMapper.insert(demo03Student); + + // 插入子表 + createDemo03CourseList(demo03Student.getId(), createReqVO.getDemo03Courses()); + createDemo03Grade(demo03Student.getId(), createReqVO.getDemo03Grade()); + // 返回 + return demo03Student.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateDemo03Student(Demo03StudentSaveReqVO updateReqVO) { + // 校验存在 + validateDemo03StudentExists(updateReqVO.getId()); + // 更新 + Demo03StudentDO updateObj = BeanUtils.toBean(updateReqVO, Demo03StudentDO.class); + demo03StudentMapper.updateById(updateObj); + + // 更新子表 + updateDemo03CourseList(updateReqVO.getId(), updateReqVO.getDemo03Courses()); + updateDemo03Grade(updateReqVO.getId(), updateReqVO.getDemo03Grade()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteDemo03Student(Long id) { + // 校验存在 + validateDemo03StudentExists(id); + // 删除 + demo03StudentMapper.deleteById(id); + + // 删除子表 + deleteDemo03CourseByStudentId(id); + deleteDemo03GradeByStudentId(id); + } + + private void validateDemo03StudentExists(Long id) { + if (demo03StudentMapper.selectById(id) == null) { + throw exception(DEMO03_STUDENT_NOT_EXISTS); + } + } + + @Override + public Demo03StudentDO getDemo03Student(Long id) { + return demo03StudentMapper.selectById(id); + } + + @Override + public PageResult getDemo03StudentPage(Demo03StudentPageReqVO pageReqVO) { + return demo03StudentMapper.selectPage(pageReqVO); + } + + // ==================== 子表(学生课程) ==================== + + @Override + public List getDemo03CourseListByStudentId(Long studentId) { + return demo03CourseMapper.selectListByStudentId(studentId); + } + + private void createDemo03CourseList(Long studentId, List list) { + if (list != null) { + list.forEach(o -> o.setStudentId(studentId)); + } + demo03CourseMapper.insertBatch(list); + } + + private void updateDemo03CourseList(Long studentId, List list) { + deleteDemo03CourseByStudentId(studentId); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + createDemo03CourseList(studentId, list); + } + + private void deleteDemo03CourseByStudentId(Long studentId) { + demo03CourseMapper.deleteByStudentId(studentId); + } + + @Override + public PageResult getDemo03CoursePage(PageParam pageReqVO, Long studentId) { + return demo03CourseMapper.selectPage(pageReqVO, studentId); + } + + @Override + public Long createDemo03Course(Demo03CourseDO demo03Course) { + demo03CourseMapper.insert(demo03Course); + return demo03Course.getId(); + } + + @Override + public void updateDemo03Course(Demo03CourseDO demo03Course) { + demo03CourseMapper.updateById(demo03Course); + } + + @Override + public void deleteDemo03Course(Long id) { + demo03CourseMapper.deleteById(id); + } + + @Override + public Demo03CourseDO getDemo03Course(Long id) { + return demo03CourseMapper.selectById(id); + } + + // ==================== 子表(学生班级) ==================== + + @Override + public Demo03GradeDO getDemo03GradeByStudentId(Long studentId) { + return demo03GradeMapper.selectByStudentId(studentId); + } + + private void createDemo03Grade(Long studentId, Demo03GradeDO demo03Grade) { + if (demo03Grade == null) { + return; + } + demo03Grade.setStudentId(studentId); + demo03GradeMapper.insert(demo03Grade); + } + + private void updateDemo03Grade(Long studentId, Demo03GradeDO demo03Grade) { + if (demo03Grade == null) { + return; + } + demo03Grade.setStudentId(studentId); + demo03Grade.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + demo03GradeMapper.insertOrUpdate(demo03Grade); + } + + private void deleteDemo03GradeByStudentId(Long studentId) { + demo03GradeMapper.deleteByStudentId(studentId); + } + + @Override + public PageResult getDemo03GradePage(PageParam pageReqVO, Long studentId) { + return demo03GradeMapper.selectPage(pageReqVO, studentId); + } + + @Override + public Long createDemo03Grade(Demo03GradeDO demo03Grade) { + // 校验是否已经存在 + if (demo03GradeMapper.selectByStudentId(demo03Grade.getStudentId()) != null) { + throw exception(DEMO03_GRADE_EXISTS); + } + demo03GradeMapper.insert(demo03Grade); + return demo03Grade.getId(); + } + + @Override + public void updateDemo03Grade(Demo03GradeDO demo03Grade) { + // 校验存在 + validateDemo03GradeExists(demo03Grade.getId()); + // 更新 + demo03GradeMapper.updateById(demo03Grade); + } + + @Override + public void deleteDemo03Grade(Long id) { + // 校验存在 + validateDemo03GradeExists(id); + // 删除 + demo03GradeMapper.deleteById(id); + } + + @Override + public Demo03GradeDO getDemo03Grade(Long id) { + return demo03GradeMapper.selectById(id); + } + + private void validateDemo03GradeExists(Long id) { + if (demo03GradeMapper.selectById(id) == null) { + throw exception(DEMO03_GRADE_NOT_EXISTS); + } + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileConfigService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileConfigService.java new file mode 100644 index 0000000..d7e45f2 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileConfigService.java @@ -0,0 +1,86 @@ +package com.tashow.cloud.infra.service.file; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; + +import com.tashow.cloud.infra.framework.file.core.client.FileClient; +import jakarta.validation.Valid; + +/** + * 文件配置 Service 接口 + * + * @author 芋道源码 + */ +public interface FileConfigService { + + /** + * 创建文件配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createFileConfig(@Valid FileConfigSaveReqVO createReqVO); + + /** + * 更新文件配置 + * + * @param updateReqVO 更新信息 + */ + void updateFileConfig(@Valid FileConfigSaveReqVO updateReqVO); + + /** + * 更新文件配置为 Master + * + * @param id 编号 + */ + void updateFileConfigMaster(Long id); + + /** + * 删除文件配置 + * + * @param id 编号 + */ + void deleteFileConfig(Long id); + + /** + * 获得文件配置 + * + * @param id 编号 + * @return 文件配置 + */ + FileConfigDO getFileConfig(Long id); + + /** + * 获得文件配置分页 + * + * @param pageReqVO 分页查询 + * @return 文件配置分页 + */ + PageResult getFileConfigPage(FileConfigPageReqVO pageReqVO); + + /** + * 测试文件配置是否正确,通过上传文件 + * + * @param id 编号 + * @return 文件 URL + */ + String testFileConfig(Long id) throws Exception; + + /** + * 获得指定编号的文件客户端 + * + * @param id 配置编号 + * @return 文件客户端 + */ + FileClient getFileClient(Long id); + + /** + * 获得 Master 文件客户端 + * + * @return 文件客户端 + */ + FileClient getMasterFileClient(); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileConfigServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileConfigServiceImpl.java new file mode 100644 index 0000000..56b27c0 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileConfigServiceImpl.java @@ -0,0 +1,189 @@ +package com.tashow.cloud.infra.service.file; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.util.IdUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.common.util.validation.ValidationUtils; +import com.tashow.cloud.infra.convert.file.FileConfigConvert; +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import com.tashow.cloud.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import com.tashow.cloud.infra.dal.dataobject.file.FileConfigDO; +import com.tashow.cloud.infra.dal.mysql.file.FileConfigMapper; +import com.tashow.cloud.infra.framework.file.core.client.FileClient; +import com.tashow.cloud.infra.framework.file.core.client.FileClientConfig; +import com.tashow.cloud.infra.framework.file.core.client.FileClientFactory; +import com.tashow.cloud.infra.framework.file.core.enums.FileStorageEnum; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import jakarta.validation.Validator; +import java.time.Duration; +import java.util.Map; +import java.util.Objects; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.cache.CacheUtils.buildAsyncReloadingCache; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS; + +/** + * 文件配置 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class FileConfigServiceImpl implements FileConfigService { + + private static final Long CACHE_MASTER_ID = 0L; + + /** + * {@link FileClient} 缓存,通过它异步刷新 fileClientFactory + */ + @Getter + private final LoadingCache clientCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public FileClient load(Long id) { + FileConfigDO config = Objects.equals(CACHE_MASTER_ID, id) ? + fileConfigMapper.selectByMaster() : fileConfigMapper.selectById(id); + if (config != null) { + fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig()); + } + return fileClientFactory.getFileClient(null == config ? id : config.getId()); + } + + }); + + @Resource + private FileClientFactory fileClientFactory; + + @Resource + private FileConfigMapper fileConfigMapper; + + @Resource + private Validator validator; + + @Override + public Long createFileConfig(FileConfigSaveReqVO createReqVO) { + FileConfigDO fileConfig = FileConfigConvert.INSTANCE.convert(createReqVO) + .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig())) + .setMaster(false); // 默认非 master + fileConfigMapper.insert(fileConfig); + return fileConfig.getId(); + } + + @Override + public void updateFileConfig(FileConfigSaveReqVO updateReqVO) { + // 校验存在 + FileConfigDO config = validateFileConfigExists(updateReqVO.getId()); + // 更新 + FileConfigDO updateObj = FileConfigConvert.INSTANCE.convert(updateReqVO) + .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig())); + fileConfigMapper.updateById(updateObj); + + // 清空缓存 + clearCache(config.getId(), null); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateFileConfigMaster(Long id) { + // 校验存在 + validateFileConfigExists(id); + // 更新其它为非 master + fileConfigMapper.updateBatch(new FileConfigDO().setMaster(false)); + // 更新 + fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true)); + + // 清空缓存 + clearCache(null, true); + } + + private FileClientConfig parseClientConfig(Integer storage, Map config) { + // 获取配置类 + Class configClass = FileStorageEnum.getByStorage(storage) + .getConfigClass(); + FileClientConfig clientConfig = JsonUtils.parseObject2(JsonUtils.toJsonString(config), configClass); + // 参数校验 + ValidationUtils.validate(validator, clientConfig); + // 设置参数 + return clientConfig; + } + + @Override + public void deleteFileConfig(Long id) { + // 校验存在 + FileConfigDO config = validateFileConfigExists(id); + if (Boolean.TRUE.equals(config.getMaster())) { + throw exception(FILE_CONFIG_DELETE_FAIL_MASTER); + } + // 删除 + fileConfigMapper.deleteById(id); + + // 清空缓存 + clearCache(id, null); + } + + /** + * 清空指定文件配置 + * + * @param id 配置编号 + * @param master 是否主配置 + */ + private void clearCache(Long id, Boolean master) { + if (id != null) { + clientCache.invalidate(id); + } + if (Boolean.TRUE.equals(master)) { + clientCache.invalidate(CACHE_MASTER_ID); + } + } + + private FileConfigDO validateFileConfigExists(Long id) { + FileConfigDO config = fileConfigMapper.selectById(id); + if (config == null) { + throw exception(FILE_CONFIG_NOT_EXISTS); + } + return config; + } + + @Override + public FileConfigDO getFileConfig(Long id) { + return fileConfigMapper.selectById(id); + } + + @Override + public PageResult getFileConfigPage(FileConfigPageReqVO pageReqVO) { + return fileConfigMapper.selectPage(pageReqVO); + } + + @Override + public String testFileConfig(Long id) throws Exception { + // 校验存在 + validateFileConfigExists(id); + // 上传文件 + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + return getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg", "image/jpeg"); + } + + @Override + public FileClient getFileClient(Long id) { + return clientCache.getUnchecked(id); + } + + @Override + public FileClient getMasterFileClient() { + return clientCache.getUnchecked(CACHE_MASTER_ID); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileService.java new file mode 100644 index 0000000..dfd26ba --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileService.java @@ -0,0 +1,66 @@ +package com.tashow.cloud.infra.service.file; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FileCreateReqVO; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FilePageReqVO; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO; +import com.tashow.cloud.infra.dal.dataobject.file.FileDO; + +/** + * 文件 Service 接口 + * + * @author 芋道源码 + */ +public interface FileService { + + /** + * 获得文件分页 + * + * @param pageReqVO 分页查询 + * @return 文件分页 + */ + PageResult getFilePage(FilePageReqVO pageReqVO); + + /** + * 保存文件,并返回文件的访问路径 + * + * @param name 文件名称 + * @param path 文件路径 + * @param content 文件内容 + * @return 文件路径 + */ + String createFile(String name, String path, byte[] content); + + /** + * 创建文件 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createFile(FileCreateReqVO createReqVO); + + /** + * 删除文件 + * + * @param id 编号 + */ + void deleteFile(Long id) throws Exception; + + /** + * 获得文件内容 + * + * @param configId 配置编号 + * @param path 文件路径 + * @return 文件内容 + */ + byte[] getFileContent(Long configId, String path) throws Exception; + + /** + * 生成文件预签名地址信息 + * + * @param path 文件路径 + * @return 预签名地址信息 + */ + FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileServiceImpl.java new file mode 100644 index 0000000..ace0d22 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/file/FileServiceImpl.java @@ -0,0 +1,116 @@ +package com.tashow.cloud.infra.service.file; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.io.FileUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FileCreateReqVO; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FilePageReqVO; +import com.tashow.cloud.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO; +import com.tashow.cloud.infra.dal.dataobject.file.FileDO; +import com.tashow.cloud.infra.dal.mysql.file.FileMapper; +import com.tashow.cloud.infra.framework.file.core.client.FileClient; +import com.tashow.cloud.infra.framework.file.core.client.s3.FilePresignedUrlRespDTO; +import com.tashow.cloud.infra.framework.file.core.utils.FileTypeUtils; +import jakarta.annotation.Resource; +import lombok.SneakyThrows; +import org.springframework.stereotype.Service; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.FILE_NOT_EXISTS; + +/** + * 文件 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class FileServiceImpl implements FileService { + + @Resource + private FileConfigService fileConfigService; + + @Resource + private FileMapper fileMapper; + + @Override + public PageResult getFilePage(FilePageReqVO pageReqVO) { + return fileMapper.selectPage(pageReqVO); + } + + @Override + @SneakyThrows + public String createFile(String name, String path, byte[] content) { + // 计算默认的 path 名 + String type = FileTypeUtils.getMineType(content, name); + if (StrUtil.isEmpty(path)) { + path = FileUtils.generatePath(content, name); + } + // 如果 name 为空,则使用 path 填充 + if (StrUtil.isEmpty(name)) { + name = path; + } + + // 上传到文件存储器 + FileClient client = fileConfigService.getMasterFileClient(); + Assert.notNull(client, "客户端(master) 不能为空"); + String url = client.upload(content, path, type); + + // 保存到数据库 + FileDO file = new FileDO(); + file.setConfigId(client.getId()); + file.setName(name); + file.setPath(path); + file.setUrl(url); + file.setType(type); + file.setSize(content.length); + fileMapper.insert(file); + return url; + } + + @Override + public Long createFile(FileCreateReqVO createReqVO) { + FileDO file = BeanUtils.toBean(createReqVO, FileDO.class); + fileMapper.insert(file); + return file.getId(); + } + + @Override + public void deleteFile(Long id) throws Exception { + // 校验存在 + FileDO file = validateFileExists(id); + + // 从文件存储器中删除 + FileClient client = fileConfigService.getFileClient(file.getConfigId()); + Assert.notNull(client, "客户端({}) 不能为空", file.getConfigId()); + client.delete(file.getPath()); + + // 删除记录 + fileMapper.deleteById(id); + } + + private FileDO validateFileExists(Long id) { + FileDO fileDO = fileMapper.selectById(id); + if (fileDO == null) { + throw exception(FILE_NOT_EXISTS); + } + return fileDO; + } + + @Override + public byte[] getFileContent(Long configId, String path) throws Exception { + FileClient client = fileConfigService.getFileClient(configId); + Assert.notNull(client, "客户端({}) 不能为空", configId); + return client.getContent(path); + } + + @Override + public FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception { + FileClient fileClient = fileConfigService.getMasterFileClient(); + FilePresignedUrlRespDTO presignedObjectUrl = fileClient.getPresignedObjectUrl(path); + return BeanUtils.toBean(presignedObjectUrl, FilePresignedUrlRespVO.class, + object -> object.setConfigId(fileClient.getId())); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiAccessLogService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiAccessLogService.java new file mode 100644 index 0000000..278086c --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiAccessLogService.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.infra.service.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import com.tashow.cloud.infraapi.api.logger.dto.ApiAccessLogCreateReqDTO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; + +/** + * API 访问日志 Service 接口 + * + * @author 芋道源码 + */ +public interface ApiAccessLogService { + + /** + * 创建 API 访问日志 + * + * @param createReqDTO API 访问日志 + */ + void createApiAccessLog(ApiAccessLogCreateReqDTO createReqDTO); + + /** + * 获得 API 访问日志分页 + * + * @param pageReqVO 分页查询 + * @return API 访问日志分页 + */ + PageResult getApiAccessLogPage(ApiAccessLogPageReqVO pageReqVO); + + /** + * 清理 exceedDay 天前的访问日志 + * + * @param exceedDay 超过多少天就进行清理 + * @param deleteLimit 清理的间隔条数 + */ + Integer cleanAccessLog(Integer exceedDay, Integer deleteLimit); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiAccessLogServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiAccessLogServiceImpl.java new file mode 100644 index 0000000..c20221b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiAccessLogServiceImpl.java @@ -0,0 +1,68 @@ +package com.tashow.cloud.infra.service.logger; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiAccessLogDO; +import com.tashow.cloud.infraapi.api.logger.dto.ApiAccessLogCreateReqDTO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import com.tashow.cloud.infra.dal.mysql.logger.ApiAccessLogMapper; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.util.TenantUtils; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDateTime; + + +/** + * API 访问日志 Service 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@Service +@Validated +public class ApiAccessLogServiceImpl implements ApiAccessLogService { + + @Resource + private ApiAccessLogMapper apiAccessLogMapper; + + @Override + public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) { + ApiAccessLogDO apiAccessLog = BeanUtils.toBean(createDTO, ApiAccessLogDO.class); + apiAccessLog.setRequestParams(StrUtil.maxLength(apiAccessLog.getRequestParams(), ApiAccessLogDO.REQUEST_PARAMS_MAX_LENGTH)); + apiAccessLog.setResultMsg(StrUtil.maxLength(apiAccessLog.getResultMsg(), ApiAccessLogDO.RESULT_MSG_MAX_LENGTH)); + if (TenantContextHolder.getTenantId() != null) { + apiAccessLogMapper.insert(apiAccessLog); + } else { + // 极端情况下,上下文中没有租户时,此时忽略租户上下文,避免插入失败! + TenantUtils.executeIgnore(() -> apiAccessLogMapper.insert(apiAccessLog)); + } + } + + @Override + public PageResult getApiAccessLogPage(ApiAccessLogPageReqVO pageReqVO) { + return apiAccessLogMapper.selectPage(pageReqVO); + } + + @Override + @SuppressWarnings("DuplicatedCode") + public Integer cleanAccessLog(Integer exceedDay, Integer deleteLimit) { + int count = 0; + LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay); + // 循环删除,直到没有满足条件的数据 + for (int i = 0; i < Short.MAX_VALUE; i++) { + int deleteCount = apiAccessLogMapper.deleteByCreateTimeLt(expireDate, deleteLimit); + count += deleteCount; + // 达到删除预期条数,说明到底了 + if (deleteCount < deleteLimit) { + break; + } + } + return count; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiErrorLogService.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiErrorLogService.java new file mode 100644 index 0000000..ac17012 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiErrorLogService.java @@ -0,0 +1,49 @@ +package com.tashow.cloud.infra.service.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiErrorLogDO; +import com.tashow.cloud.infraapi.api.logger.dto.ApiErrorLogCreateReqDTO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiErrorLogDO; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiErrorLogDO; + +/** + * API 错误日志 Service 接口 + * + * @author 芋道源码 + */ +public interface ApiErrorLogService { + + /** + * 创建 API 错误日志 + * + * @param createReqDTO API 错误日志 + */ + void createApiErrorLog(ApiErrorLogCreateReqDTO createReqDTO); + + /** + * 获得 API 错误日志分页 + * + * @param pageReqVO 分页查询 + * @return API 错误日志分页 + */ + PageResult getApiErrorLogPage(ApiErrorLogPageReqVO pageReqVO); + + /** + * 更新 API 错误日志已处理 + * + * @param id API 日志编号 + * @param processStatus 处理结果 + * @param processUserId 处理人 + */ + void updateApiErrorLogProcess(Long id, Integer processStatus, Long processUserId); + + /** + * 清理 exceedDay 天前的错误日志 + * + * @param exceedDay 超过多少天就进行清理 + * @param deleteLimit 清理的间隔条数 + */ + Integer cleanErrorLog(Integer exceedDay, Integer deleteLimit); + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiErrorLogServiceImpl.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiErrorLogServiceImpl.java new file mode 100644 index 0000000..b24bff8 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/service/logger/ApiErrorLogServiceImpl.java @@ -0,0 +1,86 @@ +package com.tashow.cloud.infra.service.logger; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infra.dal.dataobject.logger.ApiErrorLogDO; +import com.tashow.cloud.infra.enums.logger.ApiErrorLogProcessStatusEnum; +import com.tashow.cloud.infraapi.api.logger.dto.ApiErrorLogCreateReqDTO; +import com.tashow.cloud.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import com.tashow.cloud.infra.dal.mysql.logger.ApiErrorLogMapper; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.util.TenantUtils; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.API_ERROR_LOG_NOT_FOUND; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.API_ERROR_LOG_PROCESSED; + +/** + * API 错误日志 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class ApiErrorLogServiceImpl implements ApiErrorLogService { + + @Resource + private ApiErrorLogMapper apiErrorLogMapper; + + @Override + public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) { + ApiErrorLogDO apiErrorLog = BeanUtils.toBean(createDTO, ApiErrorLogDO.class) + .setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus()); + apiErrorLog.setRequestParams(StrUtil.maxLength(apiErrorLog.getRequestParams(), ApiErrorLogDO.REQUEST_PARAMS_MAX_LENGTH)); + if (TenantContextHolder.getTenantId() != null) { + apiErrorLogMapper.insert(apiErrorLog); + } else { + // 极端情况下,上下文中没有租户时,此时忽略租户上下文,避免插入失败! + TenantUtils.executeIgnore(() -> apiErrorLogMapper.insert(apiErrorLog)); + } + } + + @Override + public PageResult getApiErrorLogPage(ApiErrorLogPageReqVO pageReqVO) { + return apiErrorLogMapper.selectPage(pageReqVO); + } + + @Override + public void updateApiErrorLogProcess(Long id, Integer processStatus, Long processUserId) { + ApiErrorLogDO errorLog = apiErrorLogMapper.selectById(id); + if (errorLog == null) { + throw exception(API_ERROR_LOG_NOT_FOUND); + } + if (!ApiErrorLogProcessStatusEnum.INIT.getStatus().equals(errorLog.getProcessStatus())) { + throw exception(API_ERROR_LOG_PROCESSED); + } + // 标记处理 + apiErrorLogMapper.updateById(ApiErrorLogDO.builder().id(id).processStatus(processStatus) + .processUserId(processUserId).processTime(LocalDateTime.now()).build()); + } + + @Override + @SuppressWarnings("DuplicatedCode") + public Integer cleanErrorLog(Integer exceedDay, Integer deleteLimit) { + int count = 0; + LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay); + // 循环删除,直到没有满足条件的数据 + for (int i = 0; i < Short.MAX_VALUE; i++) { + int deleteCount = apiErrorLogMapper.deleteByCreateTimeLt(expireDate, deleteLimit); + count += deleteCount; + // 达到删除预期条数,说明到底了 + if (deleteCount < deleteLimit) { + break; + } + } + return count; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/DemoWebSocketMessageListener.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/DemoWebSocketMessageListener.java new file mode 100644 index 0000000..fafcfa4 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/DemoWebSocketMessageListener.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.infra.websocket; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.infra.websocket.message.DemoSendMessage; +import com.tashow.cloud.infra.websocket.message.DemoReceiveMessage; +import com.tashow.cloud.websocket.core.listener.WebSocketMessageListener; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.util.WebSocketFrameworkUtils; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketSession; + +import jakarta.annotation.Resource; + +/** + * WebSocket 示例:单发消息 + * + * @author 芋道源码 + */ +@Component +public class DemoWebSocketMessageListener implements WebSocketMessageListener { + + @Resource + private WebSocketMessageSender webSocketMessageSender; + + @Override + public void onMessage(WebSocketSession session, DemoSendMessage message) { + Long fromUserId = WebSocketFrameworkUtils.getLoginUserId(session); + // 情况一:单发 + if (message.getToUserId() != null) { + DemoReceiveMessage toMessage = new DemoReceiveMessage().setFromUserId(fromUserId) + .setText(message.getText()).setSingle(true); + webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getToUserId(), // 给指定用户 + "demo-message-receive", toMessage); + return; + } + // 情况二:群发 + DemoReceiveMessage toMessage = new DemoReceiveMessage().setFromUserId(fromUserId) + .setText(message.getText()).setSingle(false); + webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), // 给所有用户 + "demo-message-receive", toMessage); + } + + @Override + public String getType() { + return "demo-message-send"; + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/message/DemoReceiveMessage.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/message/DemoReceiveMessage.java new file mode 100644 index 0000000..f956ef9 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/message/DemoReceiveMessage.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.infra.websocket.message; + +import lombok.Data; + +/** + * 示例:server -> client 同步消息 + * + * @author 芋道源码 + */ +@Data +public class DemoReceiveMessage { + + /** + * 接收人的编号 + */ + private Long fromUserId; + /** + * 内容 + */ + private String text; + + /** + * 是否单聊 + */ + private Boolean single; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/message/DemoSendMessage.java b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/message/DemoSendMessage.java new file mode 100644 index 0000000..3ed3d98 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/java/com/tashow/cloud/infra/websocket/message/DemoSendMessage.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.infra.websocket.message; + +import lombok.Data; + +/** + * 示例:client -> server 发送消息 + * + * @author 芋道源码 + */ +@Data +public class DemoSendMessage { + + /** + * 发送给谁 + * + * 如果为空,说明发送给所有人 + */ + private Long toUserId; + /** + * 内容 + */ + private String text; + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application-dev.yaml b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application-dev.yaml new file mode 100644 index 0000000..80dc8f7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application-dev.yaml @@ -0,0 +1,130 @@ +--- #################### 注册中心 + 配置中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + username: # Nacos 账号 + password: # Nacos 密码 + discovery: # 【配置中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + metadata: + version: 1.0.0 # 服务实例的版本号,可用于灰度发布 + config: # 【注册中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + +--- #################### 数据库相关配置 #################### +spring: + # 数据源配置项 + autoconfigure: + exclude: + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 5 # 初始连接数 + min-idle: 10 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + username: root + password: 123456 + slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 + lazy: true # 开启懒加载,保证启动速度 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + data: + redis: + host: 400-infra.server.iocoder.cn # 地址 + port: 6379 # 端口 + database: 1 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +--- #################### MQ 消息队列相关配置 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv + +spring: + # RabbitMQ 配置项,对应 RabbitProperties 配置类 + rabbitmq: + host: 127.0.0.1 # RabbitMQ 服务的地址 + port: 5672 # RabbitMQ 服务的端口 + username: guest # RabbitMQ 服务的账号 + password: guest # RabbitMQ 服务的密码 + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔 + +--- #################### 定时任务相关配置 #################### +xxl: + job: + admin: + addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + # Spring Boot Admin Server 服务端的相关配置 + context-path: /admin # 配置 Spring + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + demo: true # 开启演示模式 diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application-local.yaml b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application-local.yaml new file mode 100644 index 0000000..8c009ea --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application-local.yaml @@ -0,0 +1,154 @@ +--- #################### 注册中心 + 配置中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + username: # Nacos 账号 + password: # Nacos 密码 + discovery: # 【配置中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + metadata: + version: 1.0.0 # 服务实例的版本号,可用于灰度发布 + config: # 【注册中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + +--- #################### 数据库相关配置 #################### +spring: + + # 数据源配置项 + autoconfigure: + exclude: + - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 + - de.codecentric.boot.admin.server.cloud.config.AdminServerDiscoveryAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 + - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 + - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 1 # 初始连接数 + min-idle: 1 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 + # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 + # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro # SQLServer 连接的示例 + # url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 + username: root + password: 123456 + # username: sa # SQL Server 连接的示例 + # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W # SQL Server 连接的示例 + # username: SYSDBA # DM 连接的示例 + # password: SYSDBA # DM 连接的示例 + slave: # 模拟从库,可根据自己需要修改 + lazy: true # 开启懒加载,保证启动速度 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + data: + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +--- #################### MQ 消息队列相关配置 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv + +spring: + # RabbitMQ 配置项,对应 RabbitProperties 配置类 + rabbitmq: + host: 127.0.0.1 # RabbitMQ 服务的地址 + port: 5672 # RabbitMQ 服务的端口 + username: guest # RabbitMQ 服务的账号 + password: guest # RabbitMQ 服务的密码 + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔 + +--- #################### 定时任务相关配置 #################### +xxl: + job: + enabled: false # 是否开启调度中心,默认为 true 开启 + admin: + addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + # Spring Boot Admin Server 服务端的相关配置 + context-path: /admin # 配置 Spring + +# 日志文件配置 +logging: + level: + com.tashow.cloud: INFO +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +tashow: + env: # 多环境的配置项 + tag: ${HOSTNAME} + security: + mock-enable: true + access-log: # 访问日志的配置项 + enable: false diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application.yaml b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application.yaml new file mode 100644 index 0000000..6c9f229 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/application.yaml @@ -0,0 +1,181 @@ +spring: + application: + name: infra-server + + profiles: + active: local + + main: + allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 + allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务 + + config: + import: + - optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置 + - optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置 + + # Servlet 配置 + servlet: + # 文件上传相关配置项 + multipart: + max-file-size: 16MB # 单个文件大小 + max-request-size: 32MB # 设置总上传的文件大小 + + # Jackson 配置项 + jackson: + serialization: + write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳 + write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401 + write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳 + fail-on-empty-beans: false # 允许序列化无属性的 Bean + + # Cache 配置项 + cache: + type: REDIS + redis: + time-to-live: 1h # 设置过期时间为 1 小时 + +server: + port: 48082 + +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + +--- #################### 接口文档配置 #################### + +springdoc: + api-docs: + enabled: true # 1. 是否开启 Swagger 接文档的元数据 + path: /v3/api-docs + swagger-ui: + enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面 + path: /swagger-ui + default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档 + +knife4j: + enable: true # 2.2 是否开启 Swagger 文档的 Knife4j UI 界面 + setting: + language: zh_cn + +# MyBatis Plus 的配置项 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 + global-config: + db-config: + id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 + # id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库 + # id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 + # id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + banner: false # 关闭控制台的 Banner 打印 + type-aliases-package: ${yudao.info.base-package}.dal.dataobject + encryptor: + password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成 + +mybatis-plus-join: + banner: false # 关闭控制台的 Banner 打印 + +# Spring Data Redis 配置 +spring: + data: + redis: + repositories: + enabled: false # 项目未使用到 Spring Data Redis 的 Repository,所以直接禁用,保证启动速度 + +# VO 转换(数据翻译)相关 +easy-trans: + is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口 + +--- #################### RPC 远程调用相关配置 #################### + +--- #################### 消息队列相关 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + # Producer 配置项 + producer: + group: ${spring.application.name}_PRODUCER # 生产者分组 + +spring: + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + # Kafka Producer 配置项 + producer: + acks: 1 # 0-不应答。1-leader 应答。all-所有 leader 和 follower 应答。 + retries: 3 # 发送失败时,重试发送的次数 + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer # 消息的 value 的序列化 + # Kafka Consumer 配置项 + consumer: + auto-offset-reset: earliest # 设置消费者分组最初的消费进度为 earliest 。可参考博客 https://blog.csdn.net/lishuangzhe7047/article/details/74530417 理解 + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: '*' + # Kafka Consumer Listener 监听器配置 + listener: + missing-topics-fatal: false # 消费监听接口监听的主题不存在时,默认会报错。所以通过设置为 false ,解决报错 + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + executor: + appname: ${spring.application.name} # 执行器 AppName + logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径 + accessToken: default_token # 执行器通讯TOKEN + +--- #################### 芋道相关配置 #################### + +tashow: + info: + version: 1.0.0 + base-package: com.tashow.cloud.infra + web: + admin-ui: + url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址 + xss: + enable: false + exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 + - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 + - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 + websocket: + enable: true # websocket的开关 + path: /infra/ws # 路径 + sender-type: local # 消息发送的类型,可选值为 local、redis、rocketmq、kafka、rabbitmq + sender-rocketmq: + topic: ${spring.application.name}-websocket # 消息发送的 RocketMQ Topic + consumer-group: ${spring.application.name}-websocket-consumer # 消息发送的 RocketMQ Consumer Group + sender-rabbitmq: + exchange: ${spring.application.name}-websocket-exchange # 消息发送的 RabbitMQ Exchange + queue: ${spring.application.name}-websocket-queue # 消息发送的 RabbitMQ Queue + sender-kafka: + topic: ${spring.application.name}-websocket # 消息发送的 Kafka Topic + consumer-group: ${spring.application.name}-websocket-consumer # 消息发送的 Kafka Consumer Group + swagger: + title: 管理后台 + description: 提供管理员管理的所有功能 + version: ${tashow.info.version} + codegen: + base-package: com.tashow.cloud + db-schemas: ${spring.datasource.dynamic.datasource.master.name} + front-type: 20 # 前端模版的类型,参见 CodegenFrontTypeEnum 枚举类 + unit-test-enable: false # 是否生成单元测试 + tenant: # 多租户相关配置项 + enable: true + ignore-urls: + - /admin-api/infra/file/*/get/** # 获取图片,和租户无关 + ignore-tables: + - infra_codegen_column + - infra_codegen_table + - infra_config + - infra_file_config + - infra_file + - infra_file_content + - infra_job + - infra_job_log + - infra_job_log + - infra_data_source_config + +debug: false diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/controller.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/controller.vm new file mode 100644 index 0000000..5aa3bae --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/controller.vm @@ -0,0 +1,233 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}; + +import org.springframework.web.bind.annotation.*; +import ${jakartaPackage}.annotation.Resource; +import org.springframework.validation.annotation.Validated; +#if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end + +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import ${jakartaPackage}.validation.constraints.*; +import ${jakartaPackage}.validation.*; +import ${jakartaPackage}.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import ${PageParamClassName}; +import ${PageResultClassName}; +import ${CommonResultClassName}; +import ${BeanUtils}; +import static ${CommonResultClassName}.success; + +import ${ExcelUtilsClassName}; + +import ${ApiAccessLogClassName}; +import static ${OperateTypeEnumClassName}.*; + +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +#end +import ${basePackage}.module.${table.moduleName}.service.${table.businessName}.${table.className}Service; + +@Tag(name = "${sceneEnum.name} - ${table.classComment}") +@RestController +##二级的 businessName 暂时不算在 HTTP 路径上,可以根据需要写 +@RequestMapping("/${table.moduleName}/${simpleClassName_strikeCase}") +@Validated +public class ${sceneEnum.prefixClass}${table.className}Controller { + + @Resource + private ${table.className}Service ${classNameVar}Service; + + @PostMapping("/create") + @Operation(summary = "创建${table.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')") +#end + public CommonResult<${primaryColumn.javaType}> create${simpleClassName}(@Valid @RequestBody ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO) { + return success(${classNameVar}Service.create${simpleClassName}(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新${table.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')") +#end + public CommonResult update${simpleClassName}(@Valid @RequestBody ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) { + ${classNameVar}Service.update${simpleClassName}(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除${table.classComment}") + @Parameter(name = "id", description = "编号", required = true) +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')") +#end + public CommonResult delete${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) { + ${classNameVar}Service.delete${simpleClassName}(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得${table.classComment}") + @Parameter(name = "id", description = "编号", required = true, example = "1024") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult<${sceneEnum.prefixClass}${table.className}RespVO> get${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) { + ${table.className}DO ${classNameVar} = ${classNameVar}Service.get${simpleClassName}(id); + return success(BeanUtils.toBean(${classNameVar}, ${sceneEnum.prefixClass}${table.className}RespVO.class)); + } + +#if ( $table.templateType != 2 ) + @GetMapping("/page") + @Operation(summary = "获得${table.classComment}分页") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult> get${simpleClassName}Page(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) { + PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(pageReqVO); + return success(BeanUtils.toBean(pageResult, ${sceneEnum.prefixClass}${table.className}RespVO.class)); + } + +## 特殊:树表专属逻辑(树不需要分页接口) +#else + @GetMapping("/list") + @Operation(summary = "获得${table.classComment}列表") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult> get${simpleClassName}List(@Valid ${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) { + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(listReqVO); + return success(BeanUtils.toBean(list, ${sceneEnum.prefixClass}${table.className}RespVO.class)); + } + +#end + @GetMapping("/export-excel") + @Operation(summary = "导出${table.classComment} Excel") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:export')") +#end + @ApiAccessLog(operateType = EXPORT) +#if ( $table.templateType != 2 ) + public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}Page(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${sceneEnum.prefixClass}${table.className}RespVO.class, + BeanUtils.toBean(list, ${sceneEnum.prefixClass}${table.className}RespVO.class)); + } +## 特殊:树表专属逻辑(树不需要分页接口) +#else + public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${table.className}RespVO.class, + BeanUtils.toBean(list, ${table.className}RespVO.class)); + } +#end + +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index)) +#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) +#set ($subClassNameVar = $subClassNameVars.get($index)) + // ==================== 子表($subTable.classComment) ==================== + +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + @GetMapping("/${subSimpleClassName_strikeCase}/page") + @Operation(summary = "获得${subTable.classComment}分页") + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult> get${subSimpleClassName}Page(PageParam pageReqVO, + @RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return success(${classNameVar}Service.get${subSimpleClassName}Page(pageReqVO, ${subJoinColumn.javaField})); + } + +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany ) + @GetMapping("/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}") + @Operation(summary = "获得${subTable.classComment}列表") + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult> get${subSimpleClassName}ListBy${SubJoinColumnName}(@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return success(${classNameVar}Service.get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField})); + } + + #else + @GetMapping("/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}") + @Operation(summary = "获得${subTable.classComment}") + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult<${subTable.className}DO> get${subSimpleClassName}By${SubJoinColumnName}(@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return success(${classNameVar}Service.get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField})); + } + + #end +#end +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作 +#if ( $table.templateType == 11 ) + @PostMapping("/${subSimpleClassName_strikeCase}/create") + @Operation(summary = "创建${subTable.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')") +#end + public CommonResult<${subPrimaryColumn.javaType}> create${subSimpleClassName}(@Valid @RequestBody ${subTable.className}DO ${subClassNameVar}) { + return success(${classNameVar}Service.create${subSimpleClassName}(${subClassNameVar})); + } + + @PutMapping("/${subSimpleClassName_strikeCase}/update") + @Operation(summary = "更新${subTable.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')") +#end + public CommonResult update${subSimpleClassName}(@Valid @RequestBody ${subTable.className}DO ${subClassNameVar}) { + ${classNameVar}Service.update${subSimpleClassName}(${subClassNameVar}); + return success(true); + } + + @DeleteMapping("/${subSimpleClassName_strikeCase}/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除${subTable.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')") +#end + public CommonResult delete${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) { + ${classNameVar}Service.delete${subSimpleClassName}(id); + return success(true); + } + + @GetMapping("/${subSimpleClassName_strikeCase}/get") + @Operation(summary = "获得${subTable.classComment}") + @Parameter(name = "id", description = "编号", required = true) +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult<${subTable.className}DO> get${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) { + return success(${classNameVar}Service.get${subSimpleClassName}(id)); + } + +#end +#end +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/listReqVO.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/listReqVO.vm new file mode 100644 index 0000000..46b6a25 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/listReqVO.vm @@ -0,0 +1,45 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import ${PageParamClassName}; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end +## 处理 LocalDateTime 字段的引入 +#foreach ($column in $columns) +#if (${column.listOperation} && ${column.javaType} == "LocalDateTime") +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +#break +#end +#end +## 字段模板 +#macro(columnTpl $prefix $prefixStr) + @Schema(description = "${prefixStr}${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end; +#end + +@Schema(description = "${sceneEnum.name} - ${table.classComment}列表 Request VO") +@Data +public class ${sceneEnum.prefixClass}${table.className}ListReqVO { + +#foreach ($column in $columns) +#if (${column.listOperation})##查询操作 +#if (${column.listOperationCondition} == "BETWEEN")## 情况一,Between 的时候 + @Schema(description = "${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private ${column.javaType}[] ${column.javaField}; +#else##情况二,非 Between 的时间 + #columnTpl('', '') +#end + +#end +#end +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm new file mode 100644 index 0000000..003bac9 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm @@ -0,0 +1,47 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import ${PageParamClassName}; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end +## 处理 LocalDateTime 字段的引入 +#foreach ($column in $columns) +#if (${column.listOperationCondition} && ${column.javaType} == "LocalDateTime") +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +#break +#end +#end +## 字段模板 +#macro(columnTpl $prefix $prefixStr) + @Schema(description = "${prefixStr}${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end; +#end + +@Schema(description = "${sceneEnum.name} - ${table.classComment}分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ${sceneEnum.prefixClass}${table.className}PageReqVO extends PageParam { + +#foreach ($column in $columns) +#if (${column.listOperation})##查询操作 +#if (${column.listOperationCondition} == "BETWEEN")## 情况一,Between 的时候 + @Schema(description = "${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private ${column.javaType}[] ${column.javaField}; +#else##情况二,非 Between 的时间 + #columnTpl('', '') +#end + +#end +#end +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/respVO.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/respVO.vm new file mode 100644 index 0000000..24c3519 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/respVO.vm @@ -0,0 +1,53 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +## 处理 BigDecimal 字段的引入 +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end +## 处理 LocalDateTime 字段的引入 +#foreach ($column in $columns) +#if (${column.listOperationResult} && ${column.javaType} == "LocalDateTime") +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +#break +#end +#end +## 处理 Excel 导出 +import com.alibaba.excel.annotation.*; +#foreach ($column in $columns) +#if ("$!column.dictType" != "")## 有设置数据字典 +import ${DictFormatClassName}; +import ${DictConvertClassName}; +#break +#end +#end + +@Schema(description = "${sceneEnum.name} - ${table.classComment} Response VO") +@Data +@ExcelIgnoreUnannotated +public class ${sceneEnum.prefixClass}${table.className}RespVO { + +## 逐个处理字段 +#foreach ($column in $columns) +#if (${column.listOperationResult}) +## 1. 处理 Swagger 注解 + @Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end) +## 2. 处理 Excel 导出 +#if ("$!column.dictType" != "")##处理枚举值 + @ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class) + @DictFormat("${column.dictType}") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 +#else + @ExcelProperty("${column.columnComment}") +#end +## 3. 处理字段定义 + private ${column.javaType} ${column.javaField}; + +#end +#end +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/saveReqVO.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/saveReqVO.vm new file mode 100644 index 0000000..b432c75 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/controller/vo/saveReqVO.vm @@ -0,0 +1,64 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import ${jakartaPackage}.validation.constraints.*; +## 处理 BigDecimal 字段的引入 +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end +## 处理 LocalDateTime 字段的引入 +#foreach ($column in $columns) +#if ((${column.createOperation} || ${column.updateOperation}) && ${column.javaType} == "LocalDateTime") +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +#break +#end +#end +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +#end + +@Schema(description = "${sceneEnum.name} - ${table.classComment}新增/修改 Request VO") +@Data +public class ${sceneEnum.prefixClass}${table.className}SaveReqVO { + +## 逐个处理字段 +#foreach ($column in $columns) +#if (${column.createOperation} || ${column.updateOperation}) +## 1. 处理 Swagger 注解 + @Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end) +## 2. 处理 Validator 参数校验 +#if (!${column.nullable} && !${column.primaryKey}) +#if (${column.javaType} == 'String') + @NotEmpty(message = "${column.columnComment}不能为空") +#else + @NotNull(message = "${column.columnComment}不能为空") +#end +#end +## 3. 处理字段定义 + private ${column.javaType} ${column.javaField}; + +#end +#end +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) + #if ( $subTable.subJoinMany) + @Schema(description = "${subTable.classComment}列表") + private List<${subTable.className}DO> ${subClassNameVars.get($index)}s; + + #else + @Schema(description = "${subTable.classComment}") + private ${subTable.className}DO ${subClassNameVars.get($index)}; + + #end +#end +#end +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/do.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/do.vm new file mode 100644 index 0000000..b019d6e --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/do.vm @@ -0,0 +1,52 @@ +package ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}; + +import lombok.*; +import java.util.*; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#end +#if (${column.javaType} == "LocalDateTime") +import java.time.LocalDateTime; +#end +#end +import com.baomidou.mybatisplus.annotation.*; +import ${BaseDOClassName}; + +/** + * ${table.classComment} DO + * + * @author ${table.author} + */ +@TableName("${table.tableName.toLowerCase()}") +@KeySequence("${table.tableName.toLowerCase()}_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ${table.className}DO extends BaseDO { + +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) + public static final Long ${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT = 0L; + +#end +#foreach ($column in $columns) +#if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段 + /** + * ${column.columnComment} + #if ("$!column.dictType" != "")##处理枚举值 + * + * 枚举 {@link TODO ${column.dictType} 对应的类} + #end + */ + #if (${column.primaryKey})##处理主键 + @TableId#if (${column.javaType} == 'String')(type = IdType.INPUT)#end + #end + private ${column.javaType} ${column.javaField}; +#end +#end + +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/do_sub.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/do_sub.vm new file mode 100644 index 0000000..16be55e --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/do_sub.vm @@ -0,0 +1,49 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +package ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}; + +import lombok.*; +import java.util.*; +#foreach ($column in $subColumns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#end +#if (${column.javaType} == "LocalDateTime") +import java.time.LocalDateTime; +#end +#end +import com.baomidou.mybatisplus.annotation.*; +import ${BaseDOClassName}; + +/** + * ${subTable.classComment} DO + * + * @author ${subTable.author} + */ +@TableName("${subTable.tableName.toLowerCase()}") +@KeySequence("${subTable.tableName.toLowerCase()}_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ${subTable.className}DO extends BaseDO { + +#foreach ($column in $subColumns) +#if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段 + /** + * ${column.columnComment} + #if ("$!column.dictType" != "")##处理枚举值 + * + * 枚举 {@link TODO ${column.dictType} 对应的类} + #end + */ + #if (${column.primaryKey})##处理主键 + @TableId#if (${column.javaType} == 'String')(type = IdType.INPUT)#end + #end + private ${column.javaType} ${column.javaField}; +#end +#end + +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm new file mode 100644 index 0000000..b98b471 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm @@ -0,0 +1,82 @@ +package ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}; + +import java.util.*; + +import ${PageResultClassName}; +import ${QueryWrapperClassName}; +import ${BaseMapperClassName}; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +import org.apache.ibatis.annotations.Mapper; +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; + +## 字段模板 +#macro(listCondition) +#foreach ($column in $columns) +#if (${column.listOperation}) +#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 +#if (${column.listOperationCondition} == "=")##情况一,= 的时候 + .eqIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "!=")##情况二,!= 的时候 + .neIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == ">")##情况三,> 的时候 + .gtIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == ">=")##情况四,>= 的时候 + .geIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "<")##情况五,< 的时候 + .ltIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "<=")##情况五,<= 的时候 + .leIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "LIKE")##情况七,Like 的时候 + .likeIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "BETWEEN")##情况八,Between 的时候 + .betweenIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#end +#end +#end +/** + * ${table.classComment} Mapper + * + * @author ${table.author} + */ +@Mapper +public interface ${table.className}Mapper extends BaseMapperX<${table.className}DO> { + +## 特殊:树表专属逻辑(树不需要分页接口) +#if ( $table.templateType != 2 ) + default PageResult<${table.className}DO> selectPage(${sceneEnum.prefixClass}${table.className}PageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX<${table.className}DO>() + #listCondition() + .orderByDesc(${table.className}DO::getId));## 大多数情况下,id 倒序 + + } +#else + default List<${table.className}DO> selectList(${sceneEnum.prefixClass}${table.className}ListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX<${table.className}DO>() + #listCondition() + .orderByDesc(${table.className}DO::getId));## 大多数情况下,id 倒序 + + } +#end + +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写 + default ${table.className}DO selectBy${TreeParentJavaField}And${TreeNameJavaField}(Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) { + return selectOne(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField}, ${table.className}DO::get${TreeNameJavaField}, ${treeNameColumn.javaField}); + } + + default Long selectCountBy${TreeParentJavaField}(${treeParentColumn.javaType} ${treeParentColumn.javaField}) { + return selectCount(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField}); + } + +#end +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper.xml.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper.xml.vm new file mode 100644 index 0000000..290378d --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper.xml.vm @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper_sub.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper_sub.vm new file mode 100644 index 0000000..6ccaea7 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/dal/mapper_sub.vm @@ -0,0 +1,57 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subJoinColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +package ${basePackage}.module.${subTable.moduleName}.dal.mysql.${subTable.businessName}; + +import java.util.*; + +import ${PageResultClassName}; +import ${PageParamClassName}; +import ${QueryWrapperClassName}; +import ${BaseMapperClassName}; +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +import org.apache.ibatis.annotations.Mapper; + +/** + * ${subTable.classComment} Mapper + * + * @author ${subTable.author} + */ +@Mapper +public interface ${subTable.className}Mapper extends BaseMapperX<${subTable.className}DO> { + +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + default PageResult<${subTable.className}DO> selectPage(PageParam reqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return selectPage(reqVO, new LambdaQueryWrapperX<${subTable.className}DO>() + .eq(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}) + .orderByDesc(${subTable.className}DO::getId));## 大多数情况下,id 倒序 + + } +## 主表与子表是一对一时 + #if (!$subTable.subJoinMany) + default ${subTable.className}DO selectBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return selectOne(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}); + } + #end + +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany) + default List<${subTable.className}DO> selectListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return selectList(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}); + } + + #else + default ${subTable.className}DO selectBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return selectOne(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}); + } + + #end + #end + default int deleteBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return delete(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}); + } + +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/enums/errorcode.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/enums/errorcode.vm new file mode 100644 index 0000000..b7e21e6 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/enums/errorcode.vm @@ -0,0 +1,22 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-${table.moduleName}-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== ${table.classComment} TODO 补充编号 ========== +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS = new ErrorCode(TODO 补充编号, "${table.classComment}不存在"); +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子${table.classComment},无法删除"); +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级${table.classComment}不存在"); +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父${table.classComment}"); +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该${treeNameColumn.columnComment}的${table.classComment}"); +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD = new ErrorCode(TODO 补充编号, "不能设置自己的子${table.className}为父${table.className}"); +#end +## 特殊:主子表专属逻辑 +#if ( $table.templateType == 11 )## 特殊:ERP 情况 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index)) +ErrorCode ${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS = new ErrorCode(TODO 补充编号, "${subTable.classComment}不存在"); +#if ( !$subTable.subJoinMany ) +ErrorCode ${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS = new ErrorCode(TODO 补充编号, "${subTable.classComment}已存在"); +#end +#end +#end \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/service/service.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/service/service.vm new file mode 100644 index 0000000..c4ee4f0 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/service/service.vm @@ -0,0 +1,147 @@ +package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; + +import java.util.*; +import ${jakartaPackage}.validation.*; +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +#end +import ${PageResultClassName}; +import ${PageParamClassName}; + +/** + * ${table.classComment} Service 接口 + * + * @author ${table.author} + */ +public interface ${table.className}Service { + + /** + * 创建${table.classComment} + * + * @param createReqVO 创建信息 + * @return 编号 + */ + ${primaryColumn.javaType} create${simpleClassName}(@Valid ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO); + + /** + * 更新${table.classComment} + * + * @param updateReqVO 更新信息 + */ + void update${simpleClassName}(@Valid ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO); + + /** + * 删除${table.classComment} + * + * @param id 编号 + */ + void delete${simpleClassName}(${primaryColumn.javaType} id); + + /** + * 获得${table.classComment} + * + * @param id 编号 + * @return ${table.classComment} + */ + ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id); + +## 特殊:树表专属逻辑(树不需要分页接口) +#if ( $table.templateType != 2 ) + /** + * 获得${table.classComment}分页 + * + * @param pageReqVO 分页查询 + * @return ${table.classComment}分页 + */ + PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO); +#else + /** + * 获得${table.classComment}列表 + * + * @param listReqVO 查询条件 + * @return ${table.classComment}列表 + */ + List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO); +#end + +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +#set ($subClassNameVar = $subClassNameVars.get($index)) + // ==================== 子表($subTable.classComment) ==================== + +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + /** + * 获得${subTable.classComment}分页 + * + * @param pageReqVO 分页查询 + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment} + * @return ${subTable.classComment}分页 + */ + PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}); + +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany ) + /** + * 获得${subTable.classComment}列表 + * + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment} + * @return ${subTable.classComment}列表 + */ + List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}); + + #else + /** + * 获得${subTable.classComment} + * + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment} + * @return ${subTable.classComment} + */ + ${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}); + + #end +#end +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作 +#if ( $table.templateType == 11 ) + /** + * 创建${subTable.classComment} + * + * @param ${subClassNameVar} 创建信息 + * @return 编号 + */ + ${subPrimaryColumn.javaType} create${subSimpleClassName}(@Valid ${subTable.className}DO ${subClassNameVar}); + + /** + * 更新${subTable.classComment} + * + * @param ${subClassNameVar} 更新信息 + */ + void update${subSimpleClassName}(@Valid ${subTable.className}DO ${subClassNameVar}); + + /** + * 删除${subTable.classComment} + * + * @param id 编号 + */ + void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id); + + /** + * 获得${subTable.classComment} + * + * @param id 编号 + * @return ${subTable.classComment} + */ + ${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id); + +#end +#end +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm new file mode 100644 index 0000000..80bc71b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm @@ -0,0 +1,351 @@ +package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; + +import org.springframework.stereotype.Service; +import ${jakartaPackage}.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +#end +import ${PageResultClassName}; +import ${PageParamClassName}; +import ${BeanUtils}; + +import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +import ${basePackage}.module.${subTable.moduleName}.dal.mysql.${subTable.businessName}.${subTable.className}Mapper; +#end + +import static ${ServiceExceptionUtilClassName}.exception; +import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*; + +/** + * ${table.classComment} Service 实现类 + * + * @author ${table.author} + */ +@Service +@Validated +public class ${table.className}ServiceImpl implements ${table.className}Service { + + @Resource + private ${table.className}Mapper ${classNameVar}Mapper; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) + @Resource + private ${subTable.className}Mapper ${subClassNameVars.get($index)}Mapper; +#end + + @Override +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) + @Transactional(rollbackFor = Exception.class) +#end + public ${primaryColumn.javaType} create${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO) { +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写 + // 校验${treeParentColumn.columnComment}的有效性 + validateParent${simpleClassName}(null, createReqVO.get${TreeParentJavaField}()); + // 校验${treeNameColumn.columnComment}的唯一性 + validate${simpleClassName}${TreeNameJavaField}Unique(null, createReqVO.get${TreeParentJavaField}(), createReqVO.get${TreeNameJavaField}()); + +#end + // 插入 + ${table.className}DO ${classNameVar} = BeanUtils.toBean(createReqVO, ${table.className}DO.class); + ${classNameVar}Mapper.insert(${classNameVar}); +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) + + // 插入子表 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + #if ( $subTable.subJoinMany) + create${subSimpleClassName}List(${classNameVar}.getId(), createReqVO.get${subSimpleClassNames.get($index)}s()); + #else + create${subSimpleClassName}(${classNameVar}.getId(), createReqVO.get${subSimpleClassNames.get($index)}()); + #end +#end +#end + // 返回 + return ${classNameVar}.getId(); + } + + @Override +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) + @Transactional(rollbackFor = Exception.class) +#end + public void update${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) { + // 校验存在 + validate${simpleClassName}Exists(updateReqVO.getId()); +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写 + // 校验${treeParentColumn.columnComment}的有效性 + validateParent${simpleClassName}(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}()); + // 校验${treeNameColumn.columnComment}的唯一性 + validate${simpleClassName}${TreeNameJavaField}Unique(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}(), updateReqVO.get${TreeNameJavaField}()); + +#end + // 更新 + ${table.className}DO updateObj = BeanUtils.toBean(updateReqVO, ${table.className}DO.class); + ${classNameVar}Mapper.updateById(updateObj); +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11) + + // 更新子表 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + #if ( $subTable.subJoinMany) + update${subSimpleClassName}List(updateReqVO.getId(), updateReqVO.get${subSimpleClassNames.get($index)}s()); + #else + update${subSimpleClassName}(updateReqVO.getId(), updateReqVO.get${subSimpleClassNames.get($index)}()); + #end +#end +#end + } + + @Override +## 特殊:主子表专属逻辑 +#if ( $subTables && $subTables.size() > 0) + @Transactional(rollbackFor = Exception.class) +#end + public void delete${simpleClassName}(${primaryColumn.javaType} id) { + // 校验存在 + validate${simpleClassName}Exists(id); +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($ParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 + // 校验是否有子${table.classComment} + if (${classNameVar}Mapper.selectCountBy${ParentJavaField}(id) > 0) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN); + } +#end + // 删除 + ${classNameVar}Mapper.deleteById(id); +## 特殊:主子表专属逻辑 +#if ( $subTables && $subTables.size() > 0) + + // 删除子表 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + delete${subSimpleClassName}By${SubJoinColumnName}(id); +#end +#end + } + + private void validate${simpleClassName}Exists(${primaryColumn.javaType} id) { + if (${classNameVar}Mapper.selectById(id) == null) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS); + } + } + +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写 + private void validateParent${simpleClassName}(Long id, Long ${treeParentColumn.javaField}) { + if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) { + return; + } + // 1. 不能设置自己为父${table.classComment} + if (Objects.equals(id, ${treeParentColumn.javaField})) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR); + } + // 2. 父${table.classComment}不存在 + ${simpleClassName}DO parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField}); + if (parent${simpleClassName} == null) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS); + } + // 3. 递归校验父${table.classComment},如果父${table.classComment}是自己的子${table.classComment},则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + ${treeParentColumn.javaField} = parent${simpleClassName}.get${TreeParentJavaField}(); + if (Objects.equals(id, ${treeParentColumn.javaField})) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父${table.classComment} + if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) { + break; + } + parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField}); + if (parent${simpleClassName} == null) { + break; + } + } + } + + private void validate${simpleClassName}${TreeNameJavaField}Unique(Long id, Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) { + ${simpleClassName}DO ${classNameVar} = ${classNameVar}Mapper.selectBy${TreeParentJavaField}And${TreeNameJavaField}(${treeParentColumn.javaField}, ${treeNameColumn.javaField}); + if (${classNameVar} == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的${table.classComment} + if (id == null) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE); + } + if (!Objects.equals(${classNameVar}.getId(), id)) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE); + } + } + +#end + @Override + public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) { + return ${classNameVar}Mapper.selectById(id); + } + +## 特殊:树表专属逻辑(树不需要分页接口) +#if ( $table.templateType != 2 ) + @Override + public PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) { + return ${classNameVar}Mapper.selectPage(pageReqVO); + } +#else + @Override + public List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) { + return ${classNameVar}Mapper.selectList(listReqVO); + } +#end + +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index)) +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +#set ($subClassNameVar = $subClassNameVars.get($index)) + // ==================== 子表($subTable.classComment) ==================== + +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + @Override + public PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return ${subClassNameVars.get($index)}Mapper.selectPage(pageReqVO, ${subJoinColumn.javaField}); + } + +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany ) + @Override + public List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return ${subClassNameVars.get($index)}Mapper.selectListBy${SubJoinColumnName}(${subJoinColumn.javaField}); + } + + #else + @Override + public ${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return ${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subJoinColumn.javaField}); + } + + #end +#end +## 情况一:MASTER_ERP 时,支持单个的新增、修改、删除操作 +#if ( $table.templateType == 11 ) + @Override + public ${subPrimaryColumn.javaType} create${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) { +## 特殊:一对一时,需要保证只有一条,不能重复插入 +#if ( !$subTable.subJoinMany) + // 校验是否已经存在 + if (${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subClassNameVar}.get${SubJoinColumnName}()) != null) { + throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS); + } + // 插入 +#end + ${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar}); + return ${subClassNameVar}.getId(); + } + + @Override + public void update${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) { + // 校验存在 + validate${subSimpleClassName}Exists(${subClassNameVar}.getId()); + // 更新 + ${subClassNameVar}.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + ${subClassNameVars.get($index)}Mapper.updateById(${subClassNameVar}); + } + + @Override + public void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id) { + // 校验存在 + validate${subSimpleClassName}Exists(id); + // 删除 + ${subClassNameVars.get($index)}Mapper.deleteById(id); + } + + @Override + public ${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id) { + return ${subClassNameVars.get($index)}Mapper.selectById(id); + } + + private void validate${subSimpleClassName}Exists(${subPrimaryColumn.javaType} id) { + if (${subClassNameVar}Mapper.selectById(id) == null) { + throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS); + } + } + +## 情况二:非 MASTER_ERP 时,支持批量的新增、修改操作 +#else + #if ( $subTable.subJoinMany) + private void create${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) { + list.forEach(o -> o.set$SubJoinColumnName(${subJoinColumn.javaField})); + ${subClassNameVars.get($index)}Mapper.insertBatch(list); + } + + private void update${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) { + delete${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + create${subSimpleClassName}List(${subJoinColumn.javaField}, list); + } + + #else + private void create${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) { + if (${subClassNameVar} == null) { + return; + } + ${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField}); + ${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar}); + } + + private void update${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) { + if (${subClassNameVar} == null) { + return; + } + ${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField}); + ${subClassNameVar}.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + ${subClassNameVars.get($index)}Mapper.insertOrUpdate(${subClassNameVar}); + } + + #end +#end + private void delete${subSimpleClassName}By${SubJoinColumnName}(${primaryColumn.javaType} ${subJoinColumn.javaField}) { + ${subClassNameVars.get($index)}Mapper.deleteBy${SubJoinColumnName}(${subJoinColumn.javaField}); + } + +#end +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm new file mode 100644 index 0000000..bfd4600 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm @@ -0,0 +1,168 @@ +package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import ${jakartaPackage}.annotation.Resource; + +import ${baseFrameworkPackage}.test.core.ut.BaseDbUnitTest; + +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper; +import ${PageResultClassName}; + +import ${jakartaPackage}.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*; +import static ${baseFrameworkPackage}.test.core.util.AssertUtils.*; +import static ${baseFrameworkPackage}.test.core.util.RandomUtils.*; +import static ${LocalDateTimeUtilsClassName}.*; +import static ${ObjectUtilsClassName}.*; +import static ${DateUtilsClassName}.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +## 字段模板 +#macro(getPageCondition $VO) + // mock 数据 + ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class, o -> { // 等会查询到 + #foreach ($column in $columns) + #if (${column.listOperation}) + #set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 + o.set$JavaField(null); + #end + #end + }); + ${classNameVar}Mapper.insert(db${simpleClassName}); + #foreach ($column in $columns) + #if (${column.listOperation}) + #set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 + // 测试 ${column.javaField} 不匹配 + ${classNameVar}Mapper.insert(cloneIgnoreId(db${simpleClassName}, o -> o.set$JavaField(null))); + #end + #end + // 准备参数 + ${sceneEnum.prefixClass}${table.className}${VO} reqVO = new ${sceneEnum.prefixClass}${table.className}${VO}(); + #foreach ($column in $columns) + #if (${column.listOperation}) + #set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 + #if (${column.listOperationCondition} == "BETWEEN")## BETWEEN 的情况 + reqVO.set${JavaField}(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + #else + reqVO.set$JavaField(null); + #end + #end + #end +#end +/** + * {@link ${table.className}ServiceImpl} 的单元测试类 + * + * @author ${table.author} + */ +@Import(${table.className}ServiceImpl.class) +public class ${table.className}ServiceImplTest extends BaseDbUnitTest { + + @Resource + private ${table.className}ServiceImpl ${classNameVar}Service; + + @Resource + private ${table.className}Mapper ${classNameVar}Mapper; + + @Test + public void testCreate${simpleClassName}_success() { + // 准备参数 + ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class).setId(null); + + // 调用 + ${primaryColumn.javaType} ${classNameVar}Id = ${classNameVar}Service.create${simpleClassName}(createReqVO); + // 断言 + assertNotNull(${classNameVar}Id); + // 校验记录的属性是否正确 + ${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(${classNameVar}Id); + assertPojoEquals(createReqVO, ${classNameVar}, "id"); + } + + @Test + public void testUpdate${simpleClassName}_success() { + // mock 数据 + ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class); + ${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据 + // 准备参数 + ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class, o -> { + o.setId(db${simpleClassName}.getId()); // 设置更新的 ID + }); + + // 调用 + ${classNameVar}Service.update${simpleClassName}(updateReqVO); + // 校验是否更新正确 + ${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, ${classNameVar}); + } + + @Test + public void testUpdate${simpleClassName}_notExists() { + // 准备参数 + ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> ${classNameVar}Service.update${simpleClassName}(updateReqVO), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS); + } + + @Test + public void testDelete${simpleClassName}_success() { + // mock 数据 + ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class); + ${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据 + // 准备参数 + ${primaryColumn.javaType} id = db${simpleClassName}.getId(); + + // 调用 + ${classNameVar}Service.delete${simpleClassName}(id); + // 校验数据不存在了 + assertNull(${classNameVar}Mapper.selectById(id)); + } + + @Test + public void testDelete${simpleClassName}_notExists() { + // 准备参数 + ${primaryColumn.javaType} id = random${primaryColumn.javaType}Id(); + + // 调用, 并断言异常 + assertServiceException(() -> ${classNameVar}Service.delete${simpleClassName}(id), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS); + } + +## 特殊:树表专属逻辑(树不需要分页接口) +#if ( $table.templateType != 2 ) + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGet${simpleClassName}Page() { + #getPageCondition("PageReqVO") + + // 调用 + PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(db${simpleClassName}, pageResult.getList().get(0)); + } +#else + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGet${simpleClassName}List() { + #getPageCondition("ListReqVO") + + // 调用 + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(db${simpleClassName}, list.get(0)); + } +#end + +} \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/sql/h2.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/sql/h2.vm new file mode 100644 index 0000000..a073fdb --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/sql/h2.vm @@ -0,0 +1,37 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-${table.moduleName}-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "${table.tableName.toLowerCase()}" ( +#foreach ($column in $columns) +#if (${column.javaType} == 'Long') + #set ($dataType='bigint') +#elseif (${column.javaType} == 'Integer') + #set ($dataType='int') +#elseif (${column.javaType} == 'Boolean') + #set ($dataType='bit') +#elseif (${column.javaType} == 'Date') + #set ($dataType='datetime') +#else + #set ($dataType='varchar') +#end + #if (${column.primaryKey})##处理主键 + "${column.javaField}"#if (${column.javaType} == 'String') ${dataType} NOT NULL#else ${dataType} NOT NULL GENERATED BY DEFAULT AS IDENTITY#end, + #else + #if (${column.columnName} == 'create_time') + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + #elseif (${column.columnName} == 'update_time') + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + #elseif (${column.columnName} == 'creator' || ${column.columnName} == 'updater') + "${column.columnName}" ${dataType} DEFAULT '', + #elseif (${column.columnName} == 'deleted') + "deleted" bit NOT NULL DEFAULT FALSE, + #elseif (${column.columnName} == 'tenant_id') + "tenant_id" bigint NOT NULL DEFAULT 0, + #else + "${column.columnName.toLowerCase()}" ${dataType}#if (${column.nullable} == false) NOT NULL#end, + #end + #end +#end + PRIMARY KEY ("${primaryColumn.columnName.toLowerCase()}") +) COMMENT '${table.tableComment}'; + +-- 将该删表 SQL 语句,添加到 yudao-module-${table.moduleName}-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "${table.tableName}"; \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/sql/sql.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/sql/sql.vm new file mode 100644 index 0000000..41b107d --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/sql/sql.vm @@ -0,0 +1,28 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '${table.classComment}管理', '', 2, 0, ${table.parentMenuId}, + '${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +#set ($functionNames = ['查询', '创建', '更新', '删除', '导出']) +#set ($functionOps = ['query', 'create', 'update', 'delete', 'export']) +#foreach ($functionName in $functionNames) +#set ($index = $foreach.count - 1) +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId, + '', '', '', 0 +); +#end \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/api/api.js.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/api/api.js.vm new file mode 100644 index 0000000..835c019 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/api/api.js.vm @@ -0,0 +1,141 @@ +import request from '@/utils/request' +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") + +// 创建${table.classComment} +export function create${simpleClassName}(data) { + return request({ + url: '${baseURL}/create', + method: 'post', + data: data + }) +} + +// 更新${table.classComment} +export function update${simpleClassName}(data) { + return request({ + url: '${baseURL}/update', + method: 'put', + data: data + }) +} + +// 删除${table.classComment} +export function delete${simpleClassName}(id) { + return request({ + url: '${baseURL}/delete?id=' + id, + method: 'delete' + }) +} + +// 获得${table.classComment} +export function get${simpleClassName}(id) { + return request({ + url: '${baseURL}/get?id=' + id, + method: 'get' + }) +} + +#if ( $table.templateType != 2 ) +// 获得${table.classComment}分页 +export function get${simpleClassName}Page(params) { + return request({ + url: '${baseURL}/page', + method: 'get', + params + }) +} +#else +// 获得${table.classComment}列表 +export function get${simpleClassName}List(params) { + return request({ + url: '${baseURL}/list', + method: 'get', + params + }) +} +#end +// 导出${table.classComment} Excel +export function export${simpleClassName}Excel(params) { + return request({ + url: '${baseURL}/export-excel', + method: 'get', + params, + responseType: 'blob' + }) +} +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) + #set ($index = $foreach.count - 1) + #set ($subSimpleClassName = $subSimpleClassNames.get($index)) + #set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 + #set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 + #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index)) + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) + #set ($subClassNameVar = $subClassNameVars.get($index)) + +// ==================== 子表($subTable.classComment) ==================== + ## 情况一:MASTER_ERP 时,需要分查询页子表 + #if ($table.templateType == 11) + // 获得${subTable.classComment}分页 + export function get${subSimpleClassName}Page(params) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/page', + method: 'get', + params + }) + } + ## 情况二:非 MASTER_ERP 时,需要列表查询子表 + #else + #if ($subTable.subJoinMany) + // 获得${subTable.classComment}列表 + export function get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=' + ${subJoinColumn.javaField}, + method: 'get' + }) + } + #else + // 获得${subTable.classComment} + export function get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=' + ${subJoinColumn.javaField}, + method: 'get' + }) + } + #end + #end + ## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作 + #if ($table.templateType == 11) + // 新增${subTable.classComment} + export function create${subSimpleClassName}(data) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/create', + method: 'post', + data + }) + } + // 修改${subTable.classComment} + export function update${subSimpleClassName}(data) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/update', + method: 'post', + data + }) + } + // 删除${subTable.classComment} + export function delete${subSimpleClassName}(id) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/delete?id=' + id, + method: 'delete' + }) + } + // 获得${subTable.classComment} + export function get${subSimpleClassName}(id) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/get?id=' + id, + method: 'get' + }) + } + #end +#end \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_erp.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_erp.vue.vm new file mode 100644 index 0000000..99aa91a --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_erp.vue.vm @@ -0,0 +1,205 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 + + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_inner.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_inner.vue.vm new file mode 100644 index 0000000..ca266be --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_inner.vue.vm @@ -0,0 +1,2 @@ +## 主表的 normal 和 inner 使用相同的 form 表单 +#parse("codegen/vue/views/components/form_sub_normal.vue.vm") \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_normal.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_normal.vue.vm new file mode 100644 index 0000000..48a404a --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_normal.vue.vm @@ -0,0 +1,347 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_erp.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_erp.vue.vm new file mode 100644 index 0000000..589736b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_erp.vue.vm @@ -0,0 +1,165 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_inner.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_inner.vue.vm new file mode 100644 index 0000000..90b8e41 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_inner.vue.vm @@ -0,0 +1,4 @@ +## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点: +## 1)inner 使用 list 不分页,erp 使用 page 分页 +## 2)erp 支持单个子表的新增、修改、删除,inner 不支持 +#parse("codegen/vue/views/components/list_sub_erp.vue.vm") \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/form.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/form.vue.vm new file mode 100644 index 0000000..634d05d --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/form.vue.vm @@ -0,0 +1,320 @@ + + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm new file mode 100644 index 0000000..9c1e124 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm @@ -0,0 +1,340 @@ + + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm new file mode 100644 index 0000000..c3044fb --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm @@ -0,0 +1,115 @@ +import request from '@/config/axios' +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") + +// ${table.classComment} VO +export interface ${simpleClassName}VO { +#foreach ($column in $columns) +#if ($column.createOperation || $column.updateOperation) +#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal") + ${column.javaField}: number // ${column.columnComment} +#elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime") + ${column.javaField}: Date // ${column.columnComment} +#else + ${column.javaField}: ${column.javaType.toLowerCase()} // ${column.columnComment} +#end +#end +#end +} + +// ${table.classComment} API +export const ${simpleClassName}Api = { +#if ( $table.templateType != 2 ) + // 查询${table.classComment}分页 + get${simpleClassName}Page: async (params: any) => { + return await request.get({ url: `${baseURL}/page`, params }) + }, +#else + // 查询${table.classComment}列表 + get${simpleClassName}List: async (params) => { + return await request.get({ url: `${baseURL}/list`, params }) + }, +#end + + // 查询${table.classComment}详情 + get${simpleClassName}: async (id: number) => { + return await request.get({ url: `${baseURL}/get?id=` + id }) + }, + + // 新增${table.classComment} + create${simpleClassName}: async (data: ${simpleClassName}VO) => { + return await request.post({ url: `${baseURL}/create`, data }) + }, + + // 修改${table.classComment} + update${simpleClassName}: async (data: ${simpleClassName}VO) => { + return await request.put({ url: `${baseURL}/update`, data }) + }, + + // 删除${table.classComment} + delete${simpleClassName}: async (id: number) => { + return await request.delete({ url: `${baseURL}/delete?id=` + id }) + }, + + // 导出${table.classComment} Excel + export${simpleClassName}: async (params) => { + return await request.download({ url: `${baseURL}/export-excel`, params }) + }, +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index)) +#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) +#set ($subClassNameVar = $subClassNameVars.get($index)) + +// ==================== 子表($subTable.classComment) ==================== +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + + // 获得${subTable.classComment}分页 + get${subSimpleClassName}Page: async (params) => { + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/page`, params }) + }, +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany ) + + // 获得${subTable.classComment}列表 + get${subSimpleClassName}ListBy${SubJoinColumnName}: async (${subJoinColumn.javaField}) => { + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} }) + }, + #else + + // 获得${subTable.classComment} + get${subSimpleClassName}By${SubJoinColumnName}: async (${subJoinColumn.javaField}) => { + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} }) + }, + #end +#end +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作 +#if ( $table.templateType == 11 ) + // 新增${subTable.classComment} + create${subSimpleClassName}: async (data) => { + return await request.post({ url: `${baseURL}/${subSimpleClassName_strikeCase}/create`, data }) + }, + + // 修改${subTable.classComment} + update${subSimpleClassName}: async (data) => { + return await request.put({ url: `${baseURL}/${subSimpleClassName_strikeCase}/update`, data }) + }, + + // 删除${subTable.classComment} + delete${subSimpleClassName}: async (id: number) => { + return await request.delete({ url: `${baseURL}/${subSimpleClassName_strikeCase}/delete?id=` + id }) + }, + + // 获得${subTable.classComment} + get${subSimpleClassName}: async (id: number) => { + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get?id=` + id }) + }, +#end +#end +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm new file mode 100644 index 0000000..81cd977 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm @@ -0,0 +1,204 @@ +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 + + \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_inner.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_inner.vue.vm new file mode 100644 index 0000000..d8542c3 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_inner.vue.vm @@ -0,0 +1,2 @@ +## 主表的 normal 和 inner 使用相同的 form 表单 +#parse("codegen/vue3/views/components/form_sub_normal.vue.vm") \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm new file mode 100644 index 0000000..3fa1eff --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm @@ -0,0 +1,360 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + + \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm new file mode 100644 index 0000000..3f0710e --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm @@ -0,0 +1,184 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + + \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_inner.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_inner.vue.vm new file mode 100644 index 0000000..3fe6488 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_inner.vue.vm @@ -0,0 +1,4 @@ +## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点: +## 1)inner 使用 list 不分页,erp 使用 page 分页 +## 2)erp 支持单个子表的新增、修改、删除,inner 不支持 +#parse("codegen/vue3/views/components/list_sub_erp.vue.vm") \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm new file mode 100644 index 0000000..e37474b --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm @@ -0,0 +1,300 @@ + + \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm new file mode 100644 index 0000000..399b58e --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm @@ -0,0 +1,374 @@ + + + \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm new file mode 100644 index 0000000..b7f2651 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm @@ -0,0 +1,32 @@ +import { defHttp } from '@/utils/http/axios' +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") + +// 查询${table.classComment}列表 +export function get${simpleClassName}Page(params) { + return defHttp.get({ url: '${baseURL}/page', params }) +} + +// 查询${table.classComment}详情 +export function get${simpleClassName}(id: number) { + return defHttp.get({ url: `${baseURL}/get?id=${id}` }) +} + +// 新增${table.classComment} +export function create${simpleClassName}(data) { + return defHttp.post({ url: '${baseURL}/create', data }) +} + +// 修改${table.classComment} +export function update${simpleClassName}(data) { + return defHttp.put({ url: '${baseURL}/update', data }) +} + +// 删除${table.classComment} +export function delete${simpleClassName}(id: number) { + return defHttp.delete({ url: `${baseURL}/delete?id=${id}` }) +} + +// 导出${table.classComment} Excel +export function export${simpleClassName}(params) { + return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls') +} diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm new file mode 100644 index 0000000..56f4e82 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm @@ -0,0 +1,260 @@ +import type {BasicColumn, FormSchema} from '@/components/Table' +import {useRender} from '@/components/Table' +import {DICT_TYPE, getDictOptions} from '@/utils/dict' + +export const columns: BasicColumn[] = [ +#foreach($column in $columns) +#if ($column.listOperationResult) + #set ($dictType=$column.dictType) + #set ($javaField = $column.javaField) + #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + #set ($comment=$column.columnComment) +#if ($column.javaType == "LocalDateTime")## 时间类型 + { + title: '${comment}', + dataIndex: '${javaField}', + width: 180, + customRender: ({ text }) => { + return useRender.renderDate(text) + }, + }, +#elseif("" != $column.dictType)## 数据字典 + { + title: '${comment}', + dataIndex: '${javaField}', + width: 180, + customRender: ({ text }) => { + return useRender.renderDict(text, DICT_TYPE.$dictType.toUpperCase()) + }, + }, +#else + { + title: '${comment}', + dataIndex: '${javaField}', + width: 160, + }, +#end +#end +#end +] + +export const searchFormSchema: FormSchema[] = [ +#foreach($column in $columns) +#if ($column.listOperation) + #set ($dictType=$column.dictType) + #set ($javaType = $column.javaType) + #set ($javaField = $column.javaField) + #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + #set ($comment=$column.columnComment) + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") + #set ($dictMethod = "number") + #elseif ($javaType == "String") + #set ($dictMethod = "string") + #elseif ($javaType == "Boolean") + #set ($dictMethod = "boolean") + #end + { + label: '${comment}', + field: '${javaField}', + #if ($column.htmlType == "input") + component: 'Input', + #elseif ($column.htmlType == "select") + component: 'Select', + componentProps: { + #if ("" != $dictType)## 设置了 dictType 数据字典的情况 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), + #else## 未设置 dictType 数据字典的情况 + options: [], + #end + }, + #elseif ($column.htmlType == "radio") + component: 'RadioButtonGroup', + componentProps: { + #if ("" != $dictType)## 设置了 dictType 数据字典的情况 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), + #else## 未设置 dictType 数据字典的情况 + options: [], + #end + }, + #elseif($column.htmlType == "datetime") + component: 'RangePicker', + #end + colProps: { span: 8 }, + }, +#end +#end +] + +export const createFormSchema: FormSchema[] = [ + { + label: '编号', + field: 'id', + show: false, + component: 'Input', + }, +#foreach($column in $columns) +#if ($column.createOperation) + #set ($dictType = $column.dictType) + #set ($javaType = $column.javaType) + #set ($javaField = $column.javaField) + #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + #set ($comment = $column.columnComment) + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") + #set ($dictMethod = "number") + #elseif ($javaType == "String") + #set ($dictMethod = "string") + #elseif ($javaType == "Boolean") + #set ($dictMethod = "boolean") + #end +#if (!$column.primaryKey)## 忽略主键,不用在表单里 + { + label: '${comment}', + field: '${javaField}', + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键 + required: true, + #end + #if ($column.htmlType == "input") + component: 'Input', + #elseif($column.htmlType == "imageUpload")## 图片上传 + component: 'FileUpload', + componentProps: { + fileType: 'image', + maxCount: 1, + }, + #elseif($column.htmlType == "fileUpload")## 文件上传 + component: 'FileUpload', + componentProps: { + fileType: 'file', + maxCount: 1, + }, + #elseif($column.htmlType == "editor")## 文本编辑器 + component: 'Editor', + #elseif($column.htmlType == "select")## 下拉框 + component: 'Select', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "checkbox")## 多选框 + component: 'Checkbox', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "radio")## 单选框 + component: 'RadioButtonGroup', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "datetime")## 时间框 + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + #elseif($column.htmlType == "textarea")## 文本域 + component: 'InputTextArea', + #end + }, +#end +#end +#end +] + +export const updateFormSchema: FormSchema[] = [ + { + label: '编号', + field: 'id', + show: false, + component: 'Input', + }, +#foreach($column in $columns) +#if ($column.updateOperation) +#set ($dictType = $column.dictType) +#set ($javaType = $column.javaType) +#set ($javaField = $column.javaField) +#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set ($comment = $column.columnComment) +#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") + #set ($dictMethod = "number") +#elseif ($javaType == "String") + #set ($dictMethod = "string") +#elseif ($javaType == "Boolean") + #set ($dictMethod = "boolean") +#end + #if (!$column.primaryKey)## 忽略主键,不用在表单里 + { + label: '${comment}', + field: '${javaField}', + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键 + required: true, + #end + #if ($column.htmlType == "input") + component: 'Input', + #elseif($column.htmlType == "imageUpload")## 图片上传 + component: 'FileUpload', + componentProps: { + fileType: 'image', + maxCount: 1, + }, + #elseif($column.htmlType == "fileUpload")## 文件上传 + component: 'FileUpload', + componentProps: { + fileType: 'file', + maxCount: 1, + }, + #elseif($column.htmlType == "editor")## 文本编辑器 + component: 'Editor', + #elseif($column.htmlType == "select")## 下拉框 + component: 'Select', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "checkbox")## 多选框 + component: 'Checkbox', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "radio")## 单选框 + component: 'RadioButtonGroup', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "datetime")## 时间框 + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + #elseif($column.htmlType == "textarea")## 文本域 + component: 'InputTextArea', + #end + }, + #end +#end +#end +] \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm new file mode 100644 index 0000000..1804365 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm @@ -0,0 +1,58 @@ + + \ No newline at end of file diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm new file mode 100644 index 0000000..9e59b12 --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm @@ -0,0 +1,92 @@ + + diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/file/erweima.jpg b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/file/erweima.jpg new file mode 100644 index 0000000..1447283 Binary files /dev/null and b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/file/erweima.jpg differ diff --git a/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/logback-spring.xml b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..b1b9f3f --- /dev/null +++ b/tashow-module/tashow-module-infra/tashow-module-infra-biz/src/main/resources/logback-spring.xml @@ -0,0 +1,76 @@ + + + + + + + + + +       + + + ${PATTERN_DEFAULT} + + + + + + + + + + ${PATTERN_DEFAULT} + + + + ${LOG_FILE} + + + ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} + + ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} + + ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} + + ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} + + ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30} + + + + + + 0 + + 256 + + + + + + + + ${PATTERN_DEFAULT} + + + + + + + + + + + + + + + + + + + + + + diff --git a/tashow-module/tashow-module-system/pom.xml b/tashow-module/tashow-module-system/pom.xml new file mode 100644 index 0000000..71191d9 --- /dev/null +++ b/tashow-module/tashow-module-system/pom.xml @@ -0,0 +1,24 @@ + + + + com.tashow.cloud + tashow-module + ${revision} + + 4.0.0 + + tashow-module-system-api + tashow-module-system-biz + + tashow-module-system + pom + + ${project.artifactId} + + system 模块下,我们放通用业务,支撑上层的核心业务。 + 例如说:用户、部门、权限、数据字典等等 + + + diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/pom.xml b/tashow-module/tashow-module-system/tashow-module-system-api/pom.xml new file mode 100644 index 0000000..1854e56 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/pom.xml @@ -0,0 +1,48 @@ + + + + com.tashow.cloud + tashow-module-system + ${revision} + + 4.0.0 + tashow-module-system-api + jar + + ${project.artifactId} + + system 模块 API,暴露给其它模块调用 + + + + + com.tashow.cloud + tashow-common + + + + + org.springdoc + springdoc-openapi-starter-webmvc-api + provided + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + true + + + + + diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/DeptApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/DeptApi.java new file mode 100644 index 0000000..111f499 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/DeptApi.java @@ -0,0 +1,58 @@ +package com.tashow.cloud.systemapi.api.dept; + +import com.tashow.cloud.systemapi.api.dept.dto.DeptRespDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 部门") +public interface DeptApi { + + String PREFIX = ApiConstants.PREFIX + "/dept"; + + @GetMapping(PREFIX + "/get") + @Operation(summary = "获得部门信息") + @Parameter(name = "id", description = "部门编号", example = "1024", required = true) + CommonResult getDept(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list") + @Operation(summary = "获得部门信息数组") + @Parameter(name = "ids", description = "部门编号数组", example = "1,2", required = true) + CommonResult> getDeptList(@RequestParam("ids") Collection ids); + + @GetMapping(PREFIX + "/valid") + @Operation(summary = "校验部门是否合法") + @Parameter(name = "ids", description = "部门编号数组", example = "1,2", required = true) + CommonResult validateDeptList(@RequestParam("ids") Collection ids); + + /** + * 获得指定编号的部门 Map + * + * @param ids 部门编号数组 + * @return 部门 Map + */ + default Map getDeptMap(Collection ids) { + List list = getDeptList(ids).getCheckedData(); + return CollectionUtils.convertMap(list, DeptRespDTO::getId); + } + + @GetMapping(PREFIX + "/list-child") + @Operation(summary = "获得指定部门的所有子部门") + @Parameter(name = "id", description = "部门编号", example = "1024", required = true) + CommonResult> getChildDeptList(@RequestParam("id") Long id); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/PostApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/PostApi.java new file mode 100644 index 0000000..665b78c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/PostApi.java @@ -0,0 +1,49 @@ +package com.tashow.cloud.systemapi.api.dept; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.systemapi.api.dept.dto.PostRespDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.dept.dto.PostRespDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.dept.dto.PostRespDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 岗位") +public interface PostApi { + + String PREFIX = ApiConstants.PREFIX + "/post"; + + @GetMapping(PREFIX + "/valid") + @Operation(summary = "校验岗位是否合法") + @Parameter(name = "ids", description = "岗位编号数组", example = "1,2", required = true) + CommonResult validPostList(@RequestParam("ids") Collection ids); + + @GetMapping(PREFIX + "/list") + @Operation(summary = "获得岗位列表") + @Parameter(name = "ids", description = "岗位编号数组", example = "1,2", required = true) + CommonResult> getPostList(@RequestParam("ids") Collection ids); + + default Map getPostMap(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return MapUtil.empty(); + } + + List list = getPostList(ids).getData(); + return CollectionUtils.convertMap(list, PostRespDTO::getId); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/dto/DeptRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/dto/DeptRespDTO.java new file mode 100644 index 0000000..be42d7d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/dto/DeptRespDTO.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.systemapi.api.dept.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "RPC 服务 - 部门 Response DTO") +@Data +public class DeptRespDTO { + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") + private String name; + + @Schema(description = "父部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long parentId; + + @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long leaderUserId; + + @Schema(description = "部门状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 CommonStatusEnum 枚举 + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/dto/PostRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/dto/PostRespDTO.java new file mode 100644 index 0000000..3959a71 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dept/dto/PostRespDTO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.systemapi.api.dept.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 岗位 Response DTO + * + * @author 芋道源码 + */ +@Schema(description = "RPC 服务 - 岗位 Response DTO") +@Data +public class PostRespDTO { + + @Schema(description = "岗位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆") + private String name; + + @Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String code; + + @Schema(description = "岗位排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sort; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 CommonStatusEnum 枚举 + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dict/DictDataApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dict/DictDataApi.java new file mode 100644 index 0000000..fd3d300 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dict/DictDataApi.java @@ -0,0 +1,85 @@ +package com.tashow.cloud.systemapi.api.dict; + +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.Operation; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.dict.dto.DictDataRespDTO; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Collection; +import java.util.List; + +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 字典数据") +public interface DictDataApi { + + String PREFIX = ApiConstants.PREFIX + "/dict-data"; + + @GetMapping(PREFIX + "/valid") + @Operation(summary = "校验字典数据们是否有效") + @Parameters({ + @Parameter(name = "dictType", description = "字典类型", example = "SEX", required = true), + @Parameter(name = "descriptions", description = "字典数据值的数组", example = "1,2", required = true) + }) + CommonResult validateDictDataList(@RequestParam("dictType") String dictType, + @RequestParam("values") Collection values); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "获得指定的字典数据") + @Parameters({ + @Parameter(name = "dictType", description = "字典类型", example = "SEX", required = true), + @Parameter(name = "description", description = "字典数据值", example = "1", required = true) + }) + CommonResult getDictData(@RequestParam("dictType") String dictType, + @RequestParam("value") String value); + + /** + * 获得指定的字典标签,从缓存中 + * + * @param type 字典类型 + * @param value 字典数据值 + * @return 字典标签 + */ + default String getDictDataLabel(String type, Integer value) { + DictDataRespDTO dictData = getDictData(type, String.valueOf(value)).getData(); + if (ObjUtil.isNull(dictData)) { + return StrUtil.EMPTY; + } + return dictData.getLabel(); + } + + @GetMapping(PREFIX + "/parse") + @Operation(summary = "解析获得指定的字典数据") + @Parameters({ + @Parameter(name = "dictType", description = "字典类型", example = "SEX", required = true), + @Parameter(name = "label", description = "字典标签", example = "男", required = true) + }) + CommonResult parseDictData(@RequestParam("dictType") String dictType, + @RequestParam("label") String label); + + @GetMapping(PREFIX + "/list") + @Operation(summary = "获得指定字典类型的字典数据列表") + @Parameter(name = "dictType", description = "字典类型", example = "SEX", required = true) + CommonResult> getDictDataList(@RequestParam("dictType") String dictType); + + /** + * 获得字典数据标签列表 + * + * @param dictType 字典类型 + * @return 字典数据标签列表 + */ + default List getDictDataLabelList(String dictType) { + List list = getDictDataList(dictType).getData(); + return convertList(list, DictDataRespDTO::getLabel); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dict/dto/DictDataRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dict/dto/DictDataRespDTO.java new file mode 100644 index 0000000..1706906 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/dict/dto/DictDataRespDTO.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.systemapi.api.dict.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "RPC 服务 - 字典数据 Response DTO") +@Data +public class DictDataRespDTO { + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String label; + + @Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder") + private String value; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + private String dictType; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 CommonStatusEnum 枚举 + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/LoginLogApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/LoginLogApi.java new file mode 100644 index 0000000..f814ddd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/LoginLogApi.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.systemapi.api.logger; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 登录日志") +public interface LoginLogApi { + + String PREFIX = ApiConstants.PREFIX + "/login-log"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "创建登录日志") + CommonResult createLoginLog(@Valid @RequestBody LoginLogCreateReqDTO reqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/OperateLogApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/OperateLogApi.java new file mode 100644 index 0000000..3b65313 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/OperateLogApi.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.systemapi.api.logger; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogRespDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.SpringQueryMap; +import org.springframework.scheduling.annotation.Async; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 操作日志") +public interface OperateLogApi { + + String PREFIX = ApiConstants.PREFIX + "/operate-log"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "创建操作日志") + CommonResult createOperateLog(@Valid @RequestBody OperateLogCreateReqDTO createReqDTO); + + /** + * 【异步】创建操作日志 + * + * @param createReqDTO 请求 + */ + @Async + default void createOperateLogAsync(OperateLogCreateReqDTO createReqDTO) { + createOperateLog(createReqDTO).checkError(); + } + + @GetMapping(PREFIX + "/page") + @Operation(summary = "获取指定模块的指定数据的操作日志分页") + CommonResult> getOperateLogPage(@SpringQueryMap OperateLogPageReqDTO pageReqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/LoginLogCreateReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/LoginLogCreateReqDTO.java new file mode 100644 index 0000000..4cdf54e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/LoginLogCreateReqDTO.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.systemapi.api.logger.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Schema(description = "RPC 服务 - 登录日志创建 Request DTO") +@Data +public class LoginLogCreateReqDTO { + + @Schema(description = "日志类型,参见 LoginLogTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1" ) + @NotNull(message = "日志类型不能为空") + private Integer logType; + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + + @Schema(description = "用户编号", example = "666") + private Long userId; + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2" ) + @NotNull(message = "用户类型不能为空") + private Integer userType; + @Schema(description = "用户账号", example = "yudao") + @Size(max = 30, message = "用户账号长度不能超过30个字符") + private String username; // 不再强制校验 username 非空,因为 Member 社交登录时,此时暂时没有 username(mobile)! + + @Schema(description = "登录结果,参见 LoginResultEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "登录结果不能为空") + private Integer result; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + + @Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + private String userAgent; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogCreateReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogCreateReqDTO.java new file mode 100644 index 0000000..399096d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogCreateReqDTO.java @@ -0,0 +1,51 @@ +package com.tashow.cloud.systemapi.api.logger.dto; + + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(name = "RPC 服务 - 系统操作日志 Create Request DTO") +@Data +public class OperateLogCreateReqDTO { + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + @NotNull(message = "用户编号不能为空") + private Long userId; + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2" ) + @NotNull(message = "用户类型不能为空") + private Integer userType; + @Schema(description = "操作模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单") + @NotEmpty(message = "操作模块类型不能为空") + private String type; + @Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建订单") + @NotEmpty(message = "操作名不能为空") + private String subType; + @Schema(description = "操作模块业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "188") + @NotNull(message = "操作模块业务编号不能为空") + private Long bizId; + @Schema(description = "操作内容", requiredMode = Schema.RequiredMode.REQUIRED, + example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码") + @NotEmpty(message = "操作内容不能为空") + private String action; + @Schema(description = "拓展字段", example = "{\"orderId\": \"1\"}") + private String extra; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @NotEmpty(message = "请求方法名不能为空") + private String requestMethod; + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/order/get") + @NotEmpty(message = "请求地址不能为空") + private String requestUrl; + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + @Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + @NotEmpty(message = "浏览器 UA 不能为空") + private String userAgent; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogPageReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogPageReqDTO.java new file mode 100644 index 0000000..9ee5693 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogPageReqDTO.java @@ -0,0 +1,20 @@ +package com.tashow.cloud.systemapi.api.logger.dto; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(name = "RPC 服务 - 操作日志分页 Request DTO") +@Data +public class OperateLogPageReqDTO extends PageParam { + + @Schema(description = "模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单") + private String type; + + @Schema(description = "模块数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "188") + private Long bizId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Long userId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogRespDTO.java new file mode 100644 index 0000000..6b3da40 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/logger/dto/OperateLogRespDTO.java @@ -0,0 +1,52 @@ +package com.tashow.cloud.systemapi.api.logger.dto; + +import com.tashow.cloud.systemapi.api.user.AdminUserApi; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.VO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(name = "RPC 服务 - 系统操作日志 Response DTO") +@Data +public class OperateLogRespDTO implements VO { + + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + @Trans(type = TransType.AUTO_TRANS, key = AdminUserApi.PREFIX, fields = "nickname", ref = "userName") + private Long userId; + @Schema(description = "用户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String userName; + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2" ) + private Integer userType; + @Schema(description = "操作模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单") + private String type; + @Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建订单") + private String subType; + @Schema(description = "操作模块业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "188") + private Long bizId; + @Schema(description = "操作内容", requiredMode = Schema.RequiredMode.REQUIRED, + example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码") + private String action; + @Schema(description = "拓展字段", example = "{\"orderId\": \"1\"}") + private String extra; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + private String requestMethod; + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/order/get") + private String requestUrl; + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + private String userIp; + @Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + private String userAgent; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/mail/MailSendApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/mail/MailSendApi.java new file mode 100644 index 0000000..5d7a46e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/mail/MailSendApi.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.systemapi.api.mail; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.mail.dto.MailSendSingleToUserReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.mail.dto.MailSendSingleToUserReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.mail.dto.MailSendSingleToUserReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; + +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.RequestBody; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 邮件发送") +public interface MailSendApi { + + String PREFIX = ApiConstants.PREFIX + "/mail/send"; + + @PostMapping(PREFIX + "/send-single-admin") + @Operation(summary = "发送单条邮件给 Admin 用户", description = "在 mail 为空时,使用 userId 加载对应 Admin 的邮箱") + CommonResult sendSingleMailToAdmin(@Valid @RequestBody MailSendSingleToUserReqDTO reqDTO); + + @PostMapping(PREFIX + "/send-single-member") + @Operation(summary = "发送单条邮件给 Member 用户", description = "在 mail 为空时,使用 userId 加载对应 Member 的邮箱") + CommonResult sendSingleMailToMember(@Valid @RequestBody MailSendSingleToUserReqDTO reqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/mail/dto/MailSendSingleToUserReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/mail/dto/MailSendSingleToUserReqDTO.java new file mode 100644 index 0000000..cf5f2a5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/mail/dto/MailSendSingleToUserReqDTO.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.systemapi.api.mail.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "RPC 服务 - 邮件发送给 Admin 或者 Member 用户 Request DTO") +@Data +public class MailSendSingleToUserReqDTO { + + @Schema(description = "用户编号", example = "1024") + private Long userId; + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @Email + private String mail; + + @Schema(description = "邮件模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "USER_SEND") + @NotNull(message = "邮件模板编号不能为空") + private String templateCode; + + @Schema(description = "邮件模板参数") + private Map templateParams; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/notify/NotifyMessageSendApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/notify/NotifyMessageSendApi.java new file mode 100644 index 0000000..3944b7c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/notify/NotifyMessageSendApi.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.systemapi.api.notify; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.notify.dto.NotifySendSingleToUserReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.notify.dto.NotifySendSingleToUserReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.notify.dto.NotifySendSingleToUserReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; + +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.RequestBody; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 站内信发送") +public interface NotifyMessageSendApi { + + String PREFIX = ApiConstants.PREFIX + "/notify/send"; + + @PostMapping(PREFIX + "/send-single-admin") + @Operation(summary = "发送单条站内信给 Admin 用户") + CommonResult sendSingleMessageToAdmin(@Valid @RequestBody NotifySendSingleToUserReqDTO reqDTO); + + @PostMapping(PREFIX + "/send-single-member") + @Operation(summary = "发送单条站内信给 Member 用户") + CommonResult sendSingleMessageToMember(@Valid @RequestBody NotifySendSingleToUserReqDTO reqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/notify/dto/NotifySendSingleToUserReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/notify/dto/NotifySendSingleToUserReqDTO.java new file mode 100644 index 0000000..b3c4130 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/notify/dto/NotifySendSingleToUserReqDTO.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.systemapi.api.notify.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "RPC 服务 - 站内信发送给 Admin 或者 Member 用户 Request DTO") +@Data +public class NotifySendSingleToUserReqDTO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "站内信模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "USER_SEND") + @NotEmpty(message = "站内信模板编号不能为空") + private String templateCode; + @Schema(description = "邮件模板参数") + private Map templateParams; +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/OAuth2TokenApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/OAuth2TokenApi.java new file mode 100644 index 0000000..bf56072 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/OAuth2TokenApi.java @@ -0,0 +1,52 @@ +package com.tashow.cloud.systemapi.api.oauth2; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenRespDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - OAuth2.0 令牌") +public interface OAuth2TokenApi { + + String PREFIX = ApiConstants.PREFIX + "/oauth2/token"; + + /** + * 校验 Token 的 URL 地址,主要是提供给 Gateway 使用 + */ + @SuppressWarnings("HttpUrlsUsage") + String URL_CHECK = "http://" + ApiConstants.NAME + PREFIX + "/check"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "创建访问令牌") + CommonResult createAccessToken(@Valid @RequestBody OAuth2AccessTokenCreateReqDTO reqDTO); + + @GetMapping(PREFIX + "/check") + @Operation(summary = "校验访问令牌") + @Parameter(name = "accessToken", description = "访问令牌", required = true, example = "tudou") + CommonResult checkAccessToken(@RequestParam("accessToken") String accessToken); + + @DeleteMapping(PREFIX + "/remove") + @Operation(summary = "移除访问令牌") + @Parameter(name = "accessToken", description = "访问令牌", required = true, example = "tudou") + CommonResult removeAccessToken(@RequestParam("accessToken") String accessToken); + + @PutMapping(PREFIX + "/refresh") + @Operation(summary = "刷新访问令牌") + @Parameters({ + @Parameter(name = "refreshToken", description = "刷新令牌", required = true, example = "haha"), + @Parameter(name = "clientId", description = "客户端编号", required = true, example = "yudaoyuanma") + }) + CommonResult refreshAccessToken(@RequestParam("refreshToken") String refreshToken, + @RequestParam("clientId") String clientId); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java new file mode 100644 index 0000000..11f744c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.systemapi.api.oauth2.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Schema(description = "RPC 服务 - OAuth2 访问令牌的校验 Response DTO") +@Data +public class OAuth2AccessTokenCheckRespDTO implements Serializable { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer userType; + + @Schema(description = "用户信息", example = "{\"nickname\": \"芋道\"}") + private Map userInfo; + + @Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long tenantId; + + @Schema(description = "授权范围的数组", example = "user_info") + private List scopes; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expiresTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenCreateReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenCreateReqDTO.java new file mode 100644 index 0000000..6b4be57 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenCreateReqDTO.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.systemapi.api.oauth2.dto; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +@Schema(description = "RPC 服务 - OAuth2 访问令牌创建 Request DTO") +@Data +public class OAuth2AccessTokenCreateReqDTO implements Serializable { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户类型不能为空") + @InEnum(value = UserTypeEnum.class, message = "用户类型必须是 {value}") + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma") + @NotNull(message = "客户端编号不能为空") + private String clientId; + + @Schema(description = "授权范围的数组", example = "user_info") + private List scopes; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenRespDTO.java new file mode 100644 index 0000000..5a3bd20 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/oauth2/dto/OAuth2AccessTokenRespDTO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.systemapi.api.oauth2.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Schema(description = "RPC 服务 - OAuth2 访问令牌的信息 Response DTO") +@Data +@Accessors(chain = true) +public class OAuth2AccessTokenRespDTO implements Serializable { + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + private String accessToken; + + @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "haha") + private String refreshToken; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1" ) + private Integer userType; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expiresTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/package-info.java new file mode 100644 index 0000000..e319fce --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/package-info.java @@ -0,0 +1,4 @@ +/** + * System API 包,定义暴露给其它模块的 API + */ +package com.tashow.cloud.systemapi.api; diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/PermissionApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/PermissionApi.java new file mode 100644 index 0000000..1b8ad3c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/PermissionApi.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.systemapi.api.permission; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Collection; +import java.util.Set; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 权限") +public interface PermissionApi { + + String PREFIX = ApiConstants.PREFIX + "/permission"; + + @GetMapping(PREFIX + "/user-role-id-list-by-role-id") + @Operation(summary = "获得拥有多个角色的用户编号集合") + @Parameter(name = "roleIds", description = "角色编号集合", example = "1,2", required = true) + CommonResult> getUserRoleIdListByRoleIds(@RequestParam("roleIds") Collection roleIds); + + @GetMapping(PREFIX + "/has-any-permissions") + @Operation(summary = "判断是否有权限,任一一个即可") + @Parameters({ + @Parameter(name = "userId", description = "用户编号", example = "1", required = true), + @Parameter(name = "permissions", description = "权限", example = "read,write", required = true) + }) + CommonResult hasAnyPermissions(@RequestParam("userId") Long userId, + @RequestParam("permissions") String... permissions); + + @GetMapping(PREFIX + "/has-any-roles") + @Operation(summary = "判断是否有角色,任一一个即可") + @Parameters({ + @Parameter(name = "userId", description = "用户编号", example = "1", required = true), + @Parameter(name = "roles", description = "角色数组", example = "2", required = true) + }) + CommonResult hasAnyRoles(@RequestParam("userId") Long userId, + @RequestParam("roles") String... roles); + + @GetMapping(PREFIX + "/get-dept-data-permission") + @Operation(summary = "获得登陆用户的部门数据权限") + @Parameter(name = "userId", description = "用户编号", example = "2", required = true) + CommonResult getDeptDataPermission(@RequestParam("userId") Long userId); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/RoleApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/RoleApi.java new file mode 100644 index 0000000..f60b945 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/RoleApi.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.systemapi.api.permission; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Collection; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 角色") +public interface RoleApi { + + String PREFIX = ApiConstants.PREFIX + "/role"; + + @GetMapping(PREFIX + "/valid") + @Operation(summary = "校验角色是否合法") + @Parameter(name = "ids", description = "角色编号数组", example = "1,2", required = true) + CommonResult validRoleList(@RequestParam("ids") Collection ids); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/dto/DeptDataPermissionRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/dto/DeptDataPermissionRespDTO.java new file mode 100644 index 0000000..857205e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/permission/dto/DeptDataPermissionRespDTO.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.systemapi.api.permission.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.HashSet; +import java.util.Set; + +@Schema(description = "RPC 服务 - 部门的数据权限 Response DTO") +@Data +public class DeptDataPermissionRespDTO { + + @Schema(description = "是否可查看全部数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean all; + + @Schema(description = "是否可查看自己的数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean self; + + @Schema(description = "可查看的部门编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 3]") + private Set deptIds; + + public DeptDataPermissionRespDTO() { + this.all = false; + this.self = false; + this.deptIds = new HashSet<>(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/SmsCodeApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/SmsCodeApi.java new file mode 100644 index 0000000..8dd6915 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/SmsCodeApi.java @@ -0,0 +1,44 @@ +package com.tashow.cloud.systemapi.api.sms; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 短信验证码") +public interface SmsCodeApi { + + String PREFIX = ApiConstants.PREFIX + "/oauth2/sms/code"; + + @PostMapping(PREFIX + "/send") + @Operation(summary = "创建短信验证码,并进行发送") + CommonResult sendSmsCode(@Valid @RequestBody SmsCodeSendReqDTO reqDTO); + + @PutMapping(PREFIX + "/use") + @Operation(summary = "验证短信验证码,并进行使用") + CommonResult useSmsCode(@Valid @RequestBody SmsCodeUseReqDTO reqDTO); + + @GetMapping(PREFIX + "/validate") + @Operation(summary = "检查验证码是否有效") + CommonResult validateSmsCode(@Valid @RequestBody SmsCodeValidateReqDTO reqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/SmsSendApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/SmsSendApi.java new file mode 100644 index 0000000..3e92c9a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/SmsSendApi.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.systemapi.api.sms; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.sms.dto.send.SmsSendSingleToUserReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 短信发送") +public interface SmsSendApi { + + String PREFIX = ApiConstants.PREFIX + "/sms/send"; + + @PostMapping(PREFIX + "/send-single-admin") + @Operation(summary = "发送单条短信给 Admin 用户", description = "在 mobile 为空时,使用 userId 加载对应 Admin 的手机号") + CommonResult sendSingleSmsToAdmin(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO); + + @PostMapping(PREFIX + "/send-single-member") + @Operation(summary = "发送单条短信给 Member 用户", description = "在 mobile 为空时,使用 userId 加载对应 Member 的手机号") + CommonResult sendSingleSmsToMember(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeSendReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeSendReqDTO.java new file mode 100644 index 0000000..d0254ad --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeSendReqDTO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.systemapi.api.sms.dto.code; + +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.common.validation.Mobile; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "RPC 服务 - 短信验证码的发送 Request DTO") +@Data +public class SmsCodeSendReqDTO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @Mobile + @NotEmpty(message = "手机号不能为空") + private String mobile; + + @Schema(description = "发送场景", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + + private Integer scene; + @Schema(description = "发送 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "10.20.30.40") + @NotEmpty(message = "发送 IP 不能为空") + private String createIp; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeUseReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeUseReqDTO.java new file mode 100644 index 0000000..bded877 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeUseReqDTO.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.systemapi.api.sms.dto.code; + +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.common.validation.Mobile; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "RPC 服务 - 短信验证码的使用 Request DTO") +@Data +public class SmsCodeUseReqDTO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @Mobile + @NotEmpty(message = "手机号不能为空") + private String mobile; + + @Schema(description = "发送场景", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + + @Schema(description = "验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "验证码") + private String code; + + @Schema(description = "发送 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "10.20.30.40") + @NotEmpty(message = "使用 IP 不能为空") + private String usedIp; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeValidateReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeValidateReqDTO.java new file mode 100644 index 0000000..0784a22 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/code/SmsCodeValidateReqDTO.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.systemapi.api.sms.dto.code; + +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.common.validation.Mobile; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "RPC 服务 - 短信验证码的校验 Request DTO") +@Data +public class SmsCodeValidateReqDTO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @Mobile + @NotEmpty(message = "手机号不能为空") + private String mobile; + + @Schema(description = "发送场景", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + + @Schema(description = "验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "验证码") + private String code; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/send/SmsSendSingleToUserReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/send/SmsSendSingleToUserReqDTO.java new file mode 100644 index 0000000..dc24e69 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/sms/dto/send/SmsSendSingleToUserReqDTO.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.systemapi.api.sms.dto.send; + +import com.tashow.cloud.common.validation.Mobile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import java.util.Map; + +@Schema(description = "RPC 服务 - 短信发送给 Admin 或者 Member 用户 Request DTO") +@Data +public class SmsSendSingleToUserReqDTO { + + @Schema(description = "用户编号", example = "1024") + private Long userId; + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @Mobile + private String mobile; + + @Schema(description = "短信模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "USER_SEND") + @NotEmpty(message = "短信模板编号不能为空") + private String templateCode; + @Schema(description = "短信模板参数") + private Map templateParams; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/SocialClientApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/SocialClientApi.java new file mode 100644 index 0000000..a34c484 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/SocialClientApi.java @@ -0,0 +1,67 @@ +package com.tashow.cloud.systemapi.api.social; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.social.dto.*; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.SpringQueryMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 社交应用") +public interface SocialClientApi { + + String PREFIX = ApiConstants.PREFIX + "/social-client"; + + @GetMapping(PREFIX + "/get-authorize-url") + @Operation(summary = "获得社交平台的授权 URL") + @Parameters({ + @Parameter(name = "socialType", description = "社交平台的类型", example = "1", required = true), + @Parameter(name = "userType", description = "用户类型", example = "1", required = true), + @Parameter(name = "redirectUri", description = "重定向 URL", example = "https://www.iocoder.cn", required = true) + }) + CommonResult getAuthorizeUrl(@RequestParam("socialType") Integer socialType, + @RequestParam("userType") Integer userType, + @RequestParam("redirectUri") String redirectUri); + + @GetMapping(PREFIX + "/create-wx-mp-jsapi-signature") + @Operation(summary = "创建微信公众号 JS SDK 初始化所需的签名") + @Parameters({ + @Parameter(name = "userType", description = "用户类型", example = "1", required = true), + @Parameter(name = "url", description = "访问 URL", example = "https://www.iocoder.cn", required = true) + }) + CommonResult createWxMpJsapiSignature(@RequestParam("userType") Integer userType, + @RequestParam("url") String url); + + @GetMapping(PREFIX + "/create-wx-ma-phone-number-info") + @Operation(summary = "获得微信小程序的手机信息") + @Parameters({ + @Parameter(name = "userType", description = "用户类型", example = "1", required = true), + @Parameter(name = "phoneCode", description = "手机授权码", example = "yudao11", required = true) + }) + CommonResult getWxMaPhoneNumberInfo(@RequestParam("userType") Integer userType, + @RequestParam("phoneCode") String phoneCode); + + @GetMapping(PREFIX + "/get-wxa-qrcode") + @Operation(summary = "获得小程序二维码") + CommonResult getWxaQrcode(@SpringQueryMap SocialWxQrcodeReqDTO reqVO); + + @GetMapping(PREFIX + "/get-wxa-subscribe-template-list") + @Operation(summary = "获得微信小程订阅模板") + CommonResult> getWxaSubscribeTemplateList(@RequestParam("userType") Integer userType); + + @PostMapping(PREFIX + "/send-wxa-subscribe-message") + @Operation(summary = "发送微信小程序订阅消息") + CommonResult sendWxaSubscribeMessage(@Valid @RequestBody SocialWxaSubscribeMessageSendReqDTO reqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/SocialUserApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/SocialUserApi.java new file mode 100644 index 0000000..a3dd9eb --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/SocialUserApi.java @@ -0,0 +1,55 @@ +package com.tashow.cloud.systemapi.api.social; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserRespDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserUnbindReqDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 社交用户") +public interface SocialUserApi { + + String PREFIX = ApiConstants.PREFIX + "/social-user"; + + @PostMapping(PREFIX + "/bind") + @Operation(summary = "绑定社交用户") + CommonResult bindSocialUser(@Valid @RequestBody SocialUserBindReqDTO reqDTO); + + @DeleteMapping(PREFIX + "/unbind") + @Operation(summary = "取消绑定社交用户") + CommonResult unbindSocialUser(@Valid @RequestBody SocialUserUnbindReqDTO reqDTO); + + @GetMapping(PREFIX + "/get-by-user-id") + @Operation(summary = "获得社交用户,基于 userId") + @Parameters({ + @Parameter(name = "userType", description = "用户类型", example = "2", required = true), + @Parameter(name = "userId", description = "用户编号", example = "1024", required = true), + @Parameter(name = "socialType", description = "社交平台的类型", example = "1", required = true), + }) + CommonResult getSocialUserByUserId(@RequestParam("userType") Integer userType, + @RequestParam("userId") Long userId, + @RequestParam("socialType") Integer socialType); + + @GetMapping(PREFIX + "/get-by-code") + @Operation(summary = "获得社交用") // 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 + @Parameters({ + @Parameter(name = "userType", description = "用户类型", example = "2", required = true), + @Parameter(name = "socialType", description = "社交平台的类型", example = "1", required = true), + @Parameter(name = "code", description = "授权码", example = "88888", required = true), + @Parameter(name = "state", description = "state", example = "666", required = true), + }) + CommonResult getSocialUserByCode(@RequestParam("userType") Integer userType, + @RequestParam("socialType") Integer socialType, + @RequestParam("code") String code, + @RequestParam("state") String state); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserBindReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserBindReqDTO.java new file mode 100644 index 0000000..174db3b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserBindReqDTO.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.systemapi.api.social.dto; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "RPC 服务 - 取消绑定社交用户 Request DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SocialUserBindReqDTO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "用户编号不能为空") + private Long userId; + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(UserTypeEnum.class) + @NotNull(message = "用户类型不能为空") + private Integer userType; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer socialType; + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "zsw") + @NotEmpty(message = "授权码不能为空") + private String code; + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "qtw") + @NotEmpty(message = "state 不能为空") + private String state; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserRespDTO.java new file mode 100644 index 0000000..0e4146c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserRespDTO.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.systemapi.api.social.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "RPC 服务 - 社交用户 Response DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SocialUserRespDTO { + + @Schema(description = "社交用户 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "zsw") + private String openid; + + @Schema(description = "社交用户的昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String nickname; + + @Schema(description = "社交用户的头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.jpg") + private String avatar; + + @Schema(description = "关联的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserUnbindReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserUnbindReqDTO.java new file mode 100644 index 0000000..12b6ee9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialUserUnbindReqDTO.java @@ -0,0 +1,38 @@ +package com.tashow.cloud.systemapi.api.social.dto; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.NoArgsConstructor; + +@Schema(description = "RPC 服务 - 取消绑定社交用户 Request DTO") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SocialUserUnbindReqDTO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "用户编号不能为空") + private Long userId; + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(UserTypeEnum.class) + @NotNull(message = "用户类型不能为空") + private Integer userType; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer socialType; + @Schema(description = "社交平台的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "zsw") + @NotEmpty(message = "社交平台的 openid 不能为空") + private String openid; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxJsapiSignatureRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxJsapiSignatureRespDTO.java new file mode 100644 index 0000000..04eed9b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxJsapiSignatureRespDTO.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.systemapi.api.social.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "RPC 服务 - 微信公众号 JSAPI 签名 Response DTO") +@Data +public class SocialWxJsapiSignatureRespDTO { + + @Schema(description = "微信公众号的 appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx123456") + private String appId; + + @Schema(description = "匿名串", requiredMode = Schema.RequiredMode.REQUIRED, example = "zsw") + private String nonceStr; + + @Schema(description = "时间戳", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789") + private Long timestamp; + + @Schema(description = "URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + private String url; + + @Schema(description = "签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "zsw") + private String signature; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxPhoneNumberInfoRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxPhoneNumberInfoRespDTO.java new file mode 100644 index 0000000..73629e6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxPhoneNumberInfoRespDTO.java @@ -0,0 +1,18 @@ +package com.tashow.cloud.systemapi.api.social.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "RPC 服务 - 微信小程序的手机信息 Response DTO") +@Data +public class SocialWxPhoneNumberInfoRespDTO { + + @Schema(description = "用户绑定的手机号(国外手机号会有区号)", requiredMode = Schema.RequiredMode.REQUIRED, example = "021-13579246810") + private String phoneNumber; + + @Schema(description = "没有区号的手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13579246810") + private String purePhoneNumber; + @Schema(description = "区号", requiredMode = Schema.RequiredMode.REQUIRED, example = "021") + private String countryCode; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxQrcodeReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxQrcodeReqDTO.java new file mode 100644 index 0000000..a7e28c8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxQrcodeReqDTO.java @@ -0,0 +1,57 @@ +package com.tashow.cloud.systemapi.api.social.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +/** + * @see 获取不限制的小程序码 + */ +@Schema(description = "RPC 服务 - 获得获取小程序码 Request DTO") +@Data +public class SocialWxQrcodeReqDTO { + + /** + * 页面路径不能携带参数(参数请放在scene字段里) + */ + public static final String SCENE = ""; + /** + * 二维码宽度 + */ + public static final Integer WIDTH = 430; + /** + * 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + */ + public static final Boolean AUTO_COLOR = true; + /** + * 检查 page 是否存在 + */ + public static final Boolean CHECK_PATH = true; + /** + * 是否需要透明底色 + * + * hyaline 为 true 时,生成透明底色的小程序码 + */ + public static final Boolean HYALINE = true; + + @Schema(description = "场景", requiredMode = Schema.RequiredMode.REQUIRED, example = "1001") + @NotEmpty(message = "场景不能为空") + private String scene; + + @Schema(description = "页面路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/goods/index") + @NotEmpty(message = "页面路径不能为空") + private String path; + + @Schema(description = "二维码宽度", example = "430") + private Integer width; + + @Schema(description = "是否需要透明底色", example = "true") + private Boolean autoColor; + + @Schema(description = "是否检查 page 是否存在", example = "true") + private Boolean checkPath; + + @Schema(description = "是否需要透明底色", example = "true") + private Boolean hyaline; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxaSubscribeMessageSendReqDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxaSubscribeMessageSendReqDTO.java new file mode 100644 index 0000000..273418b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxaSubscribeMessageSendReqDTO.java @@ -0,0 +1,43 @@ +package com.tashow.cloud.systemapi.api.social.dto; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Schema(description = "RPC 服务 - 微信小程序订阅消息发送 Request DTO") +@Data +public class SocialWxaSubscribeMessageSendReqDTO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "用户编号不能为空") + private Long userId; + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(UserTypeEnum.class) + @NotNull(message = "用户类型不能为空") + private Integer userType; + + @Schema(description = "消息模版标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "模版标题") + @NotEmpty(message = "消息模版标题不能为空") + private String templateTitle; + + @Schema(description = "点击模板卡片后的跳转页面,仅限本小程序内的页面", example = "pages/index?foo=bar") + private String page; // 支持带参数,(示例 index?foo=bar )。该字段不填则模板无跳转。 + + @Schema(description = "模板内容的参数") + private Map messages; + + public SocialWxaSubscribeMessageSendReqDTO addMessage(String key, String value) { + if (messages == null) { + messages = new HashMap<>(); + } + messages.put(key, value); + return this; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxaSubscribeTemplateRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxaSubscribeTemplateRespDTO.java new file mode 100644 index 0000000..40b46ef --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/social/dto/SocialWxaSubscribeTemplateRespDTO.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.systemapi.api.social.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "RPC 服务 - 小程序订阅消息模版 Response DTO") +@Data +public class SocialWxaSubscribeTemplateRespDTO { + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String id; + + @Schema(description = "模版标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "模版标题") + private String title; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "模版内容") + private String content; + + @Schema(description = "模板内容示例", requiredMode = Schema.RequiredMode.REQUIRED, example = "模版内容示例") + private String example; + + @Schema(description = "模版类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer type; // 2:为一次性订阅;3:为长期订阅 + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/tenant/TenantApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/tenant/TenantApi.java new file mode 100644 index 0000000..f7bbeae --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/tenant/TenantApi.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.systemapi.api.tenant; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 多租户") +public interface TenantApi { + + String PREFIX = ApiConstants.PREFIX + "/tenant"; + + @GetMapping(PREFIX + "/id-list") + @Operation(summary = "获得所有租户编号") + CommonResult> getTenantIdList(); + + @GetMapping(PREFIX + "/valid") + @Operation(summary = "校验租户是否合法") + @Parameter(name = "id", description = "租户编号", required = true, example = "1024") + CommonResult validTenant(@RequestParam("id") Long id); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/user/AdminUserApi.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/user/AdminUserApi.java new file mode 100644 index 0000000..800331a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/user/AdminUserApi.java @@ -0,0 +1,96 @@ +package com.tashow.cloud.systemapi.api.user; + +import cn.hutool.core.convert.Convert; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.trans.AutoTransable; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.systemapi.api.user.dto.AdminUserRespDTO; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import com.fhs.core.trans.anno.AutoTrans; +import feign.FeignIgnore; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static com.tashow.cloud.systemapi.api.user.AdminUserApi.PREFIX; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 管理员用户") +@AutoTrans(namespace = PREFIX, fields = {"nickname"}) +public interface AdminUserApi extends AutoTransable { + + String PREFIX = ApiConstants.PREFIX + "/user"; + + @GetMapping(PREFIX + "/get") + @Operation(summary = "通过用户 ID 查询用户") + @Parameter(name = "id", description = "用户编号", example = "1", required = true) + CommonResult getUser(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list-by-subordinate") + @Operation(summary = "通过用户 ID 查询用户下属") + @Parameter(name = "id", description = "用户编号", example = "1", required = true) + CommonResult> getUserListBySubordinate(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list") + @Operation(summary = "通过用户 ID 查询用户们") + @Parameter(name = "ids", description = "部门编号数组", example = "1,2", required = true) + CommonResult> getUserList(@RequestParam("ids") Collection ids); + + @GetMapping(PREFIX + "/list-by-dept-id") + @Operation(summary = "获得指定部门的用户数组") + @Parameter(name = "deptIds", description = "部门编号数组", example = "1,2", required = true) + CommonResult> getUserListByDeptIds(@RequestParam("deptIds") Collection deptIds); + + @GetMapping(PREFIX + "/list-by-post-id") + @Operation(summary = "获得指定岗位的用户数组") + @Parameter(name = "postIds", description = "岗位编号数组", example = "2,3", required = true) + CommonResult> getUserListByPostIds(@RequestParam("postIds") Collection postIds); + + /** + * 获得用户 Map + * + * @param ids 用户编号数组 + * @return 用户 Map + */ + default Map getUserMap(Collection ids) { + List users = getUserList(ids).getCheckedData(); + return CollectionUtils.convertMap(users, AdminUserRespDTO::getId); + } + + /** + * 校验用户是否有效。如下情况,视为无效: + * 1. 用户编号不存在 + * 2. 用户被禁用 + * + * @param id 用户编号 + */ + default void validateUser(Long id) { + validateUserList(Collections.singleton(id)); + } + + @GetMapping(PREFIX + "/valid") + @Operation(summary = "校验用户们是否有效") + @Parameter(name = "ids", description = "用户编号数组", example = "3,5", required = true) + CommonResult validateUserList(@RequestParam("ids") Collection ids); + + @Override + @FeignIgnore + default List selectByIds(List ids) { + return getUserList(Convert.toList(Long.class, ids)).getCheckedData(); + } + + @Override + @FeignIgnore + default AdminUserRespDTO selectById(Object id) { + return getUser(Convert.toLong(id)).getCheckedData(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/user/dto/AdminUserRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/user/dto/AdminUserRespDTO.java new file mode 100644 index 0000000..3040f96 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/api/user/dto/AdminUserRespDTO.java @@ -0,0 +1,34 @@ +package com.tashow.cloud.systemapi.api.user.dto; + +import com.fhs.core.trans.vo.VO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Set; + +@Schema(description = "RPC 服务 - Admin 用户 Response DTO") +@Data +public class AdminUserRespDTO implements VO { + + @Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王") + private String nickname; + + @Schema(description = "帐号状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 CommonStatusEnum 枚举 + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long deptId; + + @Schema(description = "岗位编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 3]") + private Set postIds; + + @Schema(description = "手机号码", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + private String mobile; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String avatar; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/ApiConstants.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/ApiConstants.java new file mode 100644 index 0000000..e1fa9c7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/ApiConstants.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.systemapi.enums; + + +import com.tashow.cloud.common.enums.RpcConstants; + +/** + * API 相关的枚举 + * + * @author 芋道源码 + */ +public class ApiConstants { + + /** + * 服务名 + * + * 注意,需要保证和 spring.application.name 保持一致 + */ + public static final String NAME = "system-server"; + + public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/system"; + + public static final String VERSION = "1.0.0"; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/DictTypeConstants.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/DictTypeConstants.java new file mode 100644 index 0000000..15e4af7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/DictTypeConstants.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.systemapi.enums; + +/** + * System 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String USER_TYPE = "user_type"; // 用户类型 + String COMMON_STATUS = "common_status"; // 系统状态 + + // ========== SYSTEM 模块 ========== + + String USER_SEX = "system_user_sex"; // 用户性别 + String DATA_SCOPE = "system_data_scope"; // 数据范围 + + String LOGIN_TYPE = "system_login_type"; // 登录日志的类型 + String LOGIN_RESULT = "system_login_result"; // 登录结果 + + String SMS_CHANNEL_CODE = "system_sms_channel_code"; // 短信渠道编码 + String SMS_TEMPLATE_TYPE = "system_sms_template_type"; // 短信模板类型 + String SMS_SEND_STATUS = "system_sms_send_status"; // 短信发送状态 + String SMS_RECEIVE_STATUS = "system_sms_receive_status"; // 短信接收状态 + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/ErrorCodeConstants.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..8b7c00c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/ErrorCodeConstants.java @@ -0,0 +1,169 @@ +package com.tashow.cloud.systemapi.enums; + + +import com.tashow.cloud.common.exception.ErrorCode; + +/** + * System 错误码枚举类 + * + * system 系统,使用 1-002-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== AUTH 模块 1-002-000-000 ========== + ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_002_000_000, "登录失败,账号密码不正确"); + ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_002_000_001, "登录失败,账号被禁用"); + ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_004, "验证码不正确,原因:{}"); + ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_002_000_005, "未绑定账号,需要进行绑定"); + ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "手机号不存在"); + ErrorCode AUTH_REGISTER_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_008, "验证码不正确,原因:{}"); + + // ========== 菜单模块 1-002-001-000 ========== + ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1_002_001_000, "已经存在该名字的菜单"); + ErrorCode MENU_PARENT_NOT_EXISTS = new ErrorCode(1_002_001_001, "父菜单不存在"); + ErrorCode MENU_PARENT_ERROR = new ErrorCode(1_002_001_002, "不能设置自己为父菜单"); + ErrorCode MENU_NOT_EXISTS = new ErrorCode(1_002_001_003, "菜单不存在"); + ErrorCode MENU_EXISTS_CHILDREN = new ErrorCode(1_002_001_004, "存在子菜单,无法删除"); + ErrorCode MENU_PARENT_NOT_DIR_OR_MENU = new ErrorCode(1_002_001_005, "父菜单的类型必须是目录或者菜单"); + + // ========== 角色模块 1-002-002-000 ========== + ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1_002_002_000, "角色不存在"); + ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1_002_002_001, "已经存在名为【{}】的角色"); + ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1_002_002_002, "已经存在标识为【{}】的角色"); + ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1_002_002_003, "不能操作类型为系统内置的角色"); + ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用"); + ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "标识【{}】不能使用"); + + // ========== 用户模块 1-002-003-000 ========== + ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "用户账号已经存在"); + ErrorCode USER_MOBILE_EXISTS = new ErrorCode(1_002_003_001, "手机号已经存在"); + ErrorCode USER_EMAIL_EXISTS = new ErrorCode(1_002_003_002, "邮箱已经存在"); + ErrorCode USER_NOT_EXISTS = new ErrorCode(1_002_003_003, "用户不存在"); + ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_002_003_004, "导入用户数据不能为空!"); + ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1_002_003_005, "用户密码校验失败"); + ErrorCode USER_IS_DISABLE = new ErrorCode(1_002_003_006, "名字为【{}】的用户已被禁用"); + ErrorCode USER_COUNT_MAX = new ErrorCode(1_002_003_008, "创建用户失败,原因:超过租户最大租户配额({})!"); + ErrorCode USER_IMPORT_INIT_PASSWORD = new ErrorCode(1_002_003_009, "初始密码不能为空"); + ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1_002_003_010, "该手机号尚未注册"); + + // ========== 部门模块 1-002-004-000 ========== + ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门"); + ErrorCode DEPT_PARENT_NOT_EXITS = new ErrorCode(1_002_004_001,"父级部门不存在"); + ErrorCode DEPT_NOT_FOUND = new ErrorCode(1_002_004_002, "当前部门不存在"); + ErrorCode DEPT_EXITS_CHILDREN = new ErrorCode(1_002_004_003, "存在子部门,无法删除"); + ErrorCode DEPT_PARENT_ERROR = new ErrorCode(1_002_004_004, "不能设置自己为父部门"); + ErrorCode DEPT_NOT_ENABLE = new ErrorCode(1_002_004_006, "部门({})不处于开启状态,不允许选择"); + ErrorCode DEPT_PARENT_IS_CHILD = new ErrorCode(1_002_004_007, "不能设置自己的子部门为父部门"); + + // ========== 岗位模块 1-002-005-000 ========== + ErrorCode POST_NOT_FOUND = new ErrorCode(1_002_005_000, "当前岗位不存在"); + ErrorCode POST_NOT_ENABLE = new ErrorCode(1_002_005_001, "岗位({}) 不处于开启状态,不允许选择"); + ErrorCode POST_NAME_DUPLICATE = new ErrorCode(1_002_005_002, "已经存在该名字的岗位"); + ErrorCode POST_CODE_DUPLICATE = new ErrorCode(1_002_005_003, "已经存在该标识的岗位"); + + // ========== 字典类型 1-002-006-000 ========== + ErrorCode DICT_TYPE_NOT_EXISTS = new ErrorCode(1_002_006_001, "当前字典类型不存在"); + ErrorCode DICT_TYPE_NOT_ENABLE = new ErrorCode(1_002_006_002, "字典类型不处于开启状态,不允许选择"); + ErrorCode DICT_TYPE_NAME_DUPLICATE = new ErrorCode(1_002_006_003, "已经存在该名字的字典类型"); + ErrorCode DICT_TYPE_TYPE_DUPLICATE = new ErrorCode(1_002_006_004, "已经存在该类型的字典类型"); + ErrorCode DICT_TYPE_HAS_CHILDREN = new ErrorCode(1_002_006_005, "无法删除,该字典类型还有字典数据"); + + // ========== 字典数据 1-002-007-000 ========== + ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1_002_007_001, "当前字典数据不存在"); + ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1_002_007_002, "字典数据({})不处于开启状态,不允许选择"); + ErrorCode DICT_DATA_VALUE_DUPLICATE = new ErrorCode(1_002_007_003, "已经存在该值的字典数据"); + + // ========== 通知公告 1-002-008-000 ========== + ErrorCode NOTICE_NOT_FOUND = new ErrorCode(1_002_008_001, "当前通知公告不存在"); + + // ========== 短信渠道 1-002-011-000 ========== + ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1_002_011_000, "短信渠道不存在"); + ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1_002_011_001, "短信渠道不处于开启状态,不允许选择"); + ErrorCode SMS_CHANNEL_HAS_CHILDREN = new ErrorCode(1_002_011_002, "无法删除,该短信渠道还有短信模板"); + + // ========== 短信模板 1-002-012-000 ========== + ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在"); + ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "已经存在编码为【{}】的短信模板"); + ErrorCode SMS_TEMPLATE_API_ERROR = new ErrorCode(1_002_012_002, "短信 API 模板调用失败,原因是:{}"); + ErrorCode SMS_TEMPLATE_API_AUDIT_CHECKING = new ErrorCode(1_002_012_003, "短信 API 模版无法使用,原因:审批中"); + ErrorCode SMS_TEMPLATE_API_AUDIT_FAIL = new ErrorCode(1_002_012_004, "短信 API 模版无法使用,原因:审批不通过,{}"); + ErrorCode SMS_TEMPLATE_API_NOT_FOUND = new ErrorCode(1_002_012_005, "短信 API 模版无法使用,原因:模版不存在"); + + // ========== 短信发送 1-002-013-000 ========== + ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "手机号不存在"); + ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_013_001, "模板参数({})缺失"); + ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_013_002, "短信模板不存在"); + + // ========== 短信验证码 1-002-014-000 ========== + ErrorCode SMS_CODE_NOT_FOUND = new ErrorCode(1_002_014_000, "验证码不存在"); + ErrorCode SMS_CODE_EXPIRED = new ErrorCode(1_002_014_001, "验证码已过期"); + ErrorCode SMS_CODE_USED = new ErrorCode(1_002_014_002, "验证码已使用"); + ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1_002_014_004, "超过每日短信发送数量"); + ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1_002_014_005, "短信发送过于频繁"); + + // ========== 租户信息 1-002-015-000 ========== + ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1_002_015_000, "租户不存在"); + ErrorCode TENANT_DISABLE = new ErrorCode(1_002_015_001, "名字为【{}】的租户已被禁用"); + ErrorCode TENANT_EXPIRE = new ErrorCode(1_002_015_002, "名字为【{}】的租户已过期"); + ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统租户不能进行修改、删除等操作!"); + ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在"); + ErrorCode TENANT_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的租户已存在"); + + // ========== 租户套餐 1-002-016-000 ========== + ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在"); + ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "租户正在使用该套餐,请给租户重新设置套餐后再尝试删除"); + ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用"); + ErrorCode TENANT_PACKAGE_NAME_DUPLICATE = new ErrorCode(1_002_016_003, "已经存在该名字的租户套餐"); + + // ========== 社交用户 1-002-018-000 ========== + ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}"); + ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户"); + + ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败"); + ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "获得小程序码失败"); + ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR = new ErrorCode(1_002_018_202, "获得小程序订阅消息模版失败"); + ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR = new ErrorCode(1_002_018_203, "发送小程序订阅消息失败"); + ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_210, "社交客户端不存在"); + ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "社交客户端已存在配置"); + + + // ========== OAuth2 客户端 1-002-020-000 ========= + ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在"); + ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 客户端编号已存在"); + ErrorCode OAUTH2_CLIENT_DISABLE = new ErrorCode(1_002_020_002, "OAuth2 客户端已禁用"); + ErrorCode OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS = new ErrorCode(1_002_020_003, "不支持该授权类型"); + ErrorCode OAUTH2_CLIENT_SCOPE_OVER = new ErrorCode(1_002_020_004, "授权范围过大"); + ErrorCode OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH = new ErrorCode(1_002_020_005, "无效 redirect_uri: {}"); + ErrorCode OAUTH2_CLIENT_CLIENT_SECRET_ERROR = new ErrorCode(1_002_020_006, "无效 client_secret: {}"); + + // ========== OAuth2 授权 1-002-021-000 ========= + ErrorCode OAUTH2_GRANT_CLIENT_ID_MISMATCH = new ErrorCode(1_002_021_000, "client_id 不匹配"); + ErrorCode OAUTH2_GRANT_REDIRECT_URI_MISMATCH = new ErrorCode(1_002_021_001, "redirect_uri 不匹配"); + ErrorCode OAUTH2_GRANT_STATE_MISMATCH = new ErrorCode(1_002_021_002, "state 不匹配"); + + // ========== OAuth2 授权 1-002-022-000 ========= + ErrorCode OAUTH2_CODE_NOT_EXISTS = new ErrorCode(1_002_022_000, "code 不存在"); + ErrorCode OAUTH2_CODE_EXPIRE = new ErrorCode(1_002_022_001, "code 已过期"); + + // ========== 邮箱账号 1-002-023-000 ========== + ErrorCode MAIL_ACCOUNT_NOT_EXISTS = new ErrorCode(1_002_023_000, "邮箱账号不存在"); + ErrorCode MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS = new ErrorCode(1_002_023_001, "无法删除,该邮箱账号还有邮件模板"); + + // ========== 邮件模版 1-002-024-000 ========== + ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_024_000, "邮件模版不存在"); + ErrorCode MAIL_TEMPLATE_CODE_EXISTS = new ErrorCode(1_002_024_001, "邮件模版 code({}) 已存在"); + + // ========== 邮件发送 1-002-025-000 ========== + ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_025_000, "模板参数({})缺失"); + ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1_002_025_001, "邮箱不存在"); + + // ========== 站内信模版 1-002-026-000 ========== + ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_026_000, "站内信模版不存在"); + ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_026_001, "已经存在编码为【{}】的站内信模板"); + + // ========== 站内信模版 1-002-027-000 ========== + + // ========== 站内信发送 1-002-028-000 ========== + ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "模板参数({})缺失"); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/LogRecordConstants.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/LogRecordConstants.java new file mode 100644 index 0000000..e1dd9a4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/LogRecordConstants.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.systemapi.enums; + +/** + * System 操作日志枚举 + * 目的:统一管理,也减少 Service 里各种“复杂”字符串 + * + * @author 芋道源码 + */ +public interface LogRecordConstants { + + // ======================= SYSTEM_USER 用户 ======================= + + String SYSTEM_USER_TYPE = "SYSTEM 用户"; + String SYSTEM_USER_CREATE_SUB_TYPE = "创建用户"; + String SYSTEM_USER_CREATE_SUCCESS = "创建了用户【{{#user.nickname}}】"; + String SYSTEM_USER_UPDATE_SUB_TYPE = "更新用户"; + String SYSTEM_USER_UPDATE_SUCCESS = "更新了用户【{{#user.nickname}}】: {_DIFF{#updateReqVO}}"; + String SYSTEM_USER_DELETE_SUB_TYPE = "删除用户"; + String SYSTEM_USER_DELETE_SUCCESS = "删除了用户【{{#user.nickname}}】"; + String SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE = "重置用户密码"; + String SYSTEM_USER_UPDATE_PASSWORD_SUCCESS = "将用户【{{#user.nickname}}】的密码从【{{#user.password}}】重置为【{{#newPassword}}】"; + + // ======================= SYSTEM_ROLE 角色 ======================= + + String SYSTEM_ROLE_TYPE = "SYSTEM 角色"; + String SYSTEM_ROLE_CREATE_SUB_TYPE = "创建角色"; + String SYSTEM_ROLE_CREATE_SUCCESS = "创建了角色【{{#role.name}}】"; + String SYSTEM_ROLE_UPDATE_SUB_TYPE = "更新角色"; + String SYSTEM_ROLE_UPDATE_SUCCESS = "更新了角色【{{#role.name}}】: {_DIFF{#updateReqVO}}"; + String SYSTEM_ROLE_DELETE_SUB_TYPE = "删除角色"; + String SYSTEM_ROLE_DELETE_SUCCESS = "删除了角色【{{#role.name}}】"; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/common/SexEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/common/SexEnum.java new file mode 100644 index 0000000..f01466d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/common/SexEnum.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.systemapi.enums.common; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 性别的枚举值 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SexEnum { + + /** 男 */ + MALE(1), + /** 女 */ + FEMALE(2), + /* 未知 */ + UNKNOWN(0); + + /** + * 性别 + */ + private final Integer sex; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/logger/LoginLogTypeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/logger/LoginLogTypeEnum.java new file mode 100644 index 0000000..8779293 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/logger/LoginLogTypeEnum.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.systemapi.enums.logger; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录日志的类型枚举 + */ +@Getter +@AllArgsConstructor +public enum LoginLogTypeEnum { + + LOGIN_USERNAME(100), // 使用账号登录 + LOGIN_SOCIAL(101), // 使用社交登录 + LOGIN_MOBILE(103), // 使用手机登陆 + LOGIN_SMS(104), // 使用短信登陆 + + LOGOUT_SELF(200), // 自己主动登出 + LOGOUT_DELETE(202), // 强制退出 + ; + + /** + * 日志类型 + */ + private final Integer type; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/logger/LoginResultEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/logger/LoginResultEnum.java new file mode 100644 index 0000000..fac1d52 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/logger/LoginResultEnum.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.systemapi.enums.logger; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录结果的枚举类 + */ +@Getter +@AllArgsConstructor +public enum LoginResultEnum { + + SUCCESS(0), // 成功 + BAD_CREDENTIALS(10), // 账号或密码不正确 + USER_DISABLED(20), // 用户被禁用 + CAPTCHA_NOT_FOUND(30), // 图片验证码不存在 + CAPTCHA_CODE_ERROR(31), // 图片验证码不正确 + + ; + + /** + * 结果 + */ + private final Integer result; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/mail/MailSendStatusEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/mail/MailSendStatusEnum.java new file mode 100644 index 0000000..477c3f7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/mail/MailSendStatusEnum.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.systemapi.enums.mail; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 邮件的发送状态枚举 + * + * @author wangjingyi + * @since 2022/4/10 13:39 + */ +@Getter +@AllArgsConstructor +public enum MailSendStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 发送成功 + FAILURE(20), // 发送失败 + IGNORE(30), // 忽略,即不发送 + ; + + private final int status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/notice/NoticeTypeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/notice/NoticeTypeEnum.java new file mode 100644 index 0000000..bea5f6e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/notice/NoticeTypeEnum.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.systemapi.enums.notice; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知类型 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum NoticeTypeEnum { + + NOTICE(1), + ANNOUNCEMENT(2); + + /** + * 类型 + */ + private final Integer type; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/notify/NotifyTemplateTypeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/notify/NotifyTemplateTypeEnum.java new file mode 100644 index 0000000..f3c8faf --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/notify/NotifyTemplateTypeEnum.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.systemapi.enums.notify; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知模板类型枚举 + * + * @author HUIHUI + */ +@Getter +@AllArgsConstructor +public enum NotifyTemplateTypeEnum { + + /** + * 系统消息 + */ + SYSTEM_MESSAGE(2), + /** + * 通知消息 + */ + NOTIFICATION_MESSAGE(1); + + private final Integer type; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/oauth2/OAuth2ClientConstants.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/oauth2/OAuth2ClientConstants.java new file mode 100644 index 0000000..e673bc5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/oauth2/OAuth2ClientConstants.java @@ -0,0 +1,12 @@ +package com.tashow.cloud.systemapi.enums.oauth2; + +/** + * OAuth2.0 客户端的通用枚举 + * + * @author 芋道源码 + */ +public interface OAuth2ClientConstants { + + String CLIENT_ID_DEFAULT = "default"; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/oauth2/OAuth2GrantTypeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/oauth2/OAuth2GrantTypeEnum.java new file mode 100644 index 0000000..801312d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/oauth2/OAuth2GrantTypeEnum.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.systemapi.enums.oauth2; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * OAuth2 授权类型(模式)的枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum OAuth2GrantTypeEnum { + + PASSWORD("password"), // 密码模式 + AUTHORIZATION_CODE("authorization_code"), // 授权码模式 + IMPLICIT("implicit"), // 简化模式 + CLIENT_CREDENTIALS("client_credentials"), // 客户端模式 + REFRESH_TOKEN("refresh_token"), // 刷新模式 + ; + + private final String grantType; + + public static OAuth2GrantTypeEnum getByGrantType(String grantType) { + return ArrayUtil.firstMatch(o -> o.getGrantType().equals(grantType), values()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/DataScopeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/DataScopeEnum.java new file mode 100644 index 0000000..d3d0800 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/DataScopeEnum.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.systemapi.enums.permission; + +import com.tashow.cloud.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 数据范围枚举类 + * + * 用于实现数据级别的权限 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum DataScopeEnum implements ArrayValuable { + + ALL(1), // 全部数据权限 + + DEPT_CUSTOM(2), // 指定部门数据权限 + DEPT_ONLY(3), // 部门数据权限 + DEPT_AND_CHILD(4), // 部门及以下数据权限 + + SELF(5); // 仅本人数据权限 + + /** + * 范围 + */ + private final Integer scope; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(DataScopeEnum::getScope).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/MenuTypeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/MenuTypeEnum.java new file mode 100644 index 0000000..095d43e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/MenuTypeEnum.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.systemapi.enums.permission; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 菜单类型枚举类 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MenuTypeEnum { + + DIR(1), // 目录 + MENU(2), // 菜单 + BUTTON(3) // 按钮 + ; + + /** + * 类型 + */ + private final Integer type; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/RoleCodeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/RoleCodeEnum.java new file mode 100644 index 0000000..154d45d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/RoleCodeEnum.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.systemapi.enums.permission; + +import com.tashow.cloud.common.util.object.ObjectUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 角色标识枚举 + */ +@Getter +@AllArgsConstructor +public enum RoleCodeEnum { + + SUPER_ADMIN("super_admin", "超级管理员"), + TENANT_ADMIN("tenant_admin", "租户管理员"), + CRM_ADMIN("crm_admin", "CRM 管理员"); // CRM 系统专用 + ; + + /** + * 角色编码 + */ + private final String code; + /** + * 名字 + */ + private final String name; + + public static boolean isSuperAdmin(String code) { + return ObjectUtils.equalsAny(code, SUPER_ADMIN.getCode()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/RoleTypeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/RoleTypeEnum.java new file mode 100644 index 0000000..230ea69 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/permission/RoleTypeEnum.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.systemapi.enums.permission; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum RoleTypeEnum { + + /** + * 内置角色 + */ + SYSTEM(1), + /** + * 自定义角色 + */ + CUSTOM(2); + + private final Integer type; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsReceiveStatusEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsReceiveStatusEnum.java new file mode 100644 index 0000000..546cbf1 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsReceiveStatusEnum.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.systemapi.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的接收状态枚举 + * + * @author 芋道源码 + * @date 2021/2/1 13:39 + */ +@Getter +@AllArgsConstructor +public enum SmsReceiveStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 接收成功 + FAILURE(20), // 接收失败 + ; + + private final int status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsSceneEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsSceneEnum.java new file mode 100644 index 0000000..373e6c2 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsSceneEnum.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.systemapi.enums.sms; + +import cn.hutool.core.util.ArrayUtil; +import com.tashow.cloud.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 用户短信验证码发送场景的枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SmsSceneEnum implements ArrayValuable { + + MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登陆"), + MEMBER_UPDATE_MOBILE(2, "user-update-mobile", "会员用户 - 修改手机"), + MEMBER_UPDATE_PASSWORD(3, "user-update-password", "会员用户 - 修改密码"), + MEMBER_RESET_PASSWORD(4, "user-reset-password", "会员用户 - 忘记密码"), + + ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 手机号登录"), + ADMIN_MEMBER_REGISTER(22, "admin-sms-register", "后台用户 - 手机号注册"), + ADMIN_MEMBER_RESET_PASSWORD(23, "admin-reset-password", "后台用户 - 忘记密码"); + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(SmsSceneEnum::getScene).toArray(Integer[]::new); + + /** + * 验证场景的编号 + */ + private final Integer scene; + /** + * 模版编码 + */ + private final String templateCode; + /** + * 描述 + */ + private final String description; + + @Override + public Integer[] array() { + return ARRAYS; + } + + public static SmsSceneEnum getCodeByScene(Integer scene) { + return ArrayUtil.firstMatch(sceneEnum -> sceneEnum.getScene().equals(scene), + values()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsSendStatusEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsSendStatusEnum.java new file mode 100644 index 0000000..70f1fa6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsSendStatusEnum.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.systemapi.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的发送状态枚举 + * + * @author zzf + * @date 2021/2/1 13:39 + */ +@Getter +@AllArgsConstructor +public enum SmsSendStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 发送成功 + FAILURE(20), // 发送失败 + IGNORE(30), // 忽略,即不发送 + ; + + private final int status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsTemplateTypeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsTemplateTypeEnum.java new file mode 100644 index 0000000..431beee --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/sms/SmsTemplateTypeEnum.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.systemapi.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的模板类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SmsTemplateTypeEnum { + + VERIFICATION_CODE(1), // 验证码 + NOTICE(2), // 通知 + PROMOTION(3), // 营销 + ; + + /** + * 类型 + */ + private final int type; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/social/SocialTypeEnum.java b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/social/SocialTypeEnum.java new file mode 100644 index 0000000..52903a4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-api/src/main/java/com/tashow/cloud/systemapi/enums/social/SocialTypeEnum.java @@ -0,0 +1,78 @@ +package com.tashow.cloud.systemapi.enums.social; + +import cn.hutool.core.util.ArrayUtil; +import com.tashow.cloud.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 社交平台的类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SocialTypeEnum implements ArrayValuable { + + /** + * Gitee + * + * @see 接入文档 + */ + GITEE(10, "GITEE"), + /** + * 钉钉 + * + * @see 接入文档 + */ + DINGTALK(20, "DINGTALK"), + + /** + * 企业微信 + * + * @see 接入文档 + */ + WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"), + /** + * 微信公众平台 - 移动端 H5 + * + * @see 接入文档 + */ + WECHAT_MP(31, "WECHAT_MP"), + /** + * 微信开放平台 - 网站应用 PC 端扫码授权登录 + * + * @see 接入文档 + */ + WECHAT_OPEN(32, "WECHAT_OPEN"), + /** + * 微信小程序 + * + * @see 接入文档 + */ + WECHAT_MINI_APP(34, "WECHAT_MINI_APP"), + ; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(SocialTypeEnum::getType).toArray(Integer[]::new); + + /** + * 类型 + */ + private final Integer type; + /** + * 类型的标识 + */ + private final String source; + + @Override + public Integer[] array() { + return ARRAYS; + } + + public static SocialTypeEnum valueOfType(Integer type) { + return ArrayUtil.firstMatch(o -> o.getType().equals(type), values()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/Dockerfile b/tashow-module/tashow-module-system/tashow-module-system-biz/Dockerfile new file mode 100644 index 0000000..a2ee19c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/Dockerfile @@ -0,0 +1,19 @@ +## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 +## 感谢复旦核博士的建议!灰子哥,牛皮! +FROM eclipse-temurin:21-jre + +## 创建目录,并使用它作为工作目录 +RUN mkdir -p /yudao-module-system-biz +WORKDIR /yudao-module-system-biz +## 将后端项目的 Jar 文件,复制到镜像中 +COPY ./target/yudao-module-system-biz.jar app.jar + +## 设置 TZ 时区 +## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖 +ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx512m" + +## 暴露后端项目的 48080 端口 +EXPOSE 48081 + +## 启动后端项目 +CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/pom.xml b/tashow-module/tashow-module-system/tashow-module-system-biz/pom.xml new file mode 100644 index 0000000..804c197 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/pom.xml @@ -0,0 +1,170 @@ + + + + com.tashow.cloud + tashow-module-system + ${revision} + + 4.0.0 + tashow-module-system-biz + jar + + ${project.artifactId} + + system 模块下,我们放通用业务,支撑上层的核心业务。 + 例如说:用户、部门、权限、数据字典等等 + + + + + + com.tashow.cloud + tashow-framework-env + + + + + com.tashow.cloud + tashow-module-system-api + ${revision} + + + com.tashow.cloud + tashow-module-infra-api + ${revision} + + + + + com.tashow.cloud + tashow-data-permission + + + com.tashow.cloud + tashow-framework-tenant + + + com.tashow.cloud + tashow-framework-ip + + + + + com.tashow.cloud + tashow-framework-security + + + + + com.tashow.cloud + tashow-data-mybatis + + + + com.tashow.cloud + tashow-data-redis + + + + + com.tashow.cloud + tashow-framework-rpc + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + + com.tashow.cloud + tashow-framework-job + + + + + com.tashow.cloud + tashow-framework-mq + + + + + + + + + + + com.tashow.cloud + tashow-data-excel + + + + org.springframework.boot + spring-boot-starter-mail + + + + + com.tashow.cloud + tashow-framework-monitor + + + + + com.xingyuv + spring-boot-starter-justauth + + + + com.github.binarywang + wx-java-mp-spring-boot-starter + + + com.github.binarywang + wx-java-miniapp-spring-boot-starter + + + + com.xingyuv + spring-boot-starter-captcha-plus + + + + org.dromara.hutool + hutool-extra + + + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + + diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/SystemServerApplication.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/SystemServerApplication.java new file mode 100644 index 0000000..aa8884d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/SystemServerApplication.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.system; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 项目的启动类 + * + * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * + * @author 芋道源码 + */ +@SpringBootApplication +public class SystemServerApplication { + + public static void main(String[] args) { + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到 启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + + SpringApplication.run(SystemServerApplication.class, args); + + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dept/DeptApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dept/DeptApiImpl.java new file mode 100644 index 0000000..3cf6462 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dept/DeptApiImpl.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.system.api.dept; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.dept.DeptApi; +import com.tashow.cloud.systemapi.api.dept.dto.DeptRespDTO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.service.dept.DeptService; +import com.tashow.cloud.systemapi.api.dept.dto.DeptRespDTO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.service.dept.DeptService; +import org.springframework.context.annotation.Bean; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class DeptApiImpl implements DeptApi { + + @Resource + private DeptService deptService; + + @Override + public CommonResult getDept(Long id) { + DeptDO dept = deptService.getDept(id); + return success(BeanUtils.toBean(dept, DeptRespDTO.class)); + } + + @Override + public CommonResult> getDeptList(Collection ids) { + List depts = deptService.getDeptList(ids); + return success(BeanUtils.toBean(depts, DeptRespDTO.class)); + } + + @Override + public CommonResult validateDeptList(Collection ids) { + deptService.validateDeptList(ids); + return success(true); + } + + @Override + public CommonResult> getChildDeptList(Long id) { + List depts = deptService.getChildDeptList(id); + return success(BeanUtils.toBean(depts, DeptRespDTO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dept/PostApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dept/PostApiImpl.java new file mode 100644 index 0000000..dd14641 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dept/PostApiImpl.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.system.api.dept; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.dept.PostApi; +import com.tashow.cloud.systemapi.api.dept.dto.PostRespDTO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.service.dept.PostService; +import com.tashow.cloud.systemapi.api.dept.dto.PostRespDTO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.service.dept.PostService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class PostApiImpl implements PostApi { + + @Resource + private PostService postService; + + @Override + public CommonResult validPostList(Collection ids) { + postService.validatePostList(ids); + return success(true); + } + + @Override + public CommonResult> getPostList(Collection ids) { + List list = postService.getPostList(ids); + return success(BeanUtils.toBean(list, PostRespDTO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dict/DictDataApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dict/DictDataApiImpl.java new file mode 100644 index 0000000..33f01e7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/dict/DictDataApiImpl.java @@ -0,0 +1,52 @@ +package com.tashow.cloud.system.api.dict; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.dict.DictDataApi; +import com.tashow.cloud.systemapi.api.dict.dto.DictDataRespDTO; +import com.tashow.cloud.system.dal.dataobject.dict.DictDataDO; +import com.tashow.cloud.system.service.dict.DictDataService; +import com.tashow.cloud.systemapi.api.dict.dto.DictDataRespDTO; +import com.tashow.cloud.system.dal.dataobject.dict.DictDataDO; +import com.tashow.cloud.system.service.dict.DictDataService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class DictDataApiImpl implements DictDataApi { + + @Resource + private DictDataService dictDataService; + + @Override + public CommonResult validateDictDataList(String dictType, Collection values) { + dictDataService.validateDictDataList(dictType, values); + return success(true); + } + + @Override + public CommonResult getDictData(String dictType, String value) { + DictDataDO dictData = dictDataService.getDictData(dictType, value); + return success(BeanUtils.toBean(dictData, DictDataRespDTO.class)); + } + + @Override + public CommonResult parseDictData(String dictType, String label) { + DictDataDO dictData = dictDataService.parseDictData(dictType, label); + return success(BeanUtils.toBean(dictData, DictDataRespDTO.class)); + } + + @Override + public CommonResult> getDictDataList(String dictType) { + List list = dictDataService.getDictDataListByDictType(dictType); + return success(BeanUtils.toBean(list, DictDataRespDTO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/logger/LoginLogApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/logger/LoginLogApiImpl.java new file mode 100644 index 0000000..3e2cf27 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/logger/LoginLogApiImpl.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.system.api.logger; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.logger.LoginLogApi; +import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO; +import com.tashow.cloud.system.service.logger.LoginLogService; +import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO; +import com.tashow.cloud.system.service.logger.LoginLogService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class LoginLogApiImpl implements LoginLogApi { + + @Resource + private LoginLogService loginLogService; + + @Override + public CommonResult createLoginLog(LoginLogCreateReqDTO reqDTO) { + loginLogService.createLoginLog(reqDTO); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/logger/OperateLogApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/logger/OperateLogApiImpl.java new file mode 100644 index 0000000..9c877ad --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/logger/OperateLogApiImpl.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.system.api.logger; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.logger.OperateLogApi; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogRespDTO; +import com.tashow.cloud.system.dal.dataobject.logger.OperateLogDO; +import com.tashow.cloud.system.service.logger.OperateLogService; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogRespDTO; +import com.tashow.cloud.system.dal.dataobject.logger.OperateLogDO; +import com.tashow.cloud.system.service.logger.OperateLogService; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class OperateLogApiImpl implements OperateLogApi { + + @Resource + private OperateLogService operateLogService; + + @Override + public CommonResult createOperateLog(OperateLogCreateReqDTO createReqDTO) { + operateLogService.createOperateLog(createReqDTO); + return success(true); + } + + @Override + public CommonResult> getOperateLogPage(OperateLogPageReqDTO pageReqDTO) { + PageResult operateLogPage = operateLogService.getOperateLogPage(pageReqDTO); + return success(BeanUtils.toBean(operateLogPage, OperateLogRespDTO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/mail/MailSendApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/mail/MailSendApiImpl.java new file mode 100644 index 0000000..7b4aef8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/mail/MailSendApiImpl.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.api.mail; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.mail.MailSendApi; +import com.tashow.cloud.systemapi.api.mail.dto.MailSendSingleToUserReqDTO; +import com.tashow.cloud.system.service.mail.MailSendService; +import com.tashow.cloud.systemapi.api.mail.dto.MailSendSingleToUserReqDTO; +import com.tashow.cloud.system.service.mail.MailSendService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class MailSendApiImpl implements MailSendApi { + + @Resource + private MailSendService mailSendService; + + @Override + public CommonResult sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) { + return success(mailSendService.sendSingleMailToAdmin(reqDTO.getMail(), reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams())); + } + + @Override + public CommonResult sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) { + return success(mailSendService.sendSingleMailToMember(reqDTO.getMail(), reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/notify/NotifyMessageSendApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/notify/NotifyMessageSendApiImpl.java new file mode 100644 index 0000000..32b1f07 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/notify/NotifyMessageSendApiImpl.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.api.notify; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.notify.NotifyMessageSendApi; +import com.tashow.cloud.systemapi.api.notify.dto.NotifySendSingleToUserReqDTO; +import com.tashow.cloud.system.service.notify.NotifySendService; +import com.tashow.cloud.systemapi.api.notify.dto.NotifySendSingleToUserReqDTO; +import com.tashow.cloud.system.service.notify.NotifySendService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class NotifyMessageSendApiImpl implements NotifyMessageSendApi { + + @Resource + private NotifySendService notifySendService; + + @Override + public CommonResult sendSingleMessageToAdmin(NotifySendSingleToUserReqDTO reqDTO) { + return success(notifySendService.sendSingleNotifyToAdmin(reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams())); + } + + @Override + public CommonResult sendSingleMessageToMember(NotifySendSingleToUserReqDTO reqDTO) { + return success(notifySendService.sendSingleNotifyToMember(reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/oauth2/OAuth2TokenApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/oauth2/OAuth2TokenApiImpl.java new file mode 100644 index 0000000..cc95400 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/oauth2/OAuth2TokenApiImpl.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.system.api.oauth2; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.oauth2.OAuth2TokenApi; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenRespDTO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.service.oauth2.OAuth2TokenService; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenRespDTO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.service.oauth2.OAuth2TokenService; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class OAuth2TokenApiImpl implements OAuth2TokenApi { + + @Resource + private OAuth2TokenService oauth2TokenService; + + @Override + public CommonResult createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken( + reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes()); + return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class)); + } + + @Override + public CommonResult checkAccessToken(String accessToken) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(accessToken); + return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenCheckRespDTO.class)); + } + + @Override + public CommonResult removeAccessToken(String accessToken) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken); + return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class)); + } + + @Override + public CommonResult refreshAccessToken(String refreshToken, String clientId) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId); + return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/permission/PermissionApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/permission/PermissionApiImpl.java new file mode 100644 index 0000000..f3b6b05 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/permission/PermissionApiImpl.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.system.api.permission; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.permission.PermissionApi; +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; +import com.tashow.cloud.system.service.permission.PermissionService; +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; +import com.tashow.cloud.system.service.permission.PermissionService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import java.util.Collection; +import java.util.Set; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class PermissionApiImpl implements PermissionApi { + + @Resource + private PermissionService permissionService; + + @Override + public CommonResult> getUserRoleIdListByRoleIds(Collection roleIds) { + return success(permissionService.getUserRoleIdListByRoleId(roleIds)); + } + + @Override + public CommonResult hasAnyPermissions(Long userId, String... permissions) { + return success(permissionService.hasAnyPermissions(userId, permissions)); + } + + @Override + public CommonResult hasAnyRoles(Long userId, String... roles) { + return success(permissionService.hasAnyRoles(userId, roles)); + } + + @Override + public CommonResult getDeptDataPermission(Long userId) { + return success(permissionService.getDeptDataPermission(userId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/permission/RoleApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/permission/RoleApiImpl.java new file mode 100644 index 0000000..1b653a6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/permission/RoleApiImpl.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.system.api.permission; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.system.service.permission.RoleService; +import com.tashow.cloud.system.service.permission.RoleService; +import com.tashow.cloud.systemapi.api.permission.RoleApi; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import java.util.Collection; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class RoleApiImpl implements RoleApi { + + @Resource + private RoleService roleService; + + @Override + public CommonResult validRoleList(Collection ids) { + roleService.validateRoleList(ids); + return success(true); + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/sms/SmsCodeApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/sms/SmsCodeApiImpl.java new file mode 100644 index 0000000..37db282 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/sms/SmsCodeApiImpl.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.system.api.sms; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.sms.SmsCodeApi; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; +import com.tashow.cloud.system.service.sms.SmsCodeService; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; +import com.tashow.cloud.system.service.sms.SmsCodeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class SmsCodeApiImpl implements SmsCodeApi { + + @Resource + private SmsCodeService smsCodeService; + + @Override + public CommonResult sendSmsCode(SmsCodeSendReqDTO reqDTO) { + smsCodeService.sendSmsCode(reqDTO); + return success(true); + } + + @Override + public CommonResult useSmsCode(SmsCodeUseReqDTO reqDTO) { + smsCodeService.useSmsCode(reqDTO); + return success(true); + } + + @Override + public CommonResult validateSmsCode(SmsCodeValidateReqDTO reqDTO) { + smsCodeService.validateSmsCode(reqDTO); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/sms/SmsSendApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/sms/SmsSendApiImpl.java new file mode 100644 index 0000000..37c5c9e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/sms/SmsSendApiImpl.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.api.sms; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.sms.SmsSendApi; +import com.tashow.cloud.systemapi.api.sms.dto.send.SmsSendSingleToUserReqDTO; +import com.tashow.cloud.system.service.sms.SmsSendService; +import com.tashow.cloud.systemapi.api.sms.dto.send.SmsSendSingleToUserReqDTO; +import com.tashow.cloud.system.service.sms.SmsSendService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class SmsSendApiImpl implements SmsSendApi { + + @Resource + private SmsSendService smsSendService; + + @Override + public CommonResult sendSingleSmsToAdmin(SmsSendSingleToUserReqDTO reqDTO) { + return success(smsSendService.sendSingleSmsToAdmin(reqDTO.getMobile(), reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams())); + } + + @Override + public CommonResult sendSingleSmsToMember(SmsSendSingleToUserReqDTO reqDTO) { + return success(smsSendService.sendSingleSmsToMember(reqDTO.getMobile(), reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/social/SocialClientApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/social/SocialClientApiImpl.java new file mode 100644 index 0000000..ce5682c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/social/SocialClientApiImpl.java @@ -0,0 +1,103 @@ +package com.tashow.cloud.system.api.social; + +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.social.SocialClientApi; +import com.tashow.cloud.systemapi.api.social.dto.*; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.system.service.social.SocialClientService; +import com.tashow.cloud.system.service.social.SocialUserService; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.system.service.social.SocialClientService; +import com.tashow.cloud.system.service.social.SocialUserService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import java.util.List; + +import static cn.hutool.core.collection.CollUtil.findOne; +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; + +/** + * 社交应用的 API 实现类 + * + * @author 芋道源码 + */ +@RestController +@Validated +@Slf4j +public class SocialClientApiImpl implements SocialClientApi { + + @Resource + private SocialClientService socialClientService; + @Resource + private SocialUserService socialUserService; + + @Override + public CommonResult getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) { + return success(socialClientService.getAuthorizeUrl(socialType, userType, redirectUri)); + } + + @Override + public CommonResult createWxMpJsapiSignature(Integer userType, String url) { + WxJsapiSignature signature = socialClientService.createWxMpJsapiSignature(userType, url); + return success(BeanUtils.toBean(signature, SocialWxJsapiSignatureRespDTO.class)); + } + + @Override + public CommonResult getWxMaPhoneNumberInfo(Integer userType, String phoneCode) { + WxMaPhoneNumberInfo info = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode); + return success(BeanUtils.toBean(info, SocialWxPhoneNumberInfoRespDTO.class)); + } + + @Override + public CommonResult getWxaQrcode(SocialWxQrcodeReqDTO reqVO) { + return success(socialClientService.getWxaQrcode(reqVO)); + } + + @Override + public CommonResult> getWxaSubscribeTemplateList(Integer userType) { + List list = socialClientService.getSubscribeTemplateList(userType); + return success(convertList(list, item -> BeanUtils.toBean(item, SocialWxaSubscribeTemplateRespDTO.class).setId(item.getPriTmplId()))); + } + + @Override + public CommonResult sendWxaSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO) { + // 1.1 获得订阅模版列表 + List templateList = socialClientService.getSubscribeTemplateList(reqDTO.getUserType()); + if (CollUtil.isEmpty(templateList)) { + log.warn("[sendSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:没有找到订阅模板]", reqDTO); + return success(false); + } + // 1.2 获得需要使用的模版 + TemplateInfo template = findOne(templateList, item -> + ObjUtil.equal(item.getTitle(), reqDTO.getTemplateTitle())); + if (template == null) { + log.warn("[sendWxaSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:没有找到订阅模板]", reqDTO); + return success(false); + } + + // 2. 获得社交用户 + SocialUserRespDTO socialUser = socialUserService.getSocialUserByUserId(reqDTO.getUserType(), reqDTO.getUserId(), + SocialTypeEnum.WECHAT_MINI_APP.getType()); + if (StrUtil.isBlankIfStr(socialUser.getOpenid())) { + log.warn("[sendWxaSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:会员 openid 缺失]", reqDTO); + return success(false); + } + + // 3. 发送订阅消息 + socialClientService.sendSubscribeMessage(reqDTO, template.getPriTmplId(), socialUser.getOpenid()); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/social/SocialUserApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/social/SocialUserApiImpl.java new file mode 100644 index 0000000..7285724 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/social/SocialUserApiImpl.java @@ -0,0 +1,49 @@ +package com.tashow.cloud.system.api.social; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.social.SocialUserApi; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserRespDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserUnbindReqDTO; +import com.tashow.cloud.system.service.social.SocialUserService; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserRespDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserUnbindReqDTO; +import com.tashow.cloud.system.service.social.SocialUserService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class SocialUserApiImpl implements SocialUserApi { + + @Resource + private SocialUserService socialUserService; + + @Override + public CommonResult bindSocialUser(SocialUserBindReqDTO reqDTO) { + return success(socialUserService.bindSocialUser(reqDTO)); + } + + @Override + public CommonResult unbindSocialUser(SocialUserUnbindReqDTO reqDTO) { + socialUserService.unbindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(), + reqDTO.getSocialType(), reqDTO.getOpenid()); + return success(true); + } + + @Override + public CommonResult getSocialUserByUserId(Integer userType, Long userId, Integer socialType) { + return success(socialUserService.getSocialUserByUserId(userType, userId, socialType)); + } + + @Override + public CommonResult getSocialUserByCode(Integer userType, Integer socialType, String code, String state) { + return success(socialUserService.getSocialUserByCode(userType, socialType, code, state)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/tenant/TenantApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/tenant/TenantApiImpl.java new file mode 100644 index 0000000..5305a3d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/tenant/TenantApiImpl.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.system.api.tenant; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.system.service.tenant.TenantService; +import com.tashow.cloud.system.service.tenant.TenantService; +import com.tashow.cloud.systemapi.api.tenant.TenantApi; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class TenantApiImpl implements TenantApi { + + @Resource + private TenantService tenantService; + + @Override + public CommonResult> getTenantIdList() { + return success(tenantService.getTenantIdList()); + } + + @Override + public CommonResult validTenant(Long id) { + tenantService.validTenant(id); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/user/AdminUserApiImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/user/AdminUserApiImpl.java new file mode 100644 index 0000000..851a9da --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/api/user/AdminUserApiImpl.java @@ -0,0 +1,92 @@ +package com.tashow.cloud.system.api.user; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.permission.core.annotation.DataPermission; +import com.tashow.cloud.systemapi.api.user.AdminUserApi; +import com.tashow.cloud.systemapi.api.user.dto.AdminUserRespDTO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.service.dept.DeptService; +import com.tashow.cloud.system.service.user.AdminUserService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; + +import java.util.*; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class AdminUserApiImpl implements AdminUserApi { + + @Resource + private AdminUserService userService; + @Resource + private DeptService deptService; + + @Override + public CommonResult getUser(Long id) { + AdminUserDO user = userService.getUser(id); + return success(BeanUtils.toBean(user, AdminUserRespDTO.class)); + } + + @Override + public CommonResult> getUserListBySubordinate(Long id) { + // 1.1 获取用户负责的部门 + AdminUserDO user = userService.getUser(id); + if (user == null) { + return success(Collections.emptyList()); + } + ArrayList deptIds = new ArrayList<>(); + DeptDO dept = deptService.getDept(user.getDeptId()); + if (dept == null) { + return success(Collections.emptyList()); + } + if (ObjUtil.notEqual(dept.getLeaderUserId(), id)) { // 校验为负责人 + return success(Collections.emptyList()); + } + deptIds.add(dept.getId()); + // 1.2 获取所有子部门 + List childDeptList = deptService.getChildDeptList(dept.getId()); + if (CollUtil.isNotEmpty(childDeptList)) { + deptIds.addAll(convertSet(childDeptList, DeptDO::getId)); + } + + // 2. 获取部门对应的用户信息 + List users = userService.getUserListByDeptIds(deptIds); + users.removeIf(item -> ObjUtil.equal(item.getId(), id)); // 排除自己 + return success(BeanUtils.toBean(users, AdminUserRespDTO.class)); + } + + @Override + @DataPermission(enable = false) // 禁用数据权限。原因是,一般基于指定 id 的 API 查询,都是数据拼接为主 + public CommonResult> getUserList(Collection ids) { + List users = userService.getUserList(ids); + return success(BeanUtils.toBean(users, AdminUserRespDTO.class)); + } + + @Override + public CommonResult> getUserListByDeptIds(Collection deptIds) { + List users = userService.getUserListByDeptIds(deptIds); + return success(BeanUtils.toBean(users, AdminUserRespDTO.class)); + } + + @Override + public CommonResult> getUserListByPostIds(Collection postIds) { + List users = userService.getUserListByPostIds(postIds); + return success(BeanUtils.toBean(users, AdminUserRespDTO.class)); + } + + @Override + public CommonResult validateUserList(Collection ids) { + userService.validateUserList(ids); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/AuthController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/AuthController.http new file mode 100644 index 0000000..f42dfcd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/AuthController.http @@ -0,0 +1,33 @@ +### 请求 /login 接口 => 成功 +POST {{baseUrl}}/system/auth/login +Content-Type: application/json +tenant-id: {{adminTenantId}} +tag: Yunai.local + +{ + "username": "admin", + "password": "admin123", + "uuid": "3acd87a09a4f48fb9118333780e94883", + "code": "1024" +} + +### 请求 /login 接口 => 成功(无验证码) +POST {{baseUrl}}/system/auth/login +Content-Type: application/json +tenant-id: {{adminTenantId}} + +{ + "username": "admin", + "password": "admin123" +} + +### 请求 /get-permission-info 接口 => 成功 +GET {{baseUrl}}/system/auth/get-permission-info +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +### 请求 /list-menus 接口 => 成功 +GET {{baseUrl}}/system/list-menus +Authorization: Bearer {{token}} +#Authorization: Bearer a6aa7714a2e44c95aaa8a2c5adc2a67a +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/AuthController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/AuthController.java new file mode 100644 index 0000000..5965afc --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/AuthController.java @@ -0,0 +1,184 @@ +package com.tashow.cloud.system.controller.admin.auth; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.security.security.config.SecurityProperties; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthLoginReqVO; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthLoginRespVO; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthPermissionInfoRespVO; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthRegisterReqVO; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthResetPasswordReqVO; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthSmsLoginReqVO; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthSmsSendReqVO; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthSocialLoginReqVO; +import com.tashow.cloud.system.convert.auth.AuthConvert; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.systemapi.enums.logger.LoginLogTypeEnum; +import com.tashow.cloud.system.service.auth.AdminAuthService; +import com.tashow.cloud.system.service.permission.MenuService; +import com.tashow.cloud.system.service.permission.PermissionService; +import com.tashow.cloud.system.service.permission.RoleService; +import com.tashow.cloud.system.service.social.SocialClientService; +import com.tashow.cloud.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 认证") +@RestController +@RequestMapping("/system/auth") +@Validated +@Slf4j +public class AuthController { + + @Resource + private AdminAuthService authService; + @Resource + private AdminUserService userService; + @Resource + private RoleService roleService; + @Resource + private MenuService menuService; + @Resource + private PermissionService permissionService; + @Resource + private SocialClientService socialClientService; + + @Resource + private SecurityProperties securityProperties; + + @PostMapping("/login") + @PermitAll + @Operation(summary = "使用账号密码登录") + public CommonResult login(@RequestBody @Valid AuthLoginReqVO reqVO) { + return success(authService.login(reqVO)); + } + + @PostMapping("/logout") + @PermitAll + @Operation(summary = "登出系统") + public CommonResult logout(HttpServletRequest request) { + String token = SecurityFrameworkUtils.obtainAuthorization(request, + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); + if (StrUtil.isNotBlank(token)) { + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); + } + return success(true); + } + + @PostMapping("/refresh-token") + @PermitAll + @Operation(summary = "刷新令牌") + @Parameter(name = "refreshToken", description = "刷新令牌", required = true) + public CommonResult refreshToken(@RequestParam("refreshToken") String refreshToken) { + return success(authService.refreshToken(refreshToken)); + } + + @GetMapping("/get-permission-info") + @Operation(summary = "获取登录用户的权限信息") + public CommonResult getPermissionInfo() { + // 1.1 获得用户信息 + AdminUserDO user = userService.getUser(getLoginUserId()); + if (user == null) { + return success(null); + } + + // 1.2 获得角色列表 + Set roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); + if (CollUtil.isEmpty(roleIds)) { + return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList())); + } + List roles = roleService.getRoleList(roleIds); + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 + + // 1.3 获得菜单列表 + Set menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId)); + List menuList = menuService.getMenuList(menuIds); + menuList = menuService.filterDisableMenus(menuList); + + // 2. 拼接结果返回 + return success(AuthConvert.INSTANCE.convert(user, roles, menuList)); + } + + @PostMapping("/register") + @PermitAll + @Operation(summary = "注册用户") + public CommonResult register(@RequestBody @Valid AuthRegisterReqVO registerReqVO) { + return success(authService.register(registerReqVO)); + } + + // ========== 短信登录相关 ========== + + @PostMapping("/sms-login") + @PermitAll + @Operation(summary = "使用短信验证码登录") + public CommonResult smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) { + return success(authService.smsLogin(reqVO)); + } + + @PostMapping("/send-sms-code") + @PermitAll + @Operation(summary = "发送手机验证码") + public CommonResult sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) { + authService.sendSmsCode(reqVO); + return success(true); + } + + @PostMapping("/reset-password") + @PermitAll + @Operation(summary = "重置密码") + public CommonResult resetPassword(@RequestBody @Valid AuthResetPasswordReqVO reqVO) { + authService.resetPassword(reqVO); + return success(true); + } + + // ========== 社交登录相关 ========== + + @GetMapping("/social-auth-redirect") + @PermitAll + @Operation(summary = "社交授权的跳转") + @Parameters({ + @Parameter(name = "type", description = "社交类型", required = true), + @Parameter(name = "redirectUri", description = "回调路径") + }) + public CommonResult socialLogin(@RequestParam("type") Integer type, + @RequestParam("redirectUri") String redirectUri) { + return success(socialClientService.getAuthorizeUrl( + type, UserTypeEnum.ADMIN.getValue(), redirectUri)); + } + + @PostMapping("/social-login") + @PermitAll + @Operation(summary = "社交快捷登录,使用 code 授权码", description = "适合未登录的用户,但是社交账号已绑定用户") + public CommonResult socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) { + return success(authService.socialLogin(reqVO)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthLoginReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthLoginReqVO.java new file mode 100644 index 0000000..15d0277 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthLoginReqVO.java @@ -0,0 +1,57 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Schema(description = "管理后台 - 账号密码登录 Request VO,如果登录并绑定社交用户,需要传递 social 开头的参数") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthLoginReqVO extends CaptchaVerificationReqVO { + + @Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma") + @NotEmpty(message = "登录账号不能为空") + @Length(min = 4, max = 16, message = "账号长度为 4-16 位") + @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + // ========== 绑定社交登录时,需要传递如下参数 ========== + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + private Integer socialType; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String socialCode; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + private String socialState; + + @AssertTrue(message = "授权码不能为空") + public boolean isSocialCodeValid() { + return socialType == null || StrUtil.isNotEmpty(socialCode); + } + + @AssertTrue(message = "授权 state 不能为空") + public boolean isSocialState() { + return socialType == null || StrUtil.isNotEmpty(socialState); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthLoginRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthLoginRespVO.java new file mode 100644 index 0000000..3fd9447 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthLoginRespVO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 登录 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthLoginRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "happy") + private String accessToken; + + @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") + private String refreshToken; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expiresTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthMenuRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthMenuRespVO.java new file mode 100644 index 0000000..24eb692 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthMenuRespVO.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthMenuRespVO { + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private Long id; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + private String path; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + + /** + * 子路由 + */ + private List children; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java new file mode 100644 index 0000000..7d12a72 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java @@ -0,0 +1,96 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Set; + +@Schema(description = "管理后台 - 登录用户的权限信息 Response VO,额外包括用户信息和角色列表") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthPermissionInfoRespVO { + + @Schema(description = "用户信息", requiredMode = Schema.RequiredMode.REQUIRED) + private UserVO user; + + @Schema(description = "角色标识数组", requiredMode = Schema.RequiredMode.REQUIRED) + private Set roles; + + @Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED) + private Set permissions; + + @Schema(description = "菜单树", requiredMode = Schema.RequiredMode.REQUIRED) + private List menus; + + @Schema(description = "用户信息 VO") + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class UserVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg") + private String avatar; + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long deptId; + + } + + @Schema(description = "管理后台 - 登录用户的菜单信息 Response VO") + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class MenuVO { + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private Long id; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + private String path; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + + /** + * 子路由 + */ + private List children; + + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthRegisterReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthRegisterReqVO.java new file mode 100644 index 0000000..7dd48b3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthRegisterReqVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +@Schema(description = "管理后台 - Register Request VO") +@Data +public class AuthRegisterReqVO extends CaptchaVerificationReqVO { + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotBlank(message = "用户账号不能为空") + @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成") + @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotBlank(message = "用户昵称不能为空") + @Size(max = 30, message = "用户昵称长度不能超过 30 个字符") + private String nickname; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthResetPasswordReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthResetPasswordReqVO.java new file mode 100644 index 0000000..731c10f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthResetPasswordReqVO.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import com.tashow.cloud.common.validation.Mobile; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Schema(description = "管理后台 - 短信重置账号密码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthResetPasswordReqVO { + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1234") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13312341234") + @NotEmpty(message = "手机号不能为空") + @Mobile + private String mobile; + + @Schema(description = "手机短信验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotEmpty(message = "手机手机短信验证码不能为空") + private String code; +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java new file mode 100644 index 0000000..d5eadcf --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import com.tashow.cloud.common.validation.Mobile; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 短信验证码的登录 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSmsLoginReqVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma") + @NotEmpty(message = "手机号不能为空") + @Mobile + private String mobile; + + @Schema(description = "短信验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "验证码不能为空") + private String code; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSmsSendReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSmsSendReqVO.java new file mode 100644 index 0000000..f9060d1 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSmsSendReqVO.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.common.validation.Mobile; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 发送手机验证码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSmsSendReqVO extends CaptchaVerificationReqVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma") + @NotEmpty(message = "手机号不能为空") + @Mobile + private String mobile; + + @Schema(description = "短信场景", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java new file mode 100644 index 0000000..4e48ccc --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java @@ -0,0 +1,34 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 社交绑定登录 Request VO,使用 code 授权码 + 账号密码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSocialLoginReqVO { + + @Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/CaptchaVerificationReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/CaptchaVerificationReqVO.java new file mode 100644 index 0000000..a982c16 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/auth/vo/CaptchaVerificationReqVO.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +@Schema(description = "管理后台 - 验证码 Request VO") +@Data +public class CaptchaVerificationReqVO { + + // ========== 图片验证码相关 ========== + @Schema(description = "验证码,验证码开启时,需要传递", requiredMode = Schema.RequiredMode.REQUIRED, + example = "PfcH6mgr8tpXuMWFjvW6YVaqrswIuwmWI5dsVZSg7sGpWtDCUbHuDEXl3cFB1+VvCC/rAkSwK8Fad52FSuncVg==") + @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) + private String captchaVerification; + + /** + * 开启验证码的 Group + */ + public interface CodeEnableGroup { + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/captcha/CaptchaController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/captcha/CaptchaController.java new file mode 100644 index 0000000..ce63c69 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/captcha/CaptchaController.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.system.controller.admin.captcha; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.xingyuv.captcha.model.common.ResponseModel; +import com.xingyuv.captcha.model.vo.CaptchaVO; +import com.xingyuv.captcha.service.CaptchaService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import jakarta.servlet.http.HttpServletRequest; + +@Tag(name = "管理后台 - 验证码") +@RestController("adminCaptchaController") +@RequestMapping("/system/captcha") +public class CaptchaController { + + @Resource + private CaptchaService captchaService; + + @PostMapping({"/get"}) + @Operation(summary = "获得验证码") + @PermitAll + public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) { + assert request.getRemoteHost() != null; + data.setBrowserInfo(getRemoteId(request)); + return captchaService.get(data); + } + + @PostMapping("/check") + @Operation(summary = "校验验证码") + @PermitAll + public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) { + data.setBrowserInfo(getRemoteId(request)); + return captchaService.check(data); + } + + public static String getRemoteId(HttpServletRequest request) { + String ip = ServletUtils.getClientIP(request); + String ua = request.getHeader("user-agent"); + if (StrUtil.isNotBlank(ip)) { + return ip + ua; + } + return request.getRemoteAddr() + ua; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/DeptController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/DeptController.java new file mode 100644 index 0000000..df8e90e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/DeptController.java @@ -0,0 +1,84 @@ +package com.tashow.cloud.system.controller.admin.dept; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptListReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptRespVO; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.service.dept.DeptService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 部门") +@RestController +@RequestMapping("/system/dept") +@Validated +public class DeptController { + + @Resource + private DeptService deptService; + + @PostMapping("create") + @Operation(summary = "创建部门") + @PreAuthorize("@ss.hasPermission('system:dept:create')") + public CommonResult createDept(@Valid @RequestBody DeptSaveReqVO createReqVO) { + Long deptId = deptService.createDept(createReqVO); + return success(deptId); + } + + @PutMapping("update") + @Operation(summary = "更新部门") + @PreAuthorize("@ss.hasPermission('system:dept:update')") + public CommonResult updateDept(@Valid @RequestBody DeptSaveReqVO updateReqVO) { + deptService.updateDept(updateReqVO); + return success(true); + } + + @DeleteMapping("delete") + @Operation(summary = "删除部门") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dept:delete')") + public CommonResult deleteDept(@RequestParam("id") Long id) { + deptService.deleteDept(id); + return success(true); + } + + @GetMapping("/list") + @Operation(summary = "获取部门列表") + @PreAuthorize("@ss.hasPermission('system:dept:query')") + public CommonResult> getDeptList(DeptListReqVO reqVO) { + List list = deptService.getDeptList(reqVO); + return success(BeanUtils.toBean(list, DeptRespVO.class)); + } + + @GetMapping(value = {"/list-all-simple", "/simple-list"}) + @Operation(summary = "获取部门精简信息列表", description = "只包含被开启的部门,主要用于前端的下拉选项") + public CommonResult> getSimpleDeptList() { + List list = deptService.getDeptList( + new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); + return success(BeanUtils.toBean(list, DeptSimpleRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得部门信息") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dept:query')") + public CommonResult getDept(@RequestParam("id") Long id) { + DeptDO dept = deptService.getDept(id); + return success(BeanUtils.toBean(dept, DeptRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/PostController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/PostController.java new file mode 100644 index 0000000..32fde2f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/PostController.java @@ -0,0 +1,109 @@ +package com.tashow.cloud.system.controller.admin.dept; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostPageReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostRespVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSaveReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.service.dept.PostService; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostPageReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSaveReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSimpleRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 岗位") +@RestController +@RequestMapping("/system/post") +@Validated +public class PostController { + + @Resource + private PostService postService; + + @PostMapping("/create") + @Operation(summary = "创建岗位") + @PreAuthorize("@ss.hasPermission('system:post:create')") + public CommonResult createPost(@Valid @RequestBody PostSaveReqVO createReqVO) { + Long postId = postService.createPost(createReqVO); + return success(postId); + } + + @PutMapping("/update") + @Operation(summary = "修改岗位") + @PreAuthorize("@ss.hasPermission('system:post:update')") + public CommonResult updatePost(@Valid @RequestBody PostSaveReqVO updateReqVO) { + postService.updatePost(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除岗位") + @PreAuthorize("@ss.hasPermission('system:post:delete')") + public CommonResult deletePost(@RequestParam("id") Long id) { + postService.deletePost(id); + return success(true); + } + + @GetMapping(value = "/get") + @Operation(summary = "获得岗位信息") + @Parameter(name = "id", description = "岗位编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:post:query')") + public CommonResult getPost(@RequestParam("id") Long id) { + PostDO post = postService.getPost(id); + return success(BeanUtils.toBean(post, PostRespVO.class)); + } + + @GetMapping(value = {"/list-all-simple", "simple-list"}) + @Operation(summary = "获取岗位全列表", description = "只包含被开启的岗位,主要用于前端的下拉选项") + public CommonResult> getSimplePostList() { + // 获得岗位列表,只要开启状态的 + List list = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus())); + // 排序后,返回给前端 + list.sort(Comparator.comparing(PostDO::getSort)); + return success(BeanUtils.toBean(list, PostSimpleRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得岗位分页列表") + @PreAuthorize("@ss.hasPermission('system:post:query')") + public CommonResult> getPostPage(@Validated PostPageReqVO pageReqVO) { + PageResult pageResult = postService.getPostPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, PostRespVO.class)); + } + + @GetMapping("/export") + @Operation(summary = "岗位管理") + @PreAuthorize("@ss.hasPermission('system:post:export')") + @ApiAccessLog(operateType = EXPORT) + public void export(HttpServletResponse response, @Validated PostPageReqVO reqVO) throws IOException { + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = postService.getPostPage(reqVO).getList(); + // 输出 + ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostRespVO.class, + BeanUtils.toBean(list, PostRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptListReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptListReqVO.java new file mode 100644 index 0000000..8143bf2 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptListReqVO.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.system.controller.admin.dept.vo.dept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 部门列表 Request VO") +@Data +public class DeptListReqVO { + + @Schema(description = "部门名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptRespVO.java new file mode 100644 index 0000000..d89898b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptRespVO.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.system.controller.admin.dept.vo.dept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 部门信息 Response VO") +@Data +public class DeptRespVO { + + @Schema(description = "部门编号", example = "1024") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "父部门 ID", example = "1024") + private Long parentId; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer sort; + + @Schema(description = "负责人的用户编号", example = "2048") + private Long leaderUserId; + + @Schema(description = "联系电话", example = "15601691000") + private String phone; + + @Schema(description = "邮箱", example = "yudao@iocoder.cn") + private String email; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java new file mode 100644 index 0000000..0f4255a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.system.controller.admin.dept.vo.dept; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Schema(description = "管理后台 - 部门创建/修改 Request VO") +@Data +public class DeptSaveReqVO { + + @Schema(description = "部门编号", example = "1024") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "部门名称不能为空") + @Size(max = 30, message = "部门名称长度不能超过 30 个字符") + private String name; + + @Schema(description = "父部门 ID", example = "1024") + private Long parentId; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "负责人的用户编号", example = "2048") + private Long leaderUserId; + + @Schema(description = "联系电话", example = "15601691000") + @Size(max = 11, message = "联系电话长度不能超过11个字符") + private String phone; + + @Schema(description = "邮箱", example = "yudao@iocoder.cn") + @Email(message = "邮箱格式不正确") + @Size(max = 50, message = "邮箱长度不能超过 50 个字符") + private String email; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java new file mode 100644 index 0000000..0574135 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.system.controller.admin.dept.vo.dept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 部门精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeptSimpleRespVO { + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "父部门 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostPageReqVO.java new file mode 100644 index 0000000..adf74be --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostPageReqVO.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.system.controller.admin.dept.vo.post; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 岗位分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class PostPageReqVO extends PageParam { + + @Schema(description = "岗位编码,模糊匹配", example = "yudao") + private String code; + + @Schema(description = "岗位名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostRespVO.java new file mode 100644 index 0000000..cffda00 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostRespVO.java @@ -0,0 +1,46 @@ +package com.tashow.cloud.system.controller.admin.dept.vo.post; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 岗位信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class PostRespVO { + + @Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("岗位序号") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆") + @ExcelProperty("岗位名称") + private String name; + + @Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @ExcelProperty("岗位编码") + private String code; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("岗位排序") + private Integer sort; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "备注", example = "快乐的备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostSaveReqVO.java new file mode 100644 index 0000000..61be36d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostSaveReqVO.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.system.controller.admin.dept.vo.post; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Schema(description = "管理后台 - 岗位创建/修改 Request VO") +@Data +public class PostSaveReqVO { + + @Schema(description = "岗位编号", example = "1024") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆") + @NotBlank(message = "岗位名称不能为空") + @Size(max = 50, message = "岗位名称长度不能超过 50 个字符") + private String name; + + @Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotBlank(message = "岗位编码不能为空") + @Size(max = 64, message = "岗位编码长度不能超过64个字符") + private String code; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "备注", example = "快乐的备注") + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostSimpleRespVO.java new file mode 100644 index 0000000..544ed1d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dept/vo/post/PostSimpleRespVO.java @@ -0,0 +1,19 @@ +package com.tashow.cloud.system.controller.admin.dept.vo.post; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 岗位信息的精简 Response VO") +@Data +public class PostSimpleRespVO { + + @Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("岗位序号") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆") + @ExcelProperty("岗位名称") + private String name; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictDataController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictDataController.http new file mode 100644 index 0000000..5a7ce8e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictDataController.http @@ -0,0 +1,4 @@ +### 请求 /menu/list 接口 => 成功 +GET {{baseUrl}}/system/dict-data/list-all-simple +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictDataController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictDataController.java new file mode 100644 index 0000000..15caee6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictDataController.java @@ -0,0 +1,108 @@ +package com.tashow.cloud.system.controller.admin.dict; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataRespVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictDataDO; +import com.tashow.cloud.system.service.dict.DictDataService; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataRespVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataSimpleRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 字典数据") +@RestController +@RequestMapping("/system/dict-data") +@Validated +public class DictDataController { + + @Resource + private DictDataService dictDataService; + + @PostMapping("/create") + @Operation(summary = "新增字典数据") + @PreAuthorize("@ss.hasPermission('system:dict:create')") + public CommonResult createDictData(@Valid @RequestBody DictDataSaveReqVO createReqVO) { + Long dictDataId = dictDataService.createDictData(createReqVO); + return success(dictDataId); + } + + @PutMapping("/update") + @Operation(summary = "修改字典数据") + @PreAuthorize("@ss.hasPermission('system:dict:update')") + public CommonResult updateDictData(@Valid @RequestBody DictDataSaveReqVO updateReqVO) { + dictDataService.updateDictData(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除字典数据") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dict:delete')") + public CommonResult deleteDictData(Long id) { + dictDataService.deleteDictData(id); + return success(true); + } + + @GetMapping(value = {"/list-all-simple", "simple-list"}) + @Operation(summary = "获得全部字典数据列表", description = "一般用于管理后台缓存字典数据在本地") + // 无需添加权限认证,因为前端全局都需要 + public CommonResult> getSimpleDictDataList() { + List list = dictDataService.getDictDataList( + CommonStatusEnum.ENABLE.getStatus(), null); + return success(BeanUtils.toBean(list, DictDataSimpleRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "/获得字典类型的分页列表") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + public CommonResult> getDictTypePage(@Valid DictDataPageReqVO pageReqVO) { + PageResult pageResult = dictDataService.getDictDataPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, DictDataRespVO.class)); + } + + @GetMapping(value = "/get") + @Operation(summary = "/查询字典数据详细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + public CommonResult getDictData(@RequestParam("id") Long id) { + DictDataDO dictData = dictDataService.getDictData(id); + return success(BeanUtils.toBean(dictData, DictDataRespVO.class)); + } + + @GetMapping("/export") + @Operation(summary = "导出字典数据") + @PreAuthorize("@ss.hasPermission('system:dict:export')") + @ApiAccessLog(operateType = EXPORT) + public void export(HttpServletResponse response, @Valid DictDataPageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = dictDataService.getDictDataPage(exportReqVO).getList(); + // 输出 + ExcelUtils.write(response, "字典数据.xls", "数据", DictDataRespVO.class, + BeanUtils.toBean(list, DictDataRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictTypeController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictTypeController.java new file mode 100644 index 0000000..8b4cea5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/DictTypeController.java @@ -0,0 +1,106 @@ +package com.tashow.cloud.system.controller.admin.dict; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeRespVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictTypeDO; +import com.tashow.cloud.system.service.dict.DictTypeService; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeRespVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeSimpleRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 字典类型") +@RestController +@RequestMapping("/system/dict-type") +@Validated +public class DictTypeController { + + @Resource + private DictTypeService dictTypeService; + + @PostMapping("/create") + @Operation(summary = "创建字典类型") + @PreAuthorize("@ss.hasPermission('system:dict:create')") + public CommonResult createDictType(@Valid @RequestBody DictTypeSaveReqVO createReqVO) { + Long dictTypeId = dictTypeService.createDictType(createReqVO); + return success(dictTypeId); + } + + @PutMapping("/update") + @Operation(summary = "修改字典类型") + @PreAuthorize("@ss.hasPermission('system:dict:update')") + public CommonResult updateDictType(@Valid @RequestBody DictTypeSaveReqVO updateReqVO) { + dictTypeService.updateDictType(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除字典类型") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dict:delete')") + public CommonResult deleteDictType(Long id) { + dictTypeService.deleteDictType(id); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得字典类型的分页列表") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + public CommonResult> pageDictTypes(@Valid DictTypePageReqVO pageReqVO) { + PageResult pageResult = dictTypeService.getDictTypePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, DictTypeRespVO.class)); + } + + @Operation(summary = "/查询字典类型详细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @GetMapping(value = "/get") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + public CommonResult getDictType(@RequestParam("id") Long id) { + DictTypeDO dictType = dictTypeService.getDictType(id); + return success(BeanUtils.toBean(dictType, DictTypeRespVO.class)); + } + + @GetMapping(value = {"/list-all-simple", "simple-list"}) + @Operation(summary = "获得全部字典类型列表", description = "包括开启 + 禁用的字典类型,主要用于前端的下拉选项") + // 无需添加权限认证,因为前端全局都需要 + public CommonResult> getSimpleDictTypeList() { + List list = dictTypeService.getDictTypeList(); + return success(BeanUtils.toBean(list, DictTypeSimpleRespVO.class)); + } + + @Operation(summary = "导出数据类型") + @GetMapping("/export") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + @ApiAccessLog(operateType = EXPORT) + public void export(HttpServletResponse response, @Valid DictTypePageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = dictTypeService.getDictTypePage(exportReqVO).getList(); + // 导出 + ExcelUtils.write(response, "字典类型.xls", "数据", DictTypeRespVO.class, + BeanUtils.toBean(list, DictTypeRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataPageReqVO.java new file mode 100644 index 0000000..a5567d2 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataPageReqVO.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.system.controller.admin.dict.vo.data; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 字典类型分页列表 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class DictDataPageReqVO extends PageParam { + + @Schema(description = "字典标签", example = "芋道") + @Size(max = 100, message = "字典标签长度不能超过100个字符") + private String label; + + @Schema(description = "字典类型,模糊匹配", example = "sys_common_sex") + @Size(max = 100, message = "字典类型类型长度不能超过100个字符") + private String dictType; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataRespVO.java new file mode 100644 index 0000000..c0eeb9f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataRespVO.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.system.controller.admin.dict.vo.data; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 字典数据信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class DictDataRespVO { + + @Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("字典编码") + private Long id; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("字典排序") + private Integer sort; + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @ExcelProperty("字典标签") + private String label; + + @Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder") + @ExcelProperty("字典键值") + private String value; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + @ExcelProperty("字典类型") + private String dictType; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default") + private String colorType; + + @Schema(description = "css 样式", example = "btn-visible") + private String cssClass; + + @Schema(description = "备注", example = "我是一个角色") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataSaveReqVO.java new file mode 100644 index 0000000..53e4c03 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataSaveReqVO.java @@ -0,0 +1,51 @@ +package com.tashow.cloud.system.controller.admin.dict.vo.data; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Schema(description = "管理后台 - 字典数据创建/修改 Request VO") +@Data +public class DictDataSaveReqVO { + + @Schema(description = "字典数据编号", example = "1024") + private Long id; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "字典标签不能为空") + @Size(max = 100, message = "字典标签长度不能超过100个字符") + private String label; + + @Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder") + @NotBlank(message = "字典键值不能为空") + @Size(max = 100, message = "字典键值长度不能超过100个字符") + private String value; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + @NotBlank(message = "字典类型不能为空") + @Size(max = 100, message = "字典类型长度不能超过100个字符") + private String dictType; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + + @Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default") + private String colorType; + + @Schema(description = "css 样式", example = "btn-visible") + private String cssClass; + + @Schema(description = "备注", example = "我是一个角色") + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataSimpleRespVO.java new file mode 100644 index 0000000..8b7d6e1 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/data/DictDataSimpleRespVO.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.system.controller.admin.dict.vo.data; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 数据字典精简 Response VO") +@Data +public class DictDataSimpleRespVO { + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "gender") + private String dictType; + + @Schema(description = "字典键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String value; + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "男") + private String label; + + @Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default") + private String colorType; + + @Schema(description = "css 样式", example = "btn-visible") + private String cssClass; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypePageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypePageReqVO.java new file mode 100644 index 0000000..c0620e6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypePageReqVO.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.system.controller.admin.dict.vo.type; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import jakarta.validation.constraints.Size; +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 字典类型分页列表 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class DictTypePageReqVO extends PageParam { + + @Schema(description = "字典类型名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "字典类型,模糊匹配", example = "sys_common_sex") + @Size(max = 100, message = "字典类型类型长度不能超过100个字符") + private String type; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeRespVO.java new file mode 100644 index 0000000..12966f8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeRespVO.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.system.controller.admin.dict.vo.type; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 字典类型信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class DictTypeRespVO { + + @Schema(description = "字典类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("字典主键") + private Long id; + + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "性别") + @ExcelProperty("字典名称") + private String name; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + @ExcelProperty("字典类型") + private String type; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "备注", example = "快乐的备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeSaveReqVO.java new file mode 100644 index 0000000..ade8194 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeSaveReqVO.java @@ -0,0 +1,34 @@ +package com.tashow.cloud.system.controller.admin.dict.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +@Schema(description = "管理后台 - 字典类型创建/修改 Request VO") +@Data +public class DictTypeSaveReqVO { + + @Schema(description = "字典类型编号", example = "1024") + private Long id; + + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "性别") + @NotBlank(message = "字典名称不能为空") + @Size(max = 100, message = "字典类型名称长度不能超过100个字符") + private String name; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + @NotNull(message = "字典类型不能为空") + @Size(max = 100, message = "字典类型类型长度不能超过 100 个字符") + private String type; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "快乐的备注") + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeSimpleRespVO.java new file mode 100644 index 0000000..66b0b61 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/dict/vo/type/DictTypeSimpleRespVO.java @@ -0,0 +1,19 @@ +package com.tashow.cloud.system.controller.admin.dict.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 字典类型精简信息 Response VO") +@Data +public class DictTypeSimpleRespVO { + + @Schema(description = "字典类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "字典类型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + private String type; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/AreaController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/AreaController.http new file mode 100644 index 0000000..1416561 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/AreaController.http @@ -0,0 +1,5 @@ +### 获得地区树 +GET {{baseUrl}}/system/area/tree +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/AreaController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/AreaController.java new file mode 100644 index 0000000..37f02e9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/AreaController.java @@ -0,0 +1,50 @@ +package com.tashow.cloud.system.controller.admin.ip; + +import cn.hutool.core.lang.Assert; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.ip.core.Area; +import com.tashow.cloud.ip.core.utils.AreaUtils; +import com.tashow.cloud.ip.core.utils.IPUtils; +import com.tashow.cloud.system.controller.admin.ip.vo.AreaNodeRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 地区") +@RestController +@RequestMapping("/system/area") +@Validated +public class AreaController { + + @GetMapping("/tree") + @Operation(summary = "获得地区树") + public CommonResult> getAreaTree() { + Area area = AreaUtils.getArea(Area.ID_CHINA); + Assert.notNull(area, "获取不到中国"); + return success(BeanUtils.toBean(area.getChildren(), AreaNodeRespVO.class)); + } + + @GetMapping("/get-by-ip") + @Operation(summary = "获得 IP 对应的地区名") + @Parameter(name = "ip", description = "IP", required = true) + public CommonResult getAreaByIp(@RequestParam("ip") String ip) { + // 获得城市 + Area area = IPUtils.getArea(ip); + if (area == null) { + return success("未知"); + } + // 格式化返回 + return success(AreaUtils.format(area.getId())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/vo/AreaNodeRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/vo/AreaNodeRespVO.java new file mode 100644 index 0000000..972c74d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/ip/vo/AreaNodeRespVO.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.system.controller.admin.ip.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 地区节点 Response VO") +@Data +public class AreaNodeRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000") + private Integer id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "北京") + private String name; + + /** + * 子节点 + */ + private List children; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/LoginLogController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/LoginLogController.java new file mode 100644 index 0000000..283e3bd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/LoginLogController.java @@ -0,0 +1,59 @@ +package com.tashow.cloud.system.controller.admin.logger; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import com.tashow.cloud.system.controller.admin.logger.vo.loginlog.LoginLogRespVO; +import com.tashow.cloud.system.dal.dataobject.logger.LoginLogDO; +import com.tashow.cloud.system.service.logger.LoginLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 登录日志") +@RestController +@RequestMapping("/system/login-log") +@Validated +public class LoginLogController { + + @Resource + private LoginLogService loginLogService; + + @GetMapping("/page") + @Operation(summary = "获得登录日志分页列表") + @PreAuthorize("@ss.hasPermission('system:login-log:query')") + public CommonResult> getLoginLogPage(@Valid LoginLogPageReqVO pageReqVO) { + PageResult pageResult = loginLogService.getLoginLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, LoginLogRespVO.class)); + } + + @GetMapping("/export") + @Operation(summary = "导出登录日志 Excel") + @PreAuthorize("@ss.hasPermission('system:login-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportLoginLog(HttpServletResponse response, @Valid LoginLogPageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = loginLogService.getLoginLogPage(exportReqVO).getList(); + // 输出 + ExcelUtils.write(response, "登录日志.xls", "数据列表", LoginLogRespVO.class, + BeanUtils.toBean(list, LoginLogRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/OperateLogController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/OperateLogController.http new file mode 100644 index 0000000..be3102e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/OperateLogController.http @@ -0,0 +1,4 @@ +### 请求 /system/operate-log/page 接口 => 成功 +GET {{baseUrl}}/system/operate-log/page +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/OperateLogController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/OperateLogController.java new file mode 100644 index 0000000..fd011c7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/OperateLogController.java @@ -0,0 +1,59 @@ +package com.tashow.cloud.system.controller.admin.logger; + +import com.tashow.cloud.mybatis.translate.core.TranslateUtils; +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import com.tashow.cloud.system.controller.admin.logger.vo.operatelog.OperateLogRespVO; +import com.tashow.cloud.system.dal.dataobject.logger.OperateLogDO; +import com.tashow.cloud.system.service.logger.OperateLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 操作日志") +@RestController +@RequestMapping("/system/operate-log") +@Validated +public class OperateLogController { + + @Resource + private OperateLogService operateLogService; + + @GetMapping("/page") + @Operation(summary = "查看操作日志分页列表") + @PreAuthorize("@ss.hasPermission('system:operate-log:query')") + public CommonResult> pageOperateLog(@Valid OperateLogPageReqVO pageReqVO) { + PageResult pageResult = operateLogService.getOperateLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, OperateLogRespVO.class)); + } + + @Operation(summary = "导出操作日志") + @GetMapping("/export") + @PreAuthorize("@ss.hasPermission('system:operate-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportOperateLog(HttpServletResponse response, @Valid OperateLogPageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = operateLogService.getOperateLogPage(exportReqVO).getList(); + ExcelUtils.write(response, "操作日志.xls", "数据列表", OperateLogRespVO.class, + TranslateUtils.translate(BeanUtils.toBean(list, OperateLogRespVO.class))); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java new file mode 100644 index 0000000..a505da0 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.system.controller.admin.logger.vo.loginlog; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 登录日志分页列表 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class LoginLogPageReqVO extends PageParam { + + @Schema(description = "用户 IP,模拟匹配", example = "127.0.0.1") + private String userIp; + + @Schema(description = "用户账号,模拟匹配", example = "芋道") + private String username; + + @Schema(description = "操作状态", example = "true") + private Boolean status; + + @Schema(description = "登录时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/loginlog/LoginLogRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/loginlog/LoginLogRespVO.java new file mode 100644 index 0000000..06135e0 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/loginlog/LoginLogRespVO.java @@ -0,0 +1,58 @@ +package com.tashow.cloud.system.controller.admin.logger.vo.loginlog; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 登录日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class LoginLogRespVO { + + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("日志主键") + private Long id; + + @Schema(description = "日志类型,参见 LoginLogTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "日志类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.LOGIN_TYPE) + private Integer logType; + + @Schema(description = "用户编号", example = "666") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @ExcelProperty("用户账号") + private String username; + + @Schema(description = "登录结果,参见 LoginResultEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "登录结果", converter = DictConvert.class) + @DictFormat(DictTypeConstants.LOGIN_RESULT) + private Integer result; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @ExcelProperty("登录 IP") + private String userIp; + + @Schema(description = "浏览器 UserAgent", example = "Mozilla/5.0") + @ExcelProperty("浏览器 UA") + private String userAgent; + + @Schema(description = "登录时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("登录时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java new file mode 100644 index 0000000..5700e66 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.controller.admin.logger.vo.operatelog; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 操作日志分页列表 Request VO") +@Data +public class OperateLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "芋道") + private Long userId; + + @Schema(description = "操作模块业务编号", example = "1") + private Long bizId; + + @Schema(description = "操作模块,模拟匹配", example = "订单") + private String type; + + @Schema(description = "操作名,模拟匹配", example = "创建订单") + private String subType; + + @Schema(description = "操作明细,模拟匹配", example = "修改编号为 1 的用户信息") + private String action; + + @Schema(description = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/operatelog/OperateLogRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/operatelog/OperateLogRespVO.java new file mode 100644 index 0000000..67b8703 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/logger/vo/operatelog/OperateLogRespVO.java @@ -0,0 +1,68 @@ +package com.tashow.cloud.system.controller.admin.logger.vo.operatelog; + +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.VO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 操作日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class OperateLogRespVO implements VO { + + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("日志编号") + private Long id; + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @Trans(type = TransType.SIMPLE, target = AdminUserDO.class, fields = "nickname", ref = "userName") + private Long userId; + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("操作人") + private String userName; + + @Schema(description = "操作模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单") + @ExcelProperty("操作模块类型") + private String type; + + @Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建订单") + @ExcelProperty("操作名") + private String subType; + + @Schema(description = "操作模块业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("操作模块业务编号") + private Long bizId; + + @Schema(description = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。") + private String action; + + @Schema(description = "拓展字段", example = "{'orderId': 1}") + private String extra; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @NotEmpty(message = "请求方法名不能为空") + private String requestMethod; + + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy") + private String requestUrl; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + private String userIp; + + @Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + private String userAgent; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailAccountController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailAccountController.java new file mode 100644 index 0000000..68d5462 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailAccountController.java @@ -0,0 +1,81 @@ +package com.tashow.cloud.system.controller.admin.mail; + + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountRespVO; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailAccountDO; +import com.tashow.cloud.system.service.mail.MailAccountService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 邮箱账号") +@RestController +@RequestMapping("/system/mail-account") +public class MailAccountController { + + @Resource + private MailAccountService mailAccountService; + + @PostMapping("/create") + @Operation(summary = "创建邮箱账号") + @PreAuthorize("@ss.hasPermission('system:mail-account:create')") + public CommonResult createMailAccount(@Valid @RequestBody MailAccountSaveReqVO createReqVO) { + return success(mailAccountService.createMailAccount(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改邮箱账号") + @PreAuthorize("@ss.hasPermission('system:mail-account:update')") + public CommonResult updateMailAccount(@Valid @RequestBody MailAccountSaveReqVO updateReqVO) { + mailAccountService.updateMailAccount(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除邮箱账号") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:mail-account:delete')") + public CommonResult deleteMailAccount(@RequestParam Long id) { + mailAccountService.deleteMailAccount(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得邮箱账号") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:mail-account:query')") + public CommonResult getMailAccount(@RequestParam("id") Long id) { + MailAccountDO account = mailAccountService.getMailAccount(id); + return success(BeanUtils.toBean(account, MailAccountRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得邮箱账号分页") + @PreAuthorize("@ss.hasPermission('system:mail-account:query')") + public CommonResult> getMailAccountPage(@Valid MailAccountPageReqVO pageReqVO) { + PageResult pageResult = mailAccountService.getMailAccountPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, MailAccountRespVO.class)); + } + + @GetMapping({"/list-all-simple", "simple-list"}) + @Operation(summary = "获得邮箱账号精简列表") + public CommonResult> getSimpleMailAccountList() { + List list = mailAccountService.getMailAccountList(); + return success(BeanUtils.toBean(list, MailAccountSimpleRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailLogController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailLogController.java new file mode 100644 index 0000000..e0b0acb --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailLogController.java @@ -0,0 +1,49 @@ +package com.tashow.cloud.system.controller.admin.mail; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.log.MailLogRespVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailLogDO; +import com.tashow.cloud.system.service.mail.MailLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 邮件日志") +@RestController +@RequestMapping("/system/mail-log") +public class MailLogController { + + @Resource + private MailLogService mailLogService; + + @GetMapping("/page") + @Operation(summary = "获得邮箱日志分页") + @PreAuthorize("@ss.hasPermission('system:mail-log:query')") + public CommonResult> getMailLogPage(@Valid MailLogPageReqVO pageVO) { + PageResult pageResult = mailLogService.getMailLogPage(pageVO); + return success(BeanUtils.toBean(pageResult, MailLogRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得邮箱日志") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:mail-log:query')") + public CommonResult getMailTemplate(@RequestParam("id") Long id) { + MailLogDO log = mailLogService.getMailLog(id); + return success(BeanUtils.toBean(log, MailLogRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailTemplateController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailTemplateController.http new file mode 100644 index 0000000..9ad2ed2 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailTemplateController.http @@ -0,0 +1,14 @@ +### 请求 /system/mail-template/send-mail 接口 => 成功 +POST {{baseUrl}}/system/mail-template/send-mail +Authorization: Bearer {{token}} +Content-Type: application/json +tenant-id: {{adminTenantId}} + +{ + "templateCode": "test_01", + "mail": "7685413@qq.com", + "templateParams": { + "key01": "value01", + "key02": "value02" + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailTemplateController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailTemplateController.java new file mode 100644 index 0000000..8602fed --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/MailTemplateController.java @@ -0,0 +1,89 @@ +package com.tashow.cloud.system.controller.admin.mail; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.mail.vo.template.*; +import com.tashow.cloud.system.dal.dataobject.mail.MailTemplateDO; +import com.tashow.cloud.system.service.mail.MailSendService; +import com.tashow.cloud.system.service.mail.MailTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 邮件模版") +@RestController +@RequestMapping("/system/mail-template") +public class MailTemplateController { + + @Resource + private MailTemplateService mailTempleService; + @Resource + private MailSendService mailSendService; + + @PostMapping("/create") + @Operation(summary = "创建邮件模版") + @PreAuthorize("@ss.hasPermission('system:mail-template:create')") + public CommonResult createMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO createReqVO){ + return success(mailTempleService.createMailTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改邮件模版") + @PreAuthorize("@ss.hasPermission('system:mail-template:update')") + public CommonResult updateMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO updateReqVO){ + mailTempleService.updateMailTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除邮件模版") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:mail-template:delete')") + public CommonResult deleteMailTemplate(@RequestParam("id") Long id) { + mailTempleService.deleteMailTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得邮件模版") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:mail-template:query')") + public CommonResult getMailTemplate(@RequestParam("id") Long id) { + MailTemplateDO template = mailTempleService.getMailTemplate(id); + return success(BeanUtils.toBean(template, MailTemplateRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得邮件模版分页") + @PreAuthorize("@ss.hasPermission('system:mail-template:query')") + public CommonResult> getMailTemplatePage(@Valid MailTemplatePageReqVO pageReqVO) { + PageResult pageResult = mailTempleService.getMailTemplatePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, MailTemplateRespVO.class)); + } + + @GetMapping({"/list-all-simple", "simple-list"}) + @Operation(summary = "获得邮件模版精简列表") + public CommonResult> getSimpleTemplateList() { + List list = mailTempleService.getMailTemplateList(); + return success(BeanUtils.toBean(list, MailTemplateSimpleRespVO.class)); + } + + @PostMapping("/send-mail") + @Operation(summary = "发送短信") + @PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')") + public CommonResult sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) { + return success(mailSendService.sendSingleMailToAdmin(sendReqVO.getMail(), getLoginUserId(), + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java new file mode 100644 index 0000000..da7f82d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.account; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 邮箱账号分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MailAccountPageReqVO extends PageParam { + + @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma@123.com") + private String mail; + + @Schema(description = "用户名" , requiredMode = Schema.RequiredMode.REQUIRED , example = "yudao") + private String username; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountRespVO.java new file mode 100644 index 0000000..816a8a4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountRespVO.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.account; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 邮箱账号 Response VO") +@Data +public class MailAccountRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma@123.com") + private String mail; + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + private String password; + + @Schema(description = "SMTP 服务器域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn") + private String host; + + @Schema(description = "SMTP 服务器端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") + private Integer port; + + @Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean sslEnable; + + @Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean starttlsEnable; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java new file mode 100644 index 0000000..0d856be --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java @@ -0,0 +1,44 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.account; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - 邮箱账号创建/修改 Request VO") +@Data +public class MailAccountSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma@123.com") + @NotNull(message = "邮箱不能为空") + @Email(message = "必须是 Email 格式") + private String mail; + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "用户名不能为空") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotNull(message = "密码必填") + private String password; + + @Schema(description = "SMTP 服务器域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn") + @NotNull(message = "SMTP 服务器域名不能为空") + private String host; + + @Schema(description = "SMTP 服务器端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") + @NotNull(message = "SMTP 服务器端口不能为空") + private Integer port; + + @Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否开启 ssl 必填") + private Boolean sslEnable; + + @Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否开启 starttls 必填") + private Boolean starttlsEnable; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java new file mode 100644 index 0000000..6bb14e9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.account; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 邮箱账号的精简 Response VO") +@Data +public class MailAccountSimpleRespVO { + + @Schema(description = "邮箱编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "768541388@qq.com") + private String mail; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/log/MailLogPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/log/MailLogPageReqVO.java new file mode 100644 index 0000000..fec307b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/log/MailLogPageReqVO.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.log; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 邮箱日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MailLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "30883") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", example = "2") + private Integer userType; + + @Schema(description = "接收邮箱地址,模糊匹配", example = "76854@qq.com") + private String toMail; + + @Schema(description = "邮箱账号编号", example = "18107") + private Long accountId; + + @Schema(description = "模板编号", example = "5678") + private Long templateId; + + @Schema(description = "发送状态,参见 MailSendStatusEnum 枚举", example = "1") + private Integer sendStatus; + + @Schema(description = "发送时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] sendTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/log/MailLogRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/log/MailLogRespVO.java new file mode 100644 index 0000000..9cd2121 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/log/MailLogRespVO.java @@ -0,0 +1,64 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.log; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Map; + +@Schema(description = "管理后台 - 邮件日志 Response VO") +@Data +public class MailLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31020") + private Long id; + + @Schema(description = "用户编号", example = "30883") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", example = "2") + private Byte userType; + + @Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "76854@qq.com") + private String toMail; + + @Schema(description = "邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18107") + private Long accountId; + + @Schema(description = "发送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "85757@qq.com") + private String fromMail; + + @Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5678") + private Long templateId; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + private String templateCode; + + @Schema(description = "模版发送人名称", example = "李四") + private String templateNickname; + + @Schema(description = "邮件标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试标题") + private String templateTitle; + + @Schema(description = "邮件内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试内容") + private String templateContent; + + @Schema(description = "邮件参数", requiredMode = Schema.RequiredMode.REQUIRED) + private Map templateParams; + + @Schema(description = "发送状态,参见 MailSendStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Byte sendStatus; + + @Schema(description = "发送时间") + private LocalDateTime sendTime; + + @Schema(description = "发送返回的消息 ID", example = "28568") + private String sendMessageId; + + @Schema(description = "发送异常") + private String sendException; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java new file mode 100644 index 0000000..bcf9300 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.template; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 邮件模版分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MailTemplatePageReqVO extends PageParam { + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", example = "1") + private Integer status; + + @Schema(description = "标识,模糊匹配", example = "code_1024") + private String code; + + @Schema(description = "名称,模糊匹配", example = "芋头") + private String name; + + @Schema(description = "账号编号", example = "2048") + private Long accountId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateRespVO.java new file mode 100644 index 0000000..5464545 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateRespVO.java @@ -0,0 +1,46 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 邮件末班 Response VO") +@Data +public class MailTemplateRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试名字") + private String name; + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + private String code; + + @Schema(description = "发送的邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long accountId; + + @Schema(description = "发送人名称", example = "芋头") + private String nickname; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "注册成功") + private String title; + + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,注册成功啦") + private String content; + + @Schema(description = "参数数组", example = "name,code") + private List params; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "备注", example = "奥特曼") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java new file mode 100644 index 0000000..724b055 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java @@ -0,0 +1,46 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 邮件模版创建/修改 Request VO") +@Data +public class MailTemplateSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试名字") + @NotNull(message = "名称不能为空") + private String name; + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + @NotNull(message = "模版编号不能为空") + private String code; + + @Schema(description = "发送的邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发送的邮箱账号编号不能为空") + private Long accountId; + + @Schema(description = "发送人名称", example = "芋头") + private String nickname; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "注册成功") + @NotEmpty(message = "标题不能为空") + private String title; + + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,注册成功啦") + @NotEmpty(message = "内容不能为空") + private String content; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "奥特曼") + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java new file mode 100644 index 0000000..dbfcaea --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 邮件发送 Req VO") +@Data +public class MailTemplateSendReqVO { + + @Schema(description = "接收邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "7685413@qq.com") + @NotEmpty(message = "接收邮箱不能为空") + private String mail; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + @NotNull(message = "模板编码不能为空") + private String templateCode; + + @Schema(description = "模板参数") + private Map templateParams; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java new file mode 100644 index 0000000..66a3c7d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.system.controller.admin.mail.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 邮件模版的精简 Response VO") +@Data +public class MailTemplateSimpleRespVO { + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "模版名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "哒哒哒") + private String name; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/NoticeController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/NoticeController.java new file mode 100644 index 0000000..52573de --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/NoticeController.java @@ -0,0 +1,94 @@ +package com.tashow.cloud.system.controller.admin.notice; + +import cn.hutool.core.lang.Assert; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.infraapi.api.websocket.WebSocketSenderApi; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticePageReqVO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticeRespVO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticeSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.notice.NoticeDO; +import com.tashow.cloud.system.service.notice.NoticeService; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticePageReqVO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticeRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 通知公告") +@RestController +@RequestMapping("/system/notice") +@Validated +public class NoticeController { + + @Resource + private NoticeService noticeService; + + @Resource + private WebSocketSenderApi webSocketSenderApi; + + @PostMapping("/create") + @Operation(summary = "创建通知公告") + @PreAuthorize("@ss.hasPermission('system:notice:create')") + public CommonResult createNotice(@Valid @RequestBody NoticeSaveReqVO createReqVO) { + Long noticeId = noticeService.createNotice(createReqVO); + return success(noticeId); + } + + @PutMapping("/update") + @Operation(summary = "修改通知公告") + @PreAuthorize("@ss.hasPermission('system:notice:update')") + public CommonResult updateNotice(@Valid @RequestBody NoticeSaveReqVO updateReqVO) { + noticeService.updateNotice(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除通知公告") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notice:delete')") + public CommonResult deleteNotice(@RequestParam("id") Long id) { + noticeService.deleteNotice(id); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获取通知公告列表") + @PreAuthorize("@ss.hasPermission('system:notice:query')") + public CommonResult> getNoticePage(@Validated NoticePageReqVO pageReqVO) { + PageResult pageResult = noticeService.getNoticePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, NoticeRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得通知公告") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notice:query')") + public CommonResult getNotice(@RequestParam("id") Long id) { + NoticeDO notice = noticeService.getNotice(id); + return success(BeanUtils.toBean(notice, NoticeRespVO.class)); + } + + @PostMapping("/push") + @Operation(summary = "推送通知公告", description = "只发送给 websocket 连接在线的用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notice:update')") + public CommonResult push(@RequestParam("id") Long id) { + NoticeDO notice = noticeService.getNotice(id); + Assert.notNull(notice, "公告不能为空"); + // 通过 websocket 推送给在线的用户 + webSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(), "notice-push", notice); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticePageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticePageReqVO.java new file mode 100644 index 0000000..aa023ae --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticePageReqVO.java @@ -0,0 +1,19 @@ +package com.tashow.cloud.system.controller.admin.notice.vo; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 通知公告分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class NoticePageReqVO extends PageParam { + + @Schema(description = "通知公告名称,模糊匹配", example = "芋道") + private String title; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticeRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticeRespVO.java new file mode 100644 index 0000000..30d8ded --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticeRespVO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.system.controller.admin.notice.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 通知公告信息 Response VO") +@Data +public class NoticeRespVO { + + @Schema(description = "通知公告序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "公告标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主") + private String title; + + @Schema(description = "公告类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主") + private Integer type; + + @Schema(description = "公告内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "半生编码") + private String content; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticeSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticeSaveReqVO.java new file mode 100644 index 0000000..0a0e887 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notice/vo/NoticeSaveReqVO.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.system.controller.admin.notice.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +@Schema(description = "管理后台 - 通知公告创建/修改 Request VO") +@Data +public class NoticeSaveReqVO { + + @Schema(description = "岗位公告编号", example = "1024") + private Long id; + + @Schema(description = "公告标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主") + @NotBlank(message = "公告标题不能为空") + @Size(max = 50, message = "公告标题不能超过50个字符") + private String title; + + @Schema(description = "公告类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主") + @NotNull(message = "公告类型不能为空") + private Integer type; + + @Schema(description = "公告内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "半生编码") + private String content; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/NotifyMessageController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/NotifyMessageController.java new file mode 100644 index 0000000..059228d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/NotifyMessageController.java @@ -0,0 +1,101 @@ +package com.tashow.cloud.system.controller.admin.notify; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageRespVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyMessageDO; +import com.tashow.cloud.system.service.notify.NotifyMessageService; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 我的站内信") +@RestController +@RequestMapping("/system/notify-message") +@Validated +public class NotifyMessageController { + + @Resource + private NotifyMessageService notifyMessageService; + + // ========== 管理所有的站内信 ========== + + @GetMapping("/get") + @Operation(summary = "获得站内信") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notify-message:query')") + public CommonResult getNotifyMessage(@RequestParam("id") Long id) { + NotifyMessageDO message = notifyMessageService.getNotifyMessage(id); + return success(BeanUtils.toBean(message, NotifyMessageRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得站内信分页") + @PreAuthorize("@ss.hasPermission('system:notify-message:query')") + public CommonResult> getNotifyMessagePage(@Valid NotifyMessagePageReqVO pageVO) { + PageResult pageResult = notifyMessageService.getNotifyMessagePage(pageVO); + return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class)); + } + + // ========== 查看自己的站内信 ========== + + @GetMapping("/my-page") + @Operation(summary = "获得我的站内信分页") + public CommonResult> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) { + PageResult pageResult = notifyMessageService.getMyMyNotifyMessagePage(pageVO, + getLoginUserId(), UserTypeEnum.ADMIN.getValue()); + return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class)); + } + + @PutMapping("/update-read") + @Operation(summary = "标记站内信为已读") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + public CommonResult updateNotifyMessageRead(@RequestParam("ids") List ids) { + notifyMessageService.updateNotifyMessageRead(ids, getLoginUserId(), UserTypeEnum.ADMIN.getValue()); + return success(Boolean.TRUE); + } + + @PutMapping("/update-all-read") + @Operation(summary = "标记所有站内信为已读") + public CommonResult updateAllNotifyMessageRead() { + notifyMessageService.updateAllNotifyMessageRead(getLoginUserId(), UserTypeEnum.ADMIN.getValue()); + return success(Boolean.TRUE); + } + + @GetMapping("/get-unread-list") + @Operation(summary = "获取当前用户的最新站内信列表,默认 10 条") + @Parameter(name = "size", description = "10") + public CommonResult> getUnreadNotifyMessageList( + @RequestParam(name = "size", defaultValue = "10") Integer size) { + List list = notifyMessageService.getUnreadNotifyMessageList( + getLoginUserId(), UserTypeEnum.ADMIN.getValue(), size); + return success(BeanUtils.toBean(list, NotifyMessageRespVO.class)); + } + + @GetMapping("/get-unread-count") + @Operation(summary = "获得当前用户的未读站内信数量") + @ApiAccessLog(enable = false) // 由于前端会不断轮询该接口,记录日志没有意义 + public CommonResult getUnreadNotifyMessageCount() { + return success(notifyMessageService.getUnreadNotifyMessageCount( + getLoginUserId(), UserTypeEnum.ADMIN.getValue())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/NotifyTemplateController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/NotifyTemplateController.java new file mode 100644 index 0000000..1c2d979 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/NotifyTemplateController.java @@ -0,0 +1,91 @@ +package com.tashow.cloud.system.controller.admin.notify; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplateRespVO; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplateSendReqVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyTemplateDO; +import com.tashow.cloud.system.service.notify.NotifySendService; +import com.tashow.cloud.system.service.notify.NotifyTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 站内信模版") +@RestController +@RequestMapping("/system/notify-template") +@Validated +public class NotifyTemplateController { + + @Resource + private NotifyTemplateService notifyTemplateService; + + @Resource + private NotifySendService notifySendService; + + @PostMapping("/create") + @Operation(summary = "创建站内信模版") + @PreAuthorize("@ss.hasPermission('system:notify-template:create')") + public CommonResult createNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO createReqVO) { + return success(notifyTemplateService.createNotifyTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新站内信模版") + @PreAuthorize("@ss.hasPermission('system:notify-template:update')") + public CommonResult updateNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO updateReqVO) { + notifyTemplateService.updateNotifyTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除站内信模版") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:notify-template:delete')") + public CommonResult deleteNotifyTemplate(@RequestParam("id") Long id) { + notifyTemplateService.deleteNotifyTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得站内信模版") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notify-template:query')") + public CommonResult getNotifyTemplate(@RequestParam("id") Long id) { + NotifyTemplateDO template = notifyTemplateService.getNotifyTemplate(id); + return success(BeanUtils.toBean(template, NotifyTemplateRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得站内信模版分页") + @PreAuthorize("@ss.hasPermission('system:notify-template:query')") + public CommonResult> getNotifyTemplatePage(@Valid NotifyTemplatePageReqVO pageVO) { + PageResult pageResult = notifyTemplateService.getNotifyTemplatePage(pageVO); + return success(BeanUtils.toBean(pageResult, NotifyTemplateRespVO.class)); + } + + @PostMapping("/send-notify") + @Operation(summary = "发送站内信") + @PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')") + public CommonResult sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) { + if (UserTypeEnum.MEMBER.getValue().equals(sendReqVO.getUserType())) { + return success(notifySendService.sendSingleNotifyToMember(sendReqVO.getUserId(), + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); + } else { + return success(notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserId(), + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); + } + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java new file mode 100644 index 0000000..7923f14 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.system.controller.admin.notify.vo.message; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 站内信分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class NotifyMessageMyPageReqVO extends PageParam { + + @Schema(description = "是否已读", example = "true") + private Boolean readStatus; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java new file mode 100644 index 0000000..343a33a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.system.controller.admin.notify.vo.message; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 站内信分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class NotifyMessagePageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "25025") + private Long userId; + + @Schema(description = "用户类型", example = "1") + private Integer userType; + + @Schema(description = "模板编码", example = "test_01") + private String templateCode; + + @Schema(description = "模版类型", example = "2") + private Integer templateType; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java new file mode 100644 index 0000000..5111142 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java @@ -0,0 +1,49 @@ +package com.tashow.cloud.system.controller.admin.notify.vo.message; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Map; + +@Schema(description = "管理后台 - 站内信 Response VO") +@Data +public class NotifyMessageRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25025") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Byte userType; + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13013") + private Long templateId; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + private String templateCode; + + @Schema(description = "模版发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String templateNickname; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试内容") + private String templateContent; + + @Schema(description = "模版类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer templateType; + + @Schema(description = "模版参数", requiredMode = Schema.RequiredMode.REQUIRED) + private Map templateParams; + + @Schema(description = "是否已读", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean readStatus; + + @Schema(description = "阅读时间") + private LocalDateTime readTime; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java new file mode 100644 index 0000000..9362f99 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.system.controller.admin.notify.vo.template; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 站内信模版分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class NotifyTemplatePageReqVO extends PageParam { + + @Schema(description = "模版编码", example = "test_01") + private String code; + + @Schema(description = "模版名称", example = "我是名称") + private String name; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java new file mode 100644 index 0000000..4bb318a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java @@ -0,0 +1,43 @@ +package com.tashow.cloud.system.controller.admin.notify.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 站内信模版 Response VO") +@Data +public class NotifyTemplateRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试模版") + private String name; + + @Schema(description = "模版编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "SEND_TEST") + private String code; + + @Schema(description = "模版类型,对应 system_notify_template_type 字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + private String nickname; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是模版内容") + private String content; + + @Schema(description = "参数数组", example = "name,code") + private List params; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java new file mode 100644 index 0000000..82168e8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java @@ -0,0 +1,46 @@ +package com.tashow.cloud.system.controller.admin.notify.vo.template; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 站内信模版创建/修改 Request VO") +@Data +public class NotifyTemplateSaveReqVO { + + @Schema(description = "ID", example = "1024") + private Long id; + + @Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试模版") + @NotEmpty(message = "模版名称不能为空") + private String name; + + @Schema(description = "模版编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "SEND_TEST") + @NotNull(message = "模版编码不能为空") + private String code; + + @Schema(description = "模版类型,对应 system_notify_template_type 字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "模版类型不能为空") + private Integer type; + + @Schema(description = "发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + @NotEmpty(message = "发送人名称不能为空") + private String nickname; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是模版内容") + @NotEmpty(message = "模版内容不能为空") + private String content; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + + @Schema(description = "备注", example = "我是备注") + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java new file mode 100644 index 0000000..86ddeee --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.system.controller.admin.notify.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 站内信模板的发送 Request VO") +@Data +public class NotifyTemplateSendReqVO { + + @Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "01") + @NotNull(message = "用户id不能为空") + private Long userId; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户类型不能为空") + private Integer userType; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "01") + @NotEmpty(message = "模板编码不能为空") + private String templateCode; + + @Schema(description = "模板参数") + private Map templateParams; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2ClientController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2ClientController.http new file mode 100644 index 0000000..f8d7b89 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2ClientController.http @@ -0,0 +1,23 @@ +### 请求 /login 接口 => 成功 +POST {{baseUrl}}/system/oauth2-client/create +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +{ + "id": "1", + "secret": "admin123", + "name": "芋道源码", + "logo": "https://www.iocoder.cn/images/favicon.ico", + "description": "我是描述", + "status": 0, + "accessTokenValiditySeconds": 180, + "refreshTokenValiditySeconds": 8640, + "redirectUris": ["https://www.iocoder.cn"], + "autoApprove": true, + "authorizedGrantTypes": ["password"], + "scopes": ["user_info"], + "authorities": ["system:user:query"], + "resource_ids": ["1024"], + "additionalInformation": "{}" +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2ClientController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2ClientController.java new file mode 100644 index 0000000..db5f68d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2ClientController.java @@ -0,0 +1,74 @@ +package com.tashow.cloud.system.controller.admin.oauth2; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientRespVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; +import com.tashow.cloud.system.service.oauth2.OAuth2ClientService; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - OAuth2 客户端") +@RestController +@RequestMapping("/system/oauth2-client") +@Validated +public class OAuth2ClientController { + + @Resource + private OAuth2ClientService oAuth2ClientService; + + @PostMapping("/create") + @Operation(summary = "创建 OAuth2 客户端") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:create')") + public CommonResult createOAuth2Client(@Valid @RequestBody OAuth2ClientSaveReqVO createReqVO) { + return success(oAuth2ClientService.createOAuth2Client(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新 OAuth2 客户端") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:update')") + public CommonResult updateOAuth2Client(@Valid @RequestBody OAuth2ClientSaveReqVO updateReqVO) { + oAuth2ClientService.updateOAuth2Client(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除 OAuth2 客户端") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:oauth2-client:delete')") + public CommonResult deleteOAuth2Client(@RequestParam("id") Long id) { + oAuth2ClientService.deleteOAuth2Client(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得 OAuth2 客户端") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:query')") + public CommonResult getOAuth2Client(@RequestParam("id") Long id) { + OAuth2ClientDO client = oAuth2ClientService.getOAuth2Client(id); + return success(BeanUtils.toBean(client, OAuth2ClientRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得 OAuth2 客户端分页") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:query')") + public CommonResult> getOAuth2ClientPage(@Valid OAuth2ClientPageReqVO pageVO) { + PageResult pageResult = oAuth2ClientService.getOAuth2ClientPage(pageVO); + return success(BeanUtils.toBean(pageResult, OAuth2ClientRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2OpenController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2OpenController.http new file mode 100644 index 0000000..f770ed9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2OpenController.http @@ -0,0 +1,54 @@ +### 请求 /system/oauth2/authorize 接口 => 成功 +GET {{baseUrl}}/system/oauth2/authorize?clientId=default +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +### 请求 /system/oauth2/authorize + token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/authorize +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +response_type=token&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true + +### 请求 /system/oauth2/authorize + code 接口 => 成功 +POST {{baseUrl}}/system/oauth2/authorize +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +response_type=code&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=false + +### 请求 /system/oauth2/token + code 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenantId}} + +grant_type=authorization_code&redirect_uri=https://www.iocoder.cn&code=189956c07a174588a97157eabef2f93a + +### 请求 /system/oauth2/token + password 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenantId}} + +grant_type=password&username=admin&password=admin123&scope=user.read + +### 请求 /system/oauth2/token + refresh_token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenantId}} + +grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588 + +### 请求 /system/oauth2/token + DELETE 接口 => 成功 +DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596 +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenantId}} + +### 请求 /system/oauth2/check-token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106 +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2OpenController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2OpenController.java new file mode 100644 index 0000000..d5123e9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2OpenController.java @@ -0,0 +1,298 @@ +package com.tashow.cloud.system.controller.admin.oauth2; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.http.HttpUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; +import com.tashow.cloud.system.convert.oauth2.OAuth2OpenConvert; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; +import com.tashow.cloud.systemapi.enums.oauth2.OAuth2GrantTypeEnum; +import com.tashow.cloud.system.service.oauth2.OAuth2ApproveService; +import com.tashow.cloud.system.service.oauth2.OAuth2ClientService; +import com.tashow.cloud.system.service.oauth2.OAuth2GrantService; +import com.tashow.cloud.system.service.oauth2.OAuth2TokenService; +import com.tashow.cloud.system.util.oauth2.OAuth2Utils; +import com.tashow.cloud.systemapi.enums.oauth2.OAuth2GrantTypeEnum; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception0; +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; + +/** + * 提供给外部应用调用为主 + * + * 一般来说,管理后台的 /system-api/* 是不直接提供给外部应用使用,主要是外部应用能够访问的数据与接口是有限的,而管理后台的 RBAC 无法很好的控制。 + * 参考大量的开放平台,都是独立的一套 OpenAPI,对应到【本系统】就是在 Controller 下新建 open 包,实现 /open-api/* 接口,然后通过 scope 进行控制。 + * 另外,一个公司如果有多个管理后台,它们 client_id 产生的 access token 相互之间是无法互通的,即无法访问它们系统的 API 接口,直到两个 client_id 产生信任授权。 + * + * 考虑到【本系统】暂时不想做的过于复杂,默认只有获取到 access token 之后,可以访问【本系统】管理后台的 /system-api/* 所有接口,除非手动添加 scope 控制。 + * scope 的使用示例,可见 {@link OAuth2UserController} 类 + * + * @author 芋道源码 + */ +@Tag(name = "管理后台 - OAuth2.0 授权") +@RestController +@RequestMapping("/system/oauth2") +@Validated +@Slf4j +public class OAuth2OpenController { + + @Resource + private OAuth2GrantService oauth2GrantService; + @Resource + private OAuth2ClientService oauth2ClientService; + @Resource + private OAuth2ApproveService oauth2ApproveService; + @Resource + private OAuth2TokenService oauth2TokenService; + + /** + * 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法 + * + * 授权码 authorization_code 模式时:code + redirectUri + state 参数 + * 密码 password 模式时:username + password + scope 参数 + * 刷新 refresh_token 模式时:refreshToken 参数 + * 客户端 client_credentials 模式:scope 参数 + * 简化 implicit 模式时:不支持 + * + * 注意,默认需要传递 client_id + client_secret 参数 + */ + @PostMapping("/token") + @PermitAll + @Operation(summary = "获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") + @Parameters({ + @Parameter(name = "grant_type", required = true, description = "授权类型", example = "code"), + @Parameter(name = "code", description = "授权范围", example = "userinfo.read"), + @Parameter(name = "redirect_uri", description = "重定向 URI", example = "https://www.iocoder.cn"), + @Parameter(name = "state", description = "状态", example = "1"), + @Parameter(name = "username", example = "tudou"), + @Parameter(name = "password", example = "cai"), // 多个使用空格分隔 + @Parameter(name = "scope", example = "user_info"), + @Parameter(name = "refresh_token", example = "123424233"), + }) + public CommonResult postAccessToken(HttpServletRequest request, + @RequestParam("grant_type") String grantType, + @RequestParam(value = "code", required = false) String code, // 授权码模式 + @RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式 + @RequestParam(value = "state", required = false) String state, // 授权码模式 + @RequestParam(value = "username", required = false) String username, // 密码模式 + @RequestParam(value = "password", required = false) String password, // 密码模式 + @RequestParam(value = "scope", required = false) String scope, // 密码模式 + @RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式 + List scopes = OAuth2Utils.buildScopes(scope); + // 1.1 校验授权类型 + OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGrantType(grantType); + if (grantTypeEnum == null) { + throw exception0(BAD_REQUEST.getCode(), StrUtil.format("未知授权类型({})", grantType)); + } + if (grantTypeEnum == OAuth2GrantTypeEnum.IMPLICIT) { + throw exception0(BAD_REQUEST.getCode(), "Token 接口不支持 implicit 授权模式"); + } + + // 1.2 校验客户端 + String[] clientIdAndSecret = obtainBasicAuthorization(request); + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], + grantType, scopes, redirectUri); + + // 2. 根据授权模式,获取访问令牌 + OAuth2AccessTokenDO accessTokenDO; + switch (grantTypeEnum) { + case AUTHORIZATION_CODE: + accessTokenDO = oauth2GrantService.grantAuthorizationCodeForAccessToken(client.getClientId(), code, redirectUri, state); + break; + case PASSWORD: + accessTokenDO = oauth2GrantService.grantPassword(username, password, client.getClientId(), scopes); + break; + case CLIENT_CREDENTIALS: + accessTokenDO = oauth2GrantService.grantClientCredentials(client.getClientId(), scopes); + break; + case REFRESH_TOKEN: + accessTokenDO = oauth2GrantService.grantRefreshToken(refreshToken, client.getClientId()); + break; + default: + throw new IllegalArgumentException("未知授权类型:" + grantType); + } + Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 + return success(OAuth2OpenConvert.INSTANCE.convert(accessTokenDO)); + } + + @DeleteMapping("/token") + @PermitAll + @Operation(summary = "删除访问令牌") + @Parameter(name = "token", required = true, description = "访问令牌", example = "biu") + public CommonResult revokeToken(HttpServletRequest request, + @RequestParam("token") String token) { + // 校验客户端 + String[] clientIdAndSecret = obtainBasicAuthorization(request); + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], + null, null, null); + + // 删除访问令牌 + return success(oauth2GrantService.revokeToken(client.getClientId(), token)); + } + + /** + * 对应 Spring Security OAuth 的 CheckTokenEndpoint 类的 checkToken 方法 + */ + @PostMapping("/check-token") + @PermitAll + @Operation(summary = "校验访问令牌") + @Parameter(name = "token", required = true, description = "访问令牌", example = "biu") + public CommonResult checkToken(HttpServletRequest request, + @RequestParam("token") String token) { + // 校验客户端 + String[] clientIdAndSecret = obtainBasicAuthorization(request); + oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], + null, null, null); + + // 校验令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(token); + Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 + return success(OAuth2OpenConvert.INSTANCE.convert2(accessTokenDO)); + } + + /** + * 对应 Spring Security OAuth 的 AuthorizationEndpoint 类的 authorize 方法 + */ + @GetMapping("/authorize") + @Operation(summary = "获得授权信息", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") + @Parameter(name = "clientId", required = true, description = "客户端编号", example = "tudou") + public CommonResult authorize(@RequestParam("clientId") String clientId) { + // 0. 校验用户已经登录。通过 Spring Security 实现 + + // 1. 获得 Client 客户端的信息 + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId); + // 2. 获得用户已经授权的信息 + List approves = oauth2ApproveService.getApproveList(getLoginUserId(), getUserType(), clientId); + // 拼接返回 + return success(OAuth2OpenConvert.INSTANCE.convert(client, approves)); + } + + /** + * 对应 Spring Security OAuth 的 AuthorizationEndpoint 类的 approveOrDeny 方法 + * + * 场景一:【自动授权 autoApprove = true】 + * 刚进入 sso.vue 界面,调用该接口,用户历史已经给该应用做过对应的授权,或者 OAuth2Client 支持该 scope 的自动授权 + * 场景二:【手动授权 autoApprove = false】 + * 在 sso.vue 界面,用户选择好 scope 授权范围,调用该接口,进行授权。此时,approved 为 true 或者 false + * + * 因为前后端分离,Axios 无法很好的处理 302 重定向,所以和 Spring Security OAuth 略有不同,返回结果是重定向的 URL,剩余交给前端处理 + */ + @PostMapping("/authorize") + @Operation(summary = "申请授权", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【提交】调用") + @Parameters({ + @Parameter(name = "response_type", required = true, description = "响应类型", example = "code"), + @Parameter(name = "client_id", required = true, description = "客户端编号", example = "tudou"), + @Parameter(name = "scope", description = "授权范围", example = "userinfo.read"), // 使用 Map 格式,Spring MVC 暂时不支持这么接收参数 + @Parameter(name = "redirect_uri", required = true, description = "重定向 URI", example = "https://www.iocoder.cn"), + @Parameter(name = "auto_approve", required = true, description = "用户是否接受", example = "true"), + @Parameter(name = "state", example = "1") + }) + public CommonResult approveOrDeny(@RequestParam("response_type") String responseType, + @RequestParam("client_id") String clientId, + @RequestParam(value = "scope", required = false) String scope, + @RequestParam("redirect_uri") String redirectUri, + @RequestParam(value = "auto_approve") Boolean autoApprove, + @RequestParam(value = "state", required = false) String state) { + @SuppressWarnings("unchecked") + Map scopes = JsonUtils.parseObject(scope, Map.class); + scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap()); + // 0. 校验用户已经登录。通过 Spring Security 实现 + + // 1.1 校验 responseType 是否满足 code 或者 token 值 + OAuth2GrantTypeEnum grantTypeEnum = getGrantTypeEnum(responseType); + // 1.2 校验 redirectUri 重定向域名是否合法 + 校验 scope 是否在 Client 授权范围内 + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId, null, + grantTypeEnum.getGrantType(), scopes.keySet(), redirectUri); + + // 2.1 假设 approved 为 null,说明是场景一 + if (Boolean.TRUE.equals(autoApprove)) { + // 如果无法自动授权通过,则返回空 url,前端不进行跳转 + if (!oauth2ApproveService.checkForPreApproval(getLoginUserId(), getUserType(), clientId, scopes.keySet())) { + return success(null); + } + } else { // 2.2 假设 approved 非 null,说明是场景二 + // 如果计算后不通过,则跳转一个错误链接 + if (!oauth2ApproveService.updateAfterApproval(getLoginUserId(), getUserType(), clientId, scopes)) { + return success(OAuth2Utils.buildUnsuccessfulRedirect(redirectUri, responseType, state, + "access_denied", "User denied access")); + } + } + + // 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向 + List approveScopes = convertList(scopes.entrySet(), Map.Entry::getKey, Map.Entry::getValue); + if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) { + return success(getAuthorizationCodeRedirect(getLoginUserId(), client, approveScopes, redirectUri, state)); + } + // 3.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向 + return success(getImplicitGrantRedirect(getLoginUserId(), client, approveScopes, redirectUri, state)); + } + + private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) { + if (StrUtil.equals(responseType, "code")) { + return OAuth2GrantTypeEnum.AUTHORIZATION_CODE; + } + if (StrUtil.equalsAny(responseType, "token")) { + return OAuth2GrantTypeEnum.IMPLICIT; + } + throw exception0(BAD_REQUEST.getCode(), "response_type 参数值只允许 code 和 token"); + } + + private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client, + List scopes, String redirectUri, String state) { + // 1. 创建 access token 访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2GrantService.grantImplicit(userId, getUserType(), client.getClientId(), scopes); + Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 + // 2. 拼接重定向的 URL + // noinspection unchecked + return OAuth2Utils.buildImplicitRedirectUri(redirectUri, accessTokenDO.getAccessToken(), state, accessTokenDO.getExpiresTime(), + scopes, JsonUtils.parseObject(client.getAdditionalInformation(), Map.class)); + } + + private String getAuthorizationCodeRedirect(Long userId, OAuth2ClientDO client, + List scopes, String redirectUri, String state) { + // 1. 创建 code 授权码 + String authorizationCode = oauth2GrantService.grantAuthorizationCodeForCode(userId, getUserType(), client.getClientId(), scopes, + redirectUri, state); + // 2. 拼接重定向的 URL + return OAuth2Utils.buildAuthorizationCodeRedirectUri(redirectUri, authorizationCode, state); + } + + private Integer getUserType() { + return UserTypeEnum.ADMIN.getValue(); + } + + private String[] obtainBasicAuthorization(HttpServletRequest request) { + String[] clientIdAndSecret = HttpUtils.obtainBasicAuthorization(request); + if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) { + throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递"); + } + return clientIdAndSecret; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2TokenController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2TokenController.java new file mode 100644 index 0000000..a26fcef --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2TokenController.java @@ -0,0 +1,51 @@ +package com.tashow.cloud.system.controller.admin.oauth2; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenRespVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.systemapi.enums.logger.LoginLogTypeEnum; +import com.tashow.cloud.system.service.auth.AdminAuthService; +import com.tashow.cloud.system.service.oauth2.OAuth2TokenService; +import com.tashow.cloud.systemapi.enums.logger.LoginLogTypeEnum; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - OAuth2.0 令牌") +@RestController +@RequestMapping("/system/oauth2-token") +public class OAuth2TokenController { + + @Resource + private OAuth2TokenService oauth2TokenService; + @Resource + private AdminAuthService authService; + + @GetMapping("/page") + @Operation(summary = "获得访问令牌分页", description = "只返回有效期内的") + @PreAuthorize("@ss.hasPermission('system:oauth2-token:page')") + public CommonResult> getAccessTokenPage(@Valid OAuth2AccessTokenPageReqVO reqVO) { + PageResult pageResult = oauth2TokenService.getAccessTokenPage(reqVO); + return success(BeanUtils.toBean(pageResult, OAuth2AccessTokenRespVO.class)); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除访问令牌") + @Parameter(name = "accessToken", description = "访问令牌", required = true, example = "tudou") + @PreAuthorize("@ss.hasPermission('system:oauth2-token:delete')") + public CommonResult deleteAccessToken(@RequestParam("accessToken") String accessToken) { + authService.logout(accessToken, LoginLogTypeEnum.LOGOUT_DELETE.getType()); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2UserController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2UserController.http new file mode 100644 index 0000000..9e76c7c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2UserController.http @@ -0,0 +1,14 @@ +### 请求 /system/oauth2/user/get 接口 => 成功 +GET {{baseUrl}}/system/oauth2/user/get +Authorization: Bearer 47f9c74ec11041f193b777ebb95c3b0d +tenant-id: {{adminTenantId}} + +### 请求 /system/oauth2/user/update 接口 => 成功 +PUT {{baseUrl}}/system/oauth2/user/update +Content-Type: application/json +Authorization: Bearer 47f9c74ec11041f193b777ebb95c3b0d +tenant-id: {{adminTenantId}} + +{ + "nickname": "芋道源码" +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2UserController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2UserController.java new file mode 100644 index 0000000..d4b4d7b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/OAuth2UserController.java @@ -0,0 +1,82 @@ +package com.tashow.cloud.system.controller.admin.oauth2; + +import cn.hutool.core.collection.CollUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.oauth2.vo.user.OAuth2UserInfoRespVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.user.OAuth2UserUpdateReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.service.dept.DeptService; +import com.tashow.cloud.system.service.dept.PostService; +import com.tashow.cloud.system.service.user.AdminUserService; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; + +/** + * 提供给外部应用调用为主 + * + * 1. 在 getUserInfo 方法上,添加 @PreAuthorize("@ss.hasScope('user.read')") 注解,声明需要满足 scope = user.read + * 2. 在 updateUserInfo 方法上,添加 @PreAuthorize("@ss.hasScope('user.write')") 注解,声明需要满足 scope = user.write + * + * @author 芋道源码 + */ +@Tag(name = "管理后台 - OAuth2.0 用户") +@RestController +@RequestMapping("/system/oauth2/user") +@Validated +@Slf4j +public class OAuth2UserController { + + @Resource + private AdminUserService userService; + @Resource + private DeptService deptService; + @Resource + private PostService postService; + + @GetMapping("/get") + @Operation(summary = "获得用户基本信息") + @PreAuthorize("@ss.hasScope('user.read')") // + public CommonResult getUserInfo() { + // 获得用户基本信息 + AdminUserDO user = userService.getUser(getLoginUserId()); + OAuth2UserInfoRespVO resp = BeanUtils.toBean(user, OAuth2UserInfoRespVO.class); + // 获得部门信息 + if (user.getDeptId() != null) { + DeptDO dept = deptService.getDept(user.getDeptId()); + resp.setDept(BeanUtils.toBean(dept, OAuth2UserInfoRespVO.Dept.class)); + } + // 获得岗位信息 + if (CollUtil.isNotEmpty(user.getPostIds())) { + List posts = postService.getPostList(user.getPostIds()); + resp.setPosts(BeanUtils.toBean(posts, OAuth2UserInfoRespVO.Post.class)); + } + return success(resp); + } + + @PutMapping("/update") + @Operation(summary = "更新用户基本信息") + @PreAuthorize("@ss.hasScope('user.write')") + public CommonResult updateUserInfo(@Valid @RequestBody OAuth2UserUpdateReqVO reqVO) { + // 这里将 UserProfileUpdateReqVO =》UserProfileUpdateReqVO 对象,实现接口的复用。 + // 主要是,AdminUserService 没有自己的 BO 对象,所以复用只能这么做 + userService.updateUserProfile(getLoginUserId(), BeanUtils.toBean(reqVO, UserProfileUpdateReqVO.class)); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java new file mode 100644 index 0000000..5ebf46a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.client; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - OAuth2 客户端分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OAuth2ClientPageReqVO extends PageParam { + + @Schema(description = "应用名,模糊匹配", example = "土豆") + private String name; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", example = "1") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java new file mode 100644 index 0000000..9c31692 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java @@ -0,0 +1,64 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.client; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - OAuth2 客户端 Response VO") +@Data +public class OAuth2ClientRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + private String clientId; + + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "fan") + private String secret; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + private String name; + + @Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String logo; + + @Schema(description = "应用描述", example = "我是一个应用") + private String description; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "访问令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640") + private Integer accessTokenValiditySeconds; + + @Schema(description = "刷新令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640000") + private Integer refreshTokenValiditySeconds; + + @Schema(description = "可重定向的 URI 地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + private List redirectUris; + + @Schema(description = "授权类型,参见 OAuth2GrantTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "password") + private List authorizedGrantTypes; + + @Schema(description = "授权范围", example = "user_info") + private List scopes; + + @Schema(description = "自动通过的授权范围", example = "user_info") + private List autoApproveScopes; + + @Schema(description = "权限", example = "system:user:query") + private List authorities; + + @Schema(description = "资源", example = "1024") + private List resourceIds; + + @Schema(description = "附加信息", example = "{yunai: true}") + private String additionalInformation; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientSaveReqVO.java new file mode 100644 index 0000000..f84d5d8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/client/OAuth2ClientSaveReqVO.java @@ -0,0 +1,81 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.client; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.util.json.JsonUtils; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - OAuth2 客户端创建/修改 Request VO") +@Data +public class OAuth2ClientSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + @NotNull(message = "客户端编号不能为空") + private String clientId; + + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "fan") + @NotNull(message = "客户端密钥不能为空") + private String secret; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + @NotNull(message = "应用名不能为空") + private String name; + + @Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + @NotNull(message = "应用图标不能为空") + @URL(message = "应用图标的地址不正确") + private String logo; + + @Schema(description = "应用描述", example = "我是一个应用") + private String description; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "访问令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640") + @NotNull(message = "访问令牌的有效期不能为空") + private Integer accessTokenValiditySeconds; + + @Schema(description = "刷新令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640000") + @NotNull(message = "刷新令牌的有效期不能为空") + private Integer refreshTokenValiditySeconds; + + @Schema(description = "可重定向的 URI 地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + @NotNull(message = "可重定向的 URI 地址不能为空") + private List<@NotEmpty(message = "重定向的 URI 不能为空") @URL(message = "重定向的 URI 格式不正确") String> redirectUris; + + @Schema(description = "授权类型,参见 OAuth2GrantTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "password") + @NotNull(message = "授权类型不能为空") + private List authorizedGrantTypes; + + @Schema(description = "授权范围", example = "user_info") + private List scopes; + + @Schema(description = "自动通过的授权范围", example = "user_info") + private List autoApproveScopes; + + @Schema(description = "权限", example = "system:user:query") + private List authorities; + + @Schema(description = "资源", example = "1024") + private List resourceIds; + + @Schema(description = "附加信息", example = "{yunai: true}") + private String additionalInformation; + + @AssertTrue(message = "附加信息必须是 JSON 格式") + public boolean isAdditionalInformationJson() { + return StrUtil.isEmpty(additionalInformation) || JsonUtils.isJson(additionalInformation); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java new file mode 100644 index 0000000..ca155c3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java @@ -0,0 +1,34 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.open; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 【开放接口】访问令牌 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2OpenAccessTokenRespVO { + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + @JsonProperty("access_token") + private String accessToken; + + @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") + @JsonProperty("refresh_token") + private String refreshToken; + + @Schema(description = "令牌类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bearer") + @JsonProperty("token_type") + private String tokenType; + + @Schema(description = "过期时间,单位:秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "42430") + @JsonProperty("expires_in") + private Long expiresIn; + + @Schema(description = "授权范围,如果多个授权范围,使用空格分隔", example = "user_info") + private String scope; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenAuthorizeInfoRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenAuthorizeInfoRespVO.java new file mode 100644 index 0000000..ce8f528 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenAuthorizeInfoRespVO.java @@ -0,0 +1,38 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.open; + +import com.tashow.cloud.common.core.KeyValue; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - 授权页的信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2OpenAuthorizeInfoRespVO { + + /** + * 客户端 + */ + private Client client; + + @Schema(description = "scope 的选中信息,使用 List 保证有序性,Key 是 scope,Value 为是否选中", requiredMode = Schema.RequiredMode.REQUIRED) + private List> scopes; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Client { + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + private String name; + + @Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String logo; + + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java new file mode 100644 index 0000000..c3c795b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.open; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - 【开放接口】校验令牌 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2OpenCheckTokenRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + @JsonProperty("user_id") + private Long userId; + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @JsonProperty("user_type") + private Integer userType; + @Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @JsonProperty("tenant_id") + private Long tenantId; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "car") + @JsonProperty("client_id") + private String clientId; + @Schema(description = "授权范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_info") + private List scopes; + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + @JsonProperty("access_token") + private String accessToken; + + @Schema(description = "过期时间,时间戳 / 1000,即单位:秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1593092157") + private Long exp; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java new file mode 100644 index 0000000..b7cc87e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.token; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 访问令牌分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2AccessTokenPageReqVO extends PageParam { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String clientId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java new file mode 100644 index 0000000..8c21701 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.token; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 访问令牌 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2AccessTokenRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + private String accessToken; + + @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") + private String refreshToken; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String clientId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expiresTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/user/OAuth2UserInfoRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/user/OAuth2UserInfoRespVO.java new file mode 100644 index 0000000..45556e8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/user/OAuth2UserInfoRespVO.java @@ -0,0 +1,70 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - OAuth2 获得用户基本信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2UserInfoRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String nickname; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + private String email; + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + /** + * 所在部门 + */ + private Dept dept; + + /** + * 所属岗位数组 + */ + private List posts; + + @Schema(description = "部门") + @Data + public static class Dept { + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") + private String name; + + } + + @Schema(description = "岗位") + @Data + public static class Post { + + @Schema(description = "岗位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "开发") + private String name; + + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/user/OAuth2UserUpdateReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/user/OAuth2UserUpdateReqVO.java new file mode 100644 index 0000000..6b2939a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/oauth2/vo/user/OAuth2UserUpdateReqVO.java @@ -0,0 +1,34 @@ +package com.tashow.cloud.system.controller.admin.oauth2.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Size; + +@Schema(description = "管理后台 - OAuth2 更新用户基本信息 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2UserUpdateReqVO { + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @Size(max = 30, message = "用户昵称长度不能超过 30 个字符") + private String nickname; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + @Email(message = "邮箱格式不正确") + @Size(max = 50, message = "邮箱长度不能超过 50 个字符") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + @Length(min = 11, max = 11, message = "手机号长度必须 11 位") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/MenuController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/MenuController.http new file mode 100644 index 0000000..fbaff1e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/MenuController.http @@ -0,0 +1,4 @@ +### 请求 /menu/list 接口 => 成功 +GET {{baseUrl}}/system/menu/list +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/MenuController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/MenuController.java new file mode 100644 index 0000000..b6e54c8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/MenuController.java @@ -0,0 +1,88 @@ +package com.tashow.cloud.system.controller.admin.permission; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuRespVO; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuSaveVO; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import com.tashow.cloud.system.service.permission.MenuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.Comparator; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 菜单") +@RestController +@RequestMapping("/system/menu") +@Validated +public class MenuController { + + @Resource + private MenuService menuService; + + @PostMapping("/create") + @Operation(summary = "创建菜单") + @PreAuthorize("@ss.hasPermission('system:menu:create')") + public CommonResult createMenu(@Valid @RequestBody MenuSaveVO createReqVO) { + Long menuId = menuService.createMenu(createReqVO); + return success(menuId); + } + + @PutMapping("/update") + @Operation(summary = "修改菜单") + @PreAuthorize("@ss.hasPermission('system:menu:update')") + public CommonResult updateMenu(@Valid @RequestBody MenuSaveVO updateReqVO) { + menuService.updateMenu(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除菜单") + @Parameter(name = "id", description = "菜单编号", required= true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:menu:delete')") + public CommonResult deleteMenu(@RequestParam("id") Long id) { + menuService.deleteMenu(id); + return success(true); + } + + @GetMapping("/list") + @Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面") + @PreAuthorize("@ss.hasPermission('system:menu:query')") + public CommonResult> getMenuList(MenuListReqVO reqVO) { + List list = menuService.getMenuList(reqVO); + list.sort(Comparator.comparing(MenuDO::getSort)); + return success(BeanUtils.toBean(list, MenuRespVO.class)); + } + + @GetMapping({"/list-all-simple", "simple-list"}) + @Operation(summary = "获取菜单精简信息列表", description = "只包含被开启的菜单,用于【角色分配菜单】功能的选项。" + + "在多租户的场景下,会只返回租户所在套餐有的菜单") + public CommonResult> getSimpleMenuList() { + List list = menuService.getMenuListByTenant( + new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); + list = menuService.filterDisableMenus(list); + list.sort(Comparator.comparing(MenuDO::getSort)); + return success(BeanUtils.toBean(list, MenuSimpleRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获取菜单信息") + @PreAuthorize("@ss.hasPermission('system:menu:query')") + public CommonResult getMenu(Long id) { + MenuDO menu = menuService.getMenu(id); + return success(BeanUtils.toBean(menu, MenuRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/PermissionController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/PermissionController.java new file mode 100644 index 0000000..4e3a8e4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/PermissionController.java @@ -0,0 +1,82 @@ +package com.tashow.cloud.system.controller.admin.permission; + +import cn.hutool.core.collection.CollUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.system.controller.admin.permission.vo.permission.PermissionAssignRoleDataScopeReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO; +import com.tashow.cloud.system.service.permission.PermissionService; +import com.tashow.cloud.system.service.tenant.TenantService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.Set; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +/** + * 权限 Controller,提供赋予用户、角色的权限的 API 接口 + * + * @author 芋道源码 + */ +@Tag(name = "管理后台 - 权限") +@RestController +@RequestMapping("/system/permission") +public class PermissionController { + + @Resource + private PermissionService permissionService; + @Resource + private TenantService tenantService; + + @Operation(summary = "获得角色拥有的菜单编号") + @Parameter(name = "roleId", description = "角色编号", required = true) + @GetMapping("/list-role-menus") + @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") + public CommonResult> getRoleMenuList(Long roleId) { + return success(permissionService.getRoleMenuListByRoleId(roleId)); + } + + @PostMapping("/assign-role-menu") + @Operation(summary = "赋予角色菜单") + @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") + public CommonResult assignRoleMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) { + // 开启多租户的情况下,需要过滤掉未开通的菜单 + tenantService.handleTenantMenu(menuIds -> reqVO.getMenuIds().removeIf(menuId -> !CollUtil.contains(menuIds, menuId))); + + // 执行菜单的分配 + permissionService.assignRoleMenu(reqVO.getRoleId(), reqVO.getMenuIds()); + return success(true); + } + + @PostMapping("/assign-role-data-scope") + @Operation(summary = "赋予角色数据权限") + @PreAuthorize("@ss.hasPermission('system:permission:assign-role-data-scope')") + public CommonResult assignRoleDataScope(@Valid @RequestBody PermissionAssignRoleDataScopeReqVO reqVO) { + permissionService.assignRoleDataScope(reqVO.getRoleId(), reqVO.getDataScope(), reqVO.getDataScopeDeptIds()); + return success(true); + } + + @Operation(summary = "获得管理员拥有的角色编号列表") + @Parameter(name = "userId", description = "用户编号", required = true) + @GetMapping("/list-user-roles") + @PreAuthorize("@ss.hasPermission('system:permission:assign-user-role')") + public CommonResult> listAdminRoles(@RequestParam("userId") Long userId) { + return success(permissionService.getUserRoleIdListByUserId(userId)); + } + + @Operation(summary = "赋予用户角色") + @PostMapping("/assign-user-role") + @PreAuthorize("@ss.hasPermission('system:permission:assign-user-role')") + public CommonResult assignUserRole(@Validated @RequestBody PermissionAssignUserRoleReqVO reqVO) { + permissionService.assignUserRole(reqVO.getUserId(), reqVO.getRoleIds()); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/RoleController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/RoleController.http new file mode 100644 index 0000000..375180a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/RoleController.http @@ -0,0 +1,42 @@ +### /role/create 成功 +POST {{baseUrl}}/system/role/create +Authorization: Bearer {{token}} +Content-Type: application/json +tenant-id: {{adminTenantId}} + +{ + "name": "测试角色", + "code": "test", + "sort": 0 +} + +### /role/update 成功 +POST {{baseUrl}}/system/role/update +Authorization: Bearer {{token}} +Content-Type: application/json +tenant-id: {{adminTenantId}} + +{ + "id": 100, + "name": "测试角色", + "code": "test", + "sort": 10 +} +### /resource/delete 成功 +POST {{baseUrl}}/system/role/delete +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +roleId=14 + +### /role/get 成功 +GET {{baseUrl}}/system/role/get?id=100 +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +### /role/page 成功 +GET {{baseUrl}}/system/role/page?pageNo=1&pageSize=10 +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/RoleController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/RoleController.java new file mode 100644 index 0000000..04ad540 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/RoleController.java @@ -0,0 +1,102 @@ +package com.tashow.cloud.system.controller.admin.permission; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RolePageReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleRespVO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.service.permission.RoleService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Comparator; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static java.util.Collections.singleton; + +@Tag(name = "管理后台 - 角色") +@RestController +@RequestMapping("/system/role") +@Validated +public class RoleController { + + @Resource + private RoleService roleService; + + @PostMapping("/create") + @Operation(summary = "创建角色") + @PreAuthorize("@ss.hasPermission('system:role:create')") + public CommonResult createRole(@Valid @RequestBody RoleSaveReqVO createReqVO) { + return success(roleService.createRole(createReqVO, null)); + } + + @PutMapping("/update") + @Operation(summary = "修改角色") + @PreAuthorize("@ss.hasPermission('system:role:update')") + public CommonResult updateRole(@Valid @RequestBody RoleSaveReqVO updateReqVO) { + roleService.updateRole(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除角色") + @Parameter(name = "id", description = "角色编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:role:delete')") + public CommonResult deleteRole(@RequestParam("id") Long id) { + roleService.deleteRole(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得角色信息") + @PreAuthorize("@ss.hasPermission('system:role:query')") + public CommonResult getRole(@RequestParam("id") Long id) { + RoleDO role = roleService.getRole(id); + return success(BeanUtils.toBean(role, RoleRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得角色分页") + @PreAuthorize("@ss.hasPermission('system:role:query')") + public CommonResult> getRolePage(RolePageReqVO pageReqVO) { + PageResult pageResult = roleService.getRolePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RoleRespVO.class)); + } + + @GetMapping({"/list-all-simple", "/simple-list"}) + @Operation(summary = "获取角色精简信息列表", description = "只包含被开启的角色,主要用于前端的下拉选项") + public CommonResult> getSimpleRoleList() { + List list = roleService.getRoleListByStatus(singleton(CommonStatusEnum.ENABLE.getStatus())); + list.sort(Comparator.comparing(RoleDO::getSort)); + return success(BeanUtils.toBean(list, RoleRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出角色 Excel") + @ApiAccessLog(operateType = EXPORT) + @PreAuthorize("@ss.hasPermission('system:role:export')") + public void export(HttpServletResponse response, @Validated RolePageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = roleService.getRolePage(exportReqVO).getList(); + // 输出 + ExcelUtils.write(response, "角色数据.xls", "数据", RoleRespVO.class, + BeanUtils.toBean(list, RoleRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuListReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuListReqVO.java new file mode 100644 index 0000000..fbd2dcc --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuListReqVO.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 菜单列表 Request VO") +@Data +public class MenuListReqVO { + + @Schema(description = "菜单名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuRespVO.java new file mode 100644 index 0000000..e7560fd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuRespVO.java @@ -0,0 +1,69 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 菜单信息 Response VO") +@Data +public class MenuRespVO { + + @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "菜单名称不能为空") + @Size(max = 50, message = "菜单名称长度不能超过50个字符") + private String name; + + @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") + @Size(max = 100) + private String permission; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "菜单类型不能为空") + private Integer type; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "父菜单 ID 不能为空") + private Long parentId; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + @Size(max = 200, message = "路由地址不能超过200个字符") + private String path; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + @Size(max = 200, message = "组件路径不能超过255个字符") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "是否可见", example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuSaveVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuSaveVO.java new file mode 100644 index 0000000..02fde3c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuSaveVO.java @@ -0,0 +1,64 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Schema(description = "管理后台 - 菜单创建/修改 Request VO") +@Data +public class MenuSaveVO { + + @Schema(description = "菜单编号", example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "菜单名称不能为空") + @Size(max = 50, message = "菜单名称长度不能超过50个字符") + private String name; + + @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") + @Size(max = 100) + private String permission; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "菜单类型不能为空") + private Integer type; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "父菜单 ID 不能为空") + private Long parentId; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + @Size(max = 200, message = "路由地址不能超过200个字符") + private String path; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + @Size(max = 200, message = "组件路径不能超过255个字符") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "是否可见", example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuSimpleRespVO.java new file mode 100644 index 0000000..495531b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/menu/MenuSimpleRespVO.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 菜单精简信息 Response VO") +@Data +public class MenuSimpleRespVO { + + @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignRoleDataScopeReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignRoleDataScopeReqVO.java new file mode 100644 index 0000000..259001a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignRoleDataScopeReqVO.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.permission; + +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.systemapi.enums.permission.DataScopeEnum; +import com.tashow.cloud.systemapi.enums.permission.DataScopeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.util.Collections; +import java.util.Set; + +@Schema(description = "管理后台 - 赋予角色数据权限 Request VO") +@Data +public class PermissionAssignRoleDataScopeReqVO { + + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "角色编号不能为空") + private Long roleId; + + @Schema(description = "数据范围,参见 DataScopeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数据范围不能为空") + @InEnum(value = DataScopeEnum.class, message = "数据范围必须是 {value}") + private Integer dataScope; + + @Schema(description = "部门编号列表,只有范围类型为 DEPT_CUSTOM 时,该字段才需要", example = "1,3,5") + private Set dataScopeDeptIds = Collections.emptySet(); // 兜底 + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignRoleMenuReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignRoleMenuReqVO.java new file mode 100644 index 0000000..cd559b0 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignRoleMenuReqVO.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.permission; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.util.Collections; +import java.util.Set; + +@Schema(description = "管理后台 - 赋予角色菜单 Request VO") +@Data +public class PermissionAssignRoleMenuReqVO { + + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "角色编号不能为空") + private Long roleId; + + @Schema(description = "菜单编号列表", example = "1,3,5") + private Set menuIds = Collections.emptySet(); // 兜底 + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignUserRoleReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignUserRoleReqVO.java new file mode 100644 index 0000000..5100223 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/permission/PermissionAssignUserRoleReqVO.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.permission; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.util.Collections; +import java.util.Set; + +@Schema(description = "管理后台 - 赋予用户角色 Request VO") +@Data +public class PermissionAssignUserRoleReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "角色编号列表", example = "1,3,5") + private Set roleIds = Collections.emptySet(); // 兜底 + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RolePageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RolePageReqVO.java new file mode 100644 index 0000000..b54a38d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RolePageReqVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.role; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 角色分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class RolePageReqVO extends PageParam { + + @Schema(description = "角色名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "角色标识,模糊匹配", example = "yudao") + private String code; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleRespVO.java new file mode 100644 index 0000000..50e38da --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleRespVO.java @@ -0,0 +1,60 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.role; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 角色信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class RoleRespVO { + + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("角色序号") + private Long id; + + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "管理员") + @ExcelProperty("角色名称") + private String name; + + @Schema(description = "角色标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin") + @NotBlank(message = "角色标志不能为空") + @ExcelProperty("角色标志") + private String code; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("角色排序") + private Integer sort; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "角色状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "角色类型,参见 RoleTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "备注", example = "我是一个角色") + private String remark; + + @Schema(description = "数据范围,参见 DataScopeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "数据范围", converter = DictConvert.class) + @DictFormat(DictTypeConstants.DATA_SCOPE) + private Integer dataScope; + + @Schema(description = "数据范围(指定部门数组)", example = "1") + private Set dataScopeDeptIds; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleSaveReqVO.java new file mode 100644 index 0000000..6e7c348 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleSaveReqVO.java @@ -0,0 +1,47 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.role; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.validation.InEnum; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Schema(description = "管理后台 - 角色创建/更新 Request VO") +@Data +public class RoleSaveReqVO { + + @Schema(description = "角色编号", example = "1") + private Long id; + + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "管理员") + @NotBlank(message = "角色名称不能为空") + @Size(max = 30, message = "角色名称长度不能超过 30 个字符") + @DiffLogField(name = "角色名称") + private String name; + + @NotBlank(message = "角色标志不能为空") + @Size(max = 100, message = "角色标志长度不能超过 100 个字符") + @Schema(description = "角色标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "ADMIN") + @DiffLogField(name = "角色标志") + private String code; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + @DiffLogField(name = "显示顺序") + private Integer sort; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @DiffLogField(name = "状态") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + + @Schema(description = "备注", example = "我是一个角色") + @Size(max = 500, message = "备注长度不能超过 500 个字符") + @DiffLogField(name = "备注") + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleSimpleRespVO.java new file mode 100644 index 0000000..495f525 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/permission/vo/role/RoleSimpleRespVO.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.system.controller.admin.permission.vo.role; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 角色精简信息 Response VO") +@Data +public class RoleSimpleRespVO { + + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsCallbackController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsCallbackController.java new file mode 100644 index 0000000..36057ea --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsCallbackController.java @@ -0,0 +1,60 @@ +package com.tashow.cloud.system.controller.admin.sms; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.system.framework.sms.core.enums.SmsChannelEnum; +import com.tashow.cloud.system.service.sms.SmsSendService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import jakarta.servlet.http.HttpServletRequest; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 短信回调") +@RestController +@RequestMapping("/system/sms/callback") +public class SmsCallbackController { + + @Resource + private SmsSendService smsSendService; + + @PostMapping("/aliyun") + @PermitAll + @Operation(summary = "阿里云短信的回调", description = "参见 https://help.aliyun.com/document_detail/120998.html 文档") + public CommonResult receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable { + String text = ServletUtils.getBody(request); + smsSendService.receiveSmsStatus(SmsChannelEnum.ALIYUN.getCode(), text); + return success(true); + } + + @PostMapping("/tencent") + @PermitAll + @Operation(summary = "腾讯云短信的回调", description = "参见 https://cloud.tencent.com/document/product/382/52077 文档") + public CommonResult receiveTencentSmsStatus(HttpServletRequest request) throws Throwable { + String text = ServletUtils.getBody(request); + smsSendService.receiveSmsStatus(SmsChannelEnum.TENCENT.getCode(), text); + return success(true); + } + + + @PostMapping("/huawei") + @PermitAll + @Operation(summary = "华为云短信的回调", description = "参见 https://support.huaweicloud.com/api-msgsms/sms_05_0003.html 文档") + public CommonResult receiveHuaweiSmsStatus(@RequestBody String requestBody) throws Throwable { + smsSendService.receiveSmsStatus(SmsChannelEnum.HUAWEI.getCode(), requestBody); + return success(true); + } + + @PostMapping("/qiniu") + @PermitAll + @Operation(summary = "七牛云短信的回调", description = "参见 https://developer.qiniu.com/sms/5910/message-push 文档") + public CommonResult receiveQiniuSmsStatus(@RequestBody String requestBody) throws Throwable { + smsSendService.receiveSmsStatus(SmsChannelEnum.QINIU.getCode(), requestBody); + return success(true); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsChannelController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsChannelController.java new file mode 100644 index 0000000..530fd2b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsChannelController.java @@ -0,0 +1,82 @@ +package com.tashow.cloud.system.controller.admin.sms; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelRespVO; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsChannelDO; +import com.tashow.cloud.system.service.sms.SmsChannelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.Comparator; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 短信渠道") +@RestController +@RequestMapping("system/sms-channel") +public class SmsChannelController { + + @Resource + private SmsChannelService smsChannelService; + + @PostMapping("/create") + @Operation(summary = "创建短信渠道") + @PreAuthorize("@ss.hasPermission('system:sms-channel:create')") + public CommonResult createSmsChannel(@Valid @RequestBody SmsChannelSaveReqVO createReqVO) { + return success(smsChannelService.createSmsChannel(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新短信渠道") + @PreAuthorize("@ss.hasPermission('system:sms-channel:update')") + public CommonResult updateSmsChannel(@Valid @RequestBody SmsChannelSaveReqVO updateReqVO) { + smsChannelService.updateSmsChannel(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除短信渠道") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:sms-channel:delete')") + public CommonResult deleteSmsChannel(@RequestParam("id") Long id) { + smsChannelService.deleteSmsChannel(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得短信渠道") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:sms-channel:query')") + public CommonResult getSmsChannel(@RequestParam("id") Long id) { + SmsChannelDO channel = smsChannelService.getSmsChannel(id); + return success(BeanUtils.toBean(channel, SmsChannelRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得短信渠道分页") + @PreAuthorize("@ss.hasPermission('system:sms-channel:query')") + public CommonResult> getSmsChannelPage(@Valid SmsChannelPageReqVO pageVO) { + PageResult pageResult = smsChannelService.getSmsChannelPage(pageVO); + return success(BeanUtils.toBean(pageResult, SmsChannelRespVO.class)); + } + + @GetMapping({"/list-all-simple", "/simple-list"}) + @Operation(summary = "获得短信渠道精简列表", description = "包含被禁用的短信渠道") + public CommonResult> getSimpleSmsChannelList() { + List list = smsChannelService.getSmsChannelList(); + list.sort(Comparator.comparing(SmsChannelDO::getId)); + return success(BeanUtils.toBean(list, SmsChannelSimpleRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsLogController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsLogController.java new file mode 100644 index 0000000..b7ee673 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsLogController.java @@ -0,0 +1,60 @@ +package com.tashow.cloud.system.controller.admin.sms; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.log.SmsLogRespVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsLogDO; +import com.tashow.cloud.system.service.sms.SmsLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 短信日志") +@RestController +@RequestMapping("/system/sms-log") +@Validated +public class SmsLogController { + + @Resource + private SmsLogService smsLogService; + + @GetMapping("/page") + @Operation(summary = "获得短信日志分页") + @PreAuthorize("@ss.hasPermission('system:sms-log:query')") + public CommonResult> getSmsLogPage(@Valid SmsLogPageReqVO pageReqVO) { + PageResult pageResult = smsLogService.getSmsLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, SmsLogRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出短信日志 Excel") + @PreAuthorize("@ss.hasPermission('system:sms-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSmsLogExcel(@Valid SmsLogPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = smsLogService.getSmsLogPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "短信日志.xls", "数据", SmsLogRespVO.class, + BeanUtils.toBean(list, SmsLogRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsTemplateController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsTemplateController.http new file mode 100644 index 0000000..3b975c3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsTemplateController.http @@ -0,0 +1,14 @@ +### 请求 /system/sms-template/send-sms 接口 => 成功 +POST {{baseUrl}}/system/sms-template/send-sms +Authorization: Bearer {{token}} +Content-Type: application/json +tenant-id: {{adminTenantId}} + +{ + "templateCode": "test_01", + "mobile": "15601691390", + "templateParams": { + "operation": "value01", + "code": "value02" + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsTemplateController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsTemplateController.java new file mode 100644 index 0000000..8a7405a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/SmsTemplateController.java @@ -0,0 +1,103 @@ +package com.tashow.cloud.system.controller.admin.sms; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplateRespVO; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplateSendReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsTemplateDO; +import com.tashow.cloud.system.service.sms.SmsSendService; +import com.tashow.cloud.system.service.sms.SmsTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 短信模板") +@RestController +@RequestMapping("/system/sms-template") +public class SmsTemplateController { + + @Resource + private SmsTemplateService smsTemplateService; + @Resource + private SmsSendService smsSendService; + + @PostMapping("/create") + @Operation(summary = "创建短信模板") + @PreAuthorize("@ss.hasPermission('system:sms-template:create')") + public CommonResult createSmsTemplate(@Valid @RequestBody SmsTemplateSaveReqVO createReqVO) { + return success(smsTemplateService.createSmsTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新短信模板") + @PreAuthorize("@ss.hasPermission('system:sms-template:update')") + public CommonResult updateSmsTemplate(@Valid @RequestBody SmsTemplateSaveReqVO updateReqVO) { + smsTemplateService.updateSmsTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除短信模板") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:sms-template:delete')") + public CommonResult deleteSmsTemplate(@RequestParam("id") Long id) { + smsTemplateService.deleteSmsTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得短信模板") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:sms-template:query')") + public CommonResult getSmsTemplate(@RequestParam("id") Long id) { + SmsTemplateDO template = smsTemplateService.getSmsTemplate(id); + return success(BeanUtils.toBean(template, SmsTemplateRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得短信模板分页") + @PreAuthorize("@ss.hasPermission('system:sms-template:query')") + public CommonResult> getSmsTemplatePage(@Valid SmsTemplatePageReqVO pageVO) { + PageResult pageResult = smsTemplateService.getSmsTemplatePage(pageVO); + return success(BeanUtils.toBean(pageResult, SmsTemplateRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出短信模板 Excel") + @PreAuthorize("@ss.hasPermission('system:sms-template:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSmsTemplateExcel(@Valid SmsTemplatePageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = smsTemplateService.getSmsTemplatePage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "短信模板.xls", "数据", SmsTemplateRespVO.class, + BeanUtils.toBean(list, SmsTemplateRespVO.class)); + } + + @PostMapping("/send-sms") + @Operation(summary = "发送短信") + @PreAuthorize("@ss.hasPermission('system:sms-template:send-sms')") + public CommonResult sendSms(@Valid @RequestBody SmsTemplateSendReqVO sendReqVO) { + return success(smsSendService.sendSingleSmsToAdmin(sendReqVO.getMobile(), null, + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java new file mode 100644 index 0000000..b5443cd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.channel; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 短信渠道分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsChannelPageReqVO extends PageParam { + + @Schema(description = "任务状态", example = "1") + private Integer status; + + @Schema(description = "短信签名,模糊匹配", example = "芋道源码") + private String signature; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelRespVO.java new file mode 100644 index 0000000..9545dee --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelRespVO.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.channel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 短信渠道 Response VO") +@Data +public class SmsChannelRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "短信签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotNull(message = "短信签名不能为空") + private String signature; + + @Schema(description = "渠道编码,参见 SmsChannelEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "YUN_PIAN") + private String code; + + @Schema(description = "启用状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "启用状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "好吃!") + private String remark; + + @Schema(description = "短信 API 的账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "短信 API 的账号不能为空") + private String apiKey; + + @Schema(description = "短信 API 的密钥", example = "yuanma") + private String apiSecret; + + @Schema(description = "短信发送回调 URL", example = "https://www.iocoder.cn") + @URL(message = "回调 URL 格式不正确") + private String callbackUrl; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelSaveReqVO.java new file mode 100644 index 0000000..ede9f38 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelSaveReqVO.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.channel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 短信渠道创建/修改 Request VO") +@Data +public class SmsChannelSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "短信签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotNull(message = "短信签名不能为空") + private String signature; + + @Schema(description = "渠道编码,参见 SmsChannelEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "YUN_PIAN") + @NotNull(message = "渠道编码不能为空") + private String code; + + @Schema(description = "启用状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "启用状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "好吃!") + private String remark; + + @Schema(description = "短信 API 的账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "短信 API 的账号不能为空") + private String apiKey; + + @Schema(description = "短信 API 的密钥", example = "yuanma") + private String apiSecret; + + @Schema(description = "短信发送回调 URL", example = "http://www.iocoder.cn") + @URL(message = "回调 URL 格式不正确") + private String callbackUrl; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelSimpleRespVO.java new file mode 100644 index 0000000..75c0623 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/channel/SmsChannelSimpleRespVO.java @@ -0,0 +1,19 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.channel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 短信渠道精简 Response VO") +@Data +public class SmsChannelSimpleRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "短信签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String signature; + + @Schema(description = "渠道编码,参见 SmsChannelEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "YUN_PIAN") + private String code; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java new file mode 100644 index 0000000..86782c3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java @@ -0,0 +1,43 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.log; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 短信日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsLogPageReqVO extends PageParam { + + @Schema(description = "短信渠道编号", example = "10") + private Long channelId; + + @Schema(description = "模板编号", example = "20") + private Long templateId; + + @Schema(description = "手机号", example = "15601691300") + private String mobile; + + @Schema(description = "发送状态,参见 SmsSendStatusEnum 枚举类", example = "1") + private Integer sendStatus; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "发送时间") + private LocalDateTime[] sendTime; + + @Schema(description = "接收状态,参见 SmsReceiveStatusEnum 枚举类", example = "0") + private Integer receiveStatus; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "接收时间") + private LocalDateTime[] receiveTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/log/SmsLogRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/log/SmsLogRespVO.java new file mode 100644 index 0000000..c8d1203 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/log/SmsLogRespVO.java @@ -0,0 +1,116 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.log; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.excel.excel.core.convert.JsonConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Map; + +@Schema(description = "管理后台 - 短信日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class SmsLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "短信渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("短信渠道编号") + private Long channelId; + + @Schema(description = "短信渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ALIYUN") + @ExcelProperty("短信渠道编码") + private String channelCode; + + @Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + @ExcelProperty("模板编号") + private Long templateId; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test-01") + @ExcelProperty("模板编码") + private String templateCode; + + @Schema(description = "短信类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "短信类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_TEMPLATE_TYPE) + private Integer templateType; + + @Schema(description = "短信内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你的验证码是 1024") + @ExcelProperty("短信内容") + private String templateContent; + + @Schema(description = "短信参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "name,code") + @ExcelProperty(value = "短信参数", converter = JsonConvert.class) + private Map templateParams; + + @Schema(description = "短信 API 的模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "SMS_207945135") + @ExcelProperty("短信 API 的模板编号") + private String apiTemplateId; + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @ExcelProperty("手机号") + private String mobile; + + @Schema(description = "用户编号", example = "10") + @ExcelProperty("用户编号") + private Long userId; + + @Schema(description = "用户类型", example = "1") + @ExcelProperty(value = "用户类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.USER_TYPE) + private Integer userType; + + @Schema(description = "发送状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "发送状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_SEND_STATUS) + private Integer sendStatus; + + @Schema(description = "发送时间") + @ExcelProperty("发送时间") + private LocalDateTime sendTime; + + @Schema(description = "短信 API 发送结果的编码", example = "SUCCESS") + @ExcelProperty("短信 API 发送结果的编码") + private String apiSendCode; + + @Schema(description = "短信 API 发送失败的提示", example = "成功") + @ExcelProperty("短信 API 发送失败的提示") + private String apiSendMsg; + + @Schema(description = "短信 API 发送返回的唯一请求 ID", example = "3837C6D3-B96F-428C-BBB2-86135D4B5B99") + @ExcelProperty("短信 API 发送返回的唯一请求 ID") + private String apiRequestId; + + @Schema(description = "短信 API 发送返回的序号", example = "62923244790") + @ExcelProperty("短信 API 发送返回的序号") + private String apiSerialNo; + + @Schema(description = "接收状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty(value = "接收状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_RECEIVE_STATUS) + private Integer receiveStatus; + + @Schema(description = "接收时间") + @ExcelProperty("接收时间") + private LocalDateTime receiveTime; + + @Schema(description = "API 接收结果的编码", example = "DELIVRD") + @ExcelProperty("API 接收结果的编码") + private String apiReceiveCode; + + @Schema(description = "API 接收结果的说明", example = "用户接收成功") + @ExcelProperty("API 接收结果的说明") + private String apiReceiveMsg; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java new file mode 100644 index 0000000..6f10591 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.template; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 短信模板分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsTemplatePageReqVO extends PageParam { + + @Schema(description = "短信签名", example = "1") + private Integer type; + + @Schema(description = "开启状态", example = "1") + private Integer status; + + @Schema(description = "模板编码,模糊匹配", example = "test_01") + private String code; + + @Schema(description = "模板内容,模糊匹配", example = "你好,{name}。你长的太{like}啦!") + private String content; + + @Schema(description = "短信 API 的模板编号,模糊匹配", example = "4383920") + private String apiTemplateId; + + @Schema(description = "短信渠道编号", example = "10") + private Long channelId; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateRespVO.java new file mode 100644 index 0000000..00aac1d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateRespVO.java @@ -0,0 +1,70 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.template; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 短信模板 Response VO") +@Data +@ExcelIgnoreUnannotated +public class SmsTemplateRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "短信类型,参见 SmsTemplateTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "短信签名", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_TEMPLATE_TYPE) + private Integer type; + + @Schema(description = "开启状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + @ExcelProperty("模板编码") + private String code; + + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @ExcelProperty("模板名称") + private String name; + + @Schema(description = "模板内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,{name}。你长的太{like}啦!") + @ExcelProperty("模板内容") + private String content; + + @Schema(description = "参数数组", example = "name,code") + private List params; + + @Schema(description = "备注", example = "哈哈哈") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "短信 API 的模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4383920") + @ExcelProperty("短信 API 的模板编号") + private String apiTemplateId; + + @Schema(description = "短信渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("短信渠道编号") + private Long channelId; + + @Schema(description = "短信渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ALIYUN") + @ExcelProperty(value = "短信渠道编码", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_CHANNEL_CODE) + private String channelCode; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateSaveReqVO.java new file mode 100644 index 0000000..f93c19a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateSaveReqVO.java @@ -0,0 +1,46 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 短信模板创建/修改 Request VO") +@Data +public class SmsTemplateSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "短信类型,参见 SmsTemplateTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "短信类型不能为空") + private Integer type; + + @Schema(description = "开启状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + private Integer status; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + @NotNull(message = "模板编码不能为空") + private String code; + + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "模板名称不能为空") + private String name; + + @Schema(description = "模板内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,{name}。你长的太{like}啦!") + @NotNull(message = "模板内容不能为空") + private String content; + + @Schema(description = "备注", example = "哈哈哈") + private String remark; + + @Schema(description = "短信 API 的模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4383920") + @NotNull(message = "短信 API 的模板编号不能为空") + private String apiTemplateId; + + @Schema(description = "短信渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "短信渠道编号不能为空") + private Long channelId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateSendReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateSendReqVO.java new file mode 100644 index 0000000..be801c4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/sms/vo/template/SmsTemplateSendReqVO.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.system.controller.admin.sms.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 短信模板的发送 Request VO") +@Data +public class SmsTemplateSendReqVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @NotNull(message = "手机号不能为空") + private String mobile; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + @NotNull(message = "模板编码不能为空") + private String templateCode; + + @Schema(description = "模板参数") + private Map templateParams; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialClientController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialClientController.http new file mode 100644 index 0000000..9909b51 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialClientController.http @@ -0,0 +1,20 @@ +### 请求 /system/social-client/send-subscribe-message 接口 => 发送测试订阅消息 +POST {{baseUrl}}/system/social-client/send-subscribe-message +Authorization: Bearer {{token}} +Content-Type: application/json +#Authorization: Bearer test100 +tenant-id: {{adminTenantId}} + +{ + "userId": 247, + "userType": 1, + "socialType": 34, + "templateTitle": "充值成功通知", + "page": "", + "messages": { + "character_string1":"5616122165165", + "amount2":"1000.00", + "time3":"2024-01-01 10:10:10", + "phrase4": "充值成功" + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialClientController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialClientController.java new file mode 100644 index 0000000..ea4fd34 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialClientController.java @@ -0,0 +1,88 @@ +package com.tashow.cloud.system.controller.admin.socail; + +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.social.SocialClientApi; +import com.tashow.cloud.systemapi.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientRespVO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialClientDO; +import com.tashow.cloud.system.service.social.SocialClientService; +import com.tashow.cloud.systemapi.api.social.SocialClientApi; +import com.tashow.cloud.systemapi.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientRespVO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 社交客户端") +@RestController +@RequestMapping("/system/social-client") +@Validated +public class SocialClientController { + + @Resource + private SocialClientService socialClientService; + @Resource + private SocialClientApi socialClientApi; + + @PostMapping("/create") + @Operation(summary = "创建社交客户端") + @PreAuthorize("@ss.hasPermission('system:social-client:create')") + public CommonResult createSocialClient(@Valid @RequestBody SocialClientSaveReqVO createReqVO) { + return success(socialClientService.createSocialClient(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新社交客户端") + @PreAuthorize("@ss.hasPermission('system:social-client:update')") + public CommonResult updateSocialClient(@Valid @RequestBody SocialClientSaveReqVO updateReqVO) { + socialClientService.updateSocialClient(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除社交客户端") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:social-client:delete')") + public CommonResult deleteSocialClient(@RequestParam("id") Long id) { + socialClientService.deleteSocialClient(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得社交客户端") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:social-client:query')") + public CommonResult getSocialClient(@RequestParam("id") Long id) { + SocialClientDO client = socialClientService.getSocialClient(id); + return success(BeanUtils.toBean(client, SocialClientRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得社交客户端分页") + @PreAuthorize("@ss.hasPermission('system:social-client:query')") + public CommonResult> getSocialClientPage(@Valid SocialClientPageReqVO pageVO) { + PageResult pageResult = socialClientService.getSocialClientPage(pageVO); + return success(BeanUtils.toBean(pageResult, SocialClientRespVO.class)); + } + + @PostMapping("/send-subscribe-message") + @Operation(summary = "发送订阅消息") // 用于测试 + @PreAuthorize("@ss.hasPermission('system:social-client:query')") + public void sendSubscribeMessage(@RequestBody SocialWxaSubscribeMessageSendReqDTO reqDTO) { + socialClientApi.sendWxaSubscribeMessage(reqDTO).checkError(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialUserController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialUserController.java new file mode 100644 index 0000000..bf93173 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/SocialUserController.java @@ -0,0 +1,70 @@ +package com.tashow.cloud.system.controller.admin.socail; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserBindReqVO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserRespVO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserUnbindReqVO; +import com.tashow.cloud.system.convert.social.SocialUserConvert; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserDO; +import com.tashow.cloud.system.service.social.SocialUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 社交用户") +@RestController +@RequestMapping("/system/social-user") +@Validated +public class SocialUserController { + + @Resource + private SocialUserService socialUserService; + + @PostMapping("/bind") + @Operation(summary = "社交绑定,使用 code 授权码") + public CommonResult socialBind(@RequestBody @Valid SocialUserBindReqVO reqVO) { + socialUserService.bindSocialUser(SocialUserConvert.INSTANCE.convert( + getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO)); + return CommonResult.success(true); + } + + @DeleteMapping("/unbind") + @Operation(summary = "取消社交绑定") + public CommonResult socialUnbind(@RequestBody SocialUserUnbindReqVO reqVO) { + socialUserService.unbindSocialUser(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getOpenid()); + return CommonResult.success(true); + } + + // ==================== 社交用户 CRUD ==================== + + @GetMapping("/get") + @Operation(summary = "获得社交用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:social-user:query')") + public CommonResult getSocialUser(@RequestParam("id") Long id) { + SocialUserDO socialUser = socialUserService.getSocialUser(id); + return success(BeanUtils.toBean(socialUser, SocialUserRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得社交用户分页") + @PreAuthorize("@ss.hasPermission('system:social-user:query')") + public CommonResult> getSocialUserPage(@Valid SocialUserPageReqVO pageVO) { + PageResult pageResult = socialUserService.getSocialUserPage(pageVO); + return success(BeanUtils.toBean(pageResult, SocialUserRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientPageReqVO.java new file mode 100644 index 0000000..1fb008a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientPageReqVO.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.system.controller.admin.socail.vo.client; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 社交客户端分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SocialClientPageReqVO extends PageParam { + + @Schema(description = "应用名", example = "yudao商城") + private String name; + + @Schema(description = "社交平台的类型", example = "31") + private Integer socialType; + + @Schema(description = "用户类型", example = "2") + private Integer userType; + + @Schema(description = "客户端编号", example = "145442115") + private String clientId; + + @Schema(description = "状态", example = "1") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientRespVO.java new file mode 100644 index 0000000..2607182 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientRespVO.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.system.controller.admin.socail.vo.client; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 社交客户端 Response VO") +@Data +public class SocialClientRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27162") + private Long id; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao商城") + private String name; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "31") + private Integer socialType; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "wwd411c69a39ad2e54") + private String clientId; + + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter") + private String clientSecret; + + @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") + private String agentId; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java new file mode 100644 index 0000000..951388d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java @@ -0,0 +1,62 @@ +package com.tashow.cloud.system.controller.admin.socail.vo.client; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotNull; +import java.util.Objects; + +@Schema(description = "管理后台 - 社交客户端创建/修改 Request VO") +@Data +public class SocialClientSaveReqVO { + + @Schema(description = "编号", example = "27162") + private Long id; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao商城") + @NotNull(message = "应用名不能为空") + private String name; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "31") + @NotNull(message = "社交平台的类型不能为空") + @InEnum(SocialTypeEnum.class) + private Integer socialType; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "用户类型不能为空") + @InEnum(UserTypeEnum.class) + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "wwd411c69a39ad2e54") + @NotNull(message = "客户端编号不能为空") + private String clientId; + + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter") + @NotNull(message = "客户端密钥不能为空") + private String clientSecret; + + @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") + private String agentId; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @AssertTrue(message = "agentId 不能为空") + @JsonIgnore + public boolean isAgentIdValid() { + // 如果是企业微信,必须填写 agentId 属性 + return !Objects.equals(socialType, SocialTypeEnum.WECHAT_ENTERPRISE.getType()) + || !StrUtil.isEmpty(agentId); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserBindReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserBindReqVO.java new file mode 100644 index 0000000..8379a3f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserBindReqVO.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.controller.admin.socail.vo.user; + +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 社交绑定 Request VO,使用 code 授权码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SocialUserBindReqVO { + + @Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java new file mode 100644 index 0000000..d7ff52b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.system.controller.admin.socail.vo.user; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 社交用户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SocialUserPageReqVO extends PageParam { + + @Schema(description = "社交平台的类型", example = "30") + private Integer type; + + @Schema(description = "用户昵称", example = "李四") + private String nickname; + + @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w") + private String openid; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserRespVO.java new file mode 100644 index 0000000..afecee6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserRespVO.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.system.controller.admin.socail.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 社交用户 Response VO") +@Data +public class SocialUserRespVO { + + @Schema(description = "主键(自增策略)", requiredMode = Schema.RequiredMode.REQUIRED, example = "14569") + private Long id; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") + private Integer type; + + @Schema(description = "社交 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private String openid; + + @Schema(description = "社交 token", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private String token; + + @Schema(description = "原始 Token 数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + private String rawTokenInfo; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + @Schema(description = "原始用户数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + private String rawUserInfo; + + @Schema(description = "最后一次的认证 code", requiredMode = Schema.RequiredMode.REQUIRED, example = "666666") + private String code; + + @Schema(description = "最后一次的认证 state", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + private String state; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserUnbindReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserUnbindReqVO.java new file mode 100644 index 0000000..51a73ec --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/socail/vo/user/SocialUserUnbindReqVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.system.controller.admin.socail.vo.user; + +import com.tashow.cloud.common.validation.InEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 取消社交绑定 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SocialUserUnbindReqVO { + + @Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "社交用户的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE") + @NotEmpty(message = "社交用户的 openid 不能为空") + private String openid; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantController.http new file mode 100644 index 0000000..38aa594 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantController.http @@ -0,0 +1,21 @@ +### 获取租户编号 /admin-api/system/get-id-by-name +GET {{baseUrl}}/system/tenant/get-id-by-name?name=芋道源码 + +### 创建租户 /admin-api/system/tenant/create +POST {{baseUrl}}/system/tenant/create +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +{ + "name": "芋道", + "contactName": "芋艿", + "contactMobile": "15601691300", + "status": 0, + "domain": "https://www.iocoder.cn", + "packageId": 110, + "expireTime": 1699545600000, + "accountCount": 20, + "username": "admin", + "password": "123321" +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantController.java new file mode 100644 index 0000000..28ac9c3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantController.java @@ -0,0 +1,111 @@ +package com.tashow.cloud.system.controller.admin.tenant; + +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantRespVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantDO; +import com.tashow.cloud.system.service.tenant.TenantService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 租户") +@RestController +@RequestMapping("/system/tenant") +public class TenantController { + + @Resource + private TenantService tenantService; + + @GetMapping("/get-id-by-name") + @PermitAll + @Operation(summary = "使用租户名,获得租户编号", description = "登录界面,根据用户的租户名,获得租户编号") + @Parameter(name = "name", description = "租户名", required = true, example = "1024") + public CommonResult getTenantIdByName(@RequestParam("name") String name) { + TenantDO tenant = tenantService.getTenantByName(name); + return success(tenant != null ? tenant.getId() : null); + } + + @GetMapping("/get-by-website") + @PermitAll + @Operation(summary = "使用域名,获得租户信息", description = "登录界面,根据用户的域名,获得租户信息") + @Parameter(name = "website", description = "域名", required = true, example = "www.iocoder.cn") + public CommonResult getTenantByWebsite(@RequestParam("website") String website) { + TenantDO tenant = tenantService.getTenantByWebsite(website); + return success(BeanUtils.toBean(tenant, TenantSimpleRespVO.class)); + } + + @PostMapping("/create") + @Operation(summary = "创建租户") + @PreAuthorize("@ss.hasPermission('system:tenant:create')") + public CommonResult createTenant(@Valid @RequestBody TenantSaveReqVO createReqVO) { + return success(tenantService.createTenant(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租户") + @PreAuthorize("@ss.hasPermission('system:tenant:update')") + public CommonResult updateTenant(@Valid @RequestBody TenantSaveReqVO updateReqVO) { + tenantService.updateTenant(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant:delete')") + public CommonResult deleteTenant(@RequestParam("id") Long id) { + tenantService.deleteTenant(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant:query')") + public CommonResult getTenant(@RequestParam("id") Long id) { + TenantDO tenant = tenantService.getTenant(id); + return success(BeanUtils.toBean(tenant, TenantRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租户分页") + @PreAuthorize("@ss.hasPermission('system:tenant:query')") + public CommonResult> getTenantPage(@Valid TenantPageReqVO pageVO) { + PageResult pageResult = tenantService.getTenantPage(pageVO); + return success(BeanUtils.toBean(pageResult, TenantRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出租户 Excel") + @PreAuthorize("@ss.hasPermission('system:tenant:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportTenantExcel(@Valid TenantPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = tenantService.getTenantPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "租户.xls", "数据", TenantRespVO.class, + BeanUtils.toBean(list, TenantRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantPackageController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantPackageController.java new file mode 100644 index 0000000..2105ae4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/TenantPackageController.java @@ -0,0 +1,85 @@ +package com.tashow.cloud.system.controller.admin.tenant; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageRespVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantPackageDO; +import com.tashow.cloud.system.service.tenant.TenantPackageService; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageSimpleRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 租户套餐") +@RestController +@RequestMapping("/system/tenant-package") +@Validated +public class TenantPackageController { + + @Resource + private TenantPackageService tenantPackageService; + + @PostMapping("/create") + @Operation(summary = "创建租户套餐") + @PreAuthorize("@ss.hasPermission('system:tenant-package:create')") + public CommonResult createTenantPackage(@Valid @RequestBody TenantPackageSaveReqVO createReqVO) { + return success(tenantPackageService.createTenantPackage(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租户套餐") + @PreAuthorize("@ss.hasPermission('system:tenant-package:update')") + public CommonResult updateTenantPackage(@Valid @RequestBody TenantPackageSaveReqVO updateReqVO) { + tenantPackageService.updateTenantPackage(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租户套餐") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:tenant-package:delete')") + public CommonResult deleteTenantPackage(@RequestParam("id") Long id) { + tenantPackageService.deleteTenantPackage(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租户套餐") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant-package:query')") + public CommonResult getTenantPackage(@RequestParam("id") Long id) { + TenantPackageDO tenantPackage = tenantPackageService.getTenantPackage(id); + return success(BeanUtils.toBean(tenantPackage, TenantPackageRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租户套餐分页") + @PreAuthorize("@ss.hasPermission('system:tenant-package:query')") + public CommonResult> getTenantPackagePage(@Valid TenantPackagePageReqVO pageVO) { + PageResult pageResult = tenantPackageService.getTenantPackagePage(pageVO); + return success(BeanUtils.toBean(pageResult, TenantPackageRespVO.class)); + } + + @GetMapping({"/get-simple-list", "simple-list"}) + @Operation(summary = "获取租户套餐精简信息列表", description = "只包含被开启的租户套餐,主要用于前端的下拉选项") + public CommonResult> getTenantPackageList() { + List list = tenantPackageService.getTenantPackageListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(BeanUtils.toBean(list, TenantPackageSimpleRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java new file mode 100644 index 0000000..e29598c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.system.controller.admin.tenant.vo.packages; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租户套餐分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class TenantPackagePageReqVO extends PageParam { + + @Schema(description = "套餐名", example = "VIP") + private String name; + + @Schema(description = "状态", example = "1") + private Integer status; + + @Schema(description = "备注", example = "好") + private String remark; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageRespVO.java new file mode 100644 index 0000000..09fd2a7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageRespVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.system.controller.admin.tenant.vo.packages; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 租户套餐 Response VO") +@Data +public class TenantPackageRespVO { + + @Schema(description = "套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "VIP") + private String name; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "备注", example = "好") + private String remark; + + @Schema(description = "关联的菜单编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Set menuIds; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageSaveReqVO.java new file mode 100644 index 0000000..737e110 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageSaveReqVO.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.controller.admin.tenant.vo.packages; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.Set; + +@Schema(description = "管理后台 - 租户套餐创建/修改 Request VO") +@Data +public class TenantPackageSaveReqVO { + + @Schema(description = "套餐编号", example = "1024") + private Long id; + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "VIP") + @NotEmpty(message = "套餐名不能为空") + private String name; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + + @Schema(description = "备注", example = "好") + private String remark; + + @Schema(description = "关联的菜单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "关联的菜单编号不能为空") + private Set menuIds; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java new file mode 100644 index 0000000..3b1277a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java @@ -0,0 +1,20 @@ +package com.tashow.cloud.system.controller.admin.tenant.vo.packages; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 租户套餐精简 Response VO") +@Data +public class TenantPackageSimpleRespVO { + + @Schema(description = "套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "套餐编号不能为空") + private Long id; + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "VIP") + @NotNull(message = "套餐名不能为空") + private String name; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java new file mode 100644 index 0000000..f9c12ad --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.system.controller.admin.tenant.vo.tenant; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class TenantPageReqVO extends PageParam { + + @Schema(description = "租户名", example = "芋道") + private String name; + + @Schema(description = "联系人", example = "芋艿") + private String contactName; + + @Schema(description = "联系手机", example = "15601691300") + private String contactMobile; + + @Schema(description = "租户状态(0正常 1停用)", example = "1") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantRespVO.java new file mode 100644 index 0000000..073bc9d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantRespVO.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.system.controller.admin.tenant.vo.tenant; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租户 Response VO") +@Data +@ExcelIgnoreUnannotated +public class TenantRespVO { + + @Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("租户编号") + private Long id; + + @Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @ExcelProperty("租户名") + private String name; + + @Schema(description = "联系人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("联系人") + private String contactName; + + @Schema(description = "联系手机", example = "15601691300") + @ExcelProperty("联系手机") + private String contactMobile; + + @Schema(description = "租户状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "绑定域名", example = "https://www.iocoder.cn") + private String website; + + @Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long packageId; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expireTime; + + @Schema(description = "账号数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer accountCount; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java new file mode 100644 index 0000000..2f52f2d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java @@ -0,0 +1,70 @@ +package com.tashow.cloud.system.controller.admin.tenant.vo.tenant; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租户创建/修改 Request VO") +@Data +public class TenantSaveReqVO { + + @Schema(description = "租户编号", example = "1024") + private Long id; + + @Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "租户名不能为空") + private String name; + + @Schema(description = "联系人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotNull(message = "联系人不能为空") + private String contactName; + + @Schema(description = "联系手机", example = "15601691300") + private String contactMobile; + + @Schema(description = "租户状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "租户状态") + private Integer status; + + @Schema(description = "绑定域名", example = "https://www.iocoder.cn") + private String website; + + @Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "租户套餐编号不能为空") + private Long packageId; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "过期时间不能为空") + private LocalDateTime expireTime; + + @Schema(description = "账号数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "账号数量不能为空") + private Integer accountCount; + + // ========== 仅【创建】时,需要传递的字段 ========== + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成") + @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + @AssertTrue(message = "用户账号、密码不能为空") + @JsonIgnore + public boolean isUsernameValid() { + return id != null // 修改时,不需要传递 + || (ObjectUtil.isAllNotEmpty(username, password)); // 新增时,必须都传递 username、password + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantSimpleRespVO.java new file mode 100644 index 0000000..fc53bd1 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/tenant/vo/tenant/TenantSimpleRespVO.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.system.controller.admin.tenant.vo.tenant; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 租户精简 Response VO") +@Data +public class TenantSimpleRespVO { + + @Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserController.http new file mode 100644 index 0000000..90f0c98 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserController.http @@ -0,0 +1,5 @@ +### 请求 /system/user/page 接口 => 没有权限 +GET {{baseUrl}}/system/user/page?pageNo=1&pageSize=10 +Authorization: Bearer {{token}} +#Authorization: Bearer test100 +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserController.java new file mode 100644 index 0000000..2cb67cf --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserController.java @@ -0,0 +1,172 @@ +package com.tashow.cloud.system.controller.admin.user; + +import cn.hutool.core.collection.CollUtil; +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.excel.excel.core.util.ExcelUtils; +import com.tashow.cloud.system.controller.admin.user.vo.user.*; +import com.tashow.cloud.system.convert.user.UserConvert; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.systemapi.enums.common.SexEnum; +import com.tashow.cloud.system.service.dept.DeptService; +import com.tashow.cloud.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - 用户") +@RestController +@RequestMapping("/system/user") +@Validated +public class UserController { + + @Resource + private AdminUserService userService; + @Resource + private DeptService deptService; + + @PostMapping("/create") + @Operation(summary = "新增用户") + @PreAuthorize("@ss.hasPermission('system:user:create')") + public CommonResult createUser(@Valid @RequestBody UserSaveReqVO reqVO) { + Long id = userService.createUser(reqVO); + return success(id); + } + + @PutMapping("update") + @Operation(summary = "修改用户") + @PreAuthorize("@ss.hasPermission('system:user:update')") + public CommonResult updateUser(@Valid @RequestBody UserSaveReqVO reqVO) { + userService.updateUser(reqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:user:delete')") + public CommonResult deleteUser(@RequestParam("id") Long id) { + userService.deleteUser(id); + return success(true); + } + + @PutMapping("/update-password") + @Operation(summary = "重置用户密码") + @PreAuthorize("@ss.hasPermission('system:user:update-password')") + public CommonResult updateUserPassword(@Valid @RequestBody UserUpdatePasswordReqVO reqVO) { + userService.updateUserPassword(reqVO.getId(), reqVO.getPassword()); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "修改用户状态") + @PreAuthorize("@ss.hasPermission('system:user:update')") + public CommonResult updateUserStatus(@Valid @RequestBody UserUpdateStatusReqVO reqVO) { + userService.updateUserStatus(reqVO.getId(), reqVO.getStatus()); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得用户分页列表") + @PreAuthorize("@ss.hasPermission('system:user:query')") + public CommonResult> getUserPage(@Valid UserPageReqVO pageReqVO) { + // 获得用户分页列表 + PageResult pageResult = userService.getUserPage(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(new PageResult<>(pageResult.getTotal())); + } + // 拼接数据 + Map deptMap = deptService.getDeptMap( + convertList(pageResult.getList(), AdminUserDO::getDeptId)); + return success(new PageResult<>(UserConvert.INSTANCE.convertList(pageResult.getList(), deptMap), + pageResult.getTotal())); + } + + @GetMapping({"/list-all-simple", "/simple-list"}) + @Operation(summary = "获取用户精简信息列表", description = "只包含被开启的用户,主要用于前端的下拉选项") + public CommonResult> getSimpleUserList() { + List list = userService.getUserListByStatus(CommonStatusEnum.ENABLE.getStatus()); + // 拼接数据 + Map deptMap = deptService.getDeptMap( + convertList(list, AdminUserDO::getDeptId)); + return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap)); + } + + @GetMapping("/get") + @Operation(summary = "获得用户详情") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:user:query')") + public CommonResult getUser(@RequestParam("id") Long id) { + AdminUserDO user = userService.getUser(id); + if (user == null) { + return success(null); + } + // 拼接数据 + DeptDO dept = deptService.getDept(user.getDeptId()); + return success(UserConvert.INSTANCE.convert(user, dept)); + } + + @GetMapping("/export") + @Operation(summary = "导出用户") + @PreAuthorize("@ss.hasPermission('system:user:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportUserList(@Validated UserPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = userService.getUserPage(exportReqVO).getList(); + // 输出 Excel + Map deptMap = deptService.getDeptMap( + convertList(list, AdminUserDO::getDeptId)); + ExcelUtils.write(response, "用户数据.xls", "数据", UserRespVO.class, + UserConvert.INSTANCE.convertList(list, deptMap)); + } + + @GetMapping("/get-import-template") + @Operation(summary = "获得导入用户模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List list = Arrays.asList( + UserImportExcelVO.builder().username("yunai").deptId(1L).email("yunai@iocoder.cn").mobile("15601691300") + .nickname("芋道").status(CommonStatusEnum.ENABLE.getStatus()).sex(SexEnum.MALE.getSex()).build(), + UserImportExcelVO.builder().username("yuanma").deptId(2L).email("yuanma@iocoder.cn").mobile("15601701300") + .nickname("源码").status(CommonStatusEnum.DISABLE.getStatus()).sex(SexEnum.FEMALE.getSex()).build() + ); + // 输出 + ExcelUtils.write(response, "用户导入模板.xls", "用户列表", UserImportExcelVO.class, list); + } + + @PostMapping("/import") + @Operation(summary = "导入用户") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") + }) + @PreAuthorize("@ss.hasPermission('system:user:import')") + public CommonResult importExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { + List list = ExcelUtils.read(file, UserImportExcelVO.class); + return success(userService.importUserList(list, updateSupport)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserProfileController.http b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserProfileController.http new file mode 100644 index 0000000..c94c2ad --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserProfileController.http @@ -0,0 +1,4 @@ +### 请求 /system/user/profile/get 接口 => 没有权限 +GET {{baseUrl}}/system/user/profile/get +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserProfileController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserProfileController.java new file mode 100644 index 0000000..6845710 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/UserProfileController.java @@ -0,0 +1,100 @@ +package com.tashow.cloud.system.controller.admin.user; + +import cn.hutool.core.collection.CollUtil; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.permission.core.annotation.DataPermission; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileRespVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import com.tashow.cloud.system.convert.user.UserConvert; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.service.dept.DeptService; +import com.tashow.cloud.system.service.dept.PostService; +import com.tashow.cloud.system.service.permission.PermissionService; +import com.tashow.cloud.system.service.permission.RoleService; +import com.tashow.cloud.system.service.social.SocialUserService; +import com.tashow.cloud.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.pojo.CommonResult.success; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; +import static com.tashow.cloud.infraapi.enums.ErrorCodeConstants.FILE_IS_EMPTY; + +@Tag(name = "管理后台 - 用户个人中心") +@RestController +@RequestMapping("/system/user/profile") +@Validated +@Slf4j +public class UserProfileController { + + @Resource + private AdminUserService userService; + @Resource + private DeptService deptService; + @Resource + private PostService postService; + @Resource + private PermissionService permissionService; + @Resource + private RoleService roleService; + @Resource + private SocialUserService socialService; + + @GetMapping("/get") + @Operation(summary = "获得登录用户信息") + @DataPermission(enable = false) // 关闭数据权限,避免只查看自己时,查询不到部门。 + public CommonResult getUserProfile() { + // 获得用户基本信息 + AdminUserDO user = userService.getUser(getLoginUserId()); + // 获得用户角色 + List userRoles = roleService.getRoleListFromCache(permissionService.getUserRoleIdListByUserId(user.getId())); + // 获得部门信息 + DeptDO dept = user.getDeptId() != null ? deptService.getDept(user.getDeptId()) : null; + // 获得岗位信息 + List posts = CollUtil.isNotEmpty(user.getPostIds()) ? postService.getPostList(user.getPostIds()) : null; + // 获得社交用户信息 + List socialUsers = socialService.getSocialUserList(user.getId(), UserTypeEnum.ADMIN.getValue()); + return success(UserConvert.INSTANCE.convert(user, userRoles, dept, posts, socialUsers)); + } + + @PutMapping("/update") + @Operation(summary = "修改用户个人信息") + public CommonResult updateUserProfile(@Valid @RequestBody UserProfileUpdateReqVO reqVO) { + userService.updateUserProfile(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/update-password") + @Operation(summary = "修改用户个人密码") + public CommonResult updateUserProfilePassword(@Valid @RequestBody UserProfileUpdatePasswordReqVO reqVO) { + userService.updateUserPassword(getLoginUserId(), reqVO); + return success(true); + } + + @RequestMapping(value = "/update-avatar", + method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题 + @Operation(summary = "上传用户个人头像") + public CommonResult updateUserAvatar(@RequestParam("avatarFile") MultipartFile file) throws Exception { + if (file.isEmpty()) { + throw exception(FILE_IS_EMPTY); + } + String avatar = userService.updateUserAvatar(getLoginUserId(), file.getInputStream()); + return success(avatar); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileRespVO.java new file mode 100644 index 0000000..4d7eec4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileRespVO.java @@ -0,0 +1,76 @@ +package com.tashow.cloud.system.controller.admin.user.vo.profile; + +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptSimpleRespVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSimpleRespVO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleSimpleRespVO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleSimpleRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Schema(description = "管理后台 - 用户个人中心信息 Response VO") +public class UserProfileRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + @Schema(description = "最后登录 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.1") + private String loginIp; + + @Schema(description = "最后登录时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime loginDate; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + + /** + * 所属角色 + */ + private List roles; + /** + * 所在部门 + */ + private DeptSimpleRespVO dept; + /** + * 所属岗位数组 + */ + private List posts; + /** + * 社交用户数组 + */ + private List socialUsers; + + @Schema(description = "社交用户") + @Data + public static class SocialUser { + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer type; + + @Schema(description = "社交用户的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE") + private String openid; + + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java new file mode 100644 index 0000000..748622b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.system.controller.admin.user.vo.profile; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import jakarta.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 用户个人中心更新密码 Request VO") +@Data +public class UserProfileUpdatePasswordReqVO { + + @Schema(description = "旧密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotEmpty(message = "旧密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String oldPassword; + + @Schema(description = "新密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "654321") + @NotEmpty(message = "新密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String newPassword; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileUpdateReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileUpdateReqVO.java new file mode 100644 index 0000000..50bbe3e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/profile/UserProfileUpdateReqVO.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.system.controller.admin.user.vo.profile; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Size; + + +@Schema(description = "管理后台 - 用户个人信息更新 Request VO") +@Data +public class UserProfileUpdateReqVO { + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @Size(max = 30, message = "用户昵称长度不能超过 30 个字符") + private String nickname; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + @Email(message = "邮箱格式不正确") + @Size(max = 50, message = "邮箱长度不能超过 50 个字符") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + @Length(min = 11, max = 11, message = "手机号长度必须 11 位") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserImportExcelVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserImportExcelVO.java new file mode 100644 index 0000000..32b9ff9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserImportExcelVO.java @@ -0,0 +1,47 @@ +package com.tashow.cloud.system.controller.admin.user.vo.user; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 用户 Excel 导入 VO + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +public class UserImportExcelVO { + + @ExcelProperty("登录名称") + private String username; + + @ExcelProperty("用户名称") + private String nickname; + + @ExcelProperty("部门编号") + private Long deptId; + + @ExcelProperty("用户邮箱") + private String email; + + @ExcelProperty("手机号码") + private String mobile; + + @ExcelProperty(value = "用户性别", converter = DictConvert.class) + @DictFormat(DictTypeConstants.USER_SEX) + private Integer sex; + + @ExcelProperty(value = "账号状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserImportRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserImportRespVO.java new file mode 100644 index 0000000..2d5d208 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserImportRespVO.java @@ -0,0 +1,24 @@ +package com.tashow.cloud.system.controller.admin.user.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - 用户导入 Response VO") +@Data +@Builder +public class UserImportRespVO { + + @Schema(description = "创建成功的用户名数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List createUsernames; + + @Schema(description = "更新成功的用户名数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List updateUsernames; + + @Schema(description = "导入失败的用户集合,key 为用户名,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED) + private Map failureUsernames; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserPageReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserPageReqVO.java new file mode 100644 index 0000000..f0a05ac --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserPageReqVO.java @@ -0,0 +1,41 @@ +package com.tashow.cloud.system.controller.admin.user.vo.user; + +import com.tashow.cloud.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.tashow.cloud.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 用户分页 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserPageReqVO extends PageParam { + + @Schema(description = "用户账号,模糊匹配", example = "yudao") + private String username; + + @Schema(description = "手机号码,模糊匹配", example = "yudao") + private String mobile; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "部门编号,同时筛选子部门", example = "1024") + private Long deptId; + + @Schema(description = "角色编号", example = "1024") + private Long roleId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserRespVO.java new file mode 100644 index 0000000..c192a02 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserRespVO.java @@ -0,0 +1,76 @@ +package com.tashow.cloud.system.controller.admin.user.vo.user; + +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.excel.core.convert.DictConvert; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 用户信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class UserRespVO{ + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("用户编号") + private Long id; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @ExcelProperty("用户名称") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("用户昵称") + private String nickname; + + @Schema(description = "备注", example = "我是一个用户") + private String remark; + + @Schema(description = "部门ID", example = "我是一个用户") + private Long deptId; + @Schema(description = "部门名称", example = "IT 部") + @ExcelProperty("部门名称") + private String deptName; + + @Schema(description = "岗位编号数组", example = "1") + private Set postIds; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + @ExcelProperty("用户邮箱") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + @ExcelProperty("手机号码") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + @ExcelProperty(value = "用户性别", converter = DictConvert.class) + @DictFormat(DictTypeConstants.USER_SEX) + private Integer sex; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "帐号状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "最后登录 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.1") + @ExcelProperty("最后登录IP") + private String loginIp; + + @Schema(description = "最后登录时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + @ExcelProperty("最后登录时间") + private LocalDateTime loginDate; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserSaveReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserSaveReqVO.java new file mode 100644 index 0000000..adca432 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserSaveReqVO.java @@ -0,0 +1,80 @@ +package com.tashow.cloud.system.controller.admin.user.vo.user; + +import cn.hutool.core.util.ObjectUtil; +import com.tashow.cloud.common.validation.Mobile; +import com.tashow.cloud.system.framework.operatelog.core.DeptParseFunction; +import com.tashow.cloud.system.framework.operatelog.core.PostParseFunction; +import com.tashow.cloud.system.framework.operatelog.core.SexParseFunction; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.*; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import java.util.Set; + +@Schema(description = "管理后台 - 用户创建/修改 Request VO") +@Data +public class UserSaveReqVO { + + @Schema(description = "用户编号", example = "1024") + private Long id; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotBlank(message = "用户账号不能为空") + @Pattern(regexp = "^[a-zA-Z0-9]+$", message = "用户账号由 数字、字母 组成") + @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符") + @DiffLogField(name = "用户账号") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @Size(max = 30, message = "用户昵称长度不能超过30个字符") + @DiffLogField(name = "用户昵称") + private String nickname; + + @Schema(description = "备注", example = "我是一个用户") + @DiffLogField(name = "备注") + private String remark; + + @Schema(description = "部门编号", example = "我是一个用户") + @DiffLogField(name = "部门", function = DeptParseFunction.NAME) + private Long deptId; + + @Schema(description = "岗位编号数组", example = "1") + @DiffLogField(name = "岗位", function = PostParseFunction.NAME) + private Set postIds; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + @Email(message = "邮箱格式不正确") + @Size(max = 50, message = "邮箱长度不能超过 50 个字符") + @DiffLogField(name = "用户邮箱") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + @Mobile + @DiffLogField(name = "手机号码") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + @DiffLogField(name = "用户性别", function = SexParseFunction.NAME) + private Integer sex; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + @DiffLogField(name = "用户头像") + private String avatar; + + // ========== 仅【创建】时,需要传递的字段 ========== + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + @AssertTrue(message = "密码不能为空") + @JsonIgnore + public boolean isPasswordValid() { + return id != null // 修改时,不需要传递 + || (ObjectUtil.isAllNotEmpty(password)); // 新增时,必须都传递 password + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserSimpleRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserSimpleRespVO.java new file mode 100644 index 0000000..dfe3967 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserSimpleRespVO.java @@ -0,0 +1,25 @@ +package com.tashow.cloud.system.controller.admin.user.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 用户精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserSimpleRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String nickname; + + @Schema(description = "部门ID", example = "我是一个用户") + private Long deptId; + @Schema(description = "部门名称", example = "IT 部") + private String deptName; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java new file mode 100644 index 0000000..e327864 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.system.controller.admin.user.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 用户更新密码 Request VO") +@Data +public class UserUpdatePasswordReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "用户编号不能为空") + private Long id; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java new file mode 100644 index 0000000..1290d20 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.system.controller.admin.user.vo.user; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 用户更新状态 Request VO") +@Data +public class UserUpdateStatusReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "角色编号不能为空") + private Long id; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/dict/AppDictDataController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/dict/AppDictDataController.java new file mode 100644 index 0000000..c64d4cd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/dict/AppDictDataController.java @@ -0,0 +1,43 @@ +package com.tashow.cloud.system.controller.app.dict; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.app.dict.vo.AppDictDataRespVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictDataDO; +import com.tashow.cloud.system.service.dict.DictDataService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.PermitAll; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 字典数据") +@RestController +@RequestMapping("/system/dict-data") +@Validated +public class AppDictDataController { + + @Resource + private DictDataService dictDataService; + + @GetMapping("/type") + @Operation(summary = "根据字典类型查询字典数据信息") + @Parameter(name = "type", description = "字典类型", required = true, example = "common_status") + @PermitAll + public CommonResult> getDictDataListByType(@RequestParam("type") String type) { + List list = dictDataService.getDictDataList( + CommonStatusEnum.ENABLE.getStatus(), type); + return success(BeanUtils.toBean(list, AppDictDataRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/dict/vo/AppDictDataRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/dict/vo/AppDictDataRespVO.java new file mode 100644 index 0000000..fe8ed5f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/dict/vo/AppDictDataRespVO.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.system.controller.app.dict.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "用户 App - 字典数据信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AppDictDataRespVO { + + @Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String label; + + @Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder") + private String value; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + private String dictType; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/ip/AppAreaController.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/ip/AppAreaController.java new file mode 100644 index 0000000..b7e3ca6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/ip/AppAreaController.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.system.controller.app.ip; + +import cn.hutool.core.lang.Assert; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.ip.core.Area; +import com.tashow.cloud.ip.core.utils.AreaUtils; +import com.tashow.cloud.system.controller.app.ip.vo.AppAreaNodeRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.PermitAll; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static com.tashow.cloud.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 地区") +@RestController +@RequestMapping("/system/area") +@Validated +public class AppAreaController { + + @GetMapping("/tree") + @Operation(summary = "获得地区树") + @PermitAll + public CommonResult> getAreaTree() { + Area area = AreaUtils.getArea(Area.ID_CHINA); + Assert.notNull(area, "获取不到中国"); + return success(BeanUtils.toBean(area.getChildren(), AppAreaNodeRespVO.class)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/ip/vo/AppAreaNodeRespVO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/ip/vo/AppAreaNodeRespVO.java new file mode 100644 index 0000000..28843ad --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/ip/vo/AppAreaNodeRespVO.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.system.controller.app.ip.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 地区节点 Response VO") +@Data +public class AppAreaNodeRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000") + private Integer id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "北京") + private String name; + + /** + * 子节点 + */ + private List children; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/package-info.java new file mode 100644 index 0000000..af5af4f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/app/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位,避免 package 无法提交到 Git 仓库 + */ +package com.tashow.cloud.system.controller.app; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/package-info.java new file mode 100644 index 0000000..8886d60 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package com.tashow.cloud.system.controller; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/auth/AuthConvert.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/auth/AuthConvert.java new file mode 100644 index 0000000..db5b428 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/auth/AuthConvert.java @@ -0,0 +1,88 @@ +package com.tashow.cloud.system.convert.auth; + +import cn.hutool.core.collection.CollUtil; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.systemapi.enums.permission.MenuTypeEnum; +import com.tashow.cloud.system.controller.admin.auth.vo.*; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import org.slf4j.LoggerFactory; + +import java.util.*; + +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; +import static com.tashow.cloud.common.util.collection.CollectionUtils.filterList; +import static com.tashow.cloud.system.dal.dataobject.permission.MenuDO.ID_ROOT; + +@Mapper +public interface AuthConvert { + + AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class); + + AuthLoginRespVO convert(OAuth2AccessTokenDO bean); + + default AuthPermissionInfoRespVO convert(AdminUserDO user, List roleList, List menuList) { + return AuthPermissionInfoRespVO.builder() + .user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class)) + .roles(convertSet(roleList, RoleDO::getCode)) + // 权限标识信息 + .permissions(convertSet(menuList, MenuDO::getPermission)) + // 菜单树 + .menus(buildMenuTree(menuList)) + .build(); + } + + AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu); + + /** + * 将菜单列表,构建成菜单树 + * + * @param menuList 菜单列表 + * @return 菜单树 + */ + default List buildMenuTree(List menuList) { + if (CollUtil.isEmpty(menuList)) { + return Collections.emptyList(); + } + // 移除按钮 + menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); + // 排序,保证菜单的有序性 + menuList.sort(Comparator.comparing(MenuDO::getSort)); + + // 构建菜单树 + // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 + Map treeNodeMap = new LinkedHashMap<>(); + menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); + // 处理父子关系 + treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> { + // 获得父节点 + AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId()); + if (parentNode == null) { + LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", + childNode.getId(), childNode.getParentId()); + return; + } + // 将自己添加到父节点中 + if (parentNode.getChildren() == null) { + parentNode.setChildren(new ArrayList<>()); + } + parentNode.getChildren().add(childNode); + }); + // 获得到所有的根节点 + return filterList(treeNodeMap.values(), node -> ID_ROOT.equals(node.getParentId())); + } + + SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialLoginReqVO reqVO); + + SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO); + + SmsCodeUseReqDTO convert(AuthSmsLoginReqVO reqVO, Integer scene, String usedIp); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/oauth2/OAuth2OpenConvert.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/oauth2/OAuth2OpenConvert.java new file mode 100644 index 0000000..59d7b9a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/oauth2/OAuth2OpenConvert.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.system.convert.oauth2; + +import cn.hutool.core.date.LocalDateTimeUtil; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; +import com.tashow.cloud.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; +import com.tashow.cloud.system.util.oauth2.OAuth2Utils; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Mapper +public interface OAuth2OpenConvert { + + OAuth2OpenConvert INSTANCE = Mappers.getMapper(OAuth2OpenConvert.class); + + default OAuth2OpenAccessTokenRespVO convert(OAuth2AccessTokenDO bean) { + OAuth2OpenAccessTokenRespVO respVO = BeanUtils.toBean(bean, OAuth2OpenAccessTokenRespVO.class); + respVO.setTokenType(SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase()); + respVO.setExpiresIn(OAuth2Utils.getExpiresIn(bean.getExpiresTime())); + respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes())); + return respVO; + } + + default OAuth2OpenCheckTokenRespVO convert2(OAuth2AccessTokenDO bean) { + OAuth2OpenCheckTokenRespVO respVO = BeanUtils.toBean(bean, OAuth2OpenCheckTokenRespVO.class); + respVO.setExp(LocalDateTimeUtil.toEpochMilli(bean.getExpiresTime()) / 1000L); + respVO.setUserType(UserTypeEnum.ADMIN.getValue()); + return respVO; + } + + default OAuth2OpenAuthorizeInfoRespVO convert(OAuth2ClientDO client, List approves) { + // 构建 scopes + List> scopes = new ArrayList<>(client.getScopes().size()); + Map approveMap = CollectionUtils.convertMap(approves, OAuth2ApproveDO::getScope); + client.getScopes().forEach(scope -> { + OAuth2ApproveDO approve = approveMap.get(scope); + scopes.add(new KeyValue<>(scope, approve != null ? approve.getApproved() : false)); + }); + // 拼接返回 + return new OAuth2OpenAuthorizeInfoRespVO( + new OAuth2OpenAuthorizeInfoRespVO.Client(client.getName(), client.getLogo()), scopes); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/package-info.java new file mode 100644 index 0000000..af26e66 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package com.tashow.cloud.system.convert; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/social/SocialUserConvert.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/social/SocialUserConvert.java new file mode 100644 index 0000000..dd27030 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/social/SocialUserConvert.java @@ -0,0 +1,19 @@ +package com.tashow.cloud.system.convert.social; + +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserBindReqVO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserBindReqVO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface SocialUserConvert { + + SocialUserConvert INSTANCE = Mappers.getMapper(SocialUserConvert.class); + + @Mapping(source = "reqVO.type", target = "socialType") + SocialUserBindReqDTO convert(Long userId, Integer userType, SocialUserBindReqVO reqVO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/tenant/TenantConvert.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/tenant/TenantConvert.java new file mode 100644 index 0000000..5a95cb1 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/tenant/TenantConvert.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.system.convert.tenant; + +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserSaveReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserSaveReqVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 租户 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface TenantConvert { + + TenantConvert INSTANCE = Mappers.getMapper(TenantConvert.class); + + default UserSaveReqVO convert02(TenantSaveReqVO bean) { + UserSaveReqVO reqVO = new UserSaveReqVO(); + reqVO.setUsername(bean.getUsername()); + reqVO.setPassword(bean.getPassword()); + reqVO.setNickname(bean.getContactName()).setMobile(bean.getContactMobile()); + return reqVO; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/user/UserConvert.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/user/UserConvert.java new file mode 100644 index 0000000..af36309 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/user/UserConvert.java @@ -0,0 +1,58 @@ +package com.tashow.cloud.system.convert.user; + +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.collection.MapUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptSimpleRespVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSimpleRespVO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleSimpleRespVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileRespVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserRespVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserSimpleRespVO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface UserConvert { + + UserConvert INSTANCE = Mappers.getMapper(UserConvert.class); + + default List convertList(List list, Map deptMap) { + return CollectionUtils.convertList(list, user -> convert(user, deptMap.get(user.getDeptId()))); + } + + default UserRespVO convert(AdminUserDO user, DeptDO dept) { + UserRespVO userVO = BeanUtils.toBean(user, UserRespVO.class); + if (dept != null) { + userVO.setDeptName(dept.getName()); + } + return userVO; + } + + default List convertSimpleList(List list, Map deptMap) { + return CollectionUtils.convertList(list, user -> { + UserSimpleRespVO userVO = BeanUtils.toBean(user, UserSimpleRespVO.class); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> userVO.setDeptName(dept.getName())); + return userVO; + }); + } + + default UserProfileRespVO convert(AdminUserDO user, List userRoles, + DeptDO dept, List posts, List socialUsers) { + UserProfileRespVO userVO = BeanUtils.toBean(user, UserProfileRespVO.class); + userVO.setRoles(BeanUtils.toBean(userRoles, RoleSimpleRespVO.class)); + userVO.setDept(BeanUtils.toBean(dept, DeptSimpleRespVO.class)); + userVO.setPosts(BeanUtils.toBean(posts, PostSimpleRespVO.class)); + userVO.setSocialUsers(BeanUtils.toBean(socialUsers, UserProfileRespVO.SocialUser.class)); + return userVO; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 0000000..8153487 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/DeptDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/DeptDO.java new file mode 100644 index 0000000..6726704 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/DeptDO.java @@ -0,0 +1,66 @@ +package com.tashow.cloud.system.dal.dataobject.dept; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.tenant.core.db.TenantBaseDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 部门表 + * + * @author ruoyi + * @author 芋道源码 + */ +@TableName("system_dept") +@KeySequence("system_dept_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class DeptDO extends TenantBaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 部门ID + */ + @TableId + private Long id; + /** + * 部门名称 + */ + private String name; + /** + * 父部门ID + * + * 关联 {@link #id} + */ + private Long parentId; + /** + * 显示顺序 + */ + private Integer sort; + /** + * 负责人 + * + * 关联 {@link AdminUserDO#getId()} + */ + private Long leaderUserId; + /** + * 联系电话 + */ + private String phone; + /** + * 邮箱 + */ + private String email; + /** + * 部门状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/PostDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/PostDO.java new file mode 100644 index 0000000..2b62445 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/PostDO.java @@ -0,0 +1,50 @@ +package com.tashow.cloud.system.dal.dataobject.dept; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 岗位表 + * + * @author ruoyi + */ +@TableName("system_post") +@KeySequence("system_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class PostDO extends BaseDO { + + /** + * 岗位序号 + */ + @TableId + private Long id; + /** + * 岗位名称 + */ + private String name; + /** + * 岗位编码 + */ + private String code; + /** + * 岗位排序 + */ + private Integer sort; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/UserPostDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/UserPostDO.java new file mode 100644 index 0000000..1327596 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dept/UserPostDO.java @@ -0,0 +1,41 @@ +package com.tashow.cloud.system.dal.dataobject.dept; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户和岗位关联 + * + * @author ruoyi + */ +@TableName("system_user_post") +@KeySequence("system_user_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class UserPostDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 用户 ID + * + * 关联 {@link AdminUserDO#getId()} + */ + private Long userId; + /** + * 角色 ID + * + * 关联 {@link PostDO#getId()} + */ + private Long postId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dict/DictDataDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dict/DictDataDO.java new file mode 100644 index 0000000..0c36135 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dict/DictDataDO.java @@ -0,0 +1,65 @@ +package com.tashow.cloud.system.dal.dataobject.dict; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典数据表 + * + * @author ruoyi + */ +@TableName("system_dict_data") +@KeySequence("system_dict_data_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class DictDataDO extends BaseDO { + + /** + * 字典数据编号 + */ + @TableId + private Long id; + /** + * 字典排序 + */ + private Integer sort; + /** + * 字典标签 + */ + private String label; + /** + * 字典值 + */ + private String value; + /** + * 字典类型 + * + * 冗余 {@link DictDataDO#getDictType()} + */ + private String dictType; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 颜色类型 + * + * 对应到 element-ui 为 default、primary、success、info、warning、danger + */ + private String colorType; + /** + * css 样式 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private String cssClass; + /** + * 备注 + */ + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dict/DictTypeDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dict/DictTypeDO.java new file mode 100644 index 0000000..c137067 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/dict/DictTypeDO.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.system.dal.dataobject.dict; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 字典类型表 + * + * @author ruoyi + */ +@TableName("system_dict_type") +@KeySequence("system_dict_type_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DictTypeDO extends BaseDO { + + /** + * 字典主键 + */ + @TableId + private Long id; + /** + * 字典名称 + */ + private String name; + /** + * 字典类型 + */ + private String type; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private LocalDateTime deletedTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/logger/LoginLogDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/logger/LoginLogDO.java new file mode 100644 index 0000000..1a7078f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/logger/LoginLogDO.java @@ -0,0 +1,74 @@ +package com.tashow.cloud.system.dal.dataobject.logger; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.systemapi.enums.logger.LoginLogTypeEnum; +import com.tashow.cloud.systemapi.enums.logger.LoginResultEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.systemapi.enums.logger.LoginLogTypeEnum; +import com.tashow.cloud.systemapi.enums.logger.LoginResultEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 登录日志表 + * + * 注意,包括登录和登出两种行为 + * + * @author 芋道源码 + */ +@TableName("system_login_log") +@KeySequence("system_login_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class LoginLogDO extends BaseDO { + + /** + * 日志主键 + */ + private Long id; + /** + * 日志类型 + * + * 枚举 {@link LoginLogTypeEnum} + */ + private Integer logType; + /** + * 链路追踪编号 + */ + private String traceId; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 用户账号 + * + * 冗余,因为账号可以变更 + */ + private String username; + /** + * 登录结果 + * + * 枚举 {@link LoginResultEnum} + */ + private Integer result; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/logger/OperateLogDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/logger/OperateLogDO.java new file mode 100644 index 0000000..e40f680 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/logger/OperateLogDO.java @@ -0,0 +1,85 @@ +package com.tashow.cloud.system.dal.dataobject.logger; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 操作日志表 + * + * @author 芋道源码 + */ +@TableName(value = "system_operate_log", autoResultMap = true) +@KeySequence("system_operate_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class OperateLogDO extends BaseDO { + + /** + * 日志主键 + */ + @TableId + private Long id; + /** + * 链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 + */ + private String traceId; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性 + */ + private Long userId; + /** + * 用户类型 + * + * 关联 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 操作模块类型 + */ + private String type; + /** + * 操作名 + */ + private String subType; + /** + * 操作模块业务编号 + */ + private Long bizId; + /** + * 日志内容,记录整个操作的明细 + * + * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 + */ + private String action; + /** + * 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ) + * + * 例如说,记录订单编号,{ orderId: "1"} + */ + private String extra; + + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 请求地址 + */ + private String requestUrl; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailAccountDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailAccountDO.java new file mode 100644 index 0000000..c332efb --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailAccountDO.java @@ -0,0 +1,59 @@ +package com.tashow.cloud.system.dal.dataobject.mail; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 邮箱账号 DO + * + * 用途:配置发送邮箱的账号 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@TableName(value = "system_mail_account", autoResultMap = true) +@KeySequence("system_mail_account_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class MailAccountDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 邮箱 + */ + private String mail; + + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * SMTP 服务器域名 + */ + private String host; + /** + * SMTP 服务器端口 + */ + private Integer port; + /** + * 是否开启 SSL + */ + private Boolean sslEnable; + /** + * 是否开启 STARTTLS + */ + private Boolean starttlsEnable; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailLogDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailLogDO.java new file mode 100644 index 0000000..a9f439f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailLogDO.java @@ -0,0 +1,125 @@ +package com.tashow.cloud.system.dal.dataobject.mail; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.systemapi.enums.mail.MailSendStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.tashow.cloud.systemapi.enums.mail.MailSendStatusEnum; +import lombok.*; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; +import java.util.Map; + +/** + * 邮箱日志 DO + * 记录每一次邮件的发送 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@TableName(value = "system_mail_log", autoResultMap = true) +@KeySequence("system_mail_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MailLogDO extends BaseDO implements Serializable { + + /** + * 日志编号,自增 + */ + private Long id; + + /** + * 用户编码 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 接收邮箱地址 + */ + private String toMail; + + /** + * 邮箱账号编号 + * + * 关联 {@link MailAccountDO#getId()} + */ + private Long accountId; + /** + * 发送邮箱地址 + * + * 冗余 {@link MailAccountDO#getMail()} + */ + private String fromMail; + + // ========= 模板相关字段 ========= + /** + * 模版编号 + * + * 关联 {@link MailTemplateDO#getId()} + */ + private Long templateId; + /** + * 模版编码 + * + * 冗余 {@link MailTemplateDO#getCode()} + */ + private String templateCode; + /** + * 模版发送人名称 + * + * 冗余 {@link MailTemplateDO#getNickname()} + */ + private String templateNickname; + /** + * 模版标题 + */ + private String templateTitle; + /** + * 模版内容 + * + * 基于 {@link MailTemplateDO#getContent()} 格式化后的内容 + */ + private String templateContent; + /** + * 模版参数 + * + * 基于 {@link MailTemplateDO#getParams()} 输入后的参数 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map templateParams; + + // ========= 发送相关字段 ========= + /** + * 发送状态 + * + * 枚举 {@link MailSendStatusEnum} + */ + private Integer sendStatus; + /** + * 发送时间 + */ + private LocalDateTime sendTime; + /** + * 发送返回的消息 ID + */ + private String sendMessageId; + /** + * 发送异常 + */ + private String sendException; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailTemplateDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailTemplateDO.java new file mode 100644 index 0000000..ed32f1f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/mail/MailTemplateDO.java @@ -0,0 +1,73 @@ +package com.tashow.cloud.system.dal.dataobject.mail; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 邮件模版 DO + * + * @author wangjingyi + * @since 2022-03-21 + */ +@TableName(value = "system_mail_template", autoResultMap = true) +@KeySequence("system_mail_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class MailTemplateDO extends BaseDO { + + /** + * 主键 + */ + private Long id; + /** + * 模版名称 + */ + private String name; + /** + * 模版编号 + */ + private String code; + /** + * 发送的邮箱账号编号 + * + * 关联 {@link MailAccountDO#getId()} + */ + private Long accountId; + + /** + * 发送人名称 + */ + private String nickname; + /** + * 标题 + */ + private String title; + /** + * 内容 + */ + private String content; + /** + * 参数数组(自动根据内容生成) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List params; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notice/NoticeDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notice/NoticeDO.java new file mode 100644 index 0000000..7da5750 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notice/NoticeDO.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.system.dal.dataobject.notice; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.systemapi.enums.notice.NoticeTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.systemapi.enums.notice.NoticeTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 通知公告表 + * + * @author ruoyi + */ +@TableName("system_notice") +@KeySequence("system_notice_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class NoticeDO extends BaseDO { + + /** + * 公告ID + */ + private Long id; + /** + * 公告标题 + */ + private String title; + /** + * 公告类型 + * + * 枚举 {@link NoticeTypeEnum} + */ + private Integer type; + /** + * 公告内容 + */ + private String content; + /** + * 公告状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notify/NotifyMessageDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notify/NotifyMessageDO.java new file mode 100644 index 0000000..d3d58e1 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notify/NotifyMessageDO.java @@ -0,0 +1,99 @@ +package com.tashow.cloud.system.dal.dataobject.notify; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 站内信 DO + * + * @author xrcoder + */ +@TableName(value = "system_notify_message", autoResultMap = true) +@KeySequence("system_notify_message_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NotifyMessageDO extends BaseDO { + + /** + * 站内信编号,自增 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 字段、或者 AdminUserDO 的 id 字段 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + // ========= 模板相关字段 ========= + + /** + * 模版编号 + * + * 关联 {@link NotifyTemplateDO#getId()} + */ + private Long templateId; + /** + * 模版编码 + * + * 关联 {@link NotifyTemplateDO#getCode()} + */ + private String templateCode; + /** + * 模版类型 + * + * 冗余 {@link NotifyTemplateDO#getType()} + */ + private Integer templateType; + /** + * 模版发送人名称 + * + * 冗余 {@link NotifyTemplateDO#getNickname()} + */ + private String templateNickname; + /** + * 模版内容 + * + * 基于 {@link NotifyTemplateDO#getContent()} 格式化后的内容 + */ + private String templateContent; + /** + * 模版参数 + * + * 基于 {@link NotifyTemplateDO#getParams()} 输入后的参数 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map templateParams; + + // ========= 读取相关字段 ========= + + /** + * 是否已读 + */ + private Boolean readStatus; + /** + * 阅读时间 + */ + private LocalDateTime readTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notify/NotifyTemplateDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notify/NotifyTemplateDO.java new file mode 100644 index 0000000..687964b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/notify/NotifyTemplateDO.java @@ -0,0 +1,72 @@ +package com.tashow.cloud.system.dal.dataobject.notify; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * 站内信模版 DO + * + * @author xrcoder + */ +@TableName(value = "system_notify_template", autoResultMap = true) +@KeySequence("system_notify_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NotifyTemplateDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 模版名称 + */ + private String name; + /** + * 模版编码 + */ + private String code; + /** + * 模版类型 + * + * 对应 system_notify_template_type 字典 + */ + private Integer type; + /** + * 发送人名称 + */ + private String nickname; + /** + * 模版内容 + */ + private String content; + /** + * 参数数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List params; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2AccessTokenDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2AccessTokenDO.java new file mode 100644 index 0000000..d07e668 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2AccessTokenDO.java @@ -0,0 +1,75 @@ +package com.tashow.cloud.system.dal.dataobject.oauth2; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.tenant.core.db.TenantBaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * OAuth2 访问令牌 DO + * + * 如下字段,暂时未使用,暂时不支持: + * user_name、authentication(用户信息) + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_access_token", autoResultMap = true) +@KeySequence("system_oauth2_access_token_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2AccessTokenDO extends TenantBaseDO { + + /** + * 编号,数据库递增 + */ + @TableId + private Long id; + /** + * 访问令牌 + */ + private String accessToken; + /** + * 刷新令牌 + */ + private String refreshToken; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 用户信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map userInfo; + /** + * 客户端编号 + * + * 关联 {@link OAuth2ClientDO#getId()} + */ + private String clientId; + /** + * 授权范围 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List scopes; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2ApproveDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2ApproveDO.java new file mode 100644 index 0000000..747325d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2ApproveDO.java @@ -0,0 +1,63 @@ +package com.tashow.cloud.system.dal.dataobject.oauth2; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * OAuth2 批准 DO + * + * 用户在 sso.vue 界面时,记录接受的 scope 列表 + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_approve", autoResultMap = true) +@KeySequence("system_oauth2_approve_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2ApproveDO extends BaseDO { + + /** + * 编号,数据库自增 + */ + @TableId + private Long id; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 客户端编号 + * + * 关联 {@link OAuth2ClientDO#getId()} + */ + private String clientId; + /** + * 授权范围 + */ + private String scope; + /** + * 是否接受 + * + * true - 接受 + * false - 拒绝 + */ + private Boolean approved; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2ClientDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2ClientDO.java new file mode 100644 index 0000000..1f00e22 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2ClientDO.java @@ -0,0 +1,108 @@ +package com.tashow.cloud.system.dal.dataobject.oauth2; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.systemapi.enums.oauth2.OAuth2GrantTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.tashow.cloud.systemapi.enums.oauth2.OAuth2GrantTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * OAuth2 客户端 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_client", autoResultMap = true) +@KeySequence("system_oauth2_client_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2ClientDO extends BaseDO { + + /** + * 编号,数据库自增 + * + * 由于 SQL Server 在存储 String 主键有点问题,所以暂时使用 Long 类型 + */ + @TableId + private Long id; + /** + * 客户端编号 + */ + private String clientId; + /** + * 客户端密钥 + */ + private String secret; + /** + * 应用名 + */ + private String name; + /** + * 应用图标 + */ + private String logo; + /** + * 应用描述 + */ + private String description; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 访问令牌的有效期 + */ + private Integer accessTokenValiditySeconds; + /** + * 刷新令牌的有效期 + */ + private Integer refreshTokenValiditySeconds; + /** + * 可重定向的 URI 地址 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List redirectUris; + /** + * 授权类型(模式) + * + * 枚举 {@link OAuth2GrantTypeEnum} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List authorizedGrantTypes; + /** + * 授权范围 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List scopes; + /** + * 自动授权的 Scope + * + * code 授权时,如果 scope 在这个范围内,则自动通过 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List autoApproveScopes; + /** + * 权限 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List authorities; + /** + * 资源 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List resourceIds; + /** + * 附加信息,JSON 格式 + */ + private String additionalInformation; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2CodeDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2CodeDO.java new file mode 100644 index 0000000..50d193e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2CodeDO.java @@ -0,0 +1,68 @@ +package com.tashow.cloud.system.dal.dataobject.oauth2; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * OAuth2 授权码 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_code", autoResultMap = true) +@KeySequence("system_oauth2_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2CodeDO extends BaseDO { + + /** + * 编号,数据库递增 + */ + private Long id; + /** + * 授权码 + */ + private String code; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 客户端编号 + * + * 关联 {@link OAuth2ClientDO#getClientId()} + */ + private String clientId; + /** + * 授权范围 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List scopes; + /** + * 重定向地址 + */ + private String redirectUri; + /** + * 状态 + */ + private String state; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java new file mode 100644 index 0000000..5b4f473 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java @@ -0,0 +1,63 @@ +package com.tashow.cloud.system.dal.dataobject.oauth2; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.tenant.core.db.TenantBaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * OAuth2 刷新令牌 + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_refresh_token", autoResultMap = true) +// 由于 Oracle 的 SEQ 的名字长度有限制,所以就先用 system_oauth2_access_token_seq 吧,反正也没啥问题 +@KeySequence("system_oauth2_access_token_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class OAuth2RefreshTokenDO extends TenantBaseDO { + + /** + * 编号,数据库字典 + */ + private Long id; + /** + * 刷新令牌 + */ + private String refreshToken; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 客户端编号 + * + * 关联 {@link OAuth2ClientDO#getId()} + */ + private String clientId; + /** + * 授权范围 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List scopes; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/MenuDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/MenuDO.java new file mode 100644 index 0000000..f31febe --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/MenuDO.java @@ -0,0 +1,108 @@ +package com.tashow.cloud.system.dal.dataobject.permission; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.systemapi.enums.permission.MenuTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.systemapi.enums.permission.MenuTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 菜单 DO + * + * @author ruoyi + */ +@TableName("system_menu") +@KeySequence("system_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class MenuDO extends BaseDO { + + /** + * 菜单编号 - 根节点 + */ + public static final Long ID_ROOT = 0L; + + /** + * 菜单编号 + */ + @TableId + private Long id; + /** + * 菜单名称 + */ + private String name; + /** + * 权限标识 + * + * 一般格式为:${系统}:${模块}:${操作} + * 例如说:system:admin:add,即 system 服务的添加管理员。 + * + * 当我们把该 MenuDO 赋予给角色后,意味着该角色有该资源: + * - 对于后端,配合 @PreAuthorize 注解,配置 API 接口需要该权限,从而对 API 接口进行权限控制。 + * - 对于前端,配合前端标签,配置按钮是否展示,避免用户没有该权限时,结果可以看到该操作。 + */ + private String permission; + /** + * 菜单类型 + * + * 枚举 {@link MenuTypeEnum} + */ + private Integer type; + /** + * 显示顺序 + */ + private Integer sort; + /** + * 父菜单ID + */ + private Long parentId; + /** + * 路由地址 + * + * 如果 path 为 http(s) 时,则它是外链 + */ + private String path; + /** + * 菜单图标 + */ + private String icon; + /** + * 组件路径 + */ + private String component; + /** + * 组件名 + */ + private String componentName; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 是否可见 + * + * 只有菜单、目录使用 + * 当设置为 true 时,该菜单不会展示在侧边栏,但是路由还是存在。例如说,一些独立的编辑页面 /edit/1024 等等 + */ + private Boolean visible; + /** + * 是否缓存 + * + * 只有菜单、目录使用,否使用 Vue 路由的 keep-alive 特性 + * 注意:如果开启缓存,则必须填写 {@link #componentName} 属性,否则无法缓存 + */ + private Boolean keepAlive; + /** + * 是否总是显示 + * + * 如果为 false 时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单 + */ + private Boolean alwaysShow; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/RoleDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/RoleDO.java new file mode 100644 index 0000000..3025dd5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/RoleDO.java @@ -0,0 +1,80 @@ +package com.tashow.cloud.system.dal.dataobject.permission; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.tenant.core.db.TenantBaseDO; +import com.tashow.cloud.systemapi.enums.permission.DataScopeEnum; +import com.tashow.cloud.systemapi.enums.permission.RoleTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.tashow.cloud.systemapi.enums.permission.DataScopeEnum; +import com.tashow.cloud.systemapi.enums.permission.RoleTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Set; + +/** + * 角色 DO + * + * @author ruoyi + */ +@TableName(value = "system_role", autoResultMap = true) +@KeySequence("system_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class RoleDO extends TenantBaseDO { + + /** + * 角色ID + */ + @TableId + private Long id; + /** + * 角色名称 + */ + private String name; + /** + * 角色标识 + * + * 枚举 + */ + private String code; + /** + * 角色排序 + */ + private Integer sort; + /** + * 角色状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 角色类型 + * + * 枚举 {@link RoleTypeEnum} + */ + private Integer type; + /** + * 备注 + */ + private String remark; + + /** + * 数据范围 + * + * 枚举 {@link DataScopeEnum} + */ + private Integer dataScope; + /** + * 数据范围(指定部门数组) + * + * 适用于 {@link #dataScope} 的值为 {@link DataScopeEnum#DEPT_CUSTOM} 时 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Set dataScopeDeptIds; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/RoleMenuDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/RoleMenuDO.java new file mode 100644 index 0000000..d586bf9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/RoleMenuDO.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.dal.dataobject.permission; + +import com.tashow.cloud.tenant.core.db.TenantBaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 角色和菜单关联 + * + * @author ruoyi + */ +@TableName("system_role_menu") +@KeySequence("system_role_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class RoleMenuDO extends TenantBaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 角色ID + */ + private Long roleId; + /** + * 菜单ID + */ + private Long menuId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/UserRoleDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/UserRoleDO.java new file mode 100644 index 0000000..a7b2fd4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/permission/UserRoleDO.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.dal.dataobject.permission; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户和角色关联 + * + * @author ruoyi + */ +@TableName("system_user_role") +@KeySequence("system_user_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class UserRoleDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 用户 ID + */ + private Long userId; + /** + * 角色 ID + */ + private Long roleId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsChannelDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsChannelDO.java new file mode 100644 index 0000000..10c4148 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsChannelDO.java @@ -0,0 +1,63 @@ +package com.tashow.cloud.system.dal.dataobject.sms; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.system.framework.sms.core.enums.SmsChannelEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.system.framework.sms.core.enums.SmsChannelEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 短信渠道 DO + * + * @author zzf + * @since 2021-01-25 + */ +@TableName(value = "system_sms_channel", autoResultMap = true) +@KeySequence("system_sms_channel_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsChannelDO extends BaseDO { + + /** + * 渠道编号 + */ + private Long id; + /** + * 短信签名 + */ + private String signature; + /** + * 渠道编码 + * + * 枚举 {@link SmsChannelEnum} + */ + private String code; + /** + * 启用状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 短信 API 的账号 + */ + private String apiKey; + /** + * 短信 API 的密钥 + */ + private String apiSecret; + /** + * 短信发送回调 URL + */ + private String callbackUrl; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsCodeDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsCodeDO.java new file mode 100644 index 0000000..449d28f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsCodeDO.java @@ -0,0 +1,65 @@ +package com.tashow.cloud.system.dal.dataobject.sms; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 手机验证码 DO + * + * idx_mobile 索引:基于 {@link #mobile} 字段 + * + * @author 芋道源码 + */ +@TableName("system_sms_code") +@KeySequence("system_sms_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SmsCodeDO extends BaseDO { + + /** + * 编号 + */ + private Long id; + /** + * 手机号 + */ + private String mobile; + /** + * 验证码 + */ + private String code; + /** + * 发送场景 + * + * 枚举 {@link SmsCodeDO} + */ + private Integer scene; + /** + * 创建 IP + */ + private String createIp; + /** + * 今日发送的第几条 + */ + private Integer todayIndex; + /** + * 是否使用 + */ + private Boolean used; + /** + * 使用时间 + */ + private LocalDateTime usedTime; + /** + * 使用 IP + */ + private String usedIp; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsLogDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsLogDO.java new file mode 100644 index 0000000..c0ccfd2 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsLogDO.java @@ -0,0 +1,163 @@ +package com.tashow.cloud.system.dal.dataobject.sms; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.systemapi.enums.sms.SmsReceiveStatusEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSendStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.tashow.cloud.systemapi.enums.sms.SmsReceiveStatusEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSendStatusEnum; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 短信日志 DO + * + * @author zzf + * @since 2021-01-25 + */ +@TableName(value = "system_sms_log", autoResultMap = true) +@KeySequence("system_sms_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SmsLogDO extends BaseDO { + + /** + * 自增编号 + */ + private Long id; + + // ========= 渠道相关字段 ========= + + /** + * 短信渠道编号 + * + * 关联 {@link SmsChannelDO#getId()} + */ + private Long channelId; + /** + * 短信渠道编码 + * + * 冗余 {@link SmsChannelDO#getCode()} + */ + private String channelCode; + + // ========= 模板相关字段 ========= + + /** + * 模板编号 + * + * 关联 {@link SmsTemplateDO#getId()} + */ + private Long templateId; + /** + * 模板编码 + * + * 冗余 {@link SmsTemplateDO#getCode()} + */ + private String templateCode; + /** + * 短信类型 + * + * 冗余 {@link SmsTemplateDO#getType()} + */ + private Integer templateType; + /** + * 基于 {@link SmsTemplateDO#getContent()} 格式化后的内容 + */ + private String templateContent; + /** + * 基于 {@link SmsTemplateDO#getParams()} 输入后的参数 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map templateParams; + /** + * 短信 API 的模板编号 + * + * 冗余 {@link SmsTemplateDO#getApiTemplateId()} + */ + private String apiTemplateId; + + // ========= 手机相关字段 ========= + + /** + * 手机号 + */ + private String mobile; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + // ========= 发送相关字段 ========= + + /** + * 发送状态 + * + * 枚举 {@link SmsSendStatusEnum} + */ + private Integer sendStatus; + /** + * 发送时间 + */ + private LocalDateTime sendTime; + /** + * 短信 API 发送结果的编码 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiSendCode; + /** + * 短信 API 发送失败的提示 + */ + private String apiSendMsg; + /** + * 短信 API 发送返回的唯一请求 ID + * + * 用于和短信 API 进行定位于排错 + */ + private String apiRequestId; + /** + * 短信 API 发送返回的序号 + * + * 用于和短信 API 平台的发送记录关联 + */ + private String apiSerialNo; + + // ========= 接收相关字段 ========= + + /** + * 接收状态 + * + * 枚举 {@link SmsReceiveStatusEnum} + */ + private Integer receiveStatus; + /** + * 接收时间 + */ + private LocalDateTime receiveTime; + /** + * 短信 API 接收结果的编码 + */ + private String apiReceiveCode; + /** + * 短信 API 接收结果的提示 + */ + private String apiReceiveMsg; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsTemplateDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsTemplateDO.java new file mode 100644 index 0000000..ba20c9f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/sms/SmsTemplateDO.java @@ -0,0 +1,92 @@ +package com.tashow.cloud.system.dal.dataobject.sms; + +import com.tashow.cloud.systemapi.enums.sms.SmsTemplateTypeEnum; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.tashow.cloud.systemapi.enums.sms.SmsTemplateTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +/** + * 短信模板 DO + * + * @author zzf + * @since 2021-01-25 + */ +@TableName(value = "system_sms_template", autoResultMap = true) +@KeySequence("system_sms_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsTemplateDO extends BaseDO { + + /** + * 自增编号 + */ + private Long id; + + // ========= 模板相关字段 ========= + + /** + * 短信类型 + * + * 枚举 {@link SmsTemplateTypeEnum} + */ + private Integer type; + /** + * 启用状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 模板编码,保证唯一 + */ + private String code; + /** + * 模板名称 + */ + private String name; + /** + * 模板内容 + * + * 内容的参数,使用 {} 包括,例如说 {name} + */ + private String content; + /** + * 参数数组(自动根据内容生成) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List params; + /** + * 备注 + */ + private String remark; + /** + * 短信 API 的模板编号 + */ + private String apiTemplateId; + + // ========= 渠道相关字段 ========= + + /** + * 短信渠道编号 + * + * 关联 {@link SmsChannelDO#getId()} + */ + private Long channelId; + /** + * 短信渠道编码 + * + * 冗余 {@link SmsChannelDO#getCode()} + */ + private String channelCode; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialClientDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialClientDO.java new file mode 100644 index 0000000..34ec2a4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialClientDO.java @@ -0,0 +1,77 @@ +package com.tashow.cloud.system.dal.dataobject.social; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.tenant.core.db.TenantBaseDO; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.xingyuv.jushauth.config.AuthConfig; +import lombok.*; + +/** + * 社交客户端 DO + * + * 对应 {@link AuthConfig} 配置,满足不同租户,有自己的客户端配置,实现社交(三方)登录 + * + * @author 芋道源码 + */ +@TableName(value = "system_social_client", autoResultMap = true) +@KeySequence("system_social_client_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SocialClientDO extends TenantBaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + /** + * 应用名 + */ + private String name; + /** + * 社交类型 + * + * 枚举 {@link SocialTypeEnum} + */ + private Integer socialType; + /** + * 用户类型 + * + * 目的:不同用户类型,对应不同的小程序,需要自己的配置 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 客户端 id + */ + private String clientId; + /** + * 客户端 Secret + */ + private String clientSecret; + + /** + * 代理编号 + * + * 目前只有部分“社交类型”在使用: + * 1. 企业微信:对应授权方的网页应用 ID + */ + private String agentId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialUserBindDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialUserBindDO.java new file mode 100644 index 0000000..2791de9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialUserBindDO.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.system.dal.dataobject.social; + +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 社交用户的绑定 + * 即 {@link SocialUserDO} 与 UserDO 的关联表 + * + * @author 芋道源码 + */ +@TableName(value = "system_social_user_bind", autoResultMap = true) +@KeySequence("system_social_user_bind_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SocialUserBindDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 关联的用户编号 + * + * 关联 UserDO 的编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + /** + * 社交平台的用户编号 + * + * 关联 {@link SocialUserDO#getId()} + */ + private Long socialUserId; + /** + * 社交平台的类型 + * + * 冗余 {@link SocialUserDO#getType()} + */ + private Integer socialType; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialUserDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialUserDO.java new file mode 100644 index 0000000..8c196cd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/social/SocialUserDO.java @@ -0,0 +1,74 @@ +package com.tashow.cloud.system.dal.dataobject.social; + +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import lombok.*; + +/** + * 社交(三方)用户 + * + * @author weir + */ +@TableName(value = "system_social_user", autoResultMap = true) +@KeySequence("system_social_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SocialUserDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 社交平台的类型 + * + * 枚举 {@link SocialTypeEnum} + */ + private Integer type; + + /** + * 社交 openid + */ + private String openid; + /** + * 社交 token + */ + private String token; + /** + * 原始 Token 数据,一般是 JSON 格式 + */ + private String rawTokenInfo; + + /** + * 用户昵称 + */ + private String nickname; + /** + * 用户头像 + */ + private String avatar; + /** + * 原始用户数据,一般是 JSON 格式 + */ + private String rawUserInfo; + + /** + * 最后一次的认证 code + */ + private String code; + /** + * 最后一次的认证 state + */ + private String state; + +} + + diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/tenant/TenantDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/tenant/TenantDO.java new file mode 100644 index 0000000..7e24dc7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/tenant/TenantDO.java @@ -0,0 +1,81 @@ +package com.tashow.cloud.system.dal.dataobject.tenant; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 租户 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_tenant", autoResultMap = true) +@KeySequence("system_tenant_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TenantDO extends BaseDO { + + /** + * 套餐编号 - 系统 + */ + public static final Long PACKAGE_ID_SYSTEM = 0L; + + /** + * 租户编号,自增 + */ + private Long id; + /** + * 租户名,唯一 + */ + private String name; + /** + * 联系人的用户编号 + * + * 关联 {@link AdminUserDO#getId()} + */ + private Long contactUserId; + /** + * 联系人 + */ + private String contactName; + /** + * 联系手机 + */ + private String contactMobile; + /** + * 租户状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 绑定域名 + */ + private String website; + /** + * 租户套餐编号 + * + * 关联 {@link TenantPackageDO#getId()} + * 特殊逻辑:系统内置租户,不使用套餐,暂时使用 {@link #PACKAGE_ID_SYSTEM} 标识 + */ + private Long packageId; + /** + * 过期时间 + */ + private LocalDateTime expireTime; + /** + * 账号数量 + */ + private Integer accountCount; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/tenant/TenantPackageDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/tenant/TenantPackageDO.java new file mode 100644 index 0000000..b4bd30c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/tenant/TenantPackageDO.java @@ -0,0 +1,52 @@ +package com.tashow.cloud.system.dal.dataobject.tenant; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.Set; + +/** + * 租户套餐 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_tenant_package", autoResultMap = true) +@KeySequence("system_tenant_package_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TenantPackageDO extends BaseDO { + + /** + * 套餐编号,自增 + */ + private Long id; + /** + * 套餐名,唯一 + */ + private String name; + /** + * 租户套餐状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 关联的菜单编号 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Set menuIds; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/user/AdminUserDO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/user/AdminUserDO.java new file mode 100644 index 0000000..5c3d41a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/dataobject/user/AdminUserDO.java @@ -0,0 +1,97 @@ +package com.tashow.cloud.system.dal.dataobject.user; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.tenant.core.db.TenantBaseDO; +import com.tashow.cloud.systemapi.enums.common.SexEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.tashow.cloud.systemapi.enums.common.SexEnum; +import lombok.*; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +import java.time.LocalDateTime; +import java.util.Set; + +/** + * 管理后台的用户 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_users", autoResultMap = true) // 由于 SQL Server 的 system_user 是关键字,所以使用 system_users +@KeySequence("system_users_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AdminUserDO extends TenantBaseDO { + + /** + * 用户ID + */ + @TableId + private Long id; + /** + * 用户账号 + */ + private String username; + /** + * 加密后的密码 + * + * 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐 + */ + private String password; + /** + * 用户昵称 + */ + private String nickname; + /** + * 备注 + */ + private String remark; + /** + * 部门 ID + */ + private Long deptId; + /** + * 岗位编号数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Set postIds; + /** + * 用户邮箱 + */ + private String email; + /** + * 手机号码 + */ + private String mobile; + /** + * 用户性别 + * + * 枚举类 {@link SexEnum} + */ + private Integer sex; + /** + * 用户头像 + */ + private String avatar; + /** + * 帐号状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 最后登录IP + */ + private String loginIp; + /** + * 最后登录时间 + */ + private LocalDateTime loginDate; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/DeptMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/DeptMapper.java new file mode 100644 index 0000000..c3b2142 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/DeptMapper.java @@ -0,0 +1,37 @@ +package com.tashow.cloud.system.dal.mysql.dept; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptListReqVO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface DeptMapper extends BaseMapperX { + + default List selectList(DeptListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(DeptDO::getName, reqVO.getName()) + .eqIfPresent(DeptDO::getStatus, reqVO.getStatus())); + } + + default DeptDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(DeptDO::getParentId, parentId, DeptDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(DeptDO::getParentId, parentId); + } + + default List selectListByParentId(Collection parentIds) { + return selectList(DeptDO::getParentId, parentIds); + } + + default List selectListByLeaderUserId(Long id) { + return selectList(DeptDO::getLeaderUserId, id); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/PostMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/PostMapper.java new file mode 100644 index 0000000..88e350f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/PostMapper.java @@ -0,0 +1,38 @@ +package com.tashow.cloud.system.dal.mysql.dept; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostPageReqVO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface PostMapper extends BaseMapperX { + + default List selectList(Collection ids, Collection statuses) { + return selectList(new LambdaQueryWrapperX() + .inIfPresent(PostDO::getId, ids) + .inIfPresent(PostDO::getStatus, statuses)); + } + + default PageResult selectPage(PostPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(PostDO::getCode, reqVO.getCode()) + .likeIfPresent(PostDO::getName, reqVO.getName()) + .eqIfPresent(PostDO::getStatus, reqVO.getStatus()) + .orderByDesc(PostDO::getId)); + } + + default PostDO selectByName(String name) { + return selectOne(PostDO::getName, name); + } + + default PostDO selectByCode(String code) { + return selectOne(PostDO::getCode, code); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/UserPostMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/UserPostMapper.java new file mode 100644 index 0000000..b77b834 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dept/UserPostMapper.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.system.dal.mysql.dept; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.dal.dataobject.dept.UserPostDO; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface UserPostMapper extends BaseMapperX { + + default List selectListByUserId(Long userId) { + return selectList(UserPostDO::getUserId, userId); + } + + default void deleteByUserIdAndPostId(Long userId, Collection postIds) { + delete(new LambdaQueryWrapperX() + .eq(UserPostDO::getUserId, userId) + .in(UserPostDO::getPostId, postIds)); + } + + default List selectListByPostIds(Collection postIds) { + return selectList(UserPostDO::getPostId, postIds); + } + + default void deleteByUserId(Long userId) { + delete(Wrappers.lambdaUpdate(UserPostDO.class).eq(UserPostDO::getUserId, userId)); + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dict/DictDataMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dict/DictDataMapper.java new file mode 100644 index 0000000..3e7b818 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dict/DictDataMapper.java @@ -0,0 +1,51 @@ +package com.tashow.cloud.system.dal.mysql.dict; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictDataDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictDataDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +@Mapper +public interface DictDataMapper extends BaseMapperX { + + default DictDataDO selectByDictTypeAndValue(String dictType, String value) { + return selectOne(DictDataDO::getDictType, dictType, DictDataDO::getValue, value); + } + + default DictDataDO selectByDictTypeAndLabel(String dictType, String label) { + return selectOne(DictDataDO::getDictType, dictType, DictDataDO::getLabel, label); + } + + default List selectByDictTypeAndValues(String dictType, Collection values) { + return selectList(new LambdaQueryWrapper().eq(DictDataDO::getDictType, dictType) + .in(DictDataDO::getValue, values)); + } + + default long selectCountByDictType(String dictType) { + return selectCount(DictDataDO::getDictType, dictType); + } + + default PageResult selectPage(DictDataPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DictDataDO::getLabel, reqVO.getLabel()) + .eqIfPresent(DictDataDO::getDictType, reqVO.getDictType()) + .eqIfPresent(DictDataDO::getStatus, reqVO.getStatus()) + .orderByDesc(Arrays.asList(DictDataDO::getDictType, DictDataDO::getSort))); + } + + default List selectListByStatusAndDictType(Integer status, String dictType) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(DictDataDO::getStatus, status) + .eqIfPresent(DictDataDO::getDictType, dictType)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dict/DictTypeMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dict/DictTypeMapper.java new file mode 100644 index 0000000..88344bd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/dict/DictTypeMapper.java @@ -0,0 +1,37 @@ +package com.tashow.cloud.system.dal.mysql.dict; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictTypeDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +import java.time.LocalDateTime; + +@Mapper +public interface DictTypeMapper extends BaseMapperX { + + default PageResult selectPage(DictTypePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DictTypeDO::getName, reqVO.getName()) + .likeIfPresent(DictTypeDO::getType, reqVO.getType()) + .eqIfPresent(DictTypeDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(DictTypeDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(DictTypeDO::getId)); + } + + default DictTypeDO selectByType(String type) { + return selectOne(DictTypeDO::getType, type); + } + + default DictTypeDO selectByName(String name) { + return selectOne(DictTypeDO::getName, name); + } + + @Update("UPDATE system_dict_type SET deleted = 1, deleted_time = #{deletedTime} WHERE id = #{id}") + void updateToDelete(@Param("id") Long id, @Param("deletedTime") LocalDateTime deletedTime); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/logger/LoginLogMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/logger/LoginLogMapper.java new file mode 100644 index 0000000..1e1502c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/logger/LoginLogMapper.java @@ -0,0 +1,31 @@ +package com.tashow.cloud.system.dal.mysql.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.logger.LoginLogDO; +import com.tashow.cloud.systemapi.enums.logger.LoginResultEnum; +import com.tashow.cloud.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.logger.LoginLogDO; +import com.tashow.cloud.systemapi.enums.logger.LoginResultEnum; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface LoginLogMapper extends BaseMapperX { + + default PageResult selectPage(LoginLogPageReqVO reqVO) { + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .likeIfPresent(LoginLogDO::getUserIp, reqVO.getUserIp()) + .likeIfPresent(LoginLogDO::getUsername, reqVO.getUsername()) + .betweenIfPresent(LoginLogDO::getCreateTime, reqVO.getCreateTime()); + if (Boolean.TRUE.equals(reqVO.getStatus())) { + query.eq(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()); + } else if (Boolean.FALSE.equals(reqVO.getStatus())) { + query.gt(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()); + } + query.orderByDesc(LoginLogDO::getId); // 降序 + return selectPage(reqVO, query); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/logger/OperateLogMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/logger/OperateLogMapper.java new file mode 100644 index 0000000..efa2599 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/logger/OperateLogMapper.java @@ -0,0 +1,36 @@ +package com.tashow.cloud.system.dal.mysql.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.logger.OperateLogDO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.logger.OperateLogDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OperateLogMapper extends BaseMapperX { + + default PageResult selectPage(OperateLogPageReqVO pageReqDTO) { + return selectPage(pageReqDTO, new LambdaQueryWrapperX() + .eqIfPresent(OperateLogDO::getUserId, pageReqDTO.getUserId()) + .eqIfPresent(OperateLogDO::getBizId, pageReqDTO.getBizId()) + .likeIfPresent(OperateLogDO::getType, pageReqDTO.getType()) + .likeIfPresent(OperateLogDO::getSubType, pageReqDTO.getSubType()) + .likeIfPresent(OperateLogDO::getAction, pageReqDTO.getAction()) + .betweenIfPresent(OperateLogDO::getCreateTime, pageReqDTO.getCreateTime()) + .orderByDesc(OperateLogDO::getId)); + } + + default PageResult selectPage(OperateLogPageReqDTO pageReqDTO) { + return selectPage(pageReqDTO, new LambdaQueryWrapperX() + .eqIfPresent(OperateLogDO::getType, pageReqDTO.getType()) + .eqIfPresent(OperateLogDO::getBizId, pageReqDTO.getBizId()) + .eqIfPresent(OperateLogDO::getUserId, pageReqDTO.getUserId()) + .orderByDesc(OperateLogDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailAccountMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailAccountMapper.java new file mode 100644 index 0000000..3fcaf06 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailAccountMapper.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.system.dal.mysql.mail; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailAccountDO; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailAccountDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MailAccountMapper extends BaseMapperX { + + default PageResult selectPage(MailAccountPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .likeIfPresent(MailAccountDO::getMail, pageReqVO.getMail()) + .likeIfPresent(MailAccountDO::getUsername , pageReqVO.getUsername())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailLogMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailLogMapper.java new file mode 100644 index 0000000..9d883e5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailLogMapper.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.system.dal.mysql.mail; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailLogDO; +import com.tashow.cloud.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailLogDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MailLogMapper extends BaseMapperX { + + default PageResult selectPage(MailLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(MailLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(MailLogDO::getUserType, reqVO.getUserType()) + .likeIfPresent(MailLogDO::getToMail, reqVO.getToMail()) + .eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId()) + .eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId()) + .eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus()) + .betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime()) + .orderByDesc(MailLogDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailTemplateMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailTemplateMapper.java new file mode 100644 index 0000000..6cca078 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/mail/MailTemplateMapper.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.system.dal.mysql.mail; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailTemplateDO; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailTemplateDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MailTemplateMapper extends BaseMapperX { + + default PageResult selectPage(MailTemplatePageReqVO pageReqVO){ + return selectPage(pageReqVO , new LambdaQueryWrapperX() + .eqIfPresent(MailTemplateDO::getStatus, pageReqVO.getStatus()) + .likeIfPresent(MailTemplateDO::getCode, pageReqVO.getCode()) + .likeIfPresent(MailTemplateDO::getName, pageReqVO.getName()) + .eqIfPresent(MailTemplateDO::getAccountId, pageReqVO.getAccountId()) + .betweenIfPresent(MailTemplateDO::getCreateTime, pageReqVO.getCreateTime())); + } + + default Long selectCountByAccountId(Long accountId) { + return selectCount(MailTemplateDO::getAccountId, accountId); + } + + default MailTemplateDO selectByCode(String code) { + return selectOne(MailTemplateDO::getCode, code); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notice/NoticeMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notice/NoticeMapper.java new file mode 100644 index 0000000..4e34e92 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notice/NoticeMapper.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.system.dal.mysql.notice; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticePageReqVO; +import com.tashow.cloud.system.dal.dataobject.notice.NoticeDO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticePageReqVO; +import com.tashow.cloud.system.dal.dataobject.notice.NoticeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface NoticeMapper extends BaseMapperX { + + default PageResult selectPage(NoticePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(NoticeDO::getTitle, reqVO.getTitle()) + .eqIfPresent(NoticeDO::getStatus, reqVO.getStatus()) + .orderByDesc(NoticeDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notify/NotifyMessageMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notify/NotifyMessageMapper.java new file mode 100644 index 0000000..610b5ac --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notify/NotifyMessageMapper.java @@ -0,0 +1,70 @@ +package com.tashow.cloud.system.dal.mysql.notify; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.QueryWrapperX; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyMessageDO; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +@Mapper +public interface NotifyMessageMapper extends BaseMapperX { + + default PageResult selectPage(NotifyMessagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(NotifyMessageDO::getUserId, reqVO.getUserId()) + .eqIfPresent(NotifyMessageDO::getUserType, reqVO.getUserType()) + .likeIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode()) + .eqIfPresent(NotifyMessageDO::getTemplateType, reqVO.getTemplateType()) + .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(NotifyMessageDO::getId)); + } + + default PageResult selectPage(NotifyMessageMyPageReqVO reqVO, Long userId, Integer userType) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus()) + .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime()) + .eq(NotifyMessageDO::getUserId, userId) + .eq(NotifyMessageDO::getUserType, userType) + .orderByDesc(NotifyMessageDO::getId)); + } + + default int updateListRead(Collection ids, Long userId, Integer userType) { + return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()), + new LambdaQueryWrapperX() + .in(NotifyMessageDO::getId, ids) + .eq(NotifyMessageDO::getUserId, userId) + .eq(NotifyMessageDO::getUserType, userType) + .eq(NotifyMessageDO::getReadStatus, false)); + } + + default int updateListRead(Long userId, Integer userType) { + return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()), + new LambdaQueryWrapperX() + .eq(NotifyMessageDO::getUserId, userId) + .eq(NotifyMessageDO::getUserType, userType) + .eq(NotifyMessageDO::getReadStatus, false)); + } + + default List selectUnreadListByUserIdAndUserType(Long userId, Integer userType, Integer size) { + return selectList(new QueryWrapperX() // 由于要使用 limitN 语句,所以只能用 QueryWrapperX + .eq("user_id", userId) + .eq("user_type", userType) + .eq("read_status", false) + .orderByDesc("id").limitN(size)); + } + + default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) { + return selectCount(new LambdaQueryWrapperX() + .eq(NotifyMessageDO::getReadStatus, false) + .eq(NotifyMessageDO::getUserId, userId) + .eq(NotifyMessageDO::getUserType, userType)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notify/NotifyTemplateMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notify/NotifyTemplateMapper.java new file mode 100644 index 0000000..05f102c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/notify/NotifyTemplateMapper.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.system.dal.mysql.notify; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyTemplateDO; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyTemplateDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface NotifyTemplateMapper extends BaseMapperX { + + default NotifyTemplateDO selectByCode(String code) { + return selectOne(NotifyTemplateDO::getCode, code); + } + + default PageResult selectPage(NotifyTemplatePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(NotifyTemplateDO::getCode, reqVO.getCode()) + .likeIfPresent(NotifyTemplateDO::getName, reqVO.getName()) + .eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(NotifyTemplateDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java new file mode 100644 index 0000000..f25f315 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.dal.mysql.oauth2; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.tenant.core.aop.TenantIgnore; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.List; + +@Mapper +public interface OAuth2AccessTokenMapper extends BaseMapperX { + + @TenantIgnore // 获取 token 的时候,需要忽略租户编号。原因是:一些场景下,可能不会传递 tenant-id 请求头,例如说文件上传、积木报表等等 + default OAuth2AccessTokenDO selectByAccessToken(String accessToken) { + return selectOne(OAuth2AccessTokenDO::getAccessToken, accessToken); + } + + default List selectListByRefreshToken(String refreshToken) { + return selectList(OAuth2AccessTokenDO::getRefreshToken, refreshToken); + } + + default PageResult selectPage(OAuth2AccessTokenPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(OAuth2AccessTokenDO::getUserId, reqVO.getUserId()) + .eqIfPresent(OAuth2AccessTokenDO::getUserType, reqVO.getUserType()) + .likeIfPresent(OAuth2AccessTokenDO::getClientId, reqVO.getClientId()) + .gt(OAuth2AccessTokenDO::getExpiresTime, LocalDateTime.now()) + .orderByDesc(OAuth2AccessTokenDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2ApproveMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2ApproveMapper.java new file mode 100644 index 0000000..ff9c075 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2ApproveMapper.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.system.dal.mysql.oauth2; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface OAuth2ApproveMapper extends BaseMapperX { + + default int update(OAuth2ApproveDO updateObj) { + return update(updateObj, new LambdaQueryWrapperX() + .eq(OAuth2ApproveDO::getUserId, updateObj.getUserId()) + .eq(OAuth2ApproveDO::getUserType, updateObj.getUserType()) + .eq(OAuth2ApproveDO::getClientId, updateObj.getClientId()) + .eq(OAuth2ApproveDO::getScope, updateObj.getScope())); + } + + default List selectListByUserIdAndUserTypeAndClientId(Long userId, Integer userType, String clientId) { + return selectList(new LambdaQueryWrapperX() + .eq(OAuth2ApproveDO::getUserId, userId) + .eq(OAuth2ApproveDO::getUserType, userType) + .eq(OAuth2ApproveDO::getClientId, clientId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2ClientMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2ClientMapper.java new file mode 100644 index 0000000..888be56 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2ClientMapper.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.system.dal.mysql.oauth2; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; +import org.apache.ibatis.annotations.Mapper; + + +/** + * OAuth2 客户端 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface OAuth2ClientMapper extends BaseMapperX { + + default PageResult selectPage(OAuth2ClientPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(OAuth2ClientDO::getName, reqVO.getName()) + .eqIfPresent(OAuth2ClientDO::getStatus, reqVO.getStatus()) + .orderByDesc(OAuth2ClientDO::getId)); + } + + default OAuth2ClientDO selectByClientId(String clientId) { + return selectOne(OAuth2ClientDO::getClientId, clientId); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2CodeMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2CodeMapper.java new file mode 100644 index 0000000..3a72f70 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2CodeMapper.java @@ -0,0 +1,15 @@ +package com.tashow.cloud.system.dal.mysql.oauth2; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2CodeDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2CodeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OAuth2CodeMapper extends BaseMapperX { + + default OAuth2CodeDO selectByCode(String code) { + return selectOne(OAuth2CodeDO::getCode, code); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java new file mode 100644 index 0000000..037853b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java @@ -0,0 +1,22 @@ +package com.tashow.cloud.system.dal.mysql.oauth2; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; +import com.tashow.cloud.tenant.core.aop.TenantIgnore; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OAuth2RefreshTokenMapper extends BaseMapperX { + + default int deleteByRefreshToken(String refreshToken) { + return delete(new LambdaQueryWrapperX() + .eq(OAuth2RefreshTokenDO::getRefreshToken, refreshToken)); + } + + @TenantIgnore // 获取 token 的时候,需要忽略租户编号。原因是:一些场景下,可能不会传递 tenant-id 请求头,例如说文件上传、积木报表等等 + default OAuth2RefreshTokenDO selectByRefreshToken(String refreshToken) { + return selectOne(OAuth2RefreshTokenDO::getRefreshToken, refreshToken); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/package-info.java new file mode 100644 index 0000000..5a3dc21 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/package-info.java @@ -0,0 +1,9 @@ +/** + * DAL = Data Access Layer 数据访问层 + * 1. data object:数据对象 + * 2. redis:Redis 的 CRUD 操作 + * 3. mysql:MySQL 的 CRUD 操作 + * + * 其中,MySQL 的表以 system_ 作为前缀 + */ +package com.tashow.cloud.system.dal.mysql; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/MenuMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/MenuMapper.java new file mode 100644 index 0000000..a4a55a6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/MenuMapper.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.system.dal.mysql.permission; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface MenuMapper extends BaseMapperX { + + default MenuDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(MenuDO::getParentId, parentId, MenuDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(MenuDO::getParentId, parentId); + } + + default List selectList(MenuListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(MenuDO::getName, reqVO.getName()) + .eqIfPresent(MenuDO::getStatus, reqVO.getStatus())); + } + + default List selectListByPermission(String permission) { + return selectList(MenuDO::getPermission, permission); + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/RoleMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/RoleMapper.java new file mode 100644 index 0000000..9cef51b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/RoleMapper.java @@ -0,0 +1,41 @@ +package com.tashow.cloud.system.dal.mysql.permission; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RolePageReqVO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RolePageReqVO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.lang.Nullable; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface RoleMapper extends BaseMapperX { + + default PageResult selectPage(RolePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(RoleDO::getName, reqVO.getName()) + .likeIfPresent(RoleDO::getCode, reqVO.getCode()) + .eqIfPresent(RoleDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BaseDO::getCreateTime, reqVO.getCreateTime()) + .orderByAsc(RoleDO::getSort)); + } + + default RoleDO selectByName(String name) { + return selectOne(RoleDO::getName, name); + } + + default RoleDO selectByCode(String code) { + return selectOne(RoleDO::getCode, code); + } + + default List selectListByStatus(@Nullable Collection statuses) { + return selectList(RoleDO::getStatus, statuses); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/RoleMenuMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/RoleMenuMapper.java new file mode 100644 index 0000000..518e8a3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/RoleMenuMapper.java @@ -0,0 +1,41 @@ +package com.tashow.cloud.system.dal.mysql.permission; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.system.dal.dataobject.permission.RoleMenuDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.tashow.cloud.system.dal.dataobject.permission.RoleMenuDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface RoleMenuMapper extends BaseMapperX { + + default List selectListByRoleId(Long roleId) { + return selectList(RoleMenuDO::getRoleId, roleId); + } + + default List selectListByRoleId(Collection roleIds) { + return selectList(RoleMenuDO::getRoleId, roleIds); + } + + default List selectListByMenuId(Long menuId) { + return selectList(RoleMenuDO::getMenuId, menuId); + } + + default void deleteListByRoleIdAndMenuIds(Long roleId, Collection menuIds) { + delete(new LambdaQueryWrapper() + .eq(RoleMenuDO::getRoleId, roleId) + .in(RoleMenuDO::getMenuId, menuIds)); + } + + default void deleteListByMenuId(Long menuId) { + delete(new LambdaQueryWrapper().eq(RoleMenuDO::getMenuId, menuId)); + } + + default void deleteListByRoleId(Long roleId) { + delete(new LambdaQueryWrapper().eq(RoleMenuDO::getRoleId, roleId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/UserRoleMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/UserRoleMapper.java new file mode 100644 index 0000000..fa01168 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/permission/UserRoleMapper.java @@ -0,0 +1,37 @@ +package com.tashow.cloud.system.dal.mysql.permission; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.system.dal.dataobject.permission.UserRoleDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.tashow.cloud.system.dal.dataobject.permission.UserRoleDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface UserRoleMapper extends BaseMapperX { + + default List selectListByUserId(Long userId) { + return selectList(UserRoleDO::getUserId, userId); + } + + default void deleteListByUserIdAndRoleIdIds(Long userId, Collection roleIds) { + delete(new LambdaQueryWrapper() + .eq(UserRoleDO::getUserId, userId) + .in(UserRoleDO::getRoleId, roleIds)); + } + + default void deleteListByUserId(Long userId) { + delete(new LambdaQueryWrapper().eq(UserRoleDO::getUserId, userId)); + } + + default void deleteListByRoleId(Long roleId) { + delete(new LambdaQueryWrapper().eq(UserRoleDO::getRoleId, roleId)); + } + + default List selectListByRoleIds(Collection roleIds) { + return selectList(UserRoleDO::getRoleId, roleIds); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsChannelMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsChannelMapper.java new file mode 100644 index 0000000..6975c8d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsChannelMapper.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.system.dal.mysql.sms; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsChannelDO; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsChannelDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsChannelMapper extends BaseMapperX { + + default PageResult selectPage(SmsChannelPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(SmsChannelDO::getSignature, reqVO.getSignature()) + .eqIfPresent(SmsChannelDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(SmsChannelDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(SmsChannelDO::getId)); + } + + default SmsChannelDO selectByCode(String code) { + return selectOne(SmsChannelDO::getCode, code); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsCodeMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsCodeMapper.java new file mode 100644 index 0000000..7b5fcfd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsCodeMapper.java @@ -0,0 +1,29 @@ +package com.tashow.cloud.system.dal.mysql.sms; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.QueryWrapperX; +import com.tashow.cloud.system.dal.dataobject.sms.SmsCodeDO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsCodeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsCodeMapper extends BaseMapperX { + + /** + * 获得手机号的最后一个手机验证码 + * + * @param mobile 手机号 + * @param scene 发送场景,选填 + * @param code 验证码 选填 + * @return 手机验证码 + */ + default SmsCodeDO selectLastByMobile(String mobile, String code, Integer scene) { + return selectOne(new QueryWrapperX() + .eq("mobile", mobile) + .eqIfPresent("scene", scene) + .eqIfPresent("code", code) + .orderByDesc("id") + .limitN(1)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsLogMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsLogMapper.java new file mode 100644 index 0000000..4eaafca --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsLogMapper.java @@ -0,0 +1,27 @@ +package com.tashow.cloud.system.dal.mysql.sms; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsLogDO; +import com.tashow.cloud.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsLogDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsLogMapper extends BaseMapperX { + + default PageResult selectPage(SmsLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(SmsLogDO::getChannelId, reqVO.getChannelId()) + .eqIfPresent(SmsLogDO::getTemplateId, reqVO.getTemplateId()) + .likeIfPresent(SmsLogDO::getMobile, reqVO.getMobile()) + .eqIfPresent(SmsLogDO::getSendStatus, reqVO.getSendStatus()) + .betweenIfPresent(SmsLogDO::getSendTime, reqVO.getSendTime()) + .eqIfPresent(SmsLogDO::getReceiveStatus, reqVO.getReceiveStatus()) + .betweenIfPresent(SmsLogDO::getReceiveTime, reqVO.getReceiveTime()) + .orderByDesc(SmsLogDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsTemplateMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsTemplateMapper.java new file mode 100644 index 0000000..176afc0 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/sms/SmsTemplateMapper.java @@ -0,0 +1,35 @@ +package com.tashow.cloud.system.dal.mysql.sms; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsTemplateDO; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsTemplateDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsTemplateMapper extends BaseMapperX { + + default SmsTemplateDO selectByCode(String code) { + return selectOne(SmsTemplateDO::getCode, code); + } + + default PageResult selectPage(SmsTemplatePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(SmsTemplateDO::getType, reqVO.getType()) + .eqIfPresent(SmsTemplateDO::getStatus, reqVO.getStatus()) + .likeIfPresent(SmsTemplateDO::getCode, reqVO.getCode()) + .likeIfPresent(SmsTemplateDO::getContent, reqVO.getContent()) + .likeIfPresent(SmsTemplateDO::getApiTemplateId, reqVO.getApiTemplateId()) + .eqIfPresent(SmsTemplateDO::getChannelId, reqVO.getChannelId()) + .betweenIfPresent(SmsTemplateDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(SmsTemplateDO::getId)); + } + + default Long selectCountByChannelId(Long channelId) { + return selectCount(SmsTemplateDO::getChannelId, channelId); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialClientMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialClientMapper.java new file mode 100644 index 0000000..1817a8a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialClientMapper.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.system.dal.mysql.social; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialClientDO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialClientDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SocialClientMapper extends BaseMapperX { + + default SocialClientDO selectBySocialTypeAndUserType(Integer socialType, Integer userType) { + return selectOne(SocialClientDO::getSocialType, socialType, + SocialClientDO::getUserType, userType); + } + + default PageResult selectPage(SocialClientPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(SocialClientDO::getName, reqVO.getName()) + .eqIfPresent(SocialClientDO::getSocialType, reqVO.getSocialType()) + .eqIfPresent(SocialClientDO::getUserType, reqVO.getUserType()) + .likeIfPresent(SocialClientDO::getClientId, reqVO.getClientId()) + .eqIfPresent(SocialClientDO::getStatus, reqVO.getStatus()) + .orderByDesc(SocialClientDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialUserBindMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialUserBindMapper.java new file mode 100644 index 0000000..ebaabcb --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialUserBindMapper.java @@ -0,0 +1,45 @@ +package com.tashow.cloud.system.dal.mysql.social; + +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserBindDO; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserBindDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SocialUserBindMapper extends BaseMapperX { + + default void deleteByUserTypeAndUserIdAndSocialType(Integer userType, Long userId, Integer socialType) { + delete(new LambdaQueryWrapperX() + .eq(SocialUserBindDO::getUserType, userType) + .eq(SocialUserBindDO::getUserId, userId) + .eq(SocialUserBindDO::getSocialType, socialType)); + } + + default void deleteByUserTypeAndSocialUserId(Integer userType, Long socialUserId) { + delete(new LambdaQueryWrapperX() + .eq(SocialUserBindDO::getUserType, userType) + .eq(SocialUserBindDO::getSocialUserId, socialUserId)); + } + + default SocialUserBindDO selectByUserTypeAndSocialUserId(Integer userType, Long socialUserId) { + return selectOne(SocialUserBindDO::getUserType, userType, + SocialUserBindDO::getSocialUserId, socialUserId); + } + + default List selectListByUserIdAndUserType(Long userId, Integer userType) { + return selectList(new LambdaQueryWrapperX() + .eq(SocialUserBindDO::getUserId, userId) + .eq(SocialUserBindDO::getUserType, userType)); + } + + default SocialUserBindDO selectByUserIdAndUserTypeAndSocialType(Long userId, Integer userType, Integer socialType) { + return selectOne(new LambdaQueryWrapperX() + .eq(SocialUserBindDO::getUserId, userId) + .eq(SocialUserBindDO::getUserType, userType) + .eq(SocialUserBindDO::getSocialType, socialType)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialUserMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialUserMapper.java new file mode 100644 index 0000000..c2e7e49 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/social/SocialUserMapper.java @@ -0,0 +1,38 @@ +package com.tashow.cloud.system.dal.mysql.social; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SocialUserMapper extends BaseMapperX { + + default SocialUserDO selectByTypeAndCodeAnState(Integer type, String code, String state) { + return selectOne(new LambdaQueryWrapper() + .eq(SocialUserDO::getType, type) + .eq(SocialUserDO::getCode, code) + .eq(SocialUserDO::getState, state)); + } + + default SocialUserDO selectByTypeAndOpenid(Integer type, String openid) { + return selectOne(new LambdaQueryWrapper() + .eq(SocialUserDO::getType, type) + .eq(SocialUserDO::getOpenid, openid)); + } + + default PageResult selectPage(SocialUserPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(SocialUserDO::getType, reqVO.getType()) + .likeIfPresent(SocialUserDO::getNickname, reqVO.getNickname()) + .likeIfPresent(SocialUserDO::getOpenid, reqVO.getOpenid()) + .betweenIfPresent(SocialUserDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(SocialUserDO::getId)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/tenant/TenantMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/tenant/TenantMapper.java new file mode 100644 index 0000000..9c049ae --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/tenant/TenantMapper.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.system.dal.mysql.tenant; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantDO; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 租户 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface TenantMapper extends BaseMapperX { + + default PageResult selectPage(TenantPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(TenantDO::getName, reqVO.getName()) + .likeIfPresent(TenantDO::getContactName, reqVO.getContactName()) + .likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile()) + .eqIfPresent(TenantDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(TenantDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(TenantDO::getId)); + } + + default TenantDO selectByName(String name) { + return selectOne(TenantDO::getName, name); + } + + default TenantDO selectByWebsite(String website) { + return selectOne(TenantDO::getWebsite, website); + } + + default Long selectCountByPackageId(Long packageId) { + return selectCount(TenantDO::getPackageId, packageId); + } + + default List selectListByPackageId(Long packageId) { + return selectList(TenantDO::getPackageId, packageId); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/tenant/TenantPackageMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/tenant/TenantPackageMapper.java new file mode 100644 index 0000000..0a18e69 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/tenant/TenantPackageMapper.java @@ -0,0 +1,38 @@ +package com.tashow.cloud.system.dal.mysql.tenant; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantPackageDO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantPackageDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 租户套餐 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface TenantPackageMapper extends BaseMapperX { + + default PageResult selectPage(TenantPackagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(TenantPackageDO::getName, reqVO.getName()) + .eqIfPresent(TenantPackageDO::getStatus, reqVO.getStatus()) + .likeIfPresent(TenantPackageDO::getRemark, reqVO.getRemark()) + .betweenIfPresent(TenantPackageDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(TenantPackageDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(TenantPackageDO::getStatus, status); + } + + default TenantPackageDO selectByName(String name) { + return selectOne(TenantPackageDO::getName, name); + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/user/AdminUserMapper.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/user/AdminUserMapper.java new file mode 100644 index 0000000..dd43e70 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/mysql/user/AdminUserMapper.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.system.dal.mysql.user; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.mybatis.mybatis.core.mapper.BaseMapperX; +import com.tashow.cloud.mybatis.mybatis.core.query.LambdaQueryWrapperX; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserPageReqVO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserPageReqVO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface AdminUserMapper extends BaseMapperX { + + default AdminUserDO selectByUsername(String username) { + return selectOne(AdminUserDO::getUsername, username); + } + + default AdminUserDO selectByEmail(String email) { + return selectOne(AdminUserDO::getEmail, email); + } + + default AdminUserDO selectByMobile(String mobile) { + return selectOne(AdminUserDO::getMobile, mobile); + } + + default PageResult selectPage(UserPageReqVO reqVO, Collection deptIds, Collection userIds) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(AdminUserDO::getUsername, reqVO.getUsername()) + .likeIfPresent(AdminUserDO::getMobile, reqVO.getMobile()) + .eqIfPresent(AdminUserDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(AdminUserDO::getCreateTime, reqVO.getCreateTime()) + .inIfPresent(AdminUserDO::getDeptId, deptIds) + .inIfPresent(AdminUserDO::getId, userIds) + .orderByDesc(AdminUserDO::getId)); + } + + default List selectListByNickname(String nickname) { + return selectList(new LambdaQueryWrapperX().like(AdminUserDO::getNickname, nickname)); + } + + default List selectListByStatus(Integer status) { + return selectList(AdminUserDO::getStatus, status); + } + + default List selectListByDeptIds(Collection deptIds) { + return selectList(AdminUserDO::getDeptId, deptIds); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/redis/RedisKeyConstants.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/redis/RedisKeyConstants.java new file mode 100644 index 0000000..b713489 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/redis/RedisKeyConstants.java @@ -0,0 +1,110 @@ +package com.tashow.cloud.system.dal.redis; + +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; + +/** + * System Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 指定部门的所有子部门编号数组的缓存 + *

+ * KEY 格式:dept_children_ids:{id} + * VALUE 数据类型:String 子部门编号集合 + */ + String DEPT_CHILDREN_ID_LIST = "dept_children_ids"; + + /** + * 角色的缓存 + *

+ * KEY 格式:role:{id} + * VALUE 数据类型:String 角色信息 + */ + String ROLE = "role"; + + /** + * 用户拥有的角色编号的缓存 + *

+ * KEY 格式:user_role_ids:{userId} + * VALUE 数据类型:String 角色编号集合 + */ + String USER_ROLE_ID_LIST = "user_role_ids"; + + /** + * 拥有指定菜单的角色编号的缓存 + *

+ * KEY 格式:user_role_ids:{menuId} + * VALUE 数据类型:String 角色编号集合 + */ + String MENU_ROLE_ID_LIST = "menu_role_ids"; + + /** + * 拥有权限对应的菜单编号数组的缓存 + *

+ * KEY 格式:permission_menu_ids:{permission} + * VALUE 数据类型:String 菜单编号数组 + */ + String PERMISSION_MENU_ID_LIST = "permission_menu_ids"; + + /** + * OAuth2 客户端的缓存 + *

+ * KEY 格式:oauth_client:{id} + * VALUE 数据类型:String 客户端信息 + */ + String OAUTH_CLIENT = "oauth_client"; + + /** + * 访问令牌的缓存 + *

+ * KEY 格式:oauth2_access_token:{token} + * VALUE 数据类型:String 访问令牌信息 {@link OAuth2AccessTokenDO} + *

+ * 由于动态过期时间,使用 RedisTemplate 操作 + */ + String OAUTH2_ACCESS_TOKEN = "oauth2_access_token:%s"; + + /** + * 站内信模版的缓存 + *

+ * KEY 格式:notify_template:{code} + * VALUE 数据格式:String 模版信息 + */ + String NOTIFY_TEMPLATE = "notify_template"; + + /** + * 邮件账号的缓存 + *

+ * KEY 格式:mail_account:{id} + * VALUE 数据格式:String 账号信息 + */ + String MAIL_ACCOUNT = "mail_account"; + + /** + * 邮件模版的缓存 + *

+ * KEY 格式:mail_template:{code} + * VALUE 数据格式:String 模版信息 + */ + String MAIL_TEMPLATE = "mail_template"; + + /** + * 短信模版的缓存 + *

+ * KEY 格式:sms_template:{id} + * VALUE 数据格式:String 模版信息 + */ + String SMS_TEMPLATE = "sms_template"; + + /** + * 小程序订阅模版的缓存 + * + * KEY 格式:wxa_subscribe_template:{userType} + * VALUE 数据格式 String, 模版信息 + */ + String WXA_SUBSCRIBE_TEMPLATE = "wxa_subscribe_template"; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java new file mode 100644 index 0000000..10c53a6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java @@ -0,0 +1,59 @@ +package com.tashow.cloud.system.dal.redis.oauth2; + +import cn.hutool.core.date.LocalDateTimeUtil; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; + + +/** + * {@link OAuth2AccessTokenDO} 的 RedisDAO + * + * @author 芋道源码 + */ +@Repository +public class OAuth2AccessTokenRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public OAuth2AccessTokenDO get(String accessToken) { + String redisKey = formatKey(accessToken); + return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), OAuth2AccessTokenDO.class); + } + + public void set(OAuth2AccessTokenDO accessTokenDO) { + String redisKey = formatKey(accessTokenDO.getAccessToken()); + // 清理多余字段,避免缓存 + accessTokenDO.setUpdater(null).setUpdateTime(null).setCreateTime(null).setCreator(null).setDeleted(null); + long time = LocalDateTimeUtil.between(LocalDateTime.now(), accessTokenDO.getExpiresTime(), ChronoUnit.SECONDS); + if (time > 0) { + stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(accessTokenDO), time, TimeUnit.SECONDS); + } + } + + public void delete(String accessToken) { + String redisKey = formatKey(accessToken); + stringRedisTemplate.delete(redisKey); + } + + public void deleteList(Collection accessTokens) { + List redisKeys = CollectionUtils.convertList(accessTokens, OAuth2AccessTokenRedisDAO::formatKey); + stringRedisTemplate.delete(redisKeys); + } + + private static String formatKey(String accessToken) { + return String.format(RedisKeyConstants.OAUTH2_ACCESS_TOKEN, accessToken); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/config/YudaoCaptchaConfiguration.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/config/YudaoCaptchaConfiguration.java new file mode 100644 index 0000000..a4fe2e2 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/config/YudaoCaptchaConfiguration.java @@ -0,0 +1,30 @@ +package com.tashow.cloud.system.framework.captcha.config; + +import com.tashow.cloud.system.framework.captcha.core.RedisCaptchaServiceImpl; +import com.tashow.cloud.system.framework.captcha.core.RedisCaptchaServiceImpl; +import com.xingyuv.captcha.properties.AjCaptchaProperties; +import com.xingyuv.captcha.service.CaptchaCacheService; +import com.xingyuv.captcha.service.impl.CaptchaServiceFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.StringRedisTemplate; + +/** + * 验证码的配置类 + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class YudaoCaptchaConfiguration { + + @Bean + public CaptchaCacheService captchaCacheService(AjCaptchaProperties config, + StringRedisTemplate stringRedisTemplate) { + CaptchaCacheService captchaCacheService = CaptchaServiceFactory.getCache(config.getCacheType().name()); + if (captchaCacheService instanceof RedisCaptchaServiceImpl) { + ((RedisCaptchaServiceImpl) captchaCacheService).setStringRedisTemplate(stringRedisTemplate); + } + return captchaCacheService; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/core/RedisCaptchaServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/core/RedisCaptchaServiceImpl.java new file mode 100644 index 0000000..8443abd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/core/RedisCaptchaServiceImpl.java @@ -0,0 +1,49 @@ +package com.tashow.cloud.system.framework.captcha.core; + +import com.xingyuv.captcha.service.CaptchaCacheService; +import lombok.Setter; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.concurrent.TimeUnit; + +/** + * 基于 Redis 实现验证码的存储 + * + * @author 星语 + */ +@Setter +public class RedisCaptchaServiceImpl implements CaptchaCacheService { + + private StringRedisTemplate stringRedisTemplate; + + @Override + public String type() { + return "redis"; + } + + @Override + public void set(String key, String value, long expiresInSeconds) { + stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS); + } + + @Override + public boolean exists(String key) { + return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key)); + } + + @Override + public void delete(String key) { + stringRedisTemplate.delete(key); + } + + @Override + public String get(String key) { + return stringRedisTemplate.opsForValue().get(key); + } + + @Override + public Long increment(String key, long val) { + return stringRedisTemplate.opsForValue().increment(key,val); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/package-info.java new file mode 100644 index 0000000..ad6c49f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/captcha/package-info.java @@ -0,0 +1,8 @@ +/** + * 验证码拓展 + * + * 基于 aj-captcha 实现滑块验证码,文档:https://ajcaptcha.beliefteam.cn/captcha-doc/ + * + * @author 星语 + */ +package com.tashow.cloud.system.framework.captcha; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/datapermission/config/DataPermissionConfiguration.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/datapermission/config/DataPermissionConfiguration.java new file mode 100644 index 0000000..9d9a1ee --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/datapermission/config/DataPermissionConfiguration.java @@ -0,0 +1,28 @@ +package com.tashow.cloud.system.framework.datapermission.config; + +import com.tashow.cloud.permission.core.rule.dept.DeptDataPermissionRuleCustomizer; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * system 模块的数据权限 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class DataPermissionConfiguration { + + @Bean + public DeptDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() { + return rule -> { + // dept + rule.addDeptColumn(AdminUserDO.class); + rule.addDeptColumn(DeptDO.class, "id"); + // user + rule.addUserColumn(AdminUserDO.class, "id"); + }; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/datapermission/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/datapermission/package-info.java new file mode 100644 index 0000000..a160a16 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/datapermission/package-info.java @@ -0,0 +1,4 @@ +/** + * system 模块的数据权限配置 + */ +package com.tashow.cloud.system.framework.datapermission; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/AdminUserParseFunction.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/AdminUserParseFunction.java new file mode 100644 index 0000000..167ce02 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/AdminUserParseFunction.java @@ -0,0 +1,51 @@ +package com.tashow.cloud.system.framework.operatelog.core; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.service.user.AdminUserService; +import com.mzt.logapi.service.IParseFunction; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 管理员名字的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class AdminUserParseFunction implements IParseFunction { + + public static final String NAME = "getAdminUserById"; + + @Resource + private AdminUserService adminUserService; + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + + // 获取用户信息 + AdminUserDO user = adminUserService.getUser(Convert.toLong(value)); + if (user == null) { + log.warn("[apply][获取用户{{}}为空", value); + return ""; + } + // 返回格式 芋道源码(13888888888) + String nickname = user.getNickname(); + if (StrUtil.isEmpty(user.getMobile())) { + return nickname; + } + return StrUtil.format("{}({})", nickname, user.getMobile()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/AreaParseFunction.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/AreaParseFunction.java new file mode 100644 index 0000000..a36689b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/AreaParseFunction.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.system.framework.operatelog.core; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import com.mzt.logapi.service.IParseFunction; +import com.tashow.cloud.ip.core.utils.AreaUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 地名的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class AreaParseFunction implements IParseFunction { + + public static final String NAME = "getArea"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return AreaUtils.format(Convert.toInt(value)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/BooleanParseFunction.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/BooleanParseFunction.java new file mode 100644 index 0000000..22faabb --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/BooleanParseFunction.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.system.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.excel.dict.core.DictFrameworkUtils; +import com.tashow.cloud.infraapi.enums.DictTypeConstants; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 是否类型的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class BooleanParseFunction implements IParseFunction { + + public static final String NAME = "getBoolean"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BOOLEAN_STRING, value.toString()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/DeptParseFunction.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/DeptParseFunction.java new file mode 100644 index 0000000..71fbf30 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/DeptParseFunction.java @@ -0,0 +1,46 @@ +package com.tashow.cloud.system.framework.operatelog.core; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.service.dept.DeptService; +import com.mzt.logapi.service.IParseFunction; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 部门名字的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class DeptParseFunction implements IParseFunction { + + public static final String NAME = "getDeptById"; + + @Resource + private DeptService deptService; + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + + // 获取部门信息 + DeptDO dept = deptService.getDept(Convert.toLong(value)); + if (dept == null) { + log.warn("[apply][获取部门{{}}为空", value); + return ""; + } + return dept.getName(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/PostParseFunction.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/PostParseFunction.java new file mode 100644 index 0000000..71dab95 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/PostParseFunction.java @@ -0,0 +1,46 @@ +package com.tashow.cloud.system.framework.operatelog.core; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.service.dept.PostService; +import com.mzt.logapi.service.IParseFunction; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 岗位名字的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class PostParseFunction implements IParseFunction { + + public static final String NAME = "getPostById"; + + @Resource + private PostService postService; + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + + // 获取岗位信息 + PostDO post = postService.getPost(Convert.toLong(value)); + if (post == null) { + log.warn("[apply][获取岗位{{}}为空", value); + return ""; + } + return post.getName(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/SexParseFunction.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/SexParseFunction.java new file mode 100644 index 0000000..a2f5e9e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/core/SexParseFunction.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.system.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.excel.dict.core.DictFrameworkUtils; +import com.tashow.cloud.systemapi.enums.DictTypeConstants; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 行业的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class SexParseFunction implements IParseFunction { + + public static final String NAME = "getSex"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.USER_SEX, value.toString()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/package-info.java new file mode 100644 index 0000000..fb8e562 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/operatelog/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位文件,避免文件夹缩进 + */ +package com.tashow.cloud.system.framework.operatelog; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/package-info.java new file mode 100644 index 0000000..711d921 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 system 模块的 framework 封装 + * + * @author 芋道源码 + */ +package com.tashow.cloud.system.framework; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/rpc/config/RpcConfiguration.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/rpc/config/RpcConfiguration.java new file mode 100644 index 0000000..3281ff4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/rpc/config/RpcConfiguration.java @@ -0,0 +1,12 @@ +package com.tashow.cloud.system.framework.rpc.config; + +import com.tashow.cloud.infraapi.api.config.ConfigApi; +import com.tashow.cloud.infraapi.api.file.FileApi; +import com.tashow.cloud.infraapi.api.websocket.WebSocketSenderApi; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@EnableFeignClients(clients = {FileApi.class, WebSocketSenderApi.class, ConfigApi.class}) +public class RpcConfiguration { +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/rpc/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/rpc/package-info.java new file mode 100644 index 0000000..7c17f39 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/rpc/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package com.tashow.cloud.system.framework.rpc; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/security/config/SecurityConfiguration.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/security/config/SecurityConfiguration.java new file mode 100644 index 0000000..7849017 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/security/config/SecurityConfiguration.java @@ -0,0 +1,40 @@ +package com.tashow.cloud.system.framework.security.config; + +import com.tashow.cloud.security.security.config.AuthorizeRequestsCustomizer; +import com.tashow.cloud.systemapi.enums.ApiConstants; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; + +/** + * System 模块的 Security 配置 + */ +@Configuration(proxyBeanMethods = false, value = "systemSecurityConfiguration") +public class SecurityConfiguration { + + @Bean("systemAuthorizeRequestsCustomizer") + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { + return new AuthorizeRequestsCustomizer() { + + @Override + public void customize(AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry registry) { + // TODO 芋艿:这个每个项目都需要重复配置,得捉摸有没通用的方案 + // Swagger 接口文档 + registry.requestMatchers("/v3/api-docs/**").permitAll() + .requestMatchers("/webjars/**").permitAll() + .requestMatchers("/swagger-ui").permitAll() + .requestMatchers("/swagger-ui/**").permitAll(); + // Druid 监控 + registry.requestMatchers("/druid/**").permitAll(); + // Spring Boot Actuator 的安全配置 + registry.requestMatchers("/actuator").permitAll() + .requestMatchers("/actuator/**").permitAll(); + // RPC 服务的安全配置 + registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); + } + + }; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/security/core/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/security/core/package-info.java new file mode 100644 index 0000000..61d4642 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/security/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package com.tashow.cloud.system.framework.security.core; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/config/SmsCodeProperties.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/config/SmsCodeProperties.java new file mode 100644 index 0000000..a0fae54 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/config/SmsCodeProperties.java @@ -0,0 +1,41 @@ +package com.tashow.cloud.system.framework.sms.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import jakarta.validation.constraints.NotNull; +import java.time.Duration; + +@ConfigurationProperties(prefix = "yudao.sms-code") +@Validated +@Data +public class SmsCodeProperties { + + /** + * 过期时间 + */ + @NotNull(message = "过期时间不能为空") + private Duration expireTimes; + /** + * 短信发送频率 + */ + @NotNull(message = "短信发送频率不能为空") + private Duration sendFrequency; + /** + * 每日发送最大数量 + */ + @NotNull(message = "每日发送最大数量不能为空") + private Integer sendMaximumQuantityPerDay; + /** + * 验证码最小值 + */ + @NotNull(message = "验证码最小值不能为空") + private Integer beginCode; + /** + * 验证码最大值 + */ + @NotNull(message = "验证码最大值不能为空") + private Integer endCode; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/config/SmsConfiguration.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/config/SmsConfiguration.java new file mode 100644 index 0000000..69a13d1 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/config/SmsConfiguration.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.system.framework.sms.config; + +import com.tashow.cloud.system.framework.sms.core.client.SmsClientFactory; +import com.tashow.cloud.system.framework.sms.core.client.impl.SmsClientFactoryImpl; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 短信配置类,包括短信客户端、短信验证码两部分 + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(SmsCodeProperties.class) +public class SmsConfiguration { + + @Bean + public SmsClientFactory smsClientFactory() { + return new SmsClientFactoryImpl(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/SmsClient.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/SmsClient.java new file mode 100644 index 0000000..ca6b55f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/SmsClient.java @@ -0,0 +1,56 @@ +package com.tashow.cloud.system.framework.sms.core.client; + +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsSendRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsTemplateRespDTO; + +import java.util.List; + +/** + * 短信客户端,用于对接各短信平台的 SDK,实现短信发送等功能 + * + * @author zzf + * @since 2021/1/25 14:14 + */ +public interface SmsClient { + + /** + * 获得渠道编号 + * + * @return 渠道编号 + */ + Long getId(); + + /** + * 发送消息 + * + * @param logId 日志编号 + * @param mobile 手机号 + * @param apiTemplateId 短信 API 的模板编号 + * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序 + * @return 短信发送结果 + */ + SmsSendRespDTO sendSms(Long logId, String mobile, String apiTemplateId, + List> templateParams) throws Throwable; + + /** + * 解析接收短信的接收结果 + * + * @param text 结果 + * @return 结果内容 + * @throws Throwable 当解析 text 发生异常时,则会抛出异常 + */ + List parseSmsReceiveStatus(String text) throws Throwable; + + /** + * 查询指定的短信模板 + * + * 如果查询失败,则返回 null 空 + * + * @param apiTemplateId 短信 API 的模板编号 + * @return 短信模板 + */ + SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/SmsClientFactory.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/SmsClientFactory.java new file mode 100644 index 0000000..81602ed --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/SmsClientFactory.java @@ -0,0 +1,37 @@ +package com.tashow.cloud.system.framework.sms.core.client; + +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; + +/** + * 短信客户端的工厂接口 + * + * @author zzf + * @since 2021/1/28 14:01 + */ +public interface SmsClientFactory { + + /** + * 获得短信 Client + * + * @param channelId 渠道编号 + * @return 短信 Client + */ + SmsClient getSmsClient(Long channelId); + + /** + * 获得短信 Client + * + * @param channelCode 渠道编码 + * @return 短信 Client + */ + SmsClient getSmsClient(String channelCode); + + /** + * 创建短信 Client + * + * @param properties 配置对象 + * @return 短信 Client + */ + SmsClient createOrUpdateSmsClient(SmsChannelProperties properties); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsReceiveRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsReceiveRespDTO.java new file mode 100644 index 0000000..e089f9c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsReceiveRespDTO.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.system.framework.sms.core.client.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 消息接收 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsReceiveRespDTO { + + /** + * 是否接收成功 + */ + private Boolean success; + /** + * API 接收结果的编码 + */ + private String errorCode; + /** + * API 接收结果的说明 + */ + private String errorMsg; + + /** + * 手机号 + */ + private String mobile; + /** + * 用户接收时间 + */ + private LocalDateTime receiveTime; + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + /** + * 短信日志编号 + * + * 对应 SysSmsLogDO 的编号 + */ + private Long logId; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsSendRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsSendRespDTO.java new file mode 100644 index 0000000..253b8c5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsSendRespDTO.java @@ -0,0 +1,43 @@ +package com.tashow.cloud.system.framework.sms.core.client.dto; + +import lombok.Data; + +/** + * 短信发送 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsSendRespDTO { + + /** + * 是否成功 + */ + private Boolean success; + + /** + * API 请求编号 + */ + private String apiRequestId; + + // ==================== 成功时字段 ==================== + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + + // ==================== 失败时字段 ==================== + + /** + * API 返回错误码 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiCode; + /** + * API 返回提示 + */ + private String apiMsg; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsTemplateRespDTO.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsTemplateRespDTO.java new file mode 100644 index 0000000..7bbe36f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/dto/SmsTemplateRespDTO.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.system.framework.sms.core.client.dto; + +import com.tashow.cloud.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import lombok.Data; + +/** + * 短信模板 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsTemplateRespDTO { + + /** + * 模板编号 + */ + private String id; + /** + * 短信内容 + */ + private String content; + /** + * 审核状态 + * + * 枚举 {@link SmsTemplateAuditStatusEnum} + */ + private Integer auditStatus; + /** + * 审核未通过的理由 + */ + private String auditReason; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/AbstractSmsClient.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/AbstractSmsClient.java new file mode 100644 index 0000000..6611f53 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/AbstractSmsClient.java @@ -0,0 +1,48 @@ +package com.tashow.cloud.system.framework.sms.core.client.impl; + +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; + +/** + * 短信客户端的抽象类,提供模板方法,减少子类的冗余代码 + * + * @author zzf + * @since 2021/2/1 9:28 + */ +@Slf4j +public abstract class AbstractSmsClient implements SmsClient { + + /** + * 短信渠道配置 + */ + protected volatile SmsChannelProperties properties; + + public AbstractSmsClient(SmsChannelProperties properties) { + this.properties = properties; + } + + /** + * 初始化 + */ + public final void init() { + log.debug("[init][配置({}) 初始化完成]", properties); + } + + public final void refresh(SmsChannelProperties properties) { + // 判断是否更新 + if (properties.equals(this.properties)) { + return; + } + log.info("[refresh][配置({})发生变化,重新初始化]", properties); + this.properties = properties; + // 初始化 + this.init(); + } + + @Override + public Long getId() { + return properties.getId(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/AliyunSmsClient.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/AliyunSmsClient.java new file mode 100644 index 0000000..3584dae --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/AliyunSmsClient.java @@ -0,0 +1,193 @@ +package com.tashow.cloud.system.framework.sms.core.client.impl; + +import cn.hutool.core.date.format.FastDateFormat; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.util.collection.MapUtils; +import com.tashow.cloud.common.util.http.HttpUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsSendRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import com.tashow.cloud.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; +import com.google.common.annotations.VisibleForTesting; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.stream.Collectors; + +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; + +/** + * 阿里短信客户端的实现类 + * + * @author zzf + * @since 2021/1/25 14:17 + */ +@Slf4j +public class AliyunSmsClient extends AbstractSmsClient { + + private static final String URL = "https://dysmsapi.aliyuncs.com"; + private static final String HOST = "dysmsapi.aliyuncs.com"; + private static final String VERSION = "2017-05-25"; + + private static final String RESPONSE_CODE_SUCCESS = "OK"; + + public AliyunSmsClient(SmsChannelProperties properties) { + super(properties); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + } + + @Override + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId, + List> templateParams) throws Throwable { + Assert.notBlank(properties.getSignature(), "短信签名不能为空"); + // 1. 执行请求 + // 参考链接 https://api.aliyun.com/document/Dysmsapi/2017-05-25/SendSms + TreeMap queryParam = new TreeMap<>(); + queryParam.put("PhoneNumbers", mobile); + queryParam.put("SignName", properties.getSignature()); + queryParam.put("TemplateCode", apiTemplateId); + queryParam.put("TemplateParam", JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); + queryParam.put("OutId", sendLogId); + JSONObject response = request("SendSms", queryParam); + + // 2. 解析请求 + return new SmsSendRespDTO() + .setSuccess(Objects.equals(response.getStr("Code"), RESPONSE_CODE_SUCCESS)) + .setSerialNo(response.getStr("BizId")) + .setApiRequestId(response.getStr("RequestId")) + .setApiCode(response.getStr("Code")) + .setApiMsg(response.getStr("Message")); + } + + @Override + public List parseSmsReceiveStatus(String text) { + JSONArray statuses = JSONUtil.parseArray(text); + // 字段参考 https://help.aliyun.com/zh/sms/developer-reference/smsreport-2 + return convertList(statuses, status -> { + JSONObject statusObj = (JSONObject) status; + return new SmsReceiveRespDTO() + .setSuccess(statusObj.getBool("success")) // 是否接收成功 + .setErrorCode(statusObj.getStr("err_code")) // 状态报告编码 + .setErrorMsg(statusObj.getStr("err_msg")) // 状态报告说明 + .setMobile(statusObj.getStr("phone_number")) // 手机号 + .setReceiveTime(statusObj.getLocalDateTime("report_time", null)) // 状态报告时间 + .setSerialNo(statusObj.getStr("biz_id")) // 发送序列号 + .setLogId(statusObj.getLong("out_id")); // 用户序列号 + }); + } + + @Override + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable { + // 1. 执行请求 + // 参考链接 https://api.aliyun.com/document/Dysmsapi/2017-05-25/QuerySmsTemplate + TreeMap queryParam = new TreeMap<>(); + queryParam.put("TemplateCode", apiTemplateId); + JSONObject response = request("QuerySmsTemplate", queryParam); + + // 2.1 请求失败 + String code = response.getStr("Code"); + if (ObjectUtil.notEqual(code, RESPONSE_CODE_SUCCESS)) { + log.error("[getSmsTemplate][模版编号({}) 响应不正确({})]", apiTemplateId, response); + return null; + } + // 2.2 请求成功 + return new SmsTemplateRespDTO() + .setId(response.getStr("TemplateCode")) + .setContent(response.getStr("TemplateContent")) + .setAuditStatus(convertSmsTemplateAuditStatus(response.getInt("TemplateStatus"))) + .setAuditReason(response.getStr("Reason")); + } + + @VisibleForTesting + Integer convertSmsTemplateAuditStatus(Integer templateStatus) { + switch (templateStatus) { + case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus)); + } + } + + /** + * 请求阿里云短信 + * + * @see V3 版本请求体&签名机制 + * @param apiName 请求的 API 名称 + * @param queryParams 请求参数 + * @return 请求结果 + */ + private JSONObject request(String apiName, TreeMap queryParams) { + // 1. 请求参数 + String queryString = queryParams.entrySet().stream() + .map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue()))) + .collect(Collectors.joining("&")); + + // 2.1 请求 Header + TreeMap headers = new TreeMap<>(); + headers.put("host", HOST); + headers.put("x-acs-version", VERSION); + headers.put("x-acs-action", apiName); + headers.put("x-acs-date", FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("GMT")).format(new Date())); + headers.put("x-acs-signature-nonce", IdUtil.randomUUID()); + + // 2.2 构建签名 Header + StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起 + StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔 + headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-") + || entry.getKey().equalsIgnoreCase("host") + || entry.getKey().equalsIgnoreCase("content-type")) + .sorted(Map.Entry.comparingByKey()).forEach(entry -> { + String lowerKey = entry.getKey().toLowerCase(); + canonicalHeaders.append(lowerKey).append(":").append(String.valueOf(entry.getValue()).trim()).append("\n"); + signedHeadersBuilder.append(lowerKey).append(";"); + }); + String signedHeaders = signedHeadersBuilder.substring(0, signedHeadersBuilder.length() - 1); + + // 3. 请求 Body + String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空。 + String hashedRequestBody = DigestUtil.sha256Hex(requestBody); + + // 4. 构建 Authorization 签名 + String canonicalRequest = "POST" + "\n" + "/" + "\n" + queryString + "\n" + + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody; + String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest); + String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest; + String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名 + headers.put("Authorization", "ACS3-HMAC-SHA256" + " " + "Credential=" + properties.getApiKey() + + ", " + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature); + + // 5. 发起请求 + String responseBody = HttpUtils.post(URL + "?" + queryString, headers, requestBody); + return JSONUtil.parseObj(responseBody); + } + + /** + * 对指定的字符串进行 URL 编码,并对特定的字符进行替换,以符合URL编码规范 + * + * @param str 需要进行 URL 编码的字符串 + * @return 编码后的字符串 + */ + @SneakyThrows + private static String percentCode(String str) { + Assert.notNull(str, "str 不能为空"); + return URLEncoder.encode(str, StandardCharsets.UTF_8.name()) + .replace("+", "%20") // 加号 "+" 被替换为 "%20" + .replace("*", "%2A") // 星号 "*" 被替换为 "%2A" + .replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~" + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/DebugDingTalkSmsClient.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/DebugDingTalkSmsClient.java new file mode 100644 index 0000000..22083f6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/DebugDingTalkSmsClient.java @@ -0,0 +1,91 @@ +package com.tashow.cloud.system.framework.sms.core.client.impl; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.http.HttpUtil; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.util.collection.MapUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsSendRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import com.tashow.cloud.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 基于钉钉 WebHook 实现的调试的短信客户端实现类 + * + * 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。 + * + * @author 芋道源码 + */ +public class DebugDingTalkSmsClient extends AbstractSmsClient { + + public DebugDingTalkSmsClient(SmsChannelProperties properties) { + super(properties); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + } + + @Override + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) throws Throwable { + // 构建请求 + String url = buildUrl("robot/send"); + Map params = new HashMap<>(); + params.put("msgtype", "text"); + String content = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s", + mobile, sendLogId, MapUtils.convertMap(templateParams)); + params.put("text", MapUtil.builder().put("content", content).build()); + // 执行请求 + String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params)); + // 解析结果 + Map responseObj = JsonUtils.parseObject(responseText, Map.class); + String errorCode = MapUtil.getStr(responseObj, "errcode"); + return new SmsSendRespDTO().setSuccess(Objects.equals(errorCode, "0")).setSerialNo(StrUtil.uuid()) + .setApiCode(errorCode).setApiMsg(MapUtil.getStr(responseObj, "errorMsg")); + } + + /** + * 构建请求地址 + * + * 参见 文档 + * + * @param path 请求路径 + * @return 请求地址 + */ + @SuppressWarnings("SameParameterValue") + private String buildUrl(String path) { + // 生成 timestamp + long timestamp = System.currentTimeMillis(); + // 生成 sign + String secret = properties.getApiSecret(); + String stringToSign = timestamp + "\n" + secret; + byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign); + String sign = Base64.encode(signData); + // 构建最终 URL + return String.format("https://oapi.dingtalk.com/%s?access_token=%s×tamp=%d&sign=%s", + path, properties.getApiKey(), timestamp, sign); + } + + @Override + public List parseSmsReceiveStatus(String text) { + throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调"); + } + + @Override + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) { + return new SmsTemplateRespDTO().setId(apiTemplateId).setContent("") + .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(""); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/HuaweiSmsClient.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/HuaweiSmsClient.java new file mode 100644 index 0000000..f61f3d8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/HuaweiSmsClient.java @@ -0,0 +1,166 @@ +package com.tashow.cloud.system.framework.sms.core.client.impl; + +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.date.format.FastDateFormat; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.util.http.HttpUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsSendRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import com.tashow.cloud.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; + +import static cn.hutool.crypto.digest.DigestUtil.sha256Hex; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; + +/** + * 华为短信客户端的实现类 + * + * @author scholar + * @since 2024/6/02 11:55 + */ +@Slf4j +public class HuaweiSmsClient extends AbstractSmsClient { + + private static final String URL = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1";//APP接入地址+接口访问URI + private static final String HOST = "smsapi.cn-north-4.myhuaweicloud.com:443"; + private static final String SIGNEDHEADERS = "content-type;host;x-sdk-date"; + + private static final String RESPONSE_CODE_SUCCESS = "000000"; + + public HuaweiSmsClient(SmsChannelProperties properties) { + super(properties); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + validateSender(properties); + } + + /** + * 参数校验华为云的 sender 通道号 + * + * 原因是:验华为云发放短信的时候,需要额外的参数 sender + * + * 解决方案:考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。 + * + * @param properties 配置 + */ + private static void validateSender(SmsChannelProperties properties) { + String combineKey = properties.getApiKey(); + Assert.notEmpty(combineKey, "apiKey 不能为空"); + String[] keys = combineKey.trim().split(" "); + Assert.isTrue(keys.length == 2, "华为云短信 apiKey 配置格式错误,请配置 为[accessKeyId sender]"); + } + + private String getAccessKey() { + return StrUtil.subBefore(properties.getApiKey(), " ", true); + } + + private String getSender() { + return StrUtil.subAfter(properties.getApiKey(), " ", true); + } + + @Override + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId, + List> templateParams) throws Throwable { + StringBuilder requestBody = new StringBuilder(); + appendToBody(requestBody, "from=", getSender()); + appendToBody(requestBody, "&to=", mobile); + appendToBody(requestBody, "&templateId=", apiTemplateId); + appendToBody(requestBody, "&templateParas=", JsonUtils.toJsonString( + convertList(templateParams, kv -> String.valueOf(kv.getValue())))); + appendToBody(requestBody, "&statusCallback=", properties.getCallbackUrl()); + appendToBody(requestBody, "&extend=", String.valueOf(sendLogId)); + JSONObject response = request("/sms/batchSendSms/v1/", "POST", requestBody.toString()); + + // 2. 解析请求 + if (!response.containsKey("result")) { // 例如说:密钥不正确 + return new SmsSendRespDTO().setSuccess(false) + .setApiCode(response.getStr("code")) + .setApiMsg(response.getStr("description")); + } + JSONObject sendResult = response.getJSONArray("result").getJSONObject(0); + return new SmsSendRespDTO().setSuccess(RESPONSE_CODE_SUCCESS.equals(response.getStr("code"))) + .setSerialNo(sendResult.getStr("smsMsgId")).setApiCode(sendResult.getStr("status")); + } + + /** + * 请求华为云短信 + * + * @see https://support.huaweicloud.com/api-msgsms/sms_05_0046.html + * @param uri 请求 URI + * @param method 请求 Method + * @param requestBody 请求 Body + * @return 请求结果 + */ + private JSONObject request(String uri, String method, String requestBody) { + // 1.1 请求 Header + TreeMap headers = new TreeMap<>(); + headers.put("Content-Type", "application/x-www-form-urlencoded"); + String sdkDate = FastDateFormat.getInstance("yyyyMMdd'T'HHmmss'Z'", TimeZone.getTimeZone("UTC")).format(new Date()); + headers.put("X-Sdk-Date", sdkDate); + headers.put("host", HOST); + + // 1.2 构建签名 Header + String canonicalQueryString = ""; // 查询参数为空 + String canonicalHeaders = "content-type:application/x-www-form-urlencoded\n" + + "host:"+ HOST +"\n" + "x-sdk-date:" + sdkDate + "\n"; + String canonicalRequest = method + "\n" + uri + "\n" + canonicalQueryString + "\n" + + canonicalHeaders + "\n" + SIGNEDHEADERS + "\n" + sha256Hex(requestBody); + String stringToSign = "SDK-HMAC-SHA256" + "\n" + sdkDate + "\n" + sha256Hex(canonicalRequest); + String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名 + headers.put("Authorization", "SDK-HMAC-SHA256" + " " + "Access=" + getAccessKey() + + ", " + "SignedHeaders=" + SIGNEDHEADERS + ", " + "Signature=" + signature); + + // 2. 发起请求 + String responseBody = HttpUtils.post(URL, headers, requestBody); + return JSONUtil.parseObj(responseBody); + } + + @Override + public List parseSmsReceiveStatus(String requestBody) { + Map params = HttpUtil.decodeParamMap(requestBody, StandardCharsets.UTF_8); + // 字段参考 https://support.huaweicloud.com/api-msgsms/sms_05_0003.html + return ListUtil.of(new SmsReceiveRespDTO() + .setSuccess("DELIVRD".equals(params.get("status"))) // 是否接收成功 + .setErrorCode(params.get("status")) // 状态报告编码 + .setErrorMsg(params.get("statusDesc")) + .setMobile(params.get("to")) // 手机号 + .setReceiveTime(LocalDateTime.ofInstant(Instant.parse(params.get("updateTime")), ZoneId.of("UTC"))) // 状态报告时间 + .setSerialNo(params.get("smsMsgId")) // 发送序列号 + .setLogId(Long.valueOf(params.get("extend")))); // 用户序列号 + } + + @Override + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable { + // 华为短信模板查询和发送短信,是不同的两套 key 和 secret,与阿里、腾讯的区别较大,这里模板查询校验暂不实现 + String[] strs = apiTemplateId.split(" "); + Assert.isTrue(strs.length == 2, "格式不正确,需要满足:apiTemplateId sender"); + return new SmsTemplateRespDTO().setId(apiTemplateId).setContent(null) + .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(null); + } + + @SuppressWarnings("CharsetObjectCanBeUsed") + private static void appendToBody(StringBuilder body, String key, String value) throws UnsupportedEncodingException { + if (StrUtil.isNotEmpty(value)) { + body.append(key).append(URLEncoder.encode(value, CharsetUtil.CHARSET_UTF_8.name())); + } + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/QiniuSmsClient.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/QiniuSmsClient.java new file mode 100644 index 0000000..57aeb19 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/QiniuSmsClient.java @@ -0,0 +1,155 @@ +package com.tashow.cloud.system.framework.sms.core.client.impl; + +import cn.hutool.core.collection.CollStreamUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.util.http.HttpUtils; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsSendRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import com.tashow.cloud.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.function.Function; + +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; + +/** + * 七牛云短信客户端的实现类 + * + * @author scholar + * @since 2024/08/26 15:35 + */ +@Slf4j +public class QiniuSmsClient extends AbstractSmsClient { + + private static final String HOST = "sms.qiniuapi.com"; + + public QiniuSmsClient(SmsChannelProperties properties) { + super(properties); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + } + + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId, + List> templateParams) throws Throwable { + // 1. 执行请求 + // 参考链接 https://developer.qiniu.com/sms/5824/through-the-api-send-text-messages + LinkedHashMap body = new LinkedHashMap<>(); + body.put("template_id", apiTemplateId); + body.put("mobile", mobile); + body.put("parameters", CollStreamUtil.toMap(templateParams, KeyValue::getKey, KeyValue::getValue)); + body.put("seq", Long.toString(sendLogId)); + JSONObject response = request("POST", body, "/v1/message/single"); + + // 2. 解析请求 + if (ObjectUtil.isNotEmpty(response.getStr("error"))) { + // 短信请求失败 + return new SmsSendRespDTO().setSuccess(false) + .setApiCode(response.getStr("error")) + .setApiRequestId(response.getStr("request_id")) + .setApiMsg(response.getStr("message")); + } + return new SmsSendRespDTO().setSuccess(response.containsKey("message_id")) + .setSerialNo(response.getStr("message_id")); + } + + /** + * 请求七牛云短信 + * + * @see + * @param httpMethod http请求方法 + * @param body http请求消息体 + * @param path URL path + * @return 请求结果 + */ + private JSONObject request(String httpMethod, LinkedHashMap body, String path) { + String signDate = DateUtil.date().setTimeZone(TimeZone.getTimeZone("UTC")).toString("yyyyMMdd'T'HHmmss'Z'"); + // 1. 请求头 + Map header = new HashMap<>(4); + header.put("HOST", HOST); + header.put("Authorization", getSignature(httpMethod, path, body != null ? JSONUtil.toJsonStr(body) : "", signDate)); + header.put("Content-Type", "application/json"); + header.put("X-Qiniu-Date", signDate); + + // 2. 发起请求 + String responseBody; + if (Objects.equals(httpMethod, "POST")){ + responseBody = HttpUtils.post("https://" + HOST + path, header, JSONUtil.toJsonStr(body)); + } else { + responseBody = HttpUtils.get("https://" + HOST + path, header); + } + return JSONUtil.parseObj(responseBody); + } + + private String getSignature(String method, String path, String body, String signDate) { + StringBuilder dataToSign = new StringBuilder(); + dataToSign.append(method.toUpperCase()).append(" ").append(path) + .append("\nHost: ").append(HOST) + .append("\n").append("Content-Type").append(": ").append("application/json") + .append("\n").append("X-Qiniu-Date").append(": ").append(signDate) + .append("\n\n"); + if (ObjectUtil.isNotEmpty(body)) { + dataToSign.append(body); + } + String signature = SecureUtil.hmac(HmacAlgorithm.HmacSHA1, properties.getApiSecret()) + .digestBase64(dataToSign.toString(), true); + return "Qiniu " + properties.getApiKey() + ":" + signature; + } + + @Override + public List parseSmsReceiveStatus(String text) { + JSONObject status = JSONUtil.parseObj(text); + // 字段参考 https://developer.qiniu.com/sms/5910/message-push + return convertList(status.getJSONArray("items"), new Function() { + + @Override + public SmsReceiveRespDTO apply(Object item) { + JSONObject statusObj = (JSONObject) item; + return new SmsReceiveRespDTO() + .setSuccess("DELIVRD".equals(statusObj.getStr("status"))) // 是否接收成功 + .setErrorMsg(statusObj.getStr("status")) // 状态报告编码 + .setMobile(statusObj.getStr("mobile")) // 手机号 + .setReceiveTime(LocalDateTimeUtil.of(statusObj.getLong("delivrd_at") * 1000L)) // 状态报告时间 + .setSerialNo(statusObj.getStr("message_id")) // 发送序列号 + .setLogId(statusObj.getLong("seq")); // 用户序列号 + } + + }); + } + + @Override + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable { + // 1. 执行请求 + // 参考链接 https://developer.qiniu.com/sms/5969/query-a-single-template + JSONObject response = request("GET", null, "/v1/template/" + apiTemplateId); + + // 2.2 解析请求 + return new SmsTemplateRespDTO() + .setId(response.getStr("id")) + .setContent(response.getStr("template")) + .setAuditStatus(convertSmsTemplateAuditStatus(response.getStr("audit_status"))) + .setAuditReason(response.getStr("reject_reason")); + } + + @VisibleForTesting + Integer convertSmsTemplateAuditStatus(String templateStatus) { + switch (templateStatus) { + case "passed": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case "reviewing": return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case "rejected": return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: + throw new IllegalArgumentException(String.format("未知审核状态(%str)", templateStatus)); + } + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/SmsClientFactoryImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/SmsClientFactoryImpl.java new file mode 100644 index 0000000..036f75a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/SmsClientFactoryImpl.java @@ -0,0 +1,90 @@ +package com.tashow.cloud.system.framework.sms.core.client.impl; + +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import com.tashow.cloud.system.framework.sms.core.client.SmsClientFactory; +import com.tashow.cloud.system.framework.sms.core.enums.SmsChannelEnum; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; +import org.springframework.validation.annotation.Validated; + +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 短信客户端工厂接口 + * + * @author zzf + */ +@Validated +@Slf4j +public class SmsClientFactoryImpl implements SmsClientFactory { + + /** + * 短信客户端 Map + * key:渠道编号,使用 {@link SmsChannelProperties#getId()} + */ + private final ConcurrentMap channelIdClients = new ConcurrentHashMap<>(); + + /** + * 短信客户端 Map + * key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()} + * + * 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。 + * 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients} + */ + private final ConcurrentMap channelCodeClients = new ConcurrentHashMap<>(); + + public SmsClientFactoryImpl() { + // 初始化 channelCodeClients 集合 + Arrays.stream(SmsChannelEnum.values()).forEach(channel -> { + // 创建一个空的 SmsChannelProperties 对象 + SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode()) + .setApiKey("default default").setApiSecret("default"); + // 创建 Sms 客户端 + AbstractSmsClient smsClient = createSmsClient(properties); + channelCodeClients.put(channel.getCode(), smsClient); + }); + } + + @Override + public SmsClient getSmsClient(Long channelId) { + return channelIdClients.get(channelId); + } + + @Override + public SmsClient getSmsClient(String channelCode) { + return channelCodeClients.get(channelCode); + } + + @Override + public SmsClient createOrUpdateSmsClient(SmsChannelProperties properties) { + AbstractSmsClient client = channelIdClients.get(properties.getId()); + if (client == null) { + client = this.createSmsClient(properties); + client.init(); + channelIdClients.put(client.getId(), client); + } else { + client.refresh(properties); + } + return client; + } + + private AbstractSmsClient createSmsClient(SmsChannelProperties properties) { + SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode()); + Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum)); + // 创建客户端 + switch (channelEnum) { + case ALIYUN: return new AliyunSmsClient(properties); + case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties); + case TENCENT: return new TencentSmsClient(properties); + case HUAWEI: return new HuaweiSmsClient(properties); + case QINIU: return new QiniuSmsClient(properties); + } + // 创建失败,错误日志 + 抛出异常 + log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties); + throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties)); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/TencentSmsClient.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/TencentSmsClient.java new file mode 100644 index 0000000..02293a5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/client/impl/TencentSmsClient.java @@ -0,0 +1,201 @@ +package com.tashow.cloud.system.framework.sms.core.client.impl; + +import cn.hutool.core.date.format.FastDateFormat; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.HexUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.util.collection.ArrayUtils; +import com.tashow.cloud.common.util.http.HttpUtils; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsSendRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import com.tashow.cloud.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; +import com.google.common.annotations.VisibleForTesting; + +import java.nio.charset.StandardCharsets; +import java.util.*; + +import static cn.hutool.crypto.digest.DigestUtil.sha256Hex; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; + +/** + * 腾讯云短信功能实现 + * + * 参见 文档 + * + * @author shiwp + */ +public class TencentSmsClient extends AbstractSmsClient { + + private static final String HOST = "sms.tencentcloudapi.com"; + private static final String VERSION = "2021-01-11"; + private static final String REGION = "ap-guangzhou"; + + /** + * 调用成功 code + */ + public static final String API_CODE_SUCCESS = "Ok"; + + /** + * 是否国际/港澳台短信: + * + * 0:表示国内短信。 + * 1:表示国际/港澳台短信。 + */ + private static final long INTERNATIONAL_CHINA = 0L; + + public TencentSmsClient(SmsChannelProperties properties) { + super(properties); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + validateSdkAppId(properties); + } + + /** + * 参数校验腾讯云的 SDK AppId + * + * 原因是:腾讯云发放短信的时候,需要额外的参数 sdkAppId + * + * 解决方案:考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。 + * + * @param properties 配置 + */ + private static void validateSdkAppId(SmsChannelProperties properties) { + String combineKey = properties.getApiKey(); + Assert.notEmpty(combineKey, "apiKey 不能为空"); + String[] keys = combineKey.trim().split(" "); + Assert.isTrue(keys.length == 2, "腾讯云短信 apiKey 配置格式错误,请配置 为[secretId sdkAppId]"); + } + + private String getSdkAppId() { + return StrUtil.subAfter(properties.getApiKey(), " ", true); + } + + private String getApiKey() { + return StrUtil.subBefore(properties.getApiKey(), " ", true); + } + + @Override + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) throws Throwable { + // 1. 执行请求 + // 参考链接 https://cloud.tencent.com/document/product/382/55981 + TreeMap body = new TreeMap<>(); + body.put("PhoneNumberSet", new String[]{mobile}); + body.put("SmsSdkAppId", getSdkAppId()); + body.put("SignName", properties.getSignature()); + body.put("TemplateId", apiTemplateId); + body.put("TemplateParamSet", ArrayUtils.toArray(templateParams, param -> String.valueOf(param.getValue()))); + JSONObject response = request("SendSms", body); + + // 2. 解析请求 + JSONObject responseResult = response.getJSONObject("Response"); + JSONObject error = responseResult.getJSONObject("Error"); + if (error != null) { + return new SmsSendRespDTO().setSuccess(false) + .setApiRequestId(responseResult.getStr("RequestId")) + .setApiCode(error.getStr("Code")) + .setApiMsg(error.getStr("Message")); + } + JSONObject sendResult = responseResult.getJSONArray("SendStatusSet").getJSONObject(0); + return new SmsSendRespDTO().setSuccess(Objects.equals(API_CODE_SUCCESS, sendResult.getStr("Code"))) + .setApiRequestId(responseResult.getStr("RequestId")) + .setSerialNo(sendResult.getStr("SerialNo")) + .setApiMsg(sendResult.getStr("Message")); + } + + @Override + public List parseSmsReceiveStatus(String text) { + JSONArray statuses = JSONUtil.parseArray(text); + // 字段参考 + return convertList(statuses, status -> { + JSONObject statusObj = (JSONObject) status; + return new SmsReceiveRespDTO() + .setSuccess("SUCCESS".equals(statusObj.getStr("report_status"))) // 是否接收成功 + .setErrorCode(statusObj.getStr("errmsg")) // 状态报告编码 + .setMobile(statusObj.getStr("mobile")) // 手机号 + .setReceiveTime(statusObj.getLocalDateTime("user_receive_time", null)) // 状态报告时间 + .setSerialNo(statusObj.getStr("sid")); // 发送序列号 + }); + } + + @Override + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable { + // 1. 构建请求 + // 参考链接 https://cloud.tencent.com/document/product/382/52067 + TreeMap body = new TreeMap<>(); + body.put("International", INTERNATIONAL_CHINA); + body.put("TemplateIdSet", new Integer[]{Integer.valueOf(apiTemplateId)}); + JSONObject response = request("DescribeSmsTemplateList", body); + + // 2. 解析请求 + JSONObject statusResult = response.getJSONObject("Response") + .getJSONArray("DescribeTemplateStatusSet").getJSONObject(0); + return new SmsTemplateRespDTO().setId(apiTemplateId) + .setContent(statusResult.get("TemplateContent").toString()) + .setAuditStatus(convertSmsTemplateAuditStatus(statusResult.getInt("StatusCode"))) + .setAuditReason(statusResult.get("ReviewReply").toString()); + } + + @VisibleForTesting + Integer convertSmsTemplateAuditStatus(int templateStatus) { + switch (templateStatus) { + case 1: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case 0: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case -1: return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus)); + } + } + + /** + * 请求腾讯云短信 + * + * @see 签名方法 v3 + * + * @param action 请求的 API 名称 + * @param body 请求参数 + * @return 请求结果 + */ + private JSONObject request(String action, TreeMap body) { + // 1.1 请求 Header + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json; charset=utf-8"); + headers.put("Host", HOST); + headers.put("X-TC-Action", action); + Date now = new Date(); + String nowStr = FastDateFormat.getInstance("yyyy-MM-dd", TimeZone.getTimeZone("UTC")).format(now); + headers.put("X-TC-Timestamp", String.valueOf(now.getTime() / 1000)); + headers.put("X-TC-Version", VERSION); + headers.put("X-TC-Region", REGION); + + // 1.2 构建签名 Header + String canonicalQueryString = ""; + String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + + "host:" + HOST + "\n" + "x-tc-action:" + action.toLowerCase() + "\n"; + String signedHeaders = "content-type;host;x-tc-action"; + String canonicalRequest = "POST" + "\n" + "/" + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + + signedHeaders + "\n" + sha256Hex(JSONUtil.toJsonStr(body)); + String credentialScope = nowStr + "/" + "sms" + "/" + "tc3_request"; + String stringToSign = "TC3-HMAC-SHA256" + "\n" + now.getTime() / 1000 + "\n" + credentialScope + "\n" + + sha256Hex(canonicalRequest); + byte[] secretService = hmac256(hmac256(("TC3" + properties.getApiSecret()).getBytes(StandardCharsets.UTF_8), nowStr), "sms"); + String signature = HexUtil.encodeHexStr(hmac256(hmac256(secretService, "tc3_request"), stringToSign)); + headers.put("Authorization", "TC3-HMAC-SHA256" + " " + "Credential=" + getApiKey() + "/" + credentialScope + ", " + + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature); + + // 2. 发起请求 + String responseBody = HttpUtils.post("https://" + HOST, headers, JSONUtil.toJsonStr(body)); + return JSONUtil.parseObj(responseBody); + } + + private static byte[] hmac256(byte[] key, String msg) { + return DigestUtil.hmac(HmacAlgorithm.HmacSHA256, key).digest(msg); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/enums/SmsChannelEnum.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/enums/SmsChannelEnum.java new file mode 100644 index 0000000..7ae3995 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/enums/SmsChannelEnum.java @@ -0,0 +1,38 @@ +package com.tashow.cloud.system.framework.sms.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信渠道枚举 + * + * @author zzf + * @since 2021/1/25 10:56 + */ +@Getter +@AllArgsConstructor +public enum SmsChannelEnum { + + DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"), + ALIYUN("ALIYUN", "阿里云"), + TENCENT("TENCENT", "腾讯云"), + HUAWEI("HUAWEI", "华为云"), + QINIU("QINIU", "七牛云"), + ; + + /** + * 编码 + */ + private final String code; + /** + * 名字 + */ + private final String name; + + public static SmsChannelEnum getByCode(String code) { + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); + } + +} + diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java new file mode 100644 index 0000000..9e3a93f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.system.framework.sms.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信模板的审核状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum SmsTemplateAuditStatusEnum { + + CHECKING(1), + SUCCESS(2), + FAIL(3); + + private final Integer status; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/property/SmsChannelProperties.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/property/SmsChannelProperties.java new file mode 100644 index 0000000..cefabe5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/framework/sms/core/property/SmsChannelProperties.java @@ -0,0 +1,51 @@ +package com.tashow.cloud.system.framework.sms.core.property; + +import com.tashow.cloud.system.framework.sms.core.enums.SmsChannelEnum; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.validation.annotation.Validated; + +/** + * 短信渠道配置类 + * + * @author zzf + * @since 2021/1/25 17:01 + */ +@Data +@Validated +public class SmsChannelProperties { + + /** + * 渠道编号 + */ + @NotNull(message = "短信渠道 ID 不能为空") + private Long id; + /** + * 短信签名 + */ + @NotEmpty(message = "短信签名不能为空") + private String signature; + /** + * 渠道编码 + * + * 枚举 {@link SmsChannelEnum} + */ + @NotEmpty(message = "渠道编码不能为空") + private String code; + /** + * 短信 API 的账号 + */ + @NotEmpty(message = "短信 API 的账号不能为空") + private String apiKey; + /** + * 短信 API 的密钥 + */ + @NotEmpty(message = "短信 API 的密钥不能为空") + private String apiSecret; + /** + * 短信发送回调 URL + */ + private String callbackUrl; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/job/demo/DemoJob.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/job/demo/DemoJob.java new file mode 100644 index 0000000..39b8829 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/job/demo/DemoJob.java @@ -0,0 +1,16 @@ +package com.tashow.cloud.system.job.demo; + +import com.tashow.cloud.tenant.core.job.TenantJob; +import com.xxl.job.core.handler.annotation.XxlJob; +import org.springframework.stereotype.Component; + +@Component +public class DemoJob { + + @XxlJob("demoJob") + @TenantJob + public void execute() { + System.out.println("美滋滋"); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/job/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/job/package-info.java new file mode 100644 index 0000000..6e074cb --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/job/package-info.java @@ -0,0 +1 @@ +package com.tashow.cloud.system.job; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/consumer/mail/MailSendConsumer.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/consumer/mail/MailSendConsumer.java new file mode 100644 index 0000000..b5a138d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/consumer/mail/MailSendConsumer.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.system.mq.consumer.mail; + +import com.tashow.cloud.system.mq.message.mail.MailSendMessage; +import com.tashow.cloud.system.service.mail.MailSendService; +import com.tashow.cloud.system.mq.message.mail.MailSendMessage; +import com.tashow.cloud.system.service.mail.MailSendService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +/** + * 针对 {@link MailSendMessage} 的消费者 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class MailSendConsumer { + + @Resource + private MailSendService mailSendService; + + @EventListener + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步 + public void onMessage(MailSendMessage message) { + log.info("[onMessage][消息内容({})]", message); + mailSendService.doSendMail(message); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/consumer/sms/SmsSendConsumer.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/consumer/sms/SmsSendConsumer.java new file mode 100644 index 0000000..7ed01f9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/consumer/sms/SmsSendConsumer.java @@ -0,0 +1,33 @@ +package com.tashow.cloud.system.mq.consumer.sms; + +import com.tashow.cloud.system.mq.message.sms.SmsSendMessage; +import com.tashow.cloud.system.service.sms.SmsSendService; +import com.tashow.cloud.system.mq.message.sms.SmsSendMessage; +import com.tashow.cloud.system.service.sms.SmsSendService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +/** + * 针对 {@link SmsSendMessage} 的消费者 + * + * @author zzf + */ +@Component +@Slf4j +public class SmsSendConsumer { + + @Resource + private SmsSendService smsSendService; + + @EventListener + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步 + public void onMessage(SmsSendMessage message) { + log.info("[onMessage][消息内容({})]", message); + smsSendService.doSendSms(message); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/message/mail/MailSendMessage.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/message/mail/MailSendMessage.java new file mode 100644 index 0000000..5ad1dfc --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/message/mail/MailSendMessage.java @@ -0,0 +1,47 @@ +package com.tashow.cloud.system.mq.message.mail; + +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +/** + * 邮箱发送消息 + * + * @author 芋道源码 + */ +@Data +public class MailSendMessage { + + /** + * 邮件日志编号 + */ + @NotNull(message = "邮件日志编号不能为空") + private Long logId; + /** + * 接收邮件地址 + */ + @NotNull(message = "接收邮件地址不能为空") + private String mail; + /** + * 邮件账号编号 + */ + @NotNull(message = "邮件账号编号不能为空") + private Long accountId; + + /** + * 邮件发件人 + */ + private String nickname; + /** + * 邮件标题 + */ + @NotEmpty(message = "邮件标题不能为空") + private String title; + /** + * 邮件内容 + */ + @NotEmpty(message = "邮件内容不能为空") + private String content; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/message/sms/SmsSendMessage.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/message/sms/SmsSendMessage.java new file mode 100644 index 0000000..6aa0cd3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/message/sms/SmsSendMessage.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.system.mq.message.sms; + +import com.tashow.cloud.common.core.KeyValue; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.util.List; + +/** + * 短信发送消息 + * + * @author 芋道源码 + */ +@Data +public class SmsSendMessage { + + /** + * 短信日志编号 + */ + @NotNull(message = "短信日志编号不能为空") + private Long logId; + /** + * 手机号 + */ + @NotNull(message = "手机号不能为空") + private String mobile; + /** + * 短信渠道编号 + */ + @NotNull(message = "短信渠道编号不能为空") + private Long channelId; + /** + * 短信 API 的模板编号 + */ + @NotNull(message = "短信 API 的模板编号不能为空") + private String apiTemplateId; + /** + * 短信模板参数 + */ + private List> templateParams; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/producer/mail/MailProducer.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/producer/mail/MailProducer.java new file mode 100644 index 0000000..3ae694d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/producer/mail/MailProducer.java @@ -0,0 +1,41 @@ +package com.tashow.cloud.system.mq.producer.mail; + +import com.tashow.cloud.system.mq.message.mail.MailSendMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +/** + * Mail 邮件相关消息的 Producer + * + * @author wangjingyi + * @since 2021/4/19 13:33 + */ +@Slf4j +@Component +public class MailProducer { + + @Resource + private ApplicationContext applicationContext; + + /** + * 发送 {@link MailSendMessage} 消息 + * + * @param sendLogId 发送日志编码 + * @param mail 接收邮件地址 + * @param accountId 邮件账号编号 + * @param nickname 邮件发件人 + * @param title 邮件标题 + * @param content 邮件内容 + */ + public void sendMailSendMessage(Long sendLogId, String mail, Long accountId, + String nickname, String title, String content) { + MailSendMessage message = new MailSendMessage() + .setLogId(sendLogId).setMail(mail).setAccountId(accountId) + .setNickname(nickname).setTitle(title).setContent(content); + applicationContext.publishEvent(message); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/producer/sms/SmsProducer.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/producer/sms/SmsProducer.java new file mode 100644 index 0000000..de94220 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/mq/producer/sms/SmsProducer.java @@ -0,0 +1,41 @@ +package com.tashow.cloud.system.mq.producer.sms; + +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.system.mq.message.sms.SmsSendMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; +import java.util.List; + +/** + * Sms 短信相关消息的 Producer + * + * @author zzf + * @since 2021/3/9 16:35 + */ +@Slf4j +@Component +public class SmsProducer { + + @Resource + private ApplicationContext applicationContext; + + /** + * 发送 {@link SmsSendMessage} 消息 + * + * @param logId 短信日志编号 + * @param mobile 手机号 + * @param channelId 渠道编号 + * @param apiTemplateId 短信模板编号 + * @param templateParams 短信模板参数 + */ + public void sendSmsSendMessage(Long logId, String mobile, + Long channelId, String apiTemplateId, List> templateParams) { + SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile); + message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams); + applicationContext.publishEvent(message); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/package-info.java new file mode 100644 index 0000000..f2f323a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/package-info.java @@ -0,0 +1,8 @@ +/** + * system 模块下,我们放通用业务,支撑上层的核心业务。 + * 例如说:用户、部门、权限、数据字典等等 + * + * 1. Controller URL:以 /system/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 system_ 开头,方便在数据库中区分 + */ +package com.tashow.cloud.system; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/auth/AdminAuthService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/auth/AdminAuthService.java new file mode 100644 index 0000000..ad120c6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/auth/AdminAuthService.java @@ -0,0 +1,87 @@ +package com.tashow.cloud.system.service.auth; + +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.controller.admin.auth.vo.*; +import jakarta.validation.Valid; + +/** + * 管理后台的认证 Service 接口 + * + * 提供用户的登录、登出的能力 + * + * @author 芋道源码 + */ +public interface AdminAuthService { + + /** + * 验证账号 + 密码。如果通过,则返回用户 + * + * @param username 账号 + * @param password 密码 + * @return 用户 + */ + AdminUserDO authenticate(String username, String password); + + /** + * 账号登录 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AuthLoginRespVO login(@Valid AuthLoginReqVO reqVO); + + /** + * 基于 token 退出登录 + * + * @param token token + * @param logType 登出类型 + */ + void logout(String token, Integer logType); + + /** + * 短信验证码发送 + * + * @param reqVO 发送请求 + */ + void sendSmsCode(AuthSmsSendReqVO reqVO); + + /** + * 短信登录 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO); + + /** + * 社交快捷登录,使用 code 授权码 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AuthLoginRespVO socialLogin(@Valid AuthSocialLoginReqVO reqVO); + + /** + * 刷新访问令牌 + * + * @param refreshToken 刷新令牌 + * @return 登录结果 + */ + AuthLoginRespVO refreshToken(String refreshToken); + + /** + * 用户注册 + * + * @param createReqVO 注册用户 + * @return 注册结果 + */ + AuthLoginRespVO register(AuthRegisterReqVO createReqVO); + + /** + * 重置密码 + * + * @param reqVO 验证码信息 + */ + void resetPassword(AuthResetPasswordReqVO reqVO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/auth/AdminAuthServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/auth/AdminAuthServiceImpl.java new file mode 100644 index 0000000..2eebbbd --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/auth/AdminAuthServiceImpl.java @@ -0,0 +1,304 @@ +package com.tashow.cloud.system.service.auth; + +import cn.hutool.core.util.ObjectUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.util.monitor.TracerUtils; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.common.util.validation.ValidationUtils; +import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.sms.SmsCodeApi; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserRespDTO; +import com.tashow.cloud.system.convert.auth.AuthConvert; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.systemapi.enums.logger.LoginLogTypeEnum; +import com.tashow.cloud.systemapi.enums.logger.LoginResultEnum; +import com.tashow.cloud.systemapi.enums.oauth2.OAuth2ClientConstants; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import com.tashow.cloud.system.service.logger.LoginLogService; +import com.tashow.cloud.system.service.member.MemberService; +import com.tashow.cloud.system.service.oauth2.OAuth2TokenService; +import com.tashow.cloud.system.service.social.SocialUserService; +import com.tashow.cloud.system.service.user.AdminUserService; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.system.controller.admin.auth.vo.*; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.xingyuv.captcha.model.common.ResponseModel; +import com.xingyuv.captcha.model.vo.CaptchaVO; +import com.xingyuv.captcha.service.CaptchaService; +import jakarta.annotation.Resource; +import jakarta.validation.Validator; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Objects; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.servlet.ServletUtils.getClientIP; + + +/** + * Auth Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class AdminAuthServiceImpl implements AdminAuthService { + + @Resource + private AdminUserService userService; + @Resource + private LoginLogService loginLogService; + @Resource + private OAuth2TokenService oauth2TokenService; + @Resource + private SocialUserService socialUserService; + @Resource + private MemberService memberService; + @Resource + private Validator validator; + @Resource + private CaptchaService captchaService; + @Resource + private SmsCodeApi smsCodeApi; + + /** + * 验证码的开关,默认为 true + */ + @Value("${yudao.captcha.enable:true}") + @Setter // 为了单测:开启或者关闭验证码 + private Boolean captchaEnable; + + @Override + public AdminUserDO authenticate(String username, String password) { + final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME; + // 校验账号是否存在 + AdminUserDO user = userService.getUserByUsername(username); + if (user == null) { + createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); + throw exception(ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS); + } + if (!userService.isPasswordMatch(password, user.getPassword())) { + createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); + throw exception(ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS); + } + // 校验是否禁用 + if (CommonStatusEnum.isDisable(user.getStatus())) { + createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.USER_DISABLED); + throw exception(ErrorCodeConstants.AUTH_LOGIN_USER_DISABLED); + } + return user; + } + + @Override + public AuthLoginRespVO login(AuthLoginReqVO reqVO) { + // 校验验证码 + validateCaptcha(reqVO); + + // 使用账号密码,进行登录 + AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword()); + + // 如果 socialType 非空,说明需要绑定社交用户 + if (reqVO.getSocialType() != null) { + socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), + reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); + } + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME); + } + + @Override + public void sendSmsCode(AuthSmsSendReqVO reqVO) { + // 如果是重置密码场景,需要校验图形验证码是否正确 + if (Objects.equals(SmsSceneEnum.ADMIN_MEMBER_RESET_PASSWORD.getScene(), reqVO.getScene())) { + ResponseModel response = doValidateCaptcha(reqVO); + if (!response.isSuccess()) { + throw exception(ErrorCodeConstants.AUTH_REGISTER_CAPTCHA_CODE_ERROR, response.getRepMsg()); + } + } + + // 登录场景,验证是否存在 + if (userService.getUserByMobile(reqVO.getMobile()) == null) { + throw exception(ErrorCodeConstants.AUTH_MOBILE_NOT_EXISTS); + } + // 发送验证码 + smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); + } + + @Override + public AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) { + // 校验验证码 + smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), getClientIP())).checkError(); + + // 获得用户信息 + AdminUserDO user = userService.getUserByMobile(reqVO.getMobile()); + if (user == null) { + throw exception(ErrorCodeConstants.USER_NOT_EXISTS); + } + + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE); + } + + private void createLoginLog(Long userId, String username, + LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) { + // 插入登录日志 + LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); + reqDTO.setLogType(logTypeEnum.getType()); + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setUserId(userId); + reqDTO.setUserType(getUserType().getValue()); + reqDTO.setUsername(username); + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(getClientIP()); + reqDTO.setResult(loginResult.getResult()); + loginLogService.createLoginLog(reqDTO); + // 更新最后登录时间 + if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) { + userService.updateUserLogin(userId, getClientIP()); + } + } + + @Override + public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) { + // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 + SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), + reqVO.getCode(), reqVO.getState()); + if (socialUser == null || socialUser.getUserId() == null) { + throw exception(ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND); + } + + // 获得用户 + AdminUserDO user = userService.getUser(socialUser.getUserId()); + if (user == null) { + throw exception(ErrorCodeConstants.USER_NOT_EXISTS); + } + + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); + } + + @VisibleForTesting + void validateCaptcha(AuthLoginReqVO reqVO) { + ResponseModel response = doValidateCaptcha(reqVO); + // 校验验证码 + if (!response.isSuccess()) { + // 创建登录失败日志(验证码不正确) + createLoginLog(null, reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.CAPTCHA_CODE_ERROR); + throw exception(ErrorCodeConstants.AUTH_LOGIN_CAPTCHA_CODE_ERROR, response.getRepMsg()); + } + } + + private ResponseModel doValidateCaptcha(CaptchaVerificationReqVO reqVO) { + // 如果验证码关闭,则不进行校验 + if (!captchaEnable) { + return ResponseModel.success(); + } + ValidationUtils.validate(validator, reqVO, CaptchaVerificationReqVO.CodeEnableGroup.class); + CaptchaVO captchaVO = new CaptchaVO(); + captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification()); + return captchaService.verification(captchaVO); + } + + private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) { + // 插入登陆日志 + createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS); + // 创建访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(), + OAuth2ClientConstants.CLIENT_ID_DEFAULT, null); + // 构建返回结果 + return AuthConvert.INSTANCE.convert(accessTokenDO); + } + + @Override + public AuthLoginRespVO refreshToken(String refreshToken) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT); + return AuthConvert.INSTANCE.convert(accessTokenDO); + } + + @Override + public void logout(String token, Integer logType) { + // 删除访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(token); + if (accessTokenDO == null) { + return; + } + // 删除成功,则记录登出日志 + createLogoutLog(accessTokenDO.getUserId(), accessTokenDO.getUserType(), logType); + } + + private void createLogoutLog(Long userId, Integer userType, Integer logType) { + LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); + reqDTO.setLogType(logType); + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setUserId(userId); + reqDTO.setUserType(userType); + if (ObjectUtil.equal(getUserType().getValue(), userType)) { + reqDTO.setUsername(getUsername(userId)); + } else { + reqDTO.setUsername(memberService.getMemberUserMobile(userId)); + } + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(getClientIP()); + reqDTO.setResult(LoginResultEnum.SUCCESS.getResult()); + loginLogService.createLoginLog(reqDTO); + } + + private String getUsername(Long userId) { + if (userId == null) { + return null; + } + AdminUserDO user = userService.getUser(userId); + return user != null ? user.getUsername() : null; + } + + private UserTypeEnum getUserType() { + return UserTypeEnum.ADMIN; + } + + @Override + public AuthLoginRespVO register(AuthRegisterReqVO registerReqVO) { + // 1. 校验验证码 + validateCaptcha(registerReqVO); + + // 2. 校验用户名是否已存在 + Long userId = userService.registerUser(registerReqVO); + + // 3. 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(userId, registerReqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME); + } + + @VisibleForTesting + void validateCaptcha(AuthRegisterReqVO reqVO) { + ResponseModel response = doValidateCaptcha(reqVO); + // 验证不通过 + if (!response.isSuccess()) { + throw exception(ErrorCodeConstants.AUTH_REGISTER_CAPTCHA_CODE_ERROR, response.getRepMsg()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void resetPassword(AuthResetPasswordReqVO reqVO) { + AdminUserDO userByMobile = userService.getUserByMobile(reqVO.getMobile()); + if (userByMobile == null) { + throw exception(ErrorCodeConstants.USER_MOBILE_NOT_EXISTS); + } + + smsCodeApi.useSmsCode(new SmsCodeUseReqDTO() + .setCode(reqVO.getCode()) + .setMobile(reqVO.getMobile()) + .setScene(SmsSceneEnum.ADMIN_MEMBER_RESET_PASSWORD.getScene()) + .setUsedIp(getClientIP()) + ).checkError(); + + userService.updateUserPassword(userByMobile.getId(), reqVO.getPassword()); + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/DeptService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/DeptService.java new file mode 100644 index 0000000..c0f0cf8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/DeptService.java @@ -0,0 +1,119 @@ +package com.tashow.cloud.system.service.dept; + +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptListReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptListReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptSaveReqVO; + +import java.util.*; + +/** + * 部门 Service 接口 + * + * @author 芋道源码 + */ +public interface DeptService { + + /** + * 创建部门 + * + * @param createReqVO 部门信息 + * @return 部门编号 + */ + Long createDept(DeptSaveReqVO createReqVO); + + /** + * 更新部门 + * + * @param updateReqVO 部门信息 + */ + void updateDept(DeptSaveReqVO updateReqVO); + + /** + * 删除部门 + * + * @param id 部门编号 + */ + void deleteDept(Long id); + + /** + * 获得部门信息 + * + * @param id 部门编号 + * @return 部门信息 + */ + DeptDO getDept(Long id); + + /** + * 获得部门信息数组 + * + * @param ids 部门编号数组 + * @return 部门信息数组 + */ + List getDeptList(Collection ids); + + /** + * 筛选部门列表 + * + * @param reqVO 筛选条件请求 VO + * @return 部门列表 + */ + List getDeptList(DeptListReqVO reqVO); + + /** + * 获得指定编号的部门 Map + * + * @param ids 部门编号数组 + * @return 部门 Map + */ + default Map getDeptMap(Collection ids) { + List list = getDeptList(ids); + return CollectionUtils.convertMap(list, DeptDO::getId); + } + + /** + * 获得指定部门的所有子部门 + * + * @param id 部门编号 + * @return 子部门列表 + */ + default List getChildDeptList(Long id) { + return getChildDeptList(Collections.singleton(id)); + } + + /** + * 获得指定部门的所有子部门 + * + * @param ids 部门编号数组 + * @return 子部门列表 + */ + List getChildDeptList(Collection ids); + + /** + * 获得指定领导者的部门列表 + * + * @param id 领导者编号 + * @return 部门列表 + */ + List getDeptListByLeaderUserId(Long id); + + /** + * 获得所有子部门,从缓存中 + * + * @param id 父部门编号 + * @return 子部门列表 + */ + Set getChildDeptIdListFromCache(Long id); + + /** + * 校验部门们是否有效。如下情况,视为无效: + * 1. 部门编号不存在 + * 2. 部门被禁用 + * + * @param ids 角色编号数组 + */ + void validateDeptList(Collection ids); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/DeptServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/DeptServiceImpl.java new file mode 100644 index 0000000..e23a7f5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/DeptServiceImpl.java @@ -0,0 +1,224 @@ +package com.tashow.cloud.system.service.dept; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.permission.core.annotation.DataPermission; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptListReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.dal.mysql.dept.DeptMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.*; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; + + +/** + * 部门 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class DeptServiceImpl implements DeptService { + + @Resource + private DeptMapper deptMapper; + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 + public Long createDept(DeptSaveReqVO createReqVO) { + if (createReqVO.getParentId() == null) { + createReqVO.setParentId(DeptDO.PARENT_ID_ROOT); + } + // 校验父部门的有效性 + validateParentDept(null, createReqVO.getParentId()); + // 校验部门名的唯一性 + validateDeptNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入部门 + DeptDO dept = BeanUtils.toBean(createReqVO, DeptDO.class); + deptMapper.insert(dept); + return dept.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 + public void updateDept(DeptSaveReqVO updateReqVO) { + if (updateReqVO.getParentId() == null) { + updateReqVO.setParentId(DeptDO.PARENT_ID_ROOT); + } + // 校验自己存在 + validateDeptExists(updateReqVO.getId()); + // 校验父部门的有效性 + validateParentDept(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验部门名的唯一性 + validateDeptNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新部门 + DeptDO updateObj = BeanUtils.toBean(updateReqVO, DeptDO.class); + deptMapper.updateById(updateObj); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 + public void deleteDept(Long id) { + // 校验是否存在 + validateDeptExists(id); + // 校验是否有子部门 + if (deptMapper.selectCountByParentId(id) > 0) { + throw exception(ErrorCodeConstants.DEPT_EXITS_CHILDREN); + } + // 删除部门 + deptMapper.deleteById(id); + } + + @VisibleForTesting + void validateDeptExists(Long id) { + if (id == null) { + return; + } + DeptDO dept = deptMapper.selectById(id); + if (dept == null) { + throw exception(ErrorCodeConstants.DEPT_NOT_FOUND); + } + } + + @VisibleForTesting + void validateParentDept(Long id, Long parentId) { + if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父部门 + if (Objects.equals(id, parentId)) { + throw exception(ErrorCodeConstants.DEPT_PARENT_ERROR); + } + // 2. 父部门不存在 + DeptDO parentDept = deptMapper.selectById(parentId); + if (parentDept == null) { + throw exception(ErrorCodeConstants.DEPT_PARENT_NOT_EXITS); + } + // 3. 递归校验父部门,如果父部门是自己的子部门,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentDept.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(ErrorCodeConstants.DEPT_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父部门 + if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentDept = deptMapper.selectById(parentId); + if (parentDept == null) { + break; + } + } + } + + @VisibleForTesting + void validateDeptNameUnique(Long id, Long parentId, String name) { + DeptDO dept = deptMapper.selectByParentIdAndName(parentId, name); + if (dept == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的部门 + if (id == null) { + throw exception(ErrorCodeConstants.DEPT_NAME_DUPLICATE); + } + if (ObjectUtil.notEqual(dept.getId(), id)) { + throw exception(ErrorCodeConstants.DEPT_NAME_DUPLICATE); + } + } + + @Override + public DeptDO getDept(Long id) { + return deptMapper.selectById(id); + } + + @Override + public List getDeptList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return deptMapper.selectBatchIds(ids); + } + + @Override + public List getDeptList(DeptListReqVO reqVO) { + List list = deptMapper.selectList(reqVO); + list.sort(Comparator.comparing(DeptDO::getSort)); + return list; + } + + @Override + public List getChildDeptList(Collection ids) { + List children = new LinkedList<>(); + // 遍历每一层 + Collection parentIds = ids; + for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 + // 查询当前层,所有的子部门 + List depts = deptMapper.selectListByParentId(parentIds); + // 1. 如果没有子部门,则结束遍历 + if (CollUtil.isEmpty(depts)) { + break; + } + // 2. 如果有子部门,继续遍历 + children.addAll(depts); + parentIds = convertSet(depts, DeptDO::getId); + } + return children; + } + + @Override + public List getDeptListByLeaderUserId(Long id) { + return deptMapper.selectListByLeaderUserId(id); + } + + @Override + @DataPermission(enable = false) // 禁用数据权限,避免建立不正确的缓存 + @Cacheable(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, key = "#id") + public Set getChildDeptIdListFromCache(Long id) { + List children = getChildDeptList(id); + return convertSet(children, DeptDO::getId); + } + + @Override + public void validateDeptList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得科室信息 + Map deptMap = getDeptMap(ids); + // 校验 + ids.forEach(id -> { + DeptDO dept = deptMap.get(id); + if (dept == null) { + throw exception(ErrorCodeConstants.DEPT_NOT_FOUND); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(dept.getStatus())) { + throw exception(ErrorCodeConstants.DEPT_NOT_ENABLE, dept.getName()); + } + }); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/PostService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/PostService.java new file mode 100644 index 0000000..e2cfce4 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/PostService.java @@ -0,0 +1,86 @@ +package com.tashow.cloud.system.service.dept; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostPageReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostPageReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSaveReqVO; +import org.springframework.lang.Nullable; + +import java.util.Collection; +import java.util.List; + +/** + * 岗位 Service 接口 + * + * @author 芋道源码 + */ +public interface PostService { + + /** + * 创建岗位 + * + * @param createReqVO 岗位信息 + * @return 岗位编号 + */ + Long createPost(PostSaveReqVO createReqVO); + + /** + * 更新岗位 + * + * @param updateReqVO 岗位信息 + */ + void updatePost(PostSaveReqVO updateReqVO); + + /** + * 删除岗位信息 + * + * @param id 岗位编号 + */ + void deletePost(Long id); + + /** + * 获得岗位列表 + * + * @param ids 岗位编号数组 + * @return 部门列表 + */ + List getPostList(@Nullable Collection ids); + + /** + * 获得符合条件的岗位列表 + * + * @param ids 岗位编号数组。如果为空,不进行筛选 + * @param statuses 状态数组。如果为空,不进行筛选 + * @return 部门列表 + */ + List getPostList(@Nullable Collection ids, + @Nullable Collection statuses); + + /** + * 获得岗位分页列表 + * + * @param reqVO 分页条件 + * @return 部门分页列表 + */ + PageResult getPostPage(PostPageReqVO reqVO); + + /** + * 获得岗位信息 + * + * @param id 岗位编号 + * @return 岗位信息 + */ + PostDO getPost(Long id); + + /** + * 校验岗位们是否有效。如下情况,视为无效: + * 1. 岗位编号不存在 + * 2. 岗位被禁用 + * + * @param ids 岗位编号数组 + */ + void validatePostList(Collection ids); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/PostServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/PostServiceImpl.java new file mode 100644 index 0000000..733457b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dept/PostServiceImpl.java @@ -0,0 +1,156 @@ +package com.tashow.cloud.system.service.dept; + +import cn.hutool.core.collection.CollUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostPageReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dept.PostDO; +import com.tashow.cloud.system.dal.mysql.dept.PostMapper; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostPageReqVO; +import com.tashow.cloud.system.controller.admin.dept.vo.post.PostSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertMap; + + +/** + * 岗位 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class PostServiceImpl implements PostService { + + @Resource + private PostMapper postMapper; + + @Override + public Long createPost(PostSaveReqVO createReqVO) { + // 校验正确性 + validatePostForCreateOrUpdate(null, createReqVO.getName(), createReqVO.getCode()); + + // 插入岗位 + PostDO post = BeanUtils.toBean(createReqVO, PostDO.class); + postMapper.insert(post); + return post.getId(); + } + + @Override + public void updatePost(PostSaveReqVO updateReqVO) { + // 校验正确性 + validatePostForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getName(), updateReqVO.getCode()); + + // 更新岗位 + PostDO updateObj = BeanUtils.toBean(updateReqVO, PostDO.class); + postMapper.updateById(updateObj); + } + + @Override + public void deletePost(Long id) { + // 校验是否存在 + validatePostExists(id); + // 删除部门 + postMapper.deleteById(id); + } + + private void validatePostForCreateOrUpdate(Long id, String name, String code) { + // 校验自己存在 + validatePostExists(id); + // 校验岗位名的唯一性 + validatePostNameUnique(id, name); + // 校验岗位编码的唯一性 + validatePostCodeUnique(id, code); + } + + private void validatePostNameUnique(Long id, String name) { + PostDO post = postMapper.selectByName(name); + if (post == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的岗位 + if (id == null) { + throw exception(ErrorCodeConstants.POST_NAME_DUPLICATE); + } + if (!post.getId().equals(id)) { + throw exception(ErrorCodeConstants.POST_NAME_DUPLICATE); + } + } + + private void validatePostCodeUnique(Long id, String code) { + PostDO post = postMapper.selectByCode(code); + if (post == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的岗位 + if (id == null) { + throw exception(ErrorCodeConstants.POST_CODE_DUPLICATE); + } + if (!post.getId().equals(id)) { + throw exception(ErrorCodeConstants.POST_CODE_DUPLICATE); + } + } + + private void validatePostExists(Long id) { + if (id == null) { + return; + } + if (postMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.POST_NOT_FOUND); + } + } + + @Override + public List getPostList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return postMapper.selectBatchIds(ids); + } + + @Override + public List getPostList(Collection ids, Collection statuses) { + return postMapper.selectList(ids, statuses); + } + + @Override + public PageResult getPostPage(PostPageReqVO reqVO) { + return postMapper.selectPage(reqVO); + } + + @Override + public PostDO getPost(Long id) { + return postMapper.selectById(id); + } + + @Override + public void validatePostList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得岗位信息 + List posts = postMapper.selectBatchIds(ids); + Map postMap = convertMap(posts, PostDO::getId); + // 校验 + ids.forEach(id -> { + PostDO post = postMap.get(id); + if (post == null) { + throw exception(ErrorCodeConstants.POST_NOT_FOUND); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(post.getStatus())) { + throw exception(ErrorCodeConstants.POST_NOT_ENABLE, post.getName()); + } + }); + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictDataService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictDataService.java new file mode 100644 index 0000000..fff14e9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictDataService.java @@ -0,0 +1,112 @@ +package com.tashow.cloud.system.service.dict; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictDataDO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import org.springframework.lang.Nullable; + +import java.util.Collection; +import java.util.List; + +/** + * 字典数据 Service 接口 + * + * @author ruoyi + */ +public interface DictDataService { + + /** + * 创建字典数据 + * + * @param createReqVO 字典数据信息 + * @return 字典数据编号 + */ + Long createDictData(DictDataSaveReqVO createReqVO); + + /** + * 更新字典数据 + * + * @param updateReqVO 字典数据信息 + */ + void updateDictData(DictDataSaveReqVO updateReqVO); + + /** + * 删除字典数据 + * + * @param id 字典数据编号 + */ + void deleteDictData(Long id); + + /** + * 获得字典数据列表 + * + * @param status 状态 + * @param dictType 字典类型 + * @return 字典数据全列表 + */ + List getDictDataList(@Nullable Integer status, @Nullable String dictType); + + /** + * 获得字典数据分页列表 + * + * @param pageReqVO 分页请求 + * @return 字典数据分页列表 + */ + PageResult getDictDataPage(DictDataPageReqVO pageReqVO); + + /** + * 获得字典数据详情 + * + * @param id 字典数据编号 + * @return 字典数据 + */ + DictDataDO getDictData(Long id); + + /** + * 获得指定字典类型的数据数量 + * + * @param dictType 字典类型 + * @return 数据数量 + */ + long getDictDataCountByDictType(String dictType); + + /** + * 校验字典数据们是否有效。如下情况,视为无效: + * 1. 字典数据不存在 + * 2. 字典数据被禁用 + * + * @param dictType 字典类型 + * @param values 字典数据值的数组 + */ + void validateDictDataList(String dictType, Collection values); + + /** + * 获得指定的字典数据 + * + * @param dictType 字典类型 + * @param value 字典数据值 + * @return 字典数据 + */ + DictDataDO getDictData(String dictType, String value); + + /** + * 解析获得指定的字典数据,从缓存中 + * + * @param dictType 字典类型 + * @param label 字典数据标签 + * @return 字典数据 + */ + DictDataDO parseDictData(String dictType, String label); + + /** + * 获得指定数据类型的字典数据列表 + * + * @param dictType 字典类型 + * @return 字典数据列表 + */ + List getDictDataListByDictType(String dictType); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictDataServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictDataServiceImpl.java new file mode 100644 index 0000000..c20a093 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictDataServiceImpl.java @@ -0,0 +1,181 @@ +package com.tashow.cloud.system.service.dict; + +import cn.hutool.core.collection.CollUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictDataDO; +import com.tashow.cloud.system.dal.dataobject.dict.DictTypeDO; +import com.tashow.cloud.system.dal.mysql.dict.DictDataMapper; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 字典数据 Service 实现类 + * + * @author ruoyi + */ +@Service +@Slf4j +public class DictDataServiceImpl implements DictDataService { + + /** + * 排序 dictType > sort + */ + private static final Comparator COMPARATOR_TYPE_AND_SORT = Comparator + .comparing(DictDataDO::getDictType) + .thenComparingInt(DictDataDO::getSort); + + @Resource + private DictTypeService dictTypeService; + + @Resource + private DictDataMapper dictDataMapper; + + @Override + public List getDictDataList(Integer status, String dictType) { + List list = dictDataMapper.selectListByStatusAndDictType(status, dictType); + list.sort(COMPARATOR_TYPE_AND_SORT); + return list; + } + + @Override + public PageResult getDictDataPage(DictDataPageReqVO pageReqVO) { + return dictDataMapper.selectPage(pageReqVO); + } + + @Override + public DictDataDO getDictData(Long id) { + return dictDataMapper.selectById(id); + } + + @Override + public Long createDictData(DictDataSaveReqVO createReqVO) { + // 校验字典类型有效 + validateDictTypeExists(createReqVO.getDictType()); + // 校验字典数据的值的唯一性 + validateDictDataValueUnique(null, createReqVO.getDictType(), createReqVO.getValue()); + + // 插入字典类型 + DictDataDO dictData = BeanUtils.toBean(createReqVO, DictDataDO.class); + dictDataMapper.insert(dictData); + return dictData.getId(); + } + + @Override + public void updateDictData(DictDataSaveReqVO updateReqVO) { + // 校验自己存在 + validateDictDataExists(updateReqVO.getId()); + // 校验字典类型有效 + validateDictTypeExists(updateReqVO.getDictType()); + // 校验字典数据的值的唯一性 + validateDictDataValueUnique(updateReqVO.getId(), updateReqVO.getDictType(), updateReqVO.getValue()); + + // 更新字典类型 + DictDataDO updateObj = BeanUtils.toBean(updateReqVO, DictDataDO.class); + dictDataMapper.updateById(updateObj); + } + + @Override + public void deleteDictData(Long id) { + // 校验是否存在 + validateDictDataExists(id); + + // 删除字典数据 + dictDataMapper.deleteById(id); + } + + @Override + public long getDictDataCountByDictType(String dictType) { + return dictDataMapper.selectCountByDictType(dictType); + } + + @VisibleForTesting + public void validateDictDataValueUnique(Long id, String dictType, String value) { + DictDataDO dictData = dictDataMapper.selectByDictTypeAndValue(dictType, value); + if (dictData == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典数据 + if (id == null) { + throw exception(ErrorCodeConstants.DICT_DATA_VALUE_DUPLICATE); + } + if (!dictData.getId().equals(id)) { + throw exception(ErrorCodeConstants.DICT_DATA_VALUE_DUPLICATE); + } + } + + @VisibleForTesting + public void validateDictDataExists(Long id) { + if (id == null) { + return; + } + DictDataDO dictData = dictDataMapper.selectById(id); + if (dictData == null) { + throw exception(ErrorCodeConstants.DICT_DATA_NOT_EXISTS); + } + } + + @VisibleForTesting + public void validateDictTypeExists(String type) { + DictTypeDO dictType = dictTypeService.getDictType(type); + if (dictType == null) { + throw exception(ErrorCodeConstants.DICT_TYPE_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(dictType.getStatus())) { + throw exception(ErrorCodeConstants.DICT_TYPE_NOT_ENABLE); + } + } + + @Override + public void validateDictDataList(String dictType, Collection values) { + if (CollUtil.isEmpty(values)) { + return; + } + Map dictDataMap = CollectionUtils.convertMap( + dictDataMapper.selectByDictTypeAndValues(dictType, values), DictDataDO::getValue); + // 校验 + values.forEach(value -> { + DictDataDO dictData = dictDataMap.get(value); + if (dictData == null) { + throw exception(ErrorCodeConstants.DICT_DATA_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(dictData.getStatus())) { + throw exception(ErrorCodeConstants.DICT_DATA_NOT_ENABLE, dictData.getLabel()); + } + }); + } + + @Override + public DictDataDO getDictData(String dictType, String value) { + return dictDataMapper.selectByDictTypeAndValue(dictType, value); + } + + @Override + public DictDataDO parseDictData(String dictType, String label) { + return dictDataMapper.selectByDictTypeAndLabel(dictType, label); + } + + @Override + public List getDictDataListByDictType(String dictType) { + List list = dictDataMapper.selectList(DictDataDO::getDictType, dictType); + list.sort(Comparator.comparing(DictDataDO::getSort)); + return list; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictTypeService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictTypeService.java new file mode 100644 index 0000000..8f85a0d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictTypeService.java @@ -0,0 +1,72 @@ +package com.tashow.cloud.system.service.dict; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictTypeDO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; + +import java.util.List; + +/** + * 字典类型 Service 接口 + * + * @author 芋道源码 + */ +public interface DictTypeService { + + /** + * 创建字典类型 + * + * @param createReqVO 字典类型信息 + * @return 字典类型编号 + */ + Long createDictType(DictTypeSaveReqVO createReqVO); + + /** + * 更新字典类型 + * + * @param updateReqVO 字典类型信息 + */ + void updateDictType(DictTypeSaveReqVO updateReqVO); + + /** + * 删除字典类型 + * + * @param id 字典类型编号 + */ + void deleteDictType(Long id); + + /** + * 获得字典类型分页列表 + * + * @param pageReqVO 分页请求 + * @return 字典类型分页列表 + */ + PageResult getDictTypePage(DictTypePageReqVO pageReqVO); + + /** + * 获得字典类型详情 + * + * @param id 字典类型编号 + * @return 字典类型 + */ + DictTypeDO getDictType(Long id); + + /** + * 获得字典类型详情 + * + * @param type 字典类型 + * @return 字典类型详情 + */ + DictTypeDO getDictType(String type); + + /** + * 获得全部字典类型列表 + * + * @return 字典类型列表 + */ + List getDictTypeList(); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictTypeServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictTypeServiceImpl.java new file mode 100644 index 0000000..7ff022e --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/dict/DictTypeServiceImpl.java @@ -0,0 +1,140 @@ +package com.tashow.cloud.system.service.dict; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.date.LocalDateTimeUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import com.tashow.cloud.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dict.DictTypeDO; +import com.tashow.cloud.system.dal.mysql.dict.DictTypeMapper; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 字典类型 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class DictTypeServiceImpl implements DictTypeService { + + @Resource + private DictDataService dictDataService; + + @Resource + private DictTypeMapper dictTypeMapper; + + @Override + public PageResult getDictTypePage(DictTypePageReqVO pageReqVO) { + return dictTypeMapper.selectPage(pageReqVO); + } + + @Override + public DictTypeDO getDictType(Long id) { + return dictTypeMapper.selectById(id); + } + + @Override + public DictTypeDO getDictType(String type) { + return dictTypeMapper.selectByType(type); + } + + @Override + public Long createDictType(DictTypeSaveReqVO createReqVO) { + // 校验字典类型的名字的唯一性 + validateDictTypeNameUnique(null, createReqVO.getName()); + // 校验字典类型的类型的唯一性 + validateDictTypeUnique(null, createReqVO.getType()); + + // 插入字典类型 + DictTypeDO dictType = BeanUtils.toBean(createReqVO, DictTypeDO.class); + dictType.setDeletedTime(LocalDateTimeUtils.EMPTY); // 唯一索引,避免 null 值 + dictTypeMapper.insert(dictType); + return dictType.getId(); + } + + @Override + public void updateDictType(DictTypeSaveReqVO updateReqVO) { + // 校验自己存在 + validateDictTypeExists(updateReqVO.getId()); + // 校验字典类型的名字的唯一性 + validateDictTypeNameUnique(updateReqVO.getId(), updateReqVO.getName()); + // 校验字典类型的类型的唯一性 + validateDictTypeUnique(updateReqVO.getId(), updateReqVO.getType()); + + // 更新字典类型 + DictTypeDO updateObj = BeanUtils.toBean(updateReqVO, DictTypeDO.class); + dictTypeMapper.updateById(updateObj); + } + + @Override + public void deleteDictType(Long id) { + // 校验是否存在 + DictTypeDO dictType = validateDictTypeExists(id); + // 校验是否有字典数据 + if (dictDataService.getDictDataCountByDictType(dictType.getType()) > 0) { + throw exception(ErrorCodeConstants.DICT_TYPE_HAS_CHILDREN); + } + // 删除字典类型 + dictTypeMapper.updateToDelete(id, LocalDateTime.now()); + } + + @Override + public List getDictTypeList() { + return dictTypeMapper.selectList(); + } + + @VisibleForTesting + void validateDictTypeNameUnique(Long id, String name) { + DictTypeDO dictType = dictTypeMapper.selectByName(name); + if (dictType == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(ErrorCodeConstants.DICT_TYPE_NAME_DUPLICATE); + } + if (!dictType.getId().equals(id)) { + throw exception(ErrorCodeConstants.DICT_TYPE_NAME_DUPLICATE); + } + } + + @VisibleForTesting + void validateDictTypeUnique(Long id, String type) { + if (StrUtil.isEmpty(type)) { + return; + } + DictTypeDO dictType = dictTypeMapper.selectByType(type); + if (dictType == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(ErrorCodeConstants.DICT_TYPE_TYPE_DUPLICATE); + } + if (!dictType.getId().equals(id)) { + throw exception(ErrorCodeConstants.DICT_TYPE_TYPE_DUPLICATE); + } + } + + @VisibleForTesting + DictTypeDO validateDictTypeExists(Long id) { + if (id == null) { + return null; + } + DictTypeDO dictType = dictTypeMapper.selectById(id); + if (dictType == null) { + throw exception(ErrorCodeConstants.DICT_TYPE_NOT_EXISTS); + } + return dictType; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/LoginLogService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/LoginLogService.java new file mode 100644 index 0000000..fe6afe1 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/LoginLogService.java @@ -0,0 +1,32 @@ +package com.tashow.cloud.system.service.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.logger.LoginLogDO; + +import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import jakarta.validation.Valid; + +/** + * 登录日志 Service 接口 + */ +public interface LoginLogService { + + /** + * 获得登录日志分页 + * + * @param pageReqVO 分页条件 + * @return 登录日志分页 + */ + PageResult getLoginLogPage(LoginLogPageReqVO pageReqVO); + + /** + * 创建登录日志 + * + * @param reqDTO 日志信息 + */ + void createLoginLog(@Valid LoginLogCreateReqDTO reqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/LoginLogServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/LoginLogServiceImpl.java new file mode 100644 index 0000000..8b2c183 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/LoginLogServiceImpl.java @@ -0,0 +1,37 @@ +package com.tashow.cloud.system.service.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.logger.LoginLogDO; +import com.tashow.cloud.system.dal.mysql.logger.LoginLogMapper; +import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; + +/** + * 登录日志 Service 实现 + */ +@Service +@Validated +public class LoginLogServiceImpl implements LoginLogService { + + @Resource + private LoginLogMapper loginLogMapper; + + @Override + public PageResult getLoginLogPage(LoginLogPageReqVO pageReqVO) { + return loginLogMapper.selectPage(pageReqVO); + } + + @Override + public void createLoginLog(LoginLogCreateReqDTO reqDTO) { + LoginLogDO loginLog = BeanUtils.toBean(reqDTO, LoginLogDO.class); + loginLogMapper.insert(loginLog); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/OperateLogService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/OperateLogService.java new file mode 100644 index 0000000..3d5d111 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/OperateLogService.java @@ -0,0 +1,42 @@ +package com.tashow.cloud.system.service.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.logger.OperateLogDO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; + +/** + * 操作日志 Service 接口 + * + * @author 芋道源码 + */ +public interface OperateLogService { + + /** + * 记录操作日志 + * + * @param createReqDTO 创建请求 + */ + void createOperateLog(OperateLogCreateReqDTO createReqDTO); + + /** + * 获得操作日志分页列表 + * + * @param pageReqVO 分页条件 + * @return 操作日志分页列表 + */ + PageResult getOperateLogPage(OperateLogPageReqVO pageReqVO); + + /** + * 获得操作日志分页列表 + * + * @param pageReqVO 分页条件 + * @return 操作日志分页列表 + */ + PageResult getOperateLogPage(OperateLogPageReqDTO pageReqVO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/OperateLogServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/OperateLogServiceImpl.java new file mode 100644 index 0000000..d063774 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/logger/OperateLogServiceImpl.java @@ -0,0 +1,47 @@ +package com.tashow.cloud.system.service.logger; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.logger.OperateLogDO; +import com.tashow.cloud.system.dal.mysql.logger.OperateLogMapper; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogPageReqDTO; +import com.tashow.cloud.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * 操作日志 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class OperateLogServiceImpl implements OperateLogService { + + @Resource + private OperateLogMapper operateLogMapper; + + @Override + public void createOperateLog(OperateLogCreateReqDTO createReqDTO) { + OperateLogDO log = BeanUtils.toBean(createReqDTO, OperateLogDO.class); + operateLogMapper.insert(log); + } + + @Override + public PageResult getOperateLogPage(OperateLogPageReqVO pageReqVO) { + return operateLogMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getOperateLogPage(OperateLogPageReqDTO pageReqDTO) { + return operateLogMapper.selectPage(pageReqDTO); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailAccountService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailAccountService.java new file mode 100644 index 0000000..e5734f9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailAccountService.java @@ -0,0 +1,74 @@ +package com.tashow.cloud.system.service.mail; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailAccountDO; + +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import jakarta.validation.Valid; +import java.util.List; + +/** + * 邮箱账号 Service 接口 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailAccountService { + + /** + * 创建邮箱账号 + * + * @param createReqVO 邮箱账号信息 + * @return 编号 + */ + Long createMailAccount(@Valid MailAccountSaveReqVO createReqVO); + + /** + * 修改邮箱账号 + * + * @param updateReqVO 邮箱账号信息 + */ + void updateMailAccount(@Valid MailAccountSaveReqVO updateReqVO); + + /** + * 删除邮箱账号 + * + * @param id 编号 + */ + void deleteMailAccount(Long id); + + /** + * 获取邮箱账号信息 + * + * @param id 编号 + * @return 邮箱账号信息 + */ + MailAccountDO getMailAccount(Long id); + + /** + * 从缓存中获取邮箱账号 + * + * @param id 编号 + * @return 邮箱账号 + */ + MailAccountDO getMailAccountFromCache(Long id); + + /** + * 获取邮箱账号分页信息 + * + * @param pageReqVO 邮箱账号分页参数 + * @return 邮箱账号分页信息 + */ + PageResult getMailAccountPage(MailAccountPageReqVO pageReqVO); + + /** + * 获取邮箱数组信息 + * + * @return 邮箱账号信息数组 + */ + List getMailAccountList(); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailAccountServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailAccountServiceImpl.java new file mode 100644 index 0000000..7fd665c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailAccountServiceImpl.java @@ -0,0 +1,102 @@ +package com.tashow.cloud.system.service.mail; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailAccountDO; +import com.tashow.cloud.system.dal.mysql.mail.MailAccountMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS; + +/** + * 邮箱账号 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailAccountServiceImpl implements MailAccountService { + + @Resource + private MailAccountMapper mailAccountMapper; + + @Resource + private MailTemplateService mailTemplateService; + + @Override + public Long createMailAccount(MailAccountSaveReqVO createReqVO) { + MailAccountDO account = BeanUtils.toBean(createReqVO, MailAccountDO.class); + mailAccountMapper.insert(account); + return account.getId(); + } + + @Override + @CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#updateReqVO.id") + public void updateMailAccount(MailAccountSaveReqVO updateReqVO) { + // 校验是否存在 + validateMailAccountExists(updateReqVO.getId()); + + // 更新 + MailAccountDO updateObj = BeanUtils.toBean(updateReqVO, MailAccountDO.class); + mailAccountMapper.updateById(updateObj); + } + + @Override + @CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id") + public void deleteMailAccount(Long id) { + // 校验是否存在账号 + validateMailAccountExists(id); + // 校验是否存在关联模版 + if (mailTemplateService.getMailTemplateCountByAccountId(id) > 0) { + throw exception(ErrorCodeConstants.MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS); + } + + // 删除 + mailAccountMapper.deleteById(id); + } + + private void validateMailAccountExists(Long id) { + if (mailAccountMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS); + } + } + + @Override + public MailAccountDO getMailAccount(Long id) { + return mailAccountMapper.selectById(id); + } + + @Override + @Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id", unless = "#result == null") + public MailAccountDO getMailAccountFromCache(Long id) { + return getMailAccount(id); + } + + @Override + public PageResult getMailAccountPage(MailAccountPageReqVO pageReqVO) { + return mailAccountMapper.selectPage(pageReqVO); + } + + @Override + public List getMailAccountList() { + return mailAccountMapper.selectList(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailLogService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailLogService.java new file mode 100644 index 0000000..a48b4a2 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailLogService.java @@ -0,0 +1,62 @@ +package com.tashow.cloud.system.service.mail; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailAccountDO; +import com.tashow.cloud.system.dal.dataobject.mail.MailLogDO; +import com.tashow.cloud.system.dal.dataobject.mail.MailTemplateDO; +import com.tashow.cloud.system.controller.admin.mail.vo.log.MailLogPageReqVO; + +import java.util.Map; + +/** + * 邮件日志 Service 接口 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailLogService { + + /** + * 邮件日志分页 + * + * @param pageVO 分页参数 + * @return 分页结果 + */ + PageResult getMailLogPage(MailLogPageReqVO pageVO); + + /** + * 获得指定编号的邮件日志 + * + * @param id 日志编号 + * @return 邮件日志 + */ + MailLogDO getMailLog(Long id); + + /** + * 创建邮件日志 + * + * @param userId 用户编码 + * @param userType 用户类型 + * @param toMail 收件人邮件 + * @param account 邮件账号信息 + * @param template 模版信息 + * @param templateContent 模版内容 + * @param templateParams 模版参数 + * @param isSend 是否发送成功 + * @return 日志编号 + */ + Long createMailLog(Long userId, Integer userType, String toMail, + MailAccountDO account, MailTemplateDO template , + String templateContent, Map templateParams, Boolean isSend); + + /** + * 更新邮件发送结果 + * + * @param logId 日志编号 + * @param messageId 发送后的消息编号 + * @param exception 发送异常 + */ + void updateMailSendResult(Long logId, String messageId, Exception exception); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailLogServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailLogServiceImpl.java new file mode 100644 index 0000000..716b003 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailLogServiceImpl.java @@ -0,0 +1,80 @@ +package com.tashow.cloud.system.service.mail; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailAccountDO; +import com.tashow.cloud.system.dal.dataobject.mail.MailLogDO; +import com.tashow.cloud.system.dal.dataobject.mail.MailTemplateDO; +import com.tashow.cloud.system.dal.mysql.mail.MailLogMapper; +import com.tashow.cloud.systemapi.enums.mail.MailSendStatusEnum; +import com.tashow.cloud.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import com.tashow.cloud.systemapi.enums.mail.MailSendStatusEnum; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Objects; + +import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage; + +/** + * 邮件日志 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +public class MailLogServiceImpl implements MailLogService { + + @Resource + private MailLogMapper mailLogMapper; + + @Override + public PageResult getMailLogPage(MailLogPageReqVO pageVO) { + return mailLogMapper.selectPage(pageVO); + } + + @Override + public MailLogDO getMailLog(Long id) { + return mailLogMapper.selectById(id); + } + + @Override + public Long createMailLog(Long userId, Integer userType, String toMail, + MailAccountDO account, MailTemplateDO template, + String templateContent, Map templateParams, Boolean isSend) { + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); + // 根据是否要发送,设置状态 + logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus() + : MailSendStatusEnum.IGNORE.getStatus()) + // 用户信息 + .userId(userId).userType(userType).toMail(toMail) + .accountId(account.getId()).fromMail(account.getMail()) + // 模板相关字段 + .templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname()) + .templateTitle(template.getTitle()).templateContent(templateContent).templateParams(templateParams); + + // 插入数据库 + MailLogDO logDO = logDOBuilder.build(); + mailLogMapper.insert(logDO); + return logDO.getId(); + } + + @Override + public void updateMailSendResult(Long logId, String messageId, Exception exception) { + // 1. 成功 + if (exception == null) { + mailLogMapper.updateById(new MailLogDO().setId(logId).setSendTime(LocalDateTime.now()) + .setSendStatus(MailSendStatusEnum.SUCCESS.getStatus()).setSendMessageId(messageId)); + return; + } + // 2. 失败 + mailLogMapper.updateById(new MailLogDO().setId(logId).setSendTime(LocalDateTime.now()) + .setSendStatus(MailSendStatusEnum.FAILURE.getStatus()).setSendException(getRootCauseMessage(exception))); + + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailSendService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailSendService.java new file mode 100644 index 0000000..02c7297 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailSendService.java @@ -0,0 +1,60 @@ +package com.tashow.cloud.system.service.mail; + +import com.tashow.cloud.system.mq.message.mail.MailSendMessage; + +import java.util.Map; + +/** + * 邮件发送 Service 接口 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailSendService { + + /** + * 发送单条邮件给管理后台的用户 + * + * @param mail 邮箱 + * @param userId 用户编码 + * @param templateCode 邮件模版编码 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 + */ + Long sendSingleMailToAdmin(String mail, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条邮件给用户 APP 的用户 + * + * @param mail 邮箱 + * @param userId 用户编码 + * @param templateCode 邮件模版编码 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 + */ + Long sendSingleMailToMember(String mail, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条邮件给用户 + * + * @param mail 邮箱 + * @param userId 用户编码 + * @param userType 用户类型 + * @param templateCode 邮件模版编码 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 + */ + Long sendSingleMail(String mail, Long userId, Integer userType, + String templateCode, Map templateParams); + + /** + * 执行真正的邮件发送 + * 注意,该方法仅仅提供给 MQ Consumer 使用 + * + * @param message 邮件 + */ + void doSendMail(MailSendMessage message); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailSendServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailSendServiceImpl.java new file mode 100644 index 0000000..cc94817 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailSendServiceImpl.java @@ -0,0 +1,175 @@ +package com.tashow.cloud.system.service.mail; + +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.system.dal.dataobject.mail.MailAccountDO; +import com.tashow.cloud.system.dal.dataobject.mail.MailTemplateDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.mq.message.mail.MailSendMessage; +import com.tashow.cloud.system.mq.producer.mail.MailProducer; +import com.tashow.cloud.system.service.member.MemberService; +import com.tashow.cloud.system.service.user.AdminUserService; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.system.service.member.MemberService; +import com.tashow.cloud.system.service.user.AdminUserService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.hutool.extra.mail.*; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Map; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 邮箱发送 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailSendServiceImpl implements MailSendService { + + @Resource + private AdminUserService adminUserService; + @Resource + private MemberService memberService; + + @Resource + private MailAccountService mailAccountService; + @Resource + private MailTemplateService mailTemplateService; + + @Resource + private MailLogService mailLogService; + @Resource + private MailProducer mailProducer; + + @Override + public Long sendSingleMailToAdmin(String mail, Long userId, + String templateCode, Map templateParams) { + // 如果 mail 为空,则加载用户编号对应的邮箱 + if (StrUtil.isEmpty(mail)) { + AdminUserDO user = adminUserService.getUser(userId); + if (user != null) { + mail = user.getEmail(); + } + } + // 执行发送 + return sendSingleMail(mail, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleMailToMember(String mail, Long userId, + String templateCode, Map templateParams) { + // 如果 mail 为空,则加载用户编号对应的邮箱 + if (StrUtil.isEmpty(mail)) { + mail = memberService.getMemberUserEmail(userId); + } + // 执行发送 + return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleMail(String mail, Long userId, Integer userType, + String templateCode, Map templateParams) { + // 校验邮箱模版是否合法 + MailTemplateDO template = validateMailTemplate(templateCode); + // 校验邮箱账号是否合法 + MailAccountDO account = validateMailAccount(template.getAccountId()); + + // 校验邮箱是否存在 + mail = validateMail(mail); + validateTemplateParams(template, templateParams); + + // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); + String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams); + String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams); + Long sendLogId = mailLogService.createMailLog(userId, userType, mail, + account, template, content, templateParams, isSend); + // 发送 MQ 消息,异步执行发送短信 + if (isSend) { + mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(), + template.getNickname(), title, content); + } + return sendLogId; + } + + @Override + public void doSendMail(MailSendMessage message) { + // 1. 创建发送账号 + MailAccountDO account = validateMailAccount(message.getAccountId()); + MailAccount mailAccount = buildMailAccount(account, message.getNickname()); + // 2. 发送邮件 + try { + String messageId = MailUtil.send(mailAccount, message.getMail(), + message.getTitle(), message.getContent(), true); + // 3. 更新结果(成功) + mailLogService.updateMailSendResult(message.getLogId(), messageId, null); + } catch (Exception e) { + // 3. 更新结果(异常) + mailLogService.updateMailSendResult(message.getLogId(), null, e); + } + } + + private MailAccount buildMailAccount(MailAccountDO account, String nickname) { + String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail(); + return new MailAccount().setFrom(from).setAuth(true) + .setUser(account.getUsername()).setPass(account.getPassword().toCharArray()) + .setHost(account.getHost()).setPort(account.getPort()) + .setSslEnable(account.getSslEnable()).setStarttlsEnable(account.getStarttlsEnable()); + } + + @VisibleForTesting + MailTemplateDO validateMailTemplate(String templateCode) { + // 获得邮件模板。考虑到效率,从缓存中获取 + MailTemplateDO template = mailTemplateService.getMailTemplateByCodeFromCache(templateCode); + // 邮件模板不存在 + if (template == null) { + throw exception(ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS); + } + return template; + } + + @VisibleForTesting + MailAccountDO validateMailAccount(Long accountId) { + // 获得邮箱账号。考虑到效率,从缓存中获取 + MailAccountDO account = mailAccountService.getMailAccountFromCache(accountId); + // 邮箱账号不存在 + if (account == null) { + throw exception(ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS); + } + return account; + } + + @VisibleForTesting + String validateMail(String mail) { + if (StrUtil.isEmpty(mail)) { + throw exception(ErrorCodeConstants.MAIL_SEND_MAIL_NOT_EXISTS); + } + return mail; + } + + /** + * 校验邮件参数是否确实 + * + * @param template 邮箱模板 + * @param templateParams 参数列表 + */ + @VisibleForTesting + void validateTemplateParams(MailTemplateDO template, Map templateParams) { + template.getParams().forEach(key -> { + Object value = templateParams.get(key); + if (value == null) { + throw exception(ErrorCodeConstants.MAIL_SEND_TEMPLATE_PARAM_MISS, key); + } + }); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailTemplateService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailTemplateService.java new file mode 100644 index 0000000..33afcf3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailTemplateService.java @@ -0,0 +1,92 @@ +package com.tashow.cloud.system.service.mail; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailTemplateDO; + +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO; +import jakarta.validation.Valid; +import java.util.List; +import java.util.Map; + +/** + * 邮件模版 Service 接口 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailTemplateService { + + /** + * 邮件模版创建 + * + * @param createReqVO 邮件信息 + * @return 编号 + */ + Long createMailTemplate(@Valid MailTemplateSaveReqVO createReqVO); + + /** + * 邮件模版修改 + * + * @param updateReqVO 邮件信息 + */ + void updateMailTemplate(@Valid MailTemplateSaveReqVO updateReqVO); + + /** + * 邮件模版删除 + * + * @param id 编号 + */ + void deleteMailTemplate(Long id); + + /** + * 获取邮件模版 + * + * @param id 编号 + * @return 邮件模版 + */ + MailTemplateDO getMailTemplate(Long id); + + /** + * 获取邮件模版分页 + * + * @param pageReqVO 模版信息 + * @return 邮件模版分页信息 + */ + PageResult getMailTemplatePage(MailTemplatePageReqVO pageReqVO); + + /** + * 获取邮件模板数组 + * + * @return 模版数组 + */ + List getMailTemplateList(); + + /** + * 从缓存中获取邮件模版 + * + * @param code 模板编码 + * @return 邮件模板 + */ + MailTemplateDO getMailTemplateByCodeFromCache(String code); + + /** + * 邮件模版内容合成 + * + * @param content 邮件模版 + * @param params 合成参数 + * @return 格式化后的内容 + */ + String formatMailTemplateContent(String content, Map params); + + /** + * 获得指定邮件账号下的邮件模板数量 + * + * @param accountId 账号编号 + * @return 数量 + */ + long getMailTemplateCountByAccountId(Long accountId); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailTemplateServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailTemplateServiceImpl.java new file mode 100644 index 0000000..b636662 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/mail/MailTemplateServiceImpl.java @@ -0,0 +1,141 @@ +package com.tashow.cloud.system.service.mail; + +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.mail.MailTemplateDO; +import com.tashow.cloud.system.dal.mysql.mail.MailTemplateMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.MAIL_TEMPLATE_CODE_EXISTS; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; + +/** + * 邮箱模版 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailTemplateServiceImpl implements MailTemplateService { + + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + + @Resource + private MailTemplateMapper mailTemplateMapper; + + @Override + public Long createMailTemplate(MailTemplateSaveReqVO createReqVO) { + // 校验 code 是否唯一 + validateCodeUnique(null, createReqVO.getCode()); + + // 插入 + MailTemplateDO template = BeanUtils.toBean(createReqVO, MailTemplateDO.class) + .setParams(parseTemplateContentParams(createReqVO.getContent())); + mailTemplateMapper.insert(template); + return template.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.MAIL_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 + public void updateMailTemplate(@Valid MailTemplateSaveReqVO updateReqVO) { + // 校验是否存在 + validateMailTemplateExists(updateReqVO.getId()); + // 校验 code 是否唯一 + validateCodeUnique(updateReqVO.getId(),updateReqVO.getCode()); + + // 更新 + MailTemplateDO updateObj = BeanUtils.toBean(updateReqVO, MailTemplateDO.class) + .setParams(parseTemplateContentParams(updateReqVO.getContent())); + mailTemplateMapper.updateById(updateObj); + } + + @VisibleForTesting + void validateCodeUnique(Long id, String code) { + MailTemplateDO template = mailTemplateMapper.selectByCode(code); + if (template == null) { + return; + } + // 存在 template 记录的情况下 + if (id == null // 新增时,说明重复 + || ObjUtil.notEqual(id, template.getId())) { // 更新时,如果 id 不一致,说明重复 + throw exception(ErrorCodeConstants.MAIL_TEMPLATE_CODE_EXISTS); + } + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.MAIL_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 + public void deleteMailTemplate(Long id) { + // 校验是否存在 + validateMailTemplateExists(id); + + // 删除 + mailTemplateMapper.deleteById(id); + } + + private void validateMailTemplateExists(Long id) { + if (mailTemplateMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public MailTemplateDO getMailTemplate(Long id) {return mailTemplateMapper.selectById(id);} + + @Override + @Cacheable(value = RedisKeyConstants.MAIL_TEMPLATE, key = "#code", unless = "#result == null") + public MailTemplateDO getMailTemplateByCodeFromCache(String code) { + return mailTemplateMapper.selectByCode(code); + } + + @Override + public PageResult getMailTemplatePage(MailTemplatePageReqVO pageReqVO) { + return mailTemplateMapper.selectPage(pageReqVO); + } + + @Override + public List getMailTemplateList() {return mailTemplateMapper.selectList();} + + @Override + public String formatMailTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + + @VisibleForTesting + public List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); + } + + @Override + public long getMailTemplateCountByAccountId(Long accountId) { + return mailTemplateMapper.selectCountByAccountId(accountId); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/MemberService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/MemberService.java new file mode 100644 index 0000000..884a2dc --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/MemberService.java @@ -0,0 +1,26 @@ +package com.tashow.cloud.system.service.member; + +/** + * Member Service 接口 + * + * @author 芋道源码 + */ +public interface MemberService { + + /** + * 获得会员用户的手机号码 + * + * @param id 会员用户编号 + * @return 手机号码 + */ + String getMemberUserMobile(Long id); + + /** + * 获得会员用户的邮箱 + * + * @param id 会员用户编号 + * @return 邮箱 + */ + String getMemberUserEmail(Long id); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/MemberServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/MemberServiceImpl.java new file mode 100644 index 0000000..f961a24 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/MemberServiceImpl.java @@ -0,0 +1,54 @@ +package com.tashow.cloud.system.service.member; + +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * Member Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class MemberServiceImpl implements MemberService { + + @Value("${yudao.info.base-package}") + private String basePackage; + + private volatile Object memberUserApi; + + @Override + public String getMemberUserMobile(Long id) { + Object user = getMemberUser(id); + if (user == null) { + return null; + } + return ReflectUtil.invoke(user, "getMobile"); + } + + @Override + public String getMemberUserEmail(Long id) { + Object user = getMemberUser(id); + if (user == null) { + return null; + } + return ReflectUtil.invoke(user, "getEmail"); + } + + private Object getMemberUser(Long id) { + if (id == null) { + return null; + } + return ReflectUtil.invoke(getMemberUserApi(), "getUser", id); + } + + private Object getMemberUserApi() { + if (memberUserApi == null) { + memberUserApi = SpringUtil.getBean(ClassUtil.loadClass(String.format("%s.module.member.api.user.MemberUserApi", basePackage))); + } + return memberUserApi; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/package-info.java new file mode 100644 index 0000000..73f74fe --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/member/package-info.java @@ -0,0 +1,4 @@ +/** + * yudao-module-member 模块的适配,解除 yudao-module-system 对它们的依赖 + */ +package com.tashow.cloud.system.service.member; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notice/NoticeService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notice/NoticeService.java new file mode 100644 index 0000000..cafbef6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notice/NoticeService.java @@ -0,0 +1,53 @@ +package com.tashow.cloud.system.service.notice; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticePageReqVO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticeSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.notice.NoticeDO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticePageReqVO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticeSaveReqVO; + +/** + * 通知公告 Service 接口 + */ +public interface NoticeService { + + /** + * 创建通知公告 + * + * @param createReqVO 通知公告 + * @return 编号 + */ + Long createNotice(NoticeSaveReqVO createReqVO); + + /** + * 更新通知公告 + * + * @param reqVO 通知公告 + */ + void updateNotice(NoticeSaveReqVO reqVO); + + /** + * 删除通知公告 + * + * @param id 编号 + */ + void deleteNotice(Long id); + + /** + * 获得通知公告分页列表 + * + * @param reqVO 分页条件 + * @return 部门分页列表 + */ + PageResult getNoticePage(NoticePageReqVO reqVO); + + /** + * 获得通知公告 + * + * @param id 编号 + * @return 通知公告 + */ + NoticeDO getNotice(Long id); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notice/NoticeServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notice/NoticeServiceImpl.java new file mode 100644 index 0000000..43445ef --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notice/NoticeServiceImpl.java @@ -0,0 +1,76 @@ +package com.tashow.cloud.system.service.notice; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticePageReqVO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticeSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.notice.NoticeDO; +import com.tashow.cloud.system.dal.mysql.notice.NoticeMapper; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticePageReqVO; +import com.tashow.cloud.system.controller.admin.notice.vo.NoticeSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.NOTICE_NOT_FOUND; + +/** + * 通知公告 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class NoticeServiceImpl implements NoticeService { + + @Resource + private NoticeMapper noticeMapper; + + @Override + public Long createNotice(NoticeSaveReqVO createReqVO) { + NoticeDO notice = BeanUtils.toBean(createReqVO, NoticeDO.class); + noticeMapper.insert(notice); + return notice.getId(); + } + + @Override + public void updateNotice(NoticeSaveReqVO updateReqVO) { + // 校验是否存在 + validateNoticeExists(updateReqVO.getId()); + // 更新通知公告 + NoticeDO updateObj = BeanUtils.toBean(updateReqVO, NoticeDO.class); + noticeMapper.updateById(updateObj); + } + + @Override + public void deleteNotice(Long id) { + // 校验是否存在 + validateNoticeExists(id); + // 删除通知公告 + noticeMapper.deleteById(id); + } + + @Override + public PageResult getNoticePage(NoticePageReqVO reqVO) { + return noticeMapper.selectPage(reqVO); + } + + @Override + public NoticeDO getNotice(Long id) { + return noticeMapper.selectById(id); + } + + @VisibleForTesting + public void validateNoticeExists(Long id) { + if (id == null) { + return; + } + NoticeDO notice = noticeMapper.selectById(id); + if (notice == null) { + throw exception(ErrorCodeConstants.NOTICE_NOT_FOUND); + } + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyMessageService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyMessageService.java new file mode 100644 index 0000000..d983c3a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyMessageService.java @@ -0,0 +1,99 @@ +package com.tashow.cloud.system.service.notify; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyMessageDO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyTemplateDO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 站内信 Service 接口 + * + * @author xrcoder + */ +public interface NotifyMessageService { + + /** + * 创建站内信 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param template 模版信息 + * @param templateContent 模版内容 + * @param templateParams 模版参数 + * @return 站内信编号 + */ + Long createNotifyMessage(Long userId, Integer userType, + NotifyTemplateDO template, String templateContent, Map templateParams); + + /** + * 获得站内信分页 + * + * @param pageReqVO 分页查询 + * @return 站内信分页 + */ + PageResult getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO); + + /** + * 获得【我的】站内信分页 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @param userType 用户类型 + * @return 站内信分页 + */ + PageResult getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType); + + /** + * 获得站内信 + * + * @param id 编号 + * @return 站内信 + */ + NotifyMessageDO getNotifyMessage(Long id); + + /** + * 获得【我的】未读站内信列表 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param size 数量 + * @return 站内信列表 + */ + List getUnreadNotifyMessageList(Long userId, Integer userType, Integer size); + + /** + * 统计用户未读站内信条数 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 返回未读站内信条数 + */ + Long getUnreadNotifyMessageCount(Long userId, Integer userType); + + /** + * 标记站内信为已读 + * + * @param ids 站内信编号集合 + * @param userId 用户编号 + * @param userType 用户类型 + * @return 更新到的条数 + */ + int updateNotifyMessageRead(Collection ids, Long userId, Integer userType); + + /** + * 标记所有站内信为已读 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 更新到的条数 + */ + int updateAllNotifyMessageRead(Long userId, Integer userType); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyMessageServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyMessageServiceImpl.java new file mode 100644 index 0000000..0f41285 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyMessageServiceImpl.java @@ -0,0 +1,77 @@ +package com.tashow.cloud.system.service.notify; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyMessageDO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyTemplateDO; +import com.tashow.cloud.system.dal.mysql.notify.NotifyMessageMapper; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 站内信 Service 实现类 + * + * @author xrcoder + */ +@Service +@Validated +public class NotifyMessageServiceImpl implements NotifyMessageService { + + @Resource + private NotifyMessageMapper notifyMessageMapper; + + @Override + public Long createNotifyMessage(Long userId, Integer userType, + NotifyTemplateDO template, String templateContent, Map templateParams) { + NotifyMessageDO message = new NotifyMessageDO().setUserId(userId).setUserType(userType) + .setTemplateId(template.getId()).setTemplateCode(template.getCode()) + .setTemplateType(template.getType()).setTemplateNickname(template.getNickname()) + .setTemplateContent(templateContent).setTemplateParams(templateParams).setReadStatus(false); + notifyMessageMapper.insert(message); + return message.getId(); + } + + @Override + public PageResult getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO) { + return notifyMessageMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType) { + return notifyMessageMapper.selectPage(pageReqVO, userId, userType); + } + + @Override + public NotifyMessageDO getNotifyMessage(Long id) { + return notifyMessageMapper.selectById(id); + } + + @Override + public List getUnreadNotifyMessageList(Long userId, Integer userType, Integer size) { + return notifyMessageMapper.selectUnreadListByUserIdAndUserType(userId, userType, size); + } + + @Override + public Long getUnreadNotifyMessageCount(Long userId, Integer userType) { + return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType); + } + + @Override + public int updateNotifyMessageRead(Collection ids, Long userId, Integer userType) { + return notifyMessageMapper.updateListRead(ids, userId, userType); + } + + @Override + public int updateAllNotifyMessageRead(Long userId, Integer userType) { + return notifyMessageMapper.updateListRead(userId, userType); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifySendService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifySendService.java new file mode 100644 index 0000000..0017aad --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifySendService.java @@ -0,0 +1,55 @@ +package com.tashow.cloud.system.service.notify; + +import java.util.List; +import java.util.Map; + +/** + * 站内信发送 Service 接口 + * + * @author xrcoder + */ +public interface NotifySendService { + + /** + * 发送单条站内信给管理后台的用户 + * + * 在 mobile 为空时,使用 userId 加载对应管理员的手机号 + * + * @param userId 用户编号 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @return 发送日志编号 + */ + Long sendSingleNotifyToAdmin(Long userId, + String templateCode, Map templateParams); + /** + * 发送单条站内信给用户 APP 的用户 + * + * 在 mobile 为空时,使用 userId 加载对应会员的手机号 + * + * @param userId 用户编号 + * @param templateCode 站内信模板编号 + * @param templateParams 站内信模板参数 + * @return 发送日志编号 + */ + Long sendSingleNotifyToMember(Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条站内信给用户 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param templateCode 站内信模板编号 + * @param templateParams 站内信模板参数 + * @return 发送日志编号 + */ + Long sendSingleNotify( Long userId, Integer userType, + String templateCode, Map templateParams); + + default void sendBatchNotify(List mobiles, List userIds, Integer userType, + String templateCode, Map templateParams) { + throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!"); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifySendServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifySendServiceImpl.java new file mode 100644 index 0000000..0a53bc3 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifySendServiceImpl.java @@ -0,0 +1,88 @@ +package com.tashow.cloud.system.service.notify; + +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyTemplateDO; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.Map; +import java.util.Objects; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.NOTICE_NOT_FOUND; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.NOTIFY_SEND_TEMPLATE_PARAM_MISS; + +/** + * 站内信发送 Service 实现类 + * + * @author xrcoder + */ +@Service +@Validated +@Slf4j +public class NotifySendServiceImpl implements NotifySendService { + + @Resource + private NotifyTemplateService notifyTemplateService; + + @Resource + private NotifyMessageService notifyMessageService; + + @Override + public Long sendSingleNotifyToAdmin(Long userId, String templateCode, Map templateParams) { + return sendSingleNotify(userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleNotifyToMember(Long userId, String templateCode, Map templateParams) { + return sendSingleNotify(userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleNotify(Long userId, Integer userType, String templateCode, Map templateParams) { + // 校验模版 + NotifyTemplateDO template = validateNotifyTemplate(templateCode); + if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + log.info("[sendSingleNotify][模版({})已经关闭,无法给用户({}/{})发送]", templateCode, userId, userType); + return null; + } + // 校验参数 + validateTemplateParams(template, templateParams); + + // 发送站内信 + String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams); + return notifyMessageService.createNotifyMessage(userId, userType, template, content, templateParams); + } + + @VisibleForTesting + public NotifyTemplateDO validateNotifyTemplate(String templateCode) { + // 获得站内信模板。考虑到效率,从缓存中获取 + NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode); + // 站内信模板不存在 + if (template == null) { + throw exception(ErrorCodeConstants.NOTICE_NOT_FOUND); + } + return template; + } + + /** + * 校验站内信模版参数是否确实 + * + * @param template 邮箱模板 + * @param templateParams 参数列表 + */ + @VisibleForTesting + public void validateTemplateParams(NotifyTemplateDO template, Map templateParams) { + template.getParams().forEach(key -> { + Object value = templateParams.get(key); + if (value == null) { + throw exception(ErrorCodeConstants.NOTIFY_SEND_TEMPLATE_PARAM_MISS, key); + } + }); + } +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyTemplateService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyTemplateService.java new file mode 100644 index 0000000..2a66575 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyTemplateService.java @@ -0,0 +1,75 @@ +package com.tashow.cloud.system.service.notify; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyTemplateDO; + +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO; +import jakarta.validation.Valid; +import java.util.Map; + +/** + * 站内信模版 Service 接口 + * + * @author xrcoder + */ +public interface NotifyTemplateService { + + /** + * 创建站内信模版 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createNotifyTemplate(@Valid NotifyTemplateSaveReqVO createReqVO); + + /** + * 更新站内信模版 + * + * @param updateReqVO 更新信息 + */ + void updateNotifyTemplate(@Valid NotifyTemplateSaveReqVO updateReqVO); + + /** + * 删除站内信模版 + * + * @param id 编号 + */ + void deleteNotifyTemplate(Long id); + + /** + * 获得站内信模版 + * + * @param id 编号 + * @return 站内信模版 + */ + NotifyTemplateDO getNotifyTemplate(Long id); + + /** + * 获得站内信模板,从缓存中 + * + * @param code 模板编码 + * @return 站内信模板 + */ + NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code); + + /** + * 获得站内信模版分页 + * + * @param pageReqVO 分页查询 + * @return 站内信模版分页 + */ + PageResult getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO); + + /** + * 格式化站内信内容 + * + * @param content 站内信模板的内容 + * @param params 站内信内容的参数 + * @return 格式化后的内容 + */ + String formatNotifyTemplateContent(String content, Map params); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyTemplateServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyTemplateServiceImpl.java new file mode 100644 index 0000000..7bebe78 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/notify/NotifyTemplateServiceImpl.java @@ -0,0 +1,141 @@ +package com.tashow.cloud.system.service.notify; + +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.notify.NotifyTemplateDO; +import com.tashow.cloud.system.dal.mysql.notify.NotifyTemplateMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS; + +/** + * 站内信模版 Service 实现类 + * + * @author xrcoder + */ +@Service +@Validated +@Slf4j +public class NotifyTemplateServiceImpl implements NotifyTemplateService { + + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + + @Resource + private NotifyTemplateMapper notifyTemplateMapper; + + @Override + public Long createNotifyTemplate(NotifyTemplateSaveReqVO createReqVO) { + // 校验站内信编码是否重复 + validateNotifyTemplateCodeDuplicate(null, createReqVO.getCode()); + + // 插入 + NotifyTemplateDO notifyTemplate = BeanUtils.toBean(createReqVO, NotifyTemplateDO.class); + notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent())); + notifyTemplateMapper.insert(notifyTemplate); + return notifyTemplate.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 + public void updateNotifyTemplate(NotifyTemplateSaveReqVO updateReqVO) { + // 校验存在 + validateNotifyTemplateExists(updateReqVO.getId()); + // 校验站内信编码是否重复 + validateNotifyTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode()); + + // 更新 + NotifyTemplateDO updateObj = BeanUtils.toBean(updateReqVO, NotifyTemplateDO.class); + updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); + notifyTemplateMapper.updateById(updateObj); + } + + @VisibleForTesting + public List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 + public void deleteNotifyTemplate(Long id) { + // 校验存在 + validateNotifyTemplateExists(id); + // 删除 + notifyTemplateMapper.deleteById(id); + } + + private void validateNotifyTemplateExists(Long id) { + if (notifyTemplateMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public NotifyTemplateDO getNotifyTemplate(Long id) { + return notifyTemplateMapper.selectById(id); + } + + @Override + @Cacheable(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, key = "#code", + unless = "#result == null") + public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) { + return notifyTemplateMapper.selectByCode(code); + } + + @Override + public PageResult getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) { + return notifyTemplateMapper.selectPage(pageReqVO); + } + + @VisibleForTesting + void validateNotifyTemplateCodeDuplicate(Long id, String code) { + NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code); + if (template == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE, code); + } + if (!template.getId().equals(id)) { + throw exception(ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE, code); + } + } + + /** + * 格式化站内信内容 + * + * @param content 站内信模板的内容 + * @param params 站内信内容的参数 + * @return 格式化后的内容 + */ + @Override + public String formatNotifyTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ApproveService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ApproveService.java new file mode 100644 index 0000000..682e006 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ApproveService.java @@ -0,0 +1,52 @@ +package com.tashow.cloud.system.service.oauth2; + +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ApproveDO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * OAuth2 批准 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 ApprovalStoreUserApprovalHandler 的功能,记录用户针对指定客户端的授权,减少手动确定。 + * + * @author 芋道源码 + */ +public interface OAuth2ApproveService { + + /** + * 获得指定用户,针对指定客户端的指定授权,是否通过 + * + * 参考 ApprovalStoreUserApprovalHandler 的 checkForPreApproval 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param requestedScopes 授权范围 + * @return 是否授权通过 + */ + boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection requestedScopes); + + /** + * 在用户发起批准时,基于 scopes 的选项,计算最终是否通过 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param requestedScopes 授权范围 + * @return 是否授权通过 + */ + boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map requestedScopes); + + /** + * 获得用户的批准列表,排除已过期的 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @return 是否授权通过 + */ + List getApproveList(Long userId, Integer userType, String clientId); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ApproveServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ApproveServiceImpl.java new file mode 100644 index 0000000..e392851 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ApproveServiceImpl.java @@ -0,0 +1,104 @@ +package com.tashow.cloud.system.service.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import com.tashow.cloud.common.util.date.DateUtils; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; +import com.tashow.cloud.system.dal.mysql.oauth2.OAuth2ApproveMapper; +import com.google.common.annotations.VisibleForTesting; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; + +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; + + +/** + * OAuth2 批准 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class OAuth2ApproveServiceImpl implements OAuth2ApproveService { + + /** + * 批准的过期时间,默认 30 天 + */ + private static final Integer TIMEOUT = 30 * 24 * 60 * 60; // 单位:秒 + + @Resource + private OAuth2ClientService oauth2ClientService; + + @Resource + private OAuth2ApproveMapper oauth2ApproveMapper; + + @Override + @Transactional + public boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection requestedScopes) { + // 第一步,基于 Client 的自动授权计算,如果 scopes 都在自动授权中,则返回 true 通过 + OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); + Assert.notNull(clientDO, "客户端不能为空"); // 防御性编程 + if (CollUtil.containsAll(clientDO.getAutoApproveScopes(), requestedScopes)) { + // gh-877 - if all scopes are auto approved, approvals still need to be added to the approval store. + LocalDateTime expireTime = LocalDateTime.now().plusSeconds(TIMEOUT); + for (String scope : requestedScopes) { + saveApprove(userId, userType, clientId, scope, true, expireTime); + } + return true; + } + + // 第二步,算上用户已经批准的授权。如果 scopes 都包含,则返回 true + List approveDOs = getApproveList(userId, userType, clientId); + Set scopes = convertSet(approveDOs, OAuth2ApproveDO::getScope, + OAuth2ApproveDO::getApproved); // 只保留未过期的 + 同意的 + return CollUtil.containsAll(scopes, requestedScopes); + } + + @Override + @Transactional + public boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map requestedScopes) { + // 如果 requestedScopes 为空,说明没有要求,则返回 true 通过 + if (CollUtil.isEmpty(requestedScopes)) { + return true; + } + + // 更新批准的信息 + boolean success = false; // 需要至少有一个同意 + LocalDateTime expireTime = LocalDateTime.now().plusSeconds(TIMEOUT); + for (Map.Entry entry : requestedScopes.entrySet()) { + if (entry.getValue()) { + success = true; + } + saveApprove(userId, userType, clientId, entry.getKey(), entry.getValue(), expireTime); + } + return success; + } + + @Override + public List getApproveList(Long userId, Integer userType, String clientId) { + List approveDOs = oauth2ApproveMapper.selectListByUserIdAndUserTypeAndClientId( + userId, userType, clientId); + approveDOs.removeIf(o -> DateUtils.isExpired(o.getExpiresTime())); + return approveDOs; + } + + @VisibleForTesting + void saveApprove(Long userId, Integer userType, String clientId, + String scope, Boolean approved, LocalDateTime expireTime) { + // 先更新 + OAuth2ApproveDO approveDO = new OAuth2ApproveDO().setUserId(userId).setUserType(userType) + .setClientId(clientId).setScope(scope).setApproved(approved).setExpiresTime(expireTime); + if (oauth2ApproveMapper.update(approveDO) == 1) { + return; + } + // 失败,则说明不存在,进行更新 + oauth2ApproveMapper.insert(approveDO); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ClientService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ClientService.java new file mode 100644 index 0000000..7bd944f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ClientService.java @@ -0,0 +1,92 @@ +package com.tashow.cloud.system.service.oauth2; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; + +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import jakarta.validation.Valid; +import java.util.Collection; + +/** + * OAuth2.0 Client Service 接口 + * + * 从功能上,和 JdbcClientDetailsService 的功能,提供客户端的操作 + * + * @author 芋道源码 + */ +public interface OAuth2ClientService { + + /** + * 创建 OAuth2 客户端 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createOAuth2Client(@Valid OAuth2ClientSaveReqVO createReqVO); + + /** + * 更新 OAuth2 客户端 + * + * @param updateReqVO 更新信息 + */ + void updateOAuth2Client(@Valid OAuth2ClientSaveReqVO updateReqVO); + + /** + * 删除 OAuth2 客户端 + * + * @param id 编号 + */ + void deleteOAuth2Client(Long id); + + /** + * 获得 OAuth2 客户端 + * + * @param id 编号 + * @return OAuth2 客户端 + */ + OAuth2ClientDO getOAuth2Client(Long id); + + /** + * 获得 OAuth2 客户端,从缓存中 + * + * @param clientId 客户端编号 + * @return OAuth2 客户端 + */ + OAuth2ClientDO getOAuth2ClientFromCache(String clientId); + + /** + * 获得 OAuth2 客户端分页 + * + * @param pageReqVO 分页查询 + * @return OAuth2 客户端分页 + */ + PageResult getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO); + + /** + * 从缓存中,校验客户端是否合法 + * + * @return 客户端 + */ + default OAuth2ClientDO validOAuthClientFromCache(String clientId) { + return validOAuthClientFromCache(clientId, null, null, null, null); + } + + /** + * 从缓存中,校验客户端是否合法 + * + * 非空时,进行校验 + * + * @param clientId 客户端编号 + * @param clientSecret 客户端密钥 + * @param authorizedGrantType 授权方式 + * @param scopes 授权范围 + * @param redirectUri 重定向地址 + * @return 客户端 + */ + OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType, + Collection scopes, String redirectUri); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ClientServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ClientServiceImpl.java new file mode 100644 index 0000000..66e02d6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2ClientServiceImpl.java @@ -0,0 +1,153 @@ +package com.tashow.cloud.system.service.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.common.util.string.StrUtils; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; +import com.tashow.cloud.system.dal.mysql.oauth2.OAuth2ClientMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.Collection; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; + +/** + * OAuth2.0 Client Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class OAuth2ClientServiceImpl implements OAuth2ClientService { + + @Resource + private OAuth2ClientMapper oauth2ClientMapper; + + @Override + public Long createOAuth2Client(OAuth2ClientSaveReqVO createReqVO) { + validateClientIdExists(null, createReqVO.getClientId()); + // 插入 + OAuth2ClientDO client = BeanUtils.toBean(createReqVO, OAuth2ClientDO.class); + oauth2ClientMapper.insert(client); + return client.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.OAUTH_CLIENT, + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 clientId 字段,不好清理 + public void updateOAuth2Client(OAuth2ClientSaveReqVO updateReqVO) { + // 校验存在 + validateOAuth2ClientExists(updateReqVO.getId()); + // 校验 Client 未被占用 + validateClientIdExists(updateReqVO.getId(), updateReqVO.getClientId()); + + // 更新 + OAuth2ClientDO updateObj = BeanUtils.toBean(updateReqVO, OAuth2ClientDO.class); + oauth2ClientMapper.updateById(updateObj); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.OAUTH_CLIENT, + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 key,不好清理 + public void deleteOAuth2Client(Long id) { + // 校验存在 + validateOAuth2ClientExists(id); + // 删除 + oauth2ClientMapper.deleteById(id); + } + + private void validateOAuth2ClientExists(Long id) { + if (oauth2ClientMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_NOT_EXISTS); + } + } + + @VisibleForTesting + void validateClientIdExists(Long id, String clientId) { + OAuth2ClientDO client = oauth2ClientMapper.selectByClientId(clientId); + if (client == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的客户端 + if (id == null) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_EXISTS); + } + if (!client.getId().equals(id)) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_EXISTS); + } + } + + @Override + public OAuth2ClientDO getOAuth2Client(Long id) { + return oauth2ClientMapper.selectById(id); + } + + @Override + @Cacheable(cacheNames = RedisKeyConstants.OAUTH_CLIENT, key = "#clientId", + unless = "#result == null") + public OAuth2ClientDO getOAuth2ClientFromCache(String clientId) { + return oauth2ClientMapper.selectByClientId(clientId); + } + + @Override + public PageResult getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO) { + return oauth2ClientMapper.selectPage(pageReqVO); + } + + @Override + public OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType, + Collection scopes, String redirectUri) { + // 校验客户端存在、且开启 + OAuth2ClientDO client = getSelf().getOAuth2ClientFromCache(clientId); + if (client == null) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(client.getStatus())) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_DISABLE); + } + + // 校验客户端密钥 + if (StrUtil.isNotEmpty(clientSecret) && ObjectUtil.notEqual(client.getSecret(), clientSecret)) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_CLIENT_SECRET_ERROR); + } + // 校验授权方式 + if (StrUtil.isNotEmpty(authorizedGrantType) && !CollUtil.contains(client.getAuthorizedGrantTypes(), authorizedGrantType)) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS); + } + // 校验授权范围 + if (CollUtil.isNotEmpty(scopes) && !CollUtil.containsAll(client.getScopes(), scopes)) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_SCOPE_OVER); + } + // 校验回调地址 + if (StrUtil.isNotEmpty(redirectUri) && !StrUtils.startWithAny(redirectUri, client.getRedirectUris())) { + throw exception(ErrorCodeConstants.OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, redirectUri); + } + return client; + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private OAuth2ClientServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2CodeService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2CodeService.java new file mode 100644 index 0000000..694f2c9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2CodeService.java @@ -0,0 +1,39 @@ +package com.tashow.cloud.system.service.oauth2; + +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2CodeDO; + +import java.util.List; + +/** + * OAuth2.0 授权码 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 JdbcAuthorizationCodeServices 的功能,提供授权码的操作 + * + * @author 芋道源码 + */ +public interface OAuth2CodeService { + + /** + * 创建授权码 + * + * 参考 JdbcAuthorizationCodeServices 的 createAuthorizationCode 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @param redirectUri 重定向 URI + * @param state 状态 + * @return 授权码的信息 + */ + OAuth2CodeDO createAuthorizationCode(Long userId, Integer userType, String clientId, + List scopes, String redirectUri, String state); + + /** + * 使用授权码 + * + * @param code 授权码 + */ + OAuth2CodeDO consumeAuthorizationCode(String code); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2CodeServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2CodeServiceImpl.java new file mode 100644 index 0000000..dc57fbc --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2CodeServiceImpl.java @@ -0,0 +1,65 @@ +package com.tashow.cloud.system.service.oauth2; + +import cn.hutool.core.util.IdUtil; +import com.tashow.cloud.common.util.date.DateUtils; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2CodeDO; +import com.tashow.cloud.system.dal.mysql.oauth2.OAuth2CodeMapper; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.OAUTH2_CODE_EXPIRE; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.OAUTH2_CODE_NOT_EXISTS; + +/** + * OAuth2.0 授权码 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class OAuth2CodeServiceImpl implements OAuth2CodeService { + + /** + * 授权码的过期时间,默认 5 分钟 + */ + private static final Integer TIMEOUT = 5 * 60; + + @Resource + private OAuth2CodeMapper oauth2CodeMapper; + + @Override + public OAuth2CodeDO createAuthorizationCode(Long userId, Integer userType, String clientId, + List scopes, String redirectUri, String state) { + OAuth2CodeDO codeDO = new OAuth2CodeDO().setCode(generateCode()) + .setUserId(userId).setUserType(userType) + .setClientId(clientId).setScopes(scopes) + .setExpiresTime(LocalDateTime.now().plusSeconds(TIMEOUT)) + .setRedirectUri(redirectUri).setState(state); + oauth2CodeMapper.insert(codeDO); + return codeDO; + } + + @Override + public OAuth2CodeDO consumeAuthorizationCode(String code) { + OAuth2CodeDO codeDO = oauth2CodeMapper.selectByCode(code); + if (codeDO == null) { + throw exception(ErrorCodeConstants.OAUTH2_CODE_NOT_EXISTS); + } + if (DateUtils.isExpired(codeDO.getExpiresTime())) { + throw exception(ErrorCodeConstants.OAUTH2_CODE_EXPIRE); + } + oauth2CodeMapper.deleteById(codeDO.getId()); + return codeDO; + } + + private static String generateCode() { + return IdUtil.fastSimpleUUID(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2GrantService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2GrantService.java new file mode 100644 index 0000000..38a6d5b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2GrantService.java @@ -0,0 +1,113 @@ +package com.tashow.cloud.system.service.oauth2; + +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; + +import java.util.List; + +/** + * OAuth2 授予 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 TokenGranter 的功能,提供访问令牌、刷新令牌的操作 + * + * 将自身的 AdminUser 用户,授权给第三方应用,采用 OAuth2.0 的协议。 + * + * 问题:为什么自身也作为一个第三方应用,也走这套流程呢? + * 回复:当然可以这么做,采用 password 模式。考虑到大多数开发者使用不到这个特性,OAuth2.0 毕竟有一定学习成本,所以暂时没有采取这种方式。 + * + * @author 芋道源码 + */ +public interface OAuth2GrantService { + + /** + * 简化模式 + * + * 对应 Spring Security OAuth2 的 ImplicitTokenGranter 功能 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType, + String clientId, List scopes); + + /** + * 授权码模式,第一阶段,获得 code 授权码 + * + * 对应 Spring Security OAuth2 的 AuthorizationEndpoint 的 generateCode 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @param redirectUri 重定向 URI + * @param state 状态 + * @return 授权码 + */ + String grantAuthorizationCodeForCode(Long userId, Integer userType, + String clientId, List scopes, + String redirectUri, String state); + + /** + * 授权码模式,第二阶段,获得 accessToken 访问令牌 + * + * 对应 Spring Security OAuth2 的 AuthorizationCodeTokenGranter 功能 + * + * @param clientId 客户端编号 + * @param code 授权码 + * @param redirectUri 重定向 URI + * @param state 状态 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantAuthorizationCodeForAccessToken(String clientId, String code, + String redirectUri, String state); + + /** + * 密码模式 + * + * 对应 Spring Security OAuth2 的 ResourceOwnerPasswordTokenGranter 功能 + * + * @param username 账号 + * @param password 密码 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantPassword(String username, String password, + String clientId, List scopes); + + /** + * 刷新模式 + * + * 对应 Spring Security OAuth2 的 ResourceOwnerPasswordTokenGranter 功能 + * + * @param refreshToken 刷新令牌 + * @param clientId 客户端编号 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantRefreshToken(String refreshToken, String clientId); + + /** + * 客户端模式 + * + * 对应 Spring Security OAuth2 的 ClientCredentialsTokenGranter 功能 + * + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantClientCredentials(String clientId, List scopes); + + /** + * 移除访问令牌 + * + * 对应 Spring Security OAuth2 的 ConsumerTokenServices 的 revokeToken 方法 + * + * @param accessToken 访问令牌 + * @param clientId 客户端编号 + * @return 是否移除到 + */ + boolean revokeToken(String clientId, String accessToken); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2GrantServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2GrantServiceImpl.java new file mode 100644 index 0000000..aa0f2be --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2GrantServiceImpl.java @@ -0,0 +1,105 @@ +package com.tashow.cloud.system.service.oauth2; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2CodeDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.system.service.auth.AdminAuthService; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; + +/** + * OAuth2 授予 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class OAuth2GrantServiceImpl implements OAuth2GrantService { + + @Resource + private OAuth2TokenService oauth2TokenService; + @Resource + private OAuth2CodeService oauth2CodeService; + @Resource + private AdminAuthService adminAuthService; + + @Override + public OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType, + String clientId, List scopes) { + return oauth2TokenService.createAccessToken(userId, userType, clientId, scopes); + } + + @Override + public String grantAuthorizationCodeForCode(Long userId, Integer userType, + String clientId, List scopes, + String redirectUri, String state) { + return oauth2CodeService.createAuthorizationCode(userId, userType, clientId, scopes, + redirectUri, state).getCode(); + } + + @Override + public OAuth2AccessTokenDO grantAuthorizationCodeForAccessToken(String clientId, String code, + String redirectUri, String state) { + OAuth2CodeDO codeDO = oauth2CodeService.consumeAuthorizationCode(code); + Assert.notNull(codeDO, "授权码不能为空"); // 防御性编程 + // 校验 clientId 是否匹配 + if (!StrUtil.equals(clientId, codeDO.getClientId())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_CLIENT_ID_MISMATCH); + } + // 校验 redirectUri 是否匹配 + if (!StrUtil.equals(redirectUri, codeDO.getRedirectUri())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_REDIRECT_URI_MISMATCH); + } + // 校验 state 是否匹配 + state = StrUtil.nullToDefault(state, ""); // 数据库 state 为 null 时,会设置为 "" 空串 + if (!StrUtil.equals(state, codeDO.getState())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_STATE_MISMATCH); + } + + // 创建访问令牌 + return oauth2TokenService.createAccessToken(codeDO.getUserId(), codeDO.getUserType(), + codeDO.getClientId(), codeDO.getScopes()); + } + + @Override + public OAuth2AccessTokenDO grantPassword(String username, String password, String clientId, List scopes) { + // 使用账号 + 密码进行登录 + AdminUserDO user = adminAuthService.authenticate(username, password); + Assert.notNull(user, "用户不能为空!"); // 防御性编程 + + // 创建访问令牌 + return oauth2TokenService.createAccessToken(user.getId(), UserTypeEnum.ADMIN.getValue(), clientId, scopes); + } + + @Override + public OAuth2AccessTokenDO grantRefreshToken(String refreshToken, String clientId) { + return oauth2TokenService.refreshAccessToken(refreshToken, clientId); + } + + @Override + public OAuth2AccessTokenDO grantClientCredentials(String clientId, List scopes) { + // TODO 芋艿:项目中使用 OAuth2 解决的是三方应用的授权,内部的 SSO 等问题,所以暂时不考虑 client_credentials 这个场景 + throw new UnsupportedOperationException("暂时不支持 client_credentials 授权模式"); + } + + @Override + public boolean revokeToken(String clientId, String accessToken) { + // 先查询,保证 clientId 时匹配的 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.getAccessToken(accessToken); + if (accessTokenDO == null || ObjectUtil.notEqual(clientId, accessTokenDO.getClientId())) { + return false; + } + // 再删除 + return oauth2TokenService.removeAccessToken(accessToken) != null; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2TokenService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2TokenService.java new file mode 100644 index 0000000..e141690 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2TokenService.java @@ -0,0 +1,81 @@ +package com.tashow.cloud.system.service.oauth2; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; + +import java.util.List; + +/** + * OAuth2.0 Token Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 DefaultTokenServices + JdbcTokenStore 的功能,提供访问令牌、刷新令牌的操作 + * + * @author 芋道源码 + */ +public interface OAuth2TokenService { + + /** + * 创建访问令牌 + * 注意:该流程中,会包含创建刷新令牌的创建 + * + * 参考 DefaultTokenServices 的 createAccessToken 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List scopes); + + /** + * 刷新访问令牌 + * + * 参考 DefaultTokenServices 的 refreshAccessToken 方法 + * + * @param refreshToken 刷新令牌 + * @param clientId 客户端编号 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId); + + /** + * 获得访问令牌 + * + * 参考 DefaultTokenServices 的 getAccessToken 方法 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO getAccessToken(String accessToken); + + /** + * 校验访问令牌 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO checkAccessToken(String accessToken); + + /** + * 移除访问令牌 + * 注意:该流程中,会移除相关的刷新令牌 + * + * 参考 DefaultTokenServices 的 revokeToken 方法 + * + * @param accessToken 刷新令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO removeAccessToken(String accessToken); + + /** + * 获得访问令牌分页 + * + * @param reqVO 请求 + * @return 访问令牌分页 + */ + PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2TokenServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2TokenServiceImpl.java new file mode 100644 index 0000000..2d6bdbe --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/oauth2/OAuth2TokenServiceImpl.java @@ -0,0 +1,220 @@ +package com.tashow.cloud.system.service.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.date.DateUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2ClientDO; +import com.tashow.cloud.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.dal.mysql.oauth2.OAuth2AccessTokenMapper; +import com.tashow.cloud.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper; +import com.tashow.cloud.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO; +import com.tashow.cloud.system.service.user.AdminUserService; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.util.TenantUtils; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception0; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; + + +/** + * OAuth2.0 Token Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class OAuth2TokenServiceImpl implements OAuth2TokenService { + + @Resource + private OAuth2AccessTokenMapper oauth2AccessTokenMapper; + @Resource + private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper; + + @Resource + private OAuth2AccessTokenRedisDAO oauth2AccessTokenRedisDAO; + + @Resource + private OAuth2ClientService oauth2ClientService; + @Resource + @Lazy // 懒加载,避免循环依赖 + private AdminUserService adminUserService; + + @Override + @Transactional(rollbackFor = Exception.class) + public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List scopes) { + OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); + // 创建刷新令牌 + OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, userType, clientDO, scopes); + // 创建访问令牌 + return createOAuth2AccessToken(refreshTokenDO, clientDO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId) { + // 查询访问令牌 + OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectByRefreshToken(refreshToken); + if (refreshTokenDO == null) { + throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "无效的刷新令牌"); + } + + // 校验 Client 匹配 + OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); + if (ObjectUtil.notEqual(clientId, refreshTokenDO.getClientId())) { + throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "刷新令牌的客户端编号不正确"); + } + + // 移除相关的访问令牌 + List accessTokenDOs = oauth2AccessTokenMapper.selectListByRefreshToken(refreshToken); + if (CollUtil.isNotEmpty(accessTokenDOs)) { + oauth2AccessTokenMapper.deleteByIds(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getId)); + oauth2AccessTokenRedisDAO.deleteList(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getAccessToken)); + } + + // 已过期的情况下,删除刷新令牌 + if (DateUtils.isExpired(refreshTokenDO.getExpiresTime())) { + oauth2RefreshTokenMapper.deleteById(refreshTokenDO.getId()); + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "刷新令牌已过期"); + } + + // 创建访问令牌 + return createOAuth2AccessToken(refreshTokenDO, clientDO); + } + + @Override + public OAuth2AccessTokenDO getAccessToken(String accessToken) { + // 优先从 Redis 中获取 + OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken); + if (accessTokenDO != null) { + return accessTokenDO; + } + + // 获取不到,从 MySQL 中获取访问令牌 + accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken); + if (accessTokenDO == null) { + // 特殊:从 MySQL 中获取刷新令牌。原因:解决部分场景不方便刷新访问令牌场景 + // 例如说,积木报表只允许传递 token,不允许传递 refresh_token,导致无法刷新访问令牌 + // 再例如说,前端 WebSocket 的 token 直接跟在 url 上,无法传递 refresh_token + OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectByRefreshToken(accessToken); + if (refreshTokenDO != null && !DateUtils.isExpired(refreshTokenDO.getExpiresTime())) { + accessTokenDO = convertToAccessToken(refreshTokenDO); + } + } + + // 如果在 MySQL 存在,则往 Redis 中写入 + if (accessTokenDO != null && !DateUtils.isExpired(accessTokenDO.getExpiresTime())) { + oauth2AccessTokenRedisDAO.set(accessTokenDO); + } + return accessTokenDO; + } + + @Override + public OAuth2AccessTokenDO checkAccessToken(String accessToken) { + OAuth2AccessTokenDO accessTokenDO = getAccessToken(accessToken); + if (accessTokenDO == null) { + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌不存在"); + } + if (DateUtils.isExpired(accessTokenDO.getExpiresTime())) { + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌已过期"); + } + return accessTokenDO; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public OAuth2AccessTokenDO removeAccessToken(String accessToken) { + // 删除访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken); + if (accessTokenDO == null) { + return null; + } + oauth2AccessTokenMapper.deleteById(accessTokenDO.getId()); + oauth2AccessTokenRedisDAO.delete(accessToken); + // 删除刷新令牌 + oauth2RefreshTokenMapper.deleteByRefreshToken(accessTokenDO.getRefreshToken()); + return accessTokenDO; + } + + @Override + public PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO) { + return oauth2AccessTokenMapper.selectPage(reqVO); + } + + private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO) { + OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken()) + .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType()) + .setUserInfo(buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType())) + .setClientId(clientDO.getClientId()).setScopes(refreshTokenDO.getScopes()) + .setRefreshToken(refreshTokenDO.getRefreshToken()) + .setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getAccessTokenValiditySeconds())); + accessTokenDO.setTenantId(TenantContextHolder.getTenantId()); // 手动设置租户编号,避免缓存到 Redis 的时候,无对应的租户编号 + oauth2AccessTokenMapper.insert(accessTokenDO); + // 记录到 Redis 中 + oauth2AccessTokenRedisDAO.set(accessTokenDO); + return accessTokenDO; + } + + private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, Integer userType, OAuth2ClientDO clientDO, List scopes) { + OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken()) + .setUserId(userId).setUserType(userType) + .setClientId(clientDO.getClientId()).setScopes(scopes) + .setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getRefreshTokenValiditySeconds())); + oauth2RefreshTokenMapper.insert(refreshToken); + return refreshToken; + } + + private OAuth2AccessTokenDO convertToAccessToken(OAuth2RefreshTokenDO refreshTokenDO) { + OAuth2AccessTokenDO accessTokenDO = BeanUtils.toBean(refreshTokenDO, OAuth2AccessTokenDO.class) + .setAccessToken(refreshTokenDO.getRefreshToken()); + TenantUtils.execute(refreshTokenDO.getTenantId(), + () -> accessTokenDO.setUserInfo(buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType()))); + return accessTokenDO; + } + + /** + * 加载用户信息,方便 {@link LoginUser} 获取到昵称、部门等信息 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 用户信息 + */ + private Map buildUserInfo(Long userId, Integer userType) { + if (userType.equals(UserTypeEnum.ADMIN.getValue())) { + AdminUserDO user = adminUserService.getUser(userId); + return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname()) + .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())).build(); + } else if (userType.equals(UserTypeEnum.MEMBER.getValue())) { + // 注意:目前 Member 暂时不读取,可以按需实现 + return Collections.emptyMap(); + } + return null; + } + + private static String generateAccessToken() { + return IdUtil.fastSimpleUUID(); + } + + private static String generateRefreshToken() { + return IdUtil.fastSimpleUUID(); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/MenuService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/MenuService.java new file mode 100644 index 0000000..1a6e7ba --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/MenuService.java @@ -0,0 +1,97 @@ +package com.tashow.cloud.system.service.permission; + +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuSaveVO; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuSaveVO; + +import java.util.Collection; +import java.util.List; + +/** + * 菜单 Service 接口 + * + * @author 芋道源码 + */ +public interface MenuService { + + /** + * 创建菜单 + * + * @param createReqVO 菜单信息 + * @return 创建出来的菜单编号 + */ + Long createMenu(MenuSaveVO createReqVO); + + /** + * 更新菜单 + * + * @param updateReqVO 菜单信息 + */ + void updateMenu(MenuSaveVO updateReqVO); + + /** + * 删除菜单 + * + * @param id 菜单编号 + */ + void deleteMenu(Long id); + + /** + * 获得所有菜单列表 + * + * @return 菜单列表 + */ + List getMenuList(); + + /** + * 基于租户,筛选菜单列表 + * 注意,如果是系统租户,返回的还是全菜单 + * + * @param reqVO 筛选条件请求 VO + * @return 菜单列表 + */ + List getMenuListByTenant(MenuListReqVO reqVO); + + /** + * 过滤掉关闭的菜单及其子菜单 + * + * @param list 菜单列表 + * @return 过滤后的菜单列表 + */ + List filterDisableMenus(List list); + + /** + * 筛选菜单列表 + * + * @param reqVO 筛选条件请求 VO + * @return 菜单列表 + */ + List getMenuList(MenuListReqVO reqVO); + + /** + * 获得权限对应的菜单编号数组 + * + * @param permission 权限标识 + * @return 数组 + */ + List getMenuIdListByPermissionFromCache(String permission); + + /** + * 获得菜单 + * + * @param id 菜单编号 + * @return 菜单 + */ + MenuDO getMenu(Long id); + + /** + * 获得菜单数组 + * + * @param ids 菜单编号数组 + * @return 菜单数组 + */ + List getMenuList(Collection ids); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/MenuServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/MenuServiceImpl.java new file mode 100644 index 0000000..e0ce4b8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/MenuServiceImpl.java @@ -0,0 +1,262 @@ +package com.tashow.cloud.system.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.menu.MenuSaveVO; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import com.tashow.cloud.system.dal.mysql.permission.MenuMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.tashow.cloud.systemapi.enums.permission.MenuTypeEnum; +import com.tashow.cloud.system.service.tenant.TenantService; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertMap; +import static com.tashow.cloud.system.dal.dataobject.permission.MenuDO.ID_ROOT; + +/** + * 菜单 Service 实现 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class MenuServiceImpl implements MenuService { + + @Resource + private MenuMapper menuMapper; + @Resource + private PermissionService permissionService; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private TenantService tenantService; + + @Override + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission", + condition = "#createReqVO.permission != null") + public Long createMenu(MenuSaveVO createReqVO) { + // 校验父菜单存在 + validateParentMenu(createReqVO.getParentId(), null); + // 校验菜单(自己) + validateMenu(createReqVO.getParentId(), createReqVO.getName(), null); + + // 插入数据库 + MenuDO menu = BeanUtils.toBean(createReqVO, MenuDO.class); + initMenuProperty(menu); + menuMapper.insert(menu); + // 返回 + return menu.getId(); + } + + @Override + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效 + public void updateMenu(MenuSaveVO updateReqVO) { + // 校验更新的菜单是否存在 + if (menuMapper.selectById(updateReqVO.getId()) == null) { + throw exception(ErrorCodeConstants.MENU_NOT_EXISTS); + } + // 校验父菜单存在 + validateParentMenu(updateReqVO.getParentId(), updateReqVO.getId()); + // 校验菜单(自己) + validateMenu(updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getId()); + + // 更新到数据库 + MenuDO updateObj = BeanUtils.toBean(updateReqVO, MenuDO.class); + initMenuProperty(updateObj); + menuMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效 + public void deleteMenu(Long id) { + // 校验是否还有子菜单 + if (menuMapper.selectCountByParentId(id) > 0) { + throw exception(ErrorCodeConstants.MENU_EXISTS_CHILDREN); + } + // 校验删除的菜单是否存在 + if (menuMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.MENU_NOT_EXISTS); + } + // 标记删除 + menuMapper.deleteById(id); + // 删除授予给角色的权限 + permissionService.processMenuDeleted(id); + } + + @Override + public List getMenuList() { + return menuMapper.selectList(); + } + + @Override + public List getMenuListByTenant(MenuListReqVO reqVO) { + // 查询所有菜单,并过滤掉关闭的节点 + List menus = getMenuList(reqVO); + // 开启多租户的情况下,需要过滤掉未开通的菜单 + tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); + return menus; + } + + @Override + public List filterDisableMenus(List menuList) { + if (CollUtil.isEmpty(menuList)){ + return Collections.emptyList(); + } + Map menuMap = convertMap(menuList, MenuDO::getId); + + // 遍历 menu 菜单,查找不是禁用的菜单,添加到 enabledMenus 结果 + List enabledMenus = new ArrayList<>(); + Set disabledMenuCache = new HashSet<>(); // 存下递归搜索过被禁用的菜单,防止重复的搜索 + for (MenuDO menu : menuList) { + if (isMenuDisabled(menu, menuMap, disabledMenuCache)) { + continue; + } + enabledMenus.add(menu); + } + return enabledMenus; + } + + private boolean isMenuDisabled(MenuDO node, Map menuMap, Set disabledMenuCache) { + // 如果已经判定是禁用的节点,直接结束 + if (disabledMenuCache.contains(node.getId())) { + return true; + } + + // 1. 先判断自身是否禁用 + if (CommonStatusEnum.isDisable(node.getStatus())) { + disabledMenuCache.add(node.getId()); + return true; + } + + // 2. 遍历到 parentId 为根节点,则无需判断 + Long parentId = node.getParentId(); + if (ObjUtil.equal(parentId, ID_ROOT)) { + return false; + } + + // 3. 继续遍历 parent 节点 + MenuDO parent = menuMap.get(parentId); + if (parent == null || isMenuDisabled(parent, menuMap, disabledMenuCache)) { + disabledMenuCache.add(node.getId()); + return true; + } + return false; + } + + @Override + public List getMenuList(MenuListReqVO reqVO) { + return menuMapper.selectList(reqVO); + } + + @Override + @Cacheable(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#permission") + public List getMenuIdListByPermissionFromCache(String permission) { + List menus = menuMapper.selectListByPermission(permission); + return convertList(menus, MenuDO::getId); + } + + @Override + public MenuDO getMenu(Long id) { + return menuMapper.selectById(id); + } + + @Override + public List getMenuList(Collection ids) { + // 当 ids 为空时,返回一个空的实例对象 + if (CollUtil.isEmpty(ids)) { + return Lists.newArrayList(); + } + return menuMapper.selectBatchIds(ids); + } + + /** + * 校验父菜单是否合法 + *

+ * 1. 不能设置自己为父菜单 + * 2. 父菜单不存在 + * 3. 父菜单必须是 {@link MenuTypeEnum#MENU} 菜单类型 + * + * @param parentId 父菜单编号 + * @param childId 当前菜单编号 + */ + @VisibleForTesting + void validateParentMenu(Long parentId, Long childId) { + if (parentId == null || ID_ROOT.equals(parentId)) { + return; + } + // 不能设置自己为父菜单 + if (parentId.equals(childId)) { + throw exception(ErrorCodeConstants.MENU_PARENT_ERROR); + } + MenuDO menu = menuMapper.selectById(parentId); + // 父菜单不存在 + if (menu == null) { + throw exception(ErrorCodeConstants.MENU_PARENT_NOT_EXISTS); + } + // 父菜单必须是目录或者菜单类型 + if (!MenuTypeEnum.DIR.getType().equals(menu.getType()) + && !MenuTypeEnum.MENU.getType().equals(menu.getType())) { + throw exception(ErrorCodeConstants.MENU_PARENT_NOT_DIR_OR_MENU); + } + } + + /** + * 校验菜单是否合法 + *

+ * 1. 校验相同父菜单编号下,是否存在相同的菜单名 + * + * @param name 菜单名字 + * @param parentId 父菜单编号 + * @param id 菜单编号 + */ + @VisibleForTesting + void validateMenu(Long parentId, String name, Long id) { + MenuDO menu = menuMapper.selectByParentIdAndName(parentId, name); + if (menu == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的菜单 + if (id == null) { + throw exception(ErrorCodeConstants.MENU_NAME_DUPLICATE); + } + if (!menu.getId().equals(id)) { + throw exception(ErrorCodeConstants.MENU_NAME_DUPLICATE); + } + } + + /** + * 初始化菜单的通用属性。 + *

+ * 例如说,只有目录或者菜单类型的菜单,才设置 icon + * + * @param menu 菜单 + */ + private void initMenuProperty(MenuDO menu) { + // 菜单为按钮类型时,无需 component、icon、path 属性,进行置空 + if (MenuTypeEnum.BUTTON.getType().equals(menu.getType())) { + menu.setComponent(""); + menu.setComponentName(""); + menu.setIcon(""); + menu.setPath(""); + } + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/PermissionService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/PermissionService.java new file mode 100644 index 0000000..ac6137c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/PermissionService.java @@ -0,0 +1,147 @@ +package com.tashow.cloud.system.service.permission; + +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; + +import java.util.Collection; +import java.util.Set; + +import static java.util.Collections.singleton; + +/** + * 权限 Service 接口 + *

+ * 提供用户-角色、角色-菜单、角色-部门的关联权限处理 + * + * @author 芋道源码 + */ +public interface PermissionService { + + /** + * 判断是否有权限,任一一个即可 + * + * @param userId 用户编号 + * @param permissions 权限 + * @return 是否 + */ + boolean hasAnyPermissions(Long userId, String... permissions); + + /** + * 判断是否有角色,任一一个即可 + * + * @param roles 角色数组 + * @return 是否 + */ + boolean hasAnyRoles(Long userId, String... roles); + + // ========== 角色-菜单的相关方法 ========== + + /** + * 设置角色菜单 + * + * @param roleId 角色编号 + * @param menuIds 菜单编号集合 + */ + void assignRoleMenu(Long roleId, Set menuIds); + + /** + * 处理角色删除时,删除关联授权数据 + * + * @param roleId 角色编号 + */ + void processRoleDeleted(Long roleId); + + /** + * 处理菜单删除时,删除关联授权数据 + * + * @param menuId 菜单编号 + */ + void processMenuDeleted(Long menuId); + + /** + * 获得角色拥有的菜单编号集合 + * + * @param roleId 角色编号 + * @return 菜单编号集合 + */ + default Set getRoleMenuListByRoleId(Long roleId) { + return getRoleMenuListByRoleId(singleton(roleId)); + } + + /** + * 获得角色们拥有的菜单编号集合 + * + * @param roleIds 角色编号数组 + * @return 菜单编号集合 + */ + Set getRoleMenuListByRoleId(Collection roleIds); + + /** + * 获得拥有指定菜单的角色编号数组,从缓存中获取 + * + * @param menuId 菜单编号 + * @return 角色编号数组 + */ + Set getMenuRoleIdListByMenuIdFromCache(Long menuId); + + // ========== 用户-角色的相关方法 ========== + + /** + * 设置用户角色 + * + * @param userId 角色编号 + * @param roleIds 角色编号集合 + */ + void assignUserRole(Long userId, Set roleIds); + + /** + * 处理用户删除时,删除关联授权数据 + * + * @param userId 用户编号 + */ + void processUserDeleted(Long userId); + + /** + * 获得拥有多个角色的用户编号集合 + * + * @param roleIds 角色编号集合 + * @return 用户编号集合 + */ + Set getUserRoleIdListByRoleId(Collection roleIds); + + /** + * 获得用户拥有的角色编号集合 + * + * @param userId 用户编号 + * @return 角色编号集合 + */ + Set getUserRoleIdListByUserId(Long userId); + + /** + * 获得用户拥有的角色编号集合,从缓存中获取 + * + * @param userId 用户编号 + * @return 角色编号集合 + */ + Set getUserRoleIdListByUserIdFromCache(Long userId); + + // ========== 用户-部门的相关方法 ========== + + /** + * 设置角色的数据权限 + * + * @param roleId 角色编号 + * @param dataScope 数据范围 + * @param dataScopeDeptIds 部门编号数组 + */ + void assignRoleDataScope(Long roleId, Integer dataScope, Set dataScopeDeptIds); + + /** + * 获得登陆用户的部门数据权限 + * + * @param userId 用户编号 + * @return 部门数据权限 + */ + DeptDataPermissionRespDTO getDeptDataPermission(Long userId); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/PermissionServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/PermissionServiceImpl.java new file mode 100644 index 0000000..6a48c1d --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/PermissionServiceImpl.java @@ -0,0 +1,342 @@ +package com.tashow.cloud.system.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.permission.core.annotation.DataPermission; +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleMenuDO; +import com.tashow.cloud.system.dal.dataobject.permission.UserRoleDO; +import com.tashow.cloud.system.dal.mysql.permission.RoleMenuMapper; +import com.tashow.cloud.system.dal.mysql.permission.UserRoleMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.tashow.cloud.systemapi.enums.permission.DataScopeEnum; +import com.tashow.cloud.system.service.dept.DeptService; +import com.tashow.cloud.system.service.user.AdminUserService; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Suppliers; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import jakarta.annotation.Resource; +import java.util.*; +import java.util.function.Supplier; + +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; +import static com.tashow.cloud.common.util.json.JsonUtils.toJsonString; + + +/** + * 权限 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class PermissionServiceImpl implements PermissionService { + + @Resource + private RoleMenuMapper roleMenuMapper; + @Resource + private UserRoleMapper userRoleMapper; + + @Resource + private RoleService roleService; + @Resource + private MenuService menuService; + @Resource + private DeptService deptService; + @Resource + private AdminUserService userService; + + @Override + public boolean hasAnyPermissions(Long userId, String... permissions) { + // 如果为空,说明已经有权限 + if (ArrayUtil.isEmpty(permissions)) { + return true; + } + + // 获得当前登录的角色。如果为空,说明没有权限 + List roles = getEnableUserRoleListByUserIdFromCache(userId); + if (CollUtil.isEmpty(roles)) { + return false; + } + + // 情况一:遍历判断每个权限,如果有一满足,说明有权限 + for (String permission : permissions) { + if (hasAnyPermission(roles, permission)) { + return true; + } + } + + // 情况二:如果是超管,也说明有权限 + return roleService.hasAnySuperAdmin(convertSet(roles, RoleDO::getId)); + } + + /** + * 判断指定角色,是否拥有该 permission 权限 + * + * @param roles 指定角色数组 + * @param permission 权限标识 + * @return 是否拥有 + */ + private boolean hasAnyPermission(List roles, String permission) { + List menuIds = menuService.getMenuIdListByPermissionFromCache(permission); + // 采用严格模式,如果权限找不到对应的 Menu 的话,也认为没有权限 + if (CollUtil.isEmpty(menuIds)) { + return false; + } + + // 判断是否有权限 + Set roleIds = convertSet(roles, RoleDO::getId); + for (Long menuId : menuIds) { + // 获得拥有该菜单的角色编号集合 + Set menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menuId); + // 如果有交集,说明有权限 + if (CollUtil.containsAny(menuRoleIds, roleIds)) { + return true; + } + } + return false; + } + + @Override + public boolean hasAnyRoles(Long userId, String... roles) { + // 如果为空,说明已经有权限 + if (ArrayUtil.isEmpty(roles)) { + return true; + } + + // 获得当前登录的角色。如果为空,说明没有权限 + List roleList = getEnableUserRoleListByUserIdFromCache(userId); + if (CollUtil.isEmpty(roleList)) { + return false; + } + + // 判断是否有角色 + Set userRoles = convertSet(roleList, RoleDO::getCode); + return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); + } + + // ========== 角色-菜单的相关方法 ========== + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + @Caching(evict = { + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + allEntries = true), + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 + }) + public void assignRoleMenu(Long roleId, Set menuIds) { + // 获得角色拥有菜单编号 + Set dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); + // 计算新增和删除的菜单编号 + Set menuIdList = CollUtil.emptyIfNull(menuIds); + Collection createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds); + Collection deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList); + // 执行新增和删除。对于已经授权的菜单,不用做任何处理 + if (CollUtil.isNotEmpty(createMenuIds)) { + roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { + RoleMenuDO entity = new RoleMenuDO(); + entity.setRoleId(roleId); + entity.setMenuId(menuId); + return entity; + })); + } + if (CollUtil.isNotEmpty(deleteMenuIds)) { + roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + @Caching(evict = { + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + allEntries = true), // allEntries 清空所有缓存,此处无法方便获得 roleId 对应的 menu 缓存们 + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,此处无法方便获得 roleId 对应的 user 缓存们 + }) + public void processRoleDeleted(Long roleId) { + // 标记删除 UserRole + userRoleMapper.deleteListByRoleId(roleId); + // 标记删除 RoleMenu + roleMenuMapper.deleteListByRoleId(roleId); + } + + @Override + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") + public void processMenuDeleted(Long menuId) { + roleMenuMapper.deleteListByMenuId(menuId); + } + + @Override + public Set getRoleMenuListByRoleId(Collection roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return Collections.emptySet(); + } + + // 如果是管理员的情况下,获取全部菜单编号 + if (roleService.hasAnySuperAdmin(roleIds)) { + return convertSet(menuService.getMenuList(), MenuDO::getId); + } + // 如果是非管理员的情况下,获得拥有的菜单编号 + return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); + } + + @Override + @Cacheable(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") + public Set getMenuRoleIdListByMenuIdFromCache(Long menuId) { + return convertSet(roleMenuMapper.selectListByMenuId(menuId), RoleMenuDO::getRoleId); + } + + // ========== 用户-角色的相关方法 ========== + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") + public void assignUserRole(Long userId, Set roleIds) { + // 获得角色拥有角色编号 + Set dbRoleIds = convertSet(userRoleMapper.selectListByUserId(userId), + UserRoleDO::getRoleId); + // 计算新增和删除的角色编号 + Set roleIdList = CollUtil.emptyIfNull(roleIds); + Collection createRoleIds = CollUtil.subtract(roleIdList, dbRoleIds); + Collection deleteMenuIds = CollUtil.subtract(dbRoleIds, roleIdList); + // 执行新增和删除。对于已经授权的角色,不用做任何处理 + if (!CollectionUtil.isEmpty(createRoleIds)) { + userRoleMapper.insertBatch(CollectionUtils.convertList(createRoleIds, roleId -> { + UserRoleDO entity = new UserRoleDO(); + entity.setUserId(userId); + entity.setRoleId(roleId); + return entity; + })); + } + if (!CollectionUtil.isEmpty(deleteMenuIds)) { + userRoleMapper.deleteListByUserIdAndRoleIdIds(userId, deleteMenuIds); + } + } + + @Override + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") + public void processUserDeleted(Long userId) { + userRoleMapper.deleteListByUserId(userId); + } + + @Override + public Set getUserRoleIdListByUserId(Long userId) { + return convertSet(userRoleMapper.selectListByUserId(userId), UserRoleDO::getRoleId); + } + + @Override + @Cacheable(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") + public Set getUserRoleIdListByUserIdFromCache(Long userId) { + return getUserRoleIdListByUserId(userId); + } + + @Override + public Set getUserRoleIdListByRoleId(Collection roleIds) { + return convertSet(userRoleMapper.selectListByRoleIds(roleIds), UserRoleDO::getUserId); + } + + /** + * 获得用户拥有的角色,并且这些角色是开启状态的 + * + * @param userId 用户编号 + * @return 用户拥有的角色 + */ + @VisibleForTesting + List getEnableUserRoleListByUserIdFromCache(Long userId) { + // 获得用户拥有的角色编号 + Set roleIds = getSelf().getUserRoleIdListByUserIdFromCache(userId); + // 获得角色数组,并移除被禁用的 + List roles = roleService.getRoleListFromCache(roleIds); + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); + return roles; + } + + // ========== 用户-部门的相关方法 ========== + + @Override + public void assignRoleDataScope(Long roleId, Integer dataScope, Set dataScopeDeptIds) { + roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds); + } + + @Override + @DataPermission(enable = false) // 关闭数据权限,不然就会出现递归获取数据权限的问题 + public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) { + // 获得用户的角色 + List roles = getEnableUserRoleListByUserIdFromCache(userId); + + // 如果角色为空,则只能查看自己 + DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO(); + if (CollUtil.isEmpty(roles)) { + result.setSelf(true); + return result; + } + + // 获得用户的部门编号的缓存,通过 Guava 的 Suppliers 惰性求值,即有且仅有第一次发起 DB 的查询 + Supplier userDeptId = Suppliers.memoize(() -> userService.getUser(userId).getDeptId()); + // 遍历每个角色,计算 + for (RoleDO role : roles) { + // 为空时,跳过 + if (role.getDataScope() == null) { + continue; + } + // 情况一,ALL + if (Objects.equals(role.getDataScope(), DataScopeEnum.ALL.getScope())) { + result.setAll(true); + continue; + } + // 情况二,DEPT_CUSTOM + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_CUSTOM.getScope())) { + CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds()); + // 自定义可见部门时,保证可以看到自己所在的部门。否则,一些场景下可能会有问题。 + // 例如说,登录时,基于 t_user 的 username 查询会可能被 dept_id 过滤掉 + CollUtil.addAll(result.getDeptIds(), userDeptId.get()); + continue; + } + // 情况三,DEPT_ONLY + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) { + CollectionUtils.addIfNotNull(result.getDeptIds(), userDeptId.get()); + continue; + } + // 情况四,DEPT_DEPT_AND_CHILD + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) { + CollUtil.addAll(result.getDeptIds(), deptService.getChildDeptIdListFromCache(userDeptId.get())); + // 添加本身部门编号 + CollUtil.addAll(result.getDeptIds(), userDeptId.get()); + continue; + } + // 情况五,SELF + if (Objects.equals(role.getDataScope(), DataScopeEnum.SELF.getScope())) { + result.setSelf(true); + continue; + } + // 未知情况,error log 即可 + log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", userId, toJsonString(result)); + } + return result; + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private PermissionServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/RoleService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/RoleService.java new file mode 100644 index 0000000..fa100dc --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/RoleService.java @@ -0,0 +1,126 @@ +package com.tashow.cloud.system.service.permission; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RolePageReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; + +import com.tashow.cloud.system.controller.admin.permission.vo.role.RolePageReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import jakarta.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * 角色 Service 接口 + * + * @author 芋道源码 + */ +public interface RoleService { + + /** + * 创建角色 + * + * @param createReqVO 创建角色信息 + * @param type 角色类型 + * @return 角色编号 + */ + Long createRole(@Valid RoleSaveReqVO createReqVO, Integer type); + + /** + * 更新角色 + * + * @param updateReqVO 更新角色信息 + */ + void updateRole(@Valid RoleSaveReqVO updateReqVO); + + /** + * 删除角色 + * + * @param id 角色编号 + */ + void deleteRole(Long id); + + /** + * 设置角色的数据权限 + * + * @param id 角色编号 + * @param dataScope 数据范围 + * @param dataScopeDeptIds 部门编号数组 + */ + void updateRoleDataScope(Long id, Integer dataScope, Set dataScopeDeptIds); + + /** + * 获得角色 + * + * @param id 角色编号 + * @return 角色 + */ + RoleDO getRole(Long id); + + /** + * 获得角色,从缓存中 + * + * @param id 角色编号 + * @return 角色 + */ + RoleDO getRoleFromCache(Long id); + + /** + * 获得角色列表 + * + * @param ids 角色编号数组 + * @return 角色列表 + */ + List getRoleList(Collection ids); + + /** + * 获得角色数组,从缓存中 + * + * @param ids 角色编号数组 + * @return 角色数组 + */ + List getRoleListFromCache(Collection ids); + + /** + * 获得角色列表 + * + * @param statuses 筛选的状态 + * @return 角色列表 + */ + List getRoleListByStatus(Collection statuses); + + /** + * 获得所有角色列表 + * + * @return 角色列表 + */ + List getRoleList(); + + /** + * 获得角色分页 + * + * @param reqVO 角色分页查询 + * @return 角色分页结果 + */ + PageResult getRolePage(RolePageReqVO reqVO); + + /** + * 判断角色编号数组中,是否有管理员 + * + * @param ids 角色编号数组 + * @return 是否有管理员 + */ + boolean hasAnySuperAdmin(Collection ids); + + /** + * 校验角色们是否有效。如下情况,视为无效: + * 1. 角色编号不存在 + * 2. 角色被禁用 + * + * @param ids 角色编号数组 + */ + void validateRoleList(Collection ids); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/RoleServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/RoleServiceImpl.java new file mode 100644 index 0000000..f2f220f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/permission/RoleServiceImpl.java @@ -0,0 +1,262 @@ +package com.tashow.cloud.system.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RolePageReqVO; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.dal.mysql.permission.RoleMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.tashow.cloud.systemapi.enums.permission.DataScopeEnum; +import com.tashow.cloud.systemapi.enums.permission.RoleCodeEnum; +import com.tashow.cloud.systemapi.enums.permission.RoleTypeEnum; +import com.google.common.annotations.VisibleForTesting; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.systemapi.enums.LogRecordConstants; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.util.*; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertMap; + +/** + * 角色 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class RoleServiceImpl implements RoleService { + + @Resource + private PermissionService permissionService; + + @Resource + private RoleMapper roleMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = LogRecordConstants.SYSTEM_ROLE_TYPE, subType = LogRecordConstants.SYSTEM_ROLE_CREATE_SUB_TYPE, bizNo = "{{#role.id}}", + success = LogRecordConstants.SYSTEM_ROLE_CREATE_SUCCESS) + public Long createRole(RoleSaveReqVO createReqVO, Integer type) { + // 1. 校验角色 + validateRoleDuplicate(createReqVO.getName(), createReqVO.getCode(), null); + + // 2. 插入到数据库 + RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class) + .setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType())) + .setStatus(ObjUtil.defaultIfNull(createReqVO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) + .setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限 + roleMapper.insert(role); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("role", role); + return role.getId(); + } + + @Override + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#updateReqVO.id") + @LogRecord(type = LogRecordConstants.SYSTEM_ROLE_TYPE, subType = LogRecordConstants.SYSTEM_ROLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = LogRecordConstants.SYSTEM_ROLE_UPDATE_SUCCESS) + public void updateRole(RoleSaveReqVO updateReqVO) { + // 1.1 校验是否可以更新 + RoleDO role = validateRoleForUpdate(updateReqVO.getId()); + // 1.2 校验角色的唯一字段是否重复 + validateRoleDuplicate(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId()); + + // 2. 更新到数据库 + RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class); + roleMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(role, RoleSaveReqVO.class)); + LogRecordContext.putVariable("role", role); + } + + @Override + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id") + public void updateRoleDataScope(Long id, Integer dataScope, Set dataScopeDeptIds) { + // 校验是否可以更新 + validateRoleForUpdate(id); + + // 更新数据范围 + RoleDO updateObject = new RoleDO(); + updateObject.setId(id); + updateObject.setDataScope(dataScope); + updateObject.setDataScopeDeptIds(dataScopeDeptIds); + roleMapper.updateById(updateObject); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id") + @LogRecord(type = LogRecordConstants.SYSTEM_ROLE_TYPE, subType = LogRecordConstants.SYSTEM_ROLE_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = LogRecordConstants.SYSTEM_ROLE_DELETE_SUCCESS) + public void deleteRole(Long id) { + // 1. 校验是否可以更新 + RoleDO role = validateRoleForUpdate(id); + + // 2.1 标记删除 + roleMapper.deleteById(id); + // 2.2 删除相关数据 + permissionService.processRoleDeleted(id); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("role", role); + } + + /** + * 校验角色的唯一字段是否重复 + * + * 1. 是否存在相同名字的角色 + * 2. 是否存在相同编码的角色 + * + * @param name 角色名字 + * @param code 角色额编码 + * @param id 角色编号 + */ + @VisibleForTesting + void validateRoleDuplicate(String name, String code, Long id) { + // 0. 超级管理员,不允许创建 + if (RoleCodeEnum.isSuperAdmin(code)) { + throw exception(ErrorCodeConstants.ROLE_ADMIN_CODE_ERROR, code); + } + // 1. 该 name 名字被其它角色所使用 + RoleDO role = roleMapper.selectByName(name); + if (role != null && !role.getId().equals(id)) { + throw exception(ErrorCodeConstants.ROLE_NAME_DUPLICATE, name); + } + // 2. 是否存在相同编码的角色 + if (!StringUtils.hasText(code)) { + return; + } + // 该 code 编码被其它角色所使用 + role = roleMapper.selectByCode(code); + if (role != null && !role.getId().equals(id)) { + throw exception(ErrorCodeConstants.ROLE_CODE_DUPLICATE, code); + } + } + + /** + * 校验角色是否可以被更新 + * + * @param id 角色编号 + */ + @VisibleForTesting + RoleDO validateRoleForUpdate(Long id) { + RoleDO role = roleMapper.selectById(id); + if (role == null) { + throw exception(ErrorCodeConstants.ROLE_NOT_EXISTS); + } + // 内置角色,不允许删除 + if (RoleTypeEnum.SYSTEM.getType().equals(role.getType())) { + throw exception(ErrorCodeConstants.ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE); + } + return role; + } + + @Override + public RoleDO getRole(Long id) { + return roleMapper.selectById(id); + } + + @Override + @Cacheable(value = RedisKeyConstants.ROLE, key = "#id", + unless = "#result == null") + public RoleDO getRoleFromCache(Long id) { + return roleMapper.selectById(id); + } + + + @Override + public List getRoleListByStatus(Collection statuses) { + return roleMapper.selectListByStatus(statuses); + } + + @Override + public List getRoleList() { + return roleMapper.selectList(); + } + + @Override + public List getRoleList(Collection ids) { + if (CollectionUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return roleMapper.selectBatchIds(ids); + } + + @Override + public List getRoleListFromCache(Collection ids) { + if (CollectionUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + // 这里采用 for 循环从缓存中获取,主要考虑 Spring CacheManager 无法批量操作的问题 + RoleServiceImpl self = getSelf(); + return CollectionUtils.convertList(ids, self::getRoleFromCache); + } + + @Override + public PageResult getRolePage(RolePageReqVO reqVO) { + return roleMapper.selectPage(reqVO); + } + + @Override + public boolean hasAnySuperAdmin(Collection ids) { + if (CollectionUtil.isEmpty(ids)) { + return false; + } + RoleServiceImpl self = getSelf(); + return ids.stream().anyMatch(id -> { + RoleDO role = self.getRoleFromCache(id); + return role != null && RoleCodeEnum.isSuperAdmin(role.getCode()); + }); + } + + @Override + public void validateRoleList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得角色信息 + List roles = roleMapper.selectBatchIds(ids); + Map roleMap = convertMap(roles, RoleDO::getId); + // 校验 + ids.forEach(id -> { + RoleDO role = roleMap.get(id); + if (role == null) { + throw exception(ErrorCodeConstants.ROLE_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())) { + throw exception(ErrorCodeConstants.ROLE_IS_DISABLE, role.getName()); + } + }); + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private RoleServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsChannelService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsChannelService.java new file mode 100644 index 0000000..caaf80f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsChannelService.java @@ -0,0 +1,84 @@ +package com.tashow.cloud.system.service.sms; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsChannelDO; + +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import jakarta.validation.Valid; +import java.util.List; + +/** + * 短信渠道 Service 接口 + * + * @author zzf + * @since 2021/1/25 9:24 + */ +public interface SmsChannelService { + + /** + * 创建短信渠道 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSmsChannel(@Valid SmsChannelSaveReqVO createReqVO); + + /** + * 更新短信渠道 + * + * @param updateReqVO 更新信息 + */ + void updateSmsChannel(@Valid SmsChannelSaveReqVO updateReqVO); + + /** + * 删除短信渠道 + * + * @param id 编号 + */ + void deleteSmsChannel(Long id); + + /** + * 获得短信渠道 + * + * @param id 编号 + * @return 短信渠道 + */ + SmsChannelDO getSmsChannel(Long id); + + /** + * 获得所有短信渠道列表 + * + * @return 短信渠道列表 + */ + List getSmsChannelList(); + + /** + * 获得短信渠道分页 + * + * @param pageReqVO 分页查询 + * @return 短信渠道分页 + */ + PageResult getSmsChannelPage(SmsChannelPageReqVO pageReqVO); + + /** + * 获得短信客户端 + * + * @param id 编号 + * @return 短信客户端 + */ + SmsClient getSmsClient(Long id); + + /** + * 获得短信客户端 + * + * @param code 编码 + * @return 短信客户端 + */ + SmsClient getSmsClient(String code); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsChannelServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsChannelServiceImpl.java new file mode 100644 index 0000000..45c782a --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsChannelServiceImpl.java @@ -0,0 +1,109 @@ +package com.tashow.cloud.system.service.sms; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsChannelDO; +import com.tashow.cloud.system.dal.mysql.sms.SmsChannelMapper; +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import com.tashow.cloud.system.framework.sms.core.client.SmsClientFactory; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import com.tashow.cloud.system.framework.sms.core.client.SmsClientFactory; +import com.tashow.cloud.system.framework.sms.core.property.SmsChannelProperties; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; + +/** + * 短信渠道 Service 实现类 + * + * @author zzf + */ +@Service +@Slf4j +public class SmsChannelServiceImpl implements SmsChannelService { + + @Resource + private SmsClientFactory smsClientFactory; + + @Resource + private SmsChannelMapper smsChannelMapper; + + @Resource + private SmsTemplateService smsTemplateService; + + @Override + public Long createSmsChannel(SmsChannelSaveReqVO createReqVO) { + SmsChannelDO channel = BeanUtils.toBean(createReqVO, SmsChannelDO.class); + smsChannelMapper.insert(channel); + return channel.getId(); + } + + @Override + public void updateSmsChannel(SmsChannelSaveReqVO updateReqVO) { + // 校验存在 + validateSmsChannelExists(updateReqVO.getId()); + // 更新 + SmsChannelDO updateObj = BeanUtils.toBean(updateReqVO, SmsChannelDO.class); + smsChannelMapper.updateById(updateObj); + } + + @Override + public void deleteSmsChannel(Long id) { + // 校验存在 + validateSmsChannelExists(id); + // 校验是否有在使用该账号的模版 + if (smsTemplateService.getSmsTemplateCountByChannelId(id) > 0) { + throw exception(ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN); + } + // 删除 + smsChannelMapper.deleteById(id); + } + + private SmsChannelDO validateSmsChannelExists(Long id) { + SmsChannelDO channel = smsChannelMapper.selectById(id); + if (channel == null) { + throw exception(ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS); + } + return channel; + } + + @Override + public SmsChannelDO getSmsChannel(Long id) { + return smsChannelMapper.selectById(id); + } + + @Override + public List getSmsChannelList() { + return smsChannelMapper.selectList(); + } + + @Override + public PageResult getSmsChannelPage(SmsChannelPageReqVO pageReqVO) { + return smsChannelMapper.selectPage(pageReqVO); + } + + @Override + public SmsClient getSmsClient(Long id) { + SmsChannelDO channel = smsChannelMapper.selectById(id); + SmsChannelProperties properties = BeanUtils.toBean(channel, SmsChannelProperties.class); + return smsClientFactory.createOrUpdateSmsClient(properties); + } + + @Override + public SmsClient getSmsClient(String code) { + return smsClientFactory.getSmsClient(code); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsCodeService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsCodeService.java new file mode 100644 index 0000000..3c23fad --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsCodeService.java @@ -0,0 +1,43 @@ +package com.tashow.cloud.system.service.sms; + +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; + +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; +import jakarta.validation.Valid; + +/** + * 短信验证码 Service 接口 + * + * @author 芋道源码 + */ +public interface SmsCodeService { + + /** + * 创建短信验证码,并进行发送 + * + * @param reqDTO 发送请求 + */ + void sendSmsCode(@Valid SmsCodeSendReqDTO reqDTO); + + /** + * 验证短信验证码,并进行使用 + * 如果正确,则将验证码标记成已使用 + * 如果错误,则抛出 {@link ServiceException} 异常 + * + * @param reqDTO 使用请求 + */ + void useSmsCode(@Valid SmsCodeUseReqDTO reqDTO); + + /** + * 检查验证码是否有效 + * + * @param reqDTO 校验请求 + */ + void validateSmsCode(@Valid SmsCodeValidateReqDTO reqDTO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsCodeServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsCodeServiceImpl.java new file mode 100644 index 0000000..9026ff7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsCodeServiceImpl.java @@ -0,0 +1,117 @@ +package com.tashow.cloud.system.service.sms; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsCodeDO; +import com.tashow.cloud.system.dal.mysql.sms.SmsCodeMapper; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import com.tashow.cloud.system.framework.sms.config.SmsCodeProperties; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeSendReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeUseReqDTO; +import com.tashow.cloud.systemapi.api.sms.dto.code.SmsCodeValidateReqDTO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.systemapi.enums.sms.SmsSceneEnum; +import com.tashow.cloud.system.framework.sms.config.SmsCodeProperties; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.randomInt; +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.date.DateUtils.isToday; + +/** + * 短信验证码 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class SmsCodeServiceImpl implements SmsCodeService { + + @Resource + private SmsCodeProperties smsCodeProperties; + + @Resource + private SmsCodeMapper smsCodeMapper; + + @Resource + private SmsSendService smsSendService; + + @Override + public void sendSmsCode(SmsCodeSendReqDTO reqDTO) { + SmsSceneEnum sceneEnum = SmsSceneEnum.getCodeByScene(reqDTO.getScene()); + Assert.notNull(sceneEnum, "验证码场景({}) 查找不到配置", reqDTO.getScene()); + // 创建验证码 + String code = createSmsCode(reqDTO.getMobile(), reqDTO.getScene(), reqDTO.getCreateIp()); + // 发送验证码 + smsSendService.sendSingleSms(reqDTO.getMobile(), null, null, + sceneEnum.getTemplateCode(), MapUtil.of("code", code)); + } + + private String createSmsCode(String mobile, Integer scene, String ip) { + // 校验是否可以发送验证码,不用筛选场景 + SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, null, null); + if (lastSmsCode != null) { + if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() + < smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁 + throw exception(ErrorCodeConstants.SMS_CODE_SEND_TOO_FAST); + } + if (isToday(lastSmsCode.getCreateTime()) && // 必须是今天,才能计算超过当天的上限 + lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。 + throw exception(ErrorCodeConstants.SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); + } + // TODO 芋艿:提升,每个 IP 每天可发送数量 + // TODO 芋艿:提升,每个 IP 每小时可发送数量 + } + + // 创建验证码记录 + String code = String.format("%0" + smsCodeProperties.getEndCode().toString().length() + "d", + randomInt(smsCodeProperties.getBeginCode(), smsCodeProperties.getEndCode() + 1)); + SmsCodeDO newSmsCode = SmsCodeDO.builder().mobile(mobile).code(code).scene(scene) + .todayIndex(lastSmsCode != null && isToday(lastSmsCode.getCreateTime()) ? lastSmsCode.getTodayIndex() + 1 : 1) + .createIp(ip).used(false).build(); + smsCodeMapper.insert(newSmsCode); + return code; + } + + @Override + public void useSmsCode(SmsCodeUseReqDTO reqDTO) { + // 检测验证码是否有效 + SmsCodeDO lastSmsCode = validateSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene()); + // 使用验证码 + smsCodeMapper.updateById(SmsCodeDO.builder().id(lastSmsCode.getId()) + .used(true).usedTime(LocalDateTime.now()).usedIp(reqDTO.getUsedIp()).build()); + } + + @Override + public void validateSmsCode(SmsCodeValidateReqDTO reqDTO) { + validateSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene()); + } + + private SmsCodeDO validateSmsCode0(String mobile, String code, Integer scene) { + // 校验验证码 + SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, code, scene); + // 若验证码不存在,抛出异常 + if (lastSmsCode == null) { + throw exception(ErrorCodeConstants.SMS_CODE_NOT_FOUND); + } + // 超过时间 + if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() + >= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期 + throw exception(ErrorCodeConstants.SMS_CODE_EXPIRED); + } + // 判断验证码是否已被使用 + if (Boolean.TRUE.equals(lastSmsCode.getUsed())) { + throw exception(ErrorCodeConstants.SMS_CODE_USED); + } + return lastSmsCode; + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsLogService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsLogService.java new file mode 100644 index 0000000..5b39dae --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsLogService.java @@ -0,0 +1,69 @@ +package com.tashow.cloud.system.service.sms; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsLogDO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsTemplateDO; +import com.tashow.cloud.system.controller.admin.sms.vo.log.SmsLogPageReqVO; + +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 短信日志 Service 接口 + * + * @author zzf + * @date 13:48 2021/3/2 + */ +public interface SmsLogService { + + /** + * 创建短信日志 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param isSend 是否发送 + * @param template 短信模板 + * @param templateContent 短信内容 + * @param templateParams 短信参数 + * @return 发送日志编号 + */ + Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend, + SmsTemplateDO template, String templateContent, Map templateParams); + + /** + * 更新日志的发送结果 + * + * @param id 日志编号 + * @param success 发送是否成功 + * @param apiSendCode 短信 API 发送结果的编码 + * @param apiSendMsg 短信 API 发送失败的提示 + * @param apiRequestId 短信 API 发送返回的唯一请求 ID + * @param apiSerialNo 短信 API 发送返回的序号 + */ + void updateSmsSendResult(Long id, Boolean success, + String apiSendCode, String apiSendMsg, + String apiRequestId, String apiSerialNo); + + /** + * 更新日志的接收结果 + * + * @param id 日志编号 + * @param success 是否接收成功 + * @param receiveTime 用户接收时间 + * @param apiReceiveCode API 接收结果的编码 + * @param apiReceiveMsg API 接收结果的说明 + */ + void updateSmsReceiveResult(Long id, Boolean success, + LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg); + + /** + * 获得短信日志分页 + * + * @param pageReqVO 分页查询 + * @return 短信日志分页 + */ + PageResult getSmsLogPage(SmsLogPageReqVO pageReqVO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsLogServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsLogServiceImpl.java new file mode 100644 index 0000000..6ddff26 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsLogServiceImpl.java @@ -0,0 +1,82 @@ +package com.tashow.cloud.system.service.sms; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsLogDO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsTemplateDO; +import com.tashow.cloud.system.dal.mysql.sms.SmsLogMapper; +import com.tashow.cloud.systemapi.enums.sms.SmsReceiveStatusEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSendStatusEnum; +import com.tashow.cloud.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import com.tashow.cloud.systemapi.enums.sms.SmsReceiveStatusEnum; +import com.tashow.cloud.systemapi.enums.sms.SmsSendStatusEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Objects; + +/** + * 短信日志 Service 实现类 + * + * @author zzf + */ +@Slf4j +@Service +public class SmsLogServiceImpl implements SmsLogService { + + @Resource + private SmsLogMapper smsLogMapper; + + @Override + public Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend, + SmsTemplateDO template, String templateContent, Map templateParams) { + SmsLogDO.SmsLogDOBuilder logBuilder = SmsLogDO.builder(); + // 根据是否要发送,设置状态 + logBuilder.sendStatus(Objects.equals(isSend, true) ? SmsSendStatusEnum.INIT.getStatus() + : SmsSendStatusEnum.IGNORE.getStatus()); + // 设置手机相关字段 + logBuilder.mobile(mobile).userId(userId).userType(userType); + // 设置模板相关字段 + logBuilder.templateId(template.getId()).templateCode(template.getCode()).templateType(template.getType()); + logBuilder.templateContent(templateContent).templateParams(templateParams) + .apiTemplateId(template.getApiTemplateId()); + // 设置渠道相关字段 + logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode()); + // 设置接收相关字段 + logBuilder.receiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); + + // 插入数据库 + SmsLogDO logDO = logBuilder.build(); + smsLogMapper.insert(logDO); + return logDO.getId(); + } + + @Override + public void updateSmsSendResult(Long id, Boolean success, + String apiSendCode, String apiSendMsg, + String apiRequestId, String apiSerialNo) { + SmsSendStatusEnum sendStatus = success ? SmsSendStatusEnum.SUCCESS : SmsSendStatusEnum.FAILURE; + smsLogMapper.updateById(SmsLogDO.builder().id(id) + .sendStatus(sendStatus.getStatus()).sendTime(LocalDateTime.now()) + .apiSendCode(apiSendCode).apiSendMsg(apiSendMsg) + .apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build()); + } + + @Override + public void updateSmsReceiveResult(Long id, Boolean success, LocalDateTime receiveTime, + String apiReceiveCode, String apiReceiveMsg) { + SmsReceiveStatusEnum receiveStatus = Objects.equals(success, true) ? + SmsReceiveStatusEnum.SUCCESS : SmsReceiveStatusEnum.FAILURE; + smsLogMapper.updateById(SmsLogDO.builder().id(id).receiveStatus(receiveStatus.getStatus()) + .receiveTime(receiveTime).apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build()); + } + + @Override + public PageResult getSmsLogPage(SmsLogPageReqVO pageReqVO) { + return smsLogMapper.selectPage(pageReqVO); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsSendService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsSendService.java new file mode 100644 index 0000000..dadd3a8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsSendService.java @@ -0,0 +1,78 @@ +package com.tashow.cloud.system.service.sms; + +import com.tashow.cloud.system.mq.message.sms.SmsSendMessage; + +import java.util.List; +import java.util.Map; + +/** + * 短信发送 Service 接口 + * + * @author 芋道源码 + */ +public interface SmsSendService { + + /** + * 发送单条短信给管理后台的用户 + * + * 在 mobile 为空时,使用 userId 加载对应管理员的手机号 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @return 发送日志编号 + */ + Long sendSingleSmsToAdmin(String mobile, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条短信给用户 APP 的用户 + * + * 在 mobile 为空时,使用 userId 加载对应会员的手机号 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @return 发送日志编号 + */ + Long sendSingleSmsToMember(String mobile, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条短信给用户 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @return 发送日志编号 + */ + Long sendSingleSms(String mobile, Long userId, Integer userType, + String templateCode, Map templateParams); + + default void sendBatchSms(List mobiles, List userIds, Integer userType, + String templateCode, Map templateParams) { + throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!"); + } + + /** + * 执行真正的短信发送 + * 注意,该方法仅仅提供给 MQ Consumer 使用 + * + * @param message 短信 + */ + void doSendSms(SmsSendMessage message); + + /** + * 接收短信的接收结果 + * + * @param channelCode 渠道编码 + * @param text 结果内容 + * @throws Throwable 处理失败时,抛出异常 + */ + void receiveSmsStatus(String channelCode, String text) throws Throwable; + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsSendServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsSendServiceImpl.java new file mode 100644 index 0000000..072d975 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsSendServiceImpl.java @@ -0,0 +1,191 @@ +package com.tashow.cloud.system.service.sms; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.permission.core.annotation.DataPermission; +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsSendRespDTO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsChannelDO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsTemplateDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.mq.message.sms.SmsSendMessage; +import com.tashow.cloud.system.mq.producer.sms.SmsProducer; +import com.tashow.cloud.system.service.member.MemberService; +import com.tashow.cloud.system.service.user.AdminUserService; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 短信发送 Service 发送的实现 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class SmsSendServiceImpl implements SmsSendService { + + @Resource + private AdminUserService adminUserService; + @Resource + private MemberService memberService; + @Resource + private SmsChannelService smsChannelService; + @Resource + private SmsTemplateService smsTemplateService; + @Resource + private SmsLogService smsLogService; + + @Resource + private SmsProducer smsProducer; + + @Override + @DataPermission(enable = false) // 发送短信时,无需考虑数据权限 + public Long sendSingleSmsToAdmin(String mobile, Long userId, String templateCode, Map templateParams) { + // 如果 mobile 为空,则加载用户编号对应的手机号 + if (StrUtil.isEmpty(mobile)) { + AdminUserDO user = adminUserService.getUser(userId); + if (user != null) { + mobile = user.getMobile(); + } + } + // 执行发送 + return sendSingleSms(mobile, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleSmsToMember(String mobile, Long userId, String templateCode, Map templateParams) { + // 如果 mobile 为空,则加载用户编号对应的手机号 + if (StrUtil.isEmpty(mobile)) { + mobile = memberService.getMemberUserMobile(userId); + } + // 执行发送 + return sendSingleSms(mobile, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleSms(String mobile, Long userId, Integer userType, + String templateCode, Map templateParams) { + // 校验短信模板是否合法 + SmsTemplateDO template = validateSmsTemplate(templateCode); + // 校验短信渠道是否合法 + SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId()); + + // 校验手机号码是否存在 + mobile = validateMobile(mobile); + // 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志 + List> newTemplateParams = buildTemplateParams(template, templateParams); + + // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()) + && CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus()); + String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams); + Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams); + + // 发送 MQ 消息,异步执行发送短信 + if (isSend) { + smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), + template.getApiTemplateId(), newTemplateParams); + } + return sendLogId; + } + + @VisibleForTesting + SmsChannelDO validateSmsChannel(Long channelId) { + // 获得短信模板。考虑到效率,从缓存中获取 + SmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId); + // 短信模板不存在 + if (channelDO == null) { + throw exception(ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS); + } + return channelDO; + } + + @VisibleForTesting + SmsTemplateDO validateSmsTemplate(String templateCode) { + // 获得短信模板。考虑到效率,从缓存中获取 + SmsTemplateDO template = smsTemplateService.getSmsTemplateByCodeFromCache(templateCode); + // 短信模板不存在 + if (template == null) { + throw exception(ErrorCodeConstants.SMS_SEND_TEMPLATE_NOT_EXISTS); + } + return template; + } + + /** + * 将参数模板,处理成有序的 KeyValue 数组 + *

+ * 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说 腾讯云 + * + * @param template 短信模板 + * @param templateParams 原始参数 + * @return 处理后的参数 + */ + @VisibleForTesting + List> buildTemplateParams(SmsTemplateDO template, Map templateParams) { + return template.getParams().stream().map(key -> { + Object value = templateParams.get(key); + if (value == null) { + throw exception(ErrorCodeConstants.SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, key); + } + return new KeyValue<>(key, value); + }).collect(Collectors.toList()); + } + + @VisibleForTesting + public String validateMobile(String mobile) { + if (StrUtil.isEmpty(mobile)) { + throw exception(ErrorCodeConstants.SMS_SEND_MOBILE_NOT_EXISTS); + } + return mobile; + } + + @Override + public void doSendSms(SmsSendMessage message) { + // 获得渠道对应的 SmsClient 客户端 + SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId()); + Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId()); + // 发送短信 + try { + SmsSendRespDTO sendResponse = smsClient.sendSms(message.getLogId(), message.getMobile(), + message.getApiTemplateId(), message.getTemplateParams()); + smsLogService.updateSmsSendResult(message.getLogId(), sendResponse.getSuccess(), + sendResponse.getApiCode(), sendResponse.getApiMsg(), + sendResponse.getApiRequestId(), sendResponse.getSerialNo()); + } catch (Throwable ex) { + log.error("[doSendSms][发送短信异常,日志编号({})]", message.getLogId(), ex); + smsLogService.updateSmsSendResult(message.getLogId(), false, + "EXCEPTION", ExceptionUtil.getRootCauseMessage(ex), null, null); + } + } + + @Override + public void receiveSmsStatus(String channelCode, String text) throws Throwable { + // 获得渠道对应的 SmsClient 客户端 + SmsClient smsClient = smsChannelService.getSmsClient(channelCode); + Assert.notNull(smsClient, "短信客户端({}) 不存在", channelCode); + // 解析内容 + List receiveResults = smsClient.parseSmsReceiveStatus(text); + if (CollUtil.isEmpty(receiveResults)) { + return; + } + // 更新短信日志的接收结果. 因为量一般不大,所以先使用 for 循环更新 + receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(result.getLogId(), + result.getSuccess(), result.getReceiveTime(), result.getErrorCode(), result.getErrorMsg())); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsTemplateService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsTemplateService.java new file mode 100644 index 0000000..35d9013 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsTemplateService.java @@ -0,0 +1,84 @@ +package com.tashow.cloud.system.service.sms; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsTemplateDO; + +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO; +import jakarta.validation.Valid; +import java.util.Map; + +/** + * 短信模板 Service 接口 + * + * @author zzf + * @since 2021/1/25 9:24 + */ +public interface SmsTemplateService { + + /** + * 创建短信模板 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSmsTemplate(@Valid SmsTemplateSaveReqVO createReqVO); + + /** + * 更新短信模板 + * + * @param updateReqVO 更新信息 + */ + void updateSmsTemplate(@Valid SmsTemplateSaveReqVO updateReqVO); + + /** + * 删除短信模板 + * + * @param id 编号 + */ + void deleteSmsTemplate(Long id); + + /** + * 获得短信模板 + * + * @param id 编号 + * @return 短信模板 + */ + SmsTemplateDO getSmsTemplate(Long id); + + /** + * 获得短信模板,从缓存中 + * + * @param code 模板编码 + * @return 短信模板 + */ + SmsTemplateDO getSmsTemplateByCodeFromCache(String code); + + /** + * 获得短信模板分页 + * + * @param pageReqVO 分页查询 + * @return 短信模板分页 + */ + PageResult getSmsTemplatePage(SmsTemplatePageReqVO pageReqVO); + + /** + * 获得指定短信渠道下的短信模板数量 + * + * @param channelId 短信渠道编号 + * @return 数量 + */ + Long getSmsTemplateCountByChannelId(Long channelId); + + /** + * 格式化短信内容 + * + * @param content 短信模板的内容 + * @param params 内容的参数 + * @return 格式化后的内容 + */ + String formatSmsTemplateContent(String content, Map params); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsTemplateServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsTemplateServiceImpl.java new file mode 100644 index 0000000..3a9ca9f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/sms/SmsTemplateServiceImpl.java @@ -0,0 +1,204 @@ +package com.tashow.cloud.system.service.sms; + +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import com.tashow.cloud.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsChannelDO; +import com.tashow.cloud.system.dal.dataobject.sms.SmsTemplateDO; +import com.tashow.cloud.system.dal.mysql.sms.SmsTemplateMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import com.tashow.cloud.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.system.framework.sms.core.client.SmsClient; +import com.tashow.cloud.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import com.tashow.cloud.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Pattern; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 短信模板 Service 实现类 + * + * @author zzf + * @since 2021/1/25 9:25 + */ +@Service +@Slf4j +public class SmsTemplateServiceImpl implements SmsTemplateService { + + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + + @Resource + private SmsTemplateMapper smsTemplateMapper; + + @Resource + private SmsChannelService smsChannelService; + + @Override + public Long createSmsTemplate(SmsTemplateSaveReqVO createReqVO) { + // 校验短信渠道 + SmsChannelDO channelDO = validateSmsChannel(createReqVO.getChannelId()); + // 校验短信编码是否重复 + validateSmsTemplateCodeDuplicate(null, createReqVO.getCode()); + // 校验短信模板 + validateApiTemplate(createReqVO.getChannelId(), createReqVO.getApiTemplateId()); + + // 插入 + SmsTemplateDO template = BeanUtils.toBean(createReqVO, SmsTemplateDO.class); + template.setParams(parseTemplateContentParams(template.getContent())); + template.setChannelCode(channelDO.getCode()); + smsTemplateMapper.insert(template); + // 返回 + return template.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.SMS_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 + public void updateSmsTemplate(SmsTemplateSaveReqVO updateReqVO) { + // 校验存在 + validateSmsTemplateExists(updateReqVO.getId()); + // 校验短信渠道 + SmsChannelDO channelDO = validateSmsChannel(updateReqVO.getChannelId()); + // 校验短信编码是否重复 + validateSmsTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode()); + // 校验短信模板 + validateApiTemplate(updateReqVO.getChannelId(), updateReqVO.getApiTemplateId()); + + // 更新 + SmsTemplateDO updateObj = BeanUtils.toBean(updateReqVO, SmsTemplateDO.class); + updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); + updateObj.setChannelCode(channelDO.getCode()); + smsTemplateMapper.updateById(updateObj); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.SMS_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 + public void deleteSmsTemplate(Long id) { + // 校验存在 + validateSmsTemplateExists(id); + // 更新 + smsTemplateMapper.deleteById(id); + } + + private void validateSmsTemplateExists(Long id) { + if (smsTemplateMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.SMS_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public SmsTemplateDO getSmsTemplate(Long id) { + return smsTemplateMapper.selectById(id); + } + + @Override + @Cacheable(cacheNames = RedisKeyConstants.SMS_TEMPLATE, key = "#code", + unless = "#result == null") + public SmsTemplateDO getSmsTemplateByCodeFromCache(String code) { + return smsTemplateMapper.selectByCode(code); + } + + @Override + public PageResult getSmsTemplatePage(SmsTemplatePageReqVO pageReqVO) { + return smsTemplateMapper.selectPage(pageReqVO); + } + + @Override + public Long getSmsTemplateCountByChannelId(Long channelId) { + return smsTemplateMapper.selectCountByChannelId(channelId); + } + + @VisibleForTesting + public SmsChannelDO validateSmsChannel(Long channelId) { + SmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId); + if (channelDO == null) { + throw exception(ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(channelDO.getStatus())) { + throw exception(ErrorCodeConstants.SMS_CHANNEL_DISABLE); + } + return channelDO; + } + + @VisibleForTesting + public void validateSmsTemplateCodeDuplicate(Long id, String code) { + SmsTemplateDO template = smsTemplateMapper.selectByCode(code); + if (template == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(ErrorCodeConstants.SMS_TEMPLATE_CODE_DUPLICATE, code); + } + if (!template.getId().equals(id)) { + throw exception(ErrorCodeConstants.SMS_TEMPLATE_CODE_DUPLICATE, code); + } + } + + /** + * 校验 API 短信平台的模板是否有效 + * + * @param channelId 渠道编号 + * @param apiTemplateId API 模板编号 + */ + @VisibleForTesting + void validateApiTemplate(Long channelId, String apiTemplateId) { + // 获得短信模板 + SmsClient smsClient = smsChannelService.getSmsClient(channelId); + Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId)); + SmsTemplateRespDTO template; + try { + template = smsClient.getSmsTemplate(apiTemplateId); + } catch (Throwable ex) { + throw exception(ErrorCodeConstants.SMS_TEMPLATE_API_ERROR, ExceptionUtil.getRootCauseMessage(ex)); + } + // 校验短信模版 + if (template == null) { + throw exception(ErrorCodeConstants.SMS_TEMPLATE_API_NOT_FOUND); + } + if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.CHECKING.getStatus())) { + throw exception(ErrorCodeConstants.SMS_TEMPLATE_API_AUDIT_CHECKING); + } + if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.FAIL.getStatus())) { + throw exception(ErrorCodeConstants.SMS_TEMPLATE_API_AUDIT_FAIL, template.getAuditReason()); + } + Assert.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), + String.format("短信模板(%s) 审核状态(%d) 不正确", apiTemplateId, template.getAuditStatus())); + } + + @Override + public String formatSmsTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + + @VisibleForTesting + List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialClientService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialClientService.java new file mode 100644 index 0000000..a82c463 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialClientService.java @@ -0,0 +1,140 @@ +package com.tashow.cloud.system.service.social; + +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.systemapi.api.social.dto.SocialWxQrcodeReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialClientDO; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.api.social.dto.SocialWxQrcodeReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.xingyuv.jushauth.model.AuthUser; +import jakarta.validation.Valid; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo; + +import java.util.List; + +/** + * 社交应用 Service 接口 + * + * @author 芋道源码 + */ +public interface SocialClientService { + + /** + * 获得社交平台的授权 URL + * + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param userType 用户类型 + * @param redirectUri 重定向 URL + * @return 社交平台的授权 URL + */ + String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri); + + /** + * 请求社交平台,获得授权的用户 + * + * @param socialType 社交平台的类型 + * @param userType 用户类型 + * @param code 授权码 + * @param state 授权 state + * @return 授权的用户 + */ + AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state); + + // =================== 微信公众号独有 =================== + + /** + * 创建微信公众号的 JS SDK 初始化所需的签名 + * + * @param userType 用户类型 + * @param url 访问的 URL 地址 + * @return 签名 + */ + WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url); + + // =================== 微信小程序独有 =================== + + /** + * 获得微信小程序的手机信息 + * + * @param userType 用户类型 + * @param phoneCode 手机授权码 + * @return 手机信息 + */ + WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode); + + /** + * 获得小程序二维码 + * + * @param reqVO 请求信息 + * @return 小程序二维码 + */ + byte[] getWxaQrcode(SocialWxQrcodeReqDTO reqVO); + + /** + * 获得微信小程订阅模板 + * + * 缓存的目的:考虑到微信小程序订阅消息选择好模版后几乎不会变动,缓存增加查询效率 + * + * @param userType 用户类型 + * @return 微信小程订阅模板 + */ + List getSubscribeTemplateList(Integer userType); + + /** + * 发送微信小程序订阅消息 + * + * @param reqDTO 请求 + * @param templateId 模版编号 + * @param openId 会员 openId + */ + void sendSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO, String templateId, String openId); + + // =================== 客户端管理 =================== + + /** + * 创建社交客户端 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSocialClient(@Valid SocialClientSaveReqVO createReqVO); + + /** + * 更新社交客户端 + * + * @param updateReqVO 更新信息 + */ + void updateSocialClient(@Valid SocialClientSaveReqVO updateReqVO); + + /** + * 删除社交客户端 + * + * @param id 编号 + */ + void deleteSocialClient(Long id); + + /** + * 获得社交客户端 + * + * @param id 编号 + * @return 社交客户端 + */ + SocialClientDO getSocialClient(Long id); + + /** + * 获得社交客户端分页 + * + * @param pageReqVO 分页查询 + * @return 社交客户端分页 + */ + PageResult getSocialClientPage(SocialClientPageReqVO pageReqVO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialClientServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialClientServiceImpl.java new file mode 100644 index 0000000..dba09cb --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialClientServiceImpl.java @@ -0,0 +1,439 @@ +package com.tashow.cloud.system.service.social; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.WxMaSubscribeService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; +import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ReflectUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.cache.CacheUtils; +import com.tashow.cloud.common.util.http.HttpUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.systemapi.api.social.dto.SocialWxQrcodeReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import com.tashow.cloud.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialClientDO; +import com.tashow.cloud.system.dal.mysql.social.SocialClientMapper; +import com.tashow.cloud.system.dal.redis.RedisKeyConstants; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.xingyuv.jushauth.config.AuthConfig; +import com.xingyuv.jushauth.model.AuthCallback; +import com.xingyuv.jushauth.model.AuthResponse; +import com.xingyuv.jushauth.model.AuthUser; +import com.xingyuv.jushauth.request.AuthRequest; +import com.xingyuv.jushauth.utils.AuthStateUtils; +import com.xingyuv.justauth.AuthRequestFactory; +import jakarta.annotation.Resource; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.collection.MapUtils.findAndThen; +import static com.tashow.cloud.common.util.json.JsonUtils.toJsonString; + +/** + * 社交应用 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class SocialClientServiceImpl implements SocialClientService { + + /** + * 小程序码要打开的小程序版本 + * + * 1. release:正式版 + * 2. trial:体验版 + * 3. developer:开发版 + */ + @Value("${yudao.wxa-code.env-version:release}") + public String envVersion; + /** + * 订阅消息跳转小程序类型 + * + * 1. developer:开发版 + * 2. trial:体验版 + * 3. formal:正式版 + */ + @Value("${yudao.wxa-subscribe-message.miniprogram-state:formal}") + public String miniprogramState; + + @Resource + private AuthRequestFactory authRequestFactory; + + @Resource + private WxMpService wxMpService; + @Resource + private WxMpProperties wxMpProperties; + @Resource + private StringRedisTemplate stringRedisTemplate; // WxMpService 需要使用到,所以在 Service 注入了它 + /** + * 缓存 WxMpService 对象 + * + * key:使用微信公众号的 appId + secret 拼接,即 {@link SocialClientDO} 的 clientId 和 clientSecret 属性。 + * 为什么 key 使用这种格式?因为 {@link SocialClientDO} 在管理后台可以变更,通过这个 key 存储它的单例。 + * + * 为什么要做 WxMpService 缓存?因为 WxMpService 构建成本比较大,所以尽量保证它是单例。 + */ + private final LoadingCache wxMpServiceCache = CacheUtils.buildAsyncReloadingCache( + Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public WxMpService load(String key) { + String[] keys = key.split(":"); + return buildWxMpService(keys[0], keys[1]); + } + + }); + + @Resource + private WxMaService wxMaService; + @Resource + private WxMaProperties wxMaProperties; + /** + * 缓存 WxMaService 对象 + * + * 说明同 {@link #wxMpServiceCache} 变量 + */ + private final LoadingCache wxMaServiceCache = CacheUtils.buildAsyncReloadingCache( + Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public WxMaService load(String key) { + String[] keys = key.split(":"); + return buildWxMaService(keys[0], keys[1]); + } + + }); + + @Resource + private SocialClientMapper socialClientMapper; + + @Override + public String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) { + // 获得对应的 AuthRequest 实现 + AuthRequest authRequest = buildAuthRequest(socialType, userType); + // 生成跳转地址 + String authorizeUri = authRequest.authorize(AuthStateUtils.createState()); + return HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri); + } + + @Override + public AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state) { + // 构建请求 + AuthRequest authRequest = buildAuthRequest(socialType, userType); + AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build(); + // 执行请求 + AuthResponse authResponse = authRequest.login(authCallback); + log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType, + toJsonString(authCallback), toJsonString(authResponse)); + if (!authResponse.ok()) { + throw exception(ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg()); + } + return (AuthUser) authResponse.getData(); + } + + /** + * 构建 AuthRequest 对象,支持多租户配置 + * + * @param socialType 社交类型 + * @param userType 用户类型 + * @return AuthRequest 对象 + */ + @VisibleForTesting + AuthRequest buildAuthRequest(Integer socialType, Integer userType) { + // 1. 先查找默认的配置项,从 application-*.yaml 中读取 + AuthRequest request = authRequestFactory.get(SocialTypeEnum.valueOfType(socialType).getSource()); + Assert.notNull(request, String.format("社交平台(%d) 不存在", socialType)); + // 2. 查询 DB 的配置项,如果存在则进行覆盖 + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(socialType, userType); + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + // 2.1 构造新的 AuthConfig 对象 + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(request, "config"); + AuthConfig newAuthConfig = ReflectUtil.newInstance(authConfig.getClass()); + BeanUtil.copyProperties(authConfig, newAuthConfig); + // 2.2 修改对应的 clientId + clientSecret 密钥 + newAuthConfig.setClientId(client.getClientId()); + newAuthConfig.setClientSecret(client.getClientSecret()); + if (client.getAgentId() != null) { // 如果有 agentId 则修改 agentId + newAuthConfig.setAgentId(client.getAgentId()); + } + // 2.3 设置会 request 里,进行后续使用 + ReflectUtil.setFieldValue(request, "config", newAuthConfig); + } + return request; + } + + // =================== 微信公众号独有 =================== + + @Override + @SneakyThrows + public WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url) { + WxMpService service = getWxMpService(userType); + return service.createJsapiSignature(url); + } + + /** + * 获得 clientId + clientSecret 对应的 WxMpService 对象 + * + * @param userType 用户类型 + * @return WxMpService 对象 + */ + @VisibleForTesting + WxMpService getWxMpService(Integer userType) { + // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象 + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( + SocialTypeEnum.WECHAT_MP.getType(), userType); + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + return wxMpServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret()); + } + // 第二步,不存在 DB 配置项,则使用 application-*.yaml 对应的 WxMpService 对象 + return wxMpService; + } + + /** + * 创建 clientId + clientSecret 对应的 WxMpService 对象 + * + * @param clientId 微信公众号 appId + * @param clientSecret 微信公众号 secret + * @return WxMpService 对象 + */ + public WxMpService buildWxMpService(String clientId, String clientSecret) { + // 第一步,创建 WxMpRedisConfigImpl 对象 + WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl( + new RedisTemplateWxRedisOps(stringRedisTemplate), + wxMpProperties.getConfigStorage().getKeyPrefix()); + configStorage.setAppId(clientId); + configStorage.setSecret(clientSecret); + + // 第二步,创建 WxMpService 对象 + WxMpService service = new WxMpServiceImpl(); + service.setWxMpConfigStorage(configStorage); + return service; + } + + // =================== 微信小程序独有 =================== + + @Override + public WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode) { + WxMaService service = getWxMaService(userType); + try { + return service.getUserService().getPhoneNoInfo(phoneCode); + } catch (WxErrorException e) { + log.error("[getPhoneNoInfo][userType({}) phoneCode({}) 获得手机号失败]", userType, phoneCode, e); + throw exception(ErrorCodeConstants.SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR); + } + } + + @Override + public byte[] getWxaQrcode(SocialWxQrcodeReqDTO reqVO) { + WxMaService service = getWxMaService(UserTypeEnum.MEMBER.getValue()); + try { + return service.getQrcodeService().createWxaCodeUnlimitBytes( + ObjUtil.defaultIfEmpty(reqVO.getScene(), SocialWxQrcodeReqDTO.SCENE), + reqVO.getPath(), + ObjUtil.defaultIfNull(reqVO.getCheckPath(), SocialWxQrcodeReqDTO.CHECK_PATH), + envVersion, + ObjUtil.defaultIfNull(reqVO.getWidth(), SocialWxQrcodeReqDTO.WIDTH), + ObjUtil.defaultIfNull(reqVO.getAutoColor(), SocialWxQrcodeReqDTO.AUTO_COLOR), + null, + ObjUtil.defaultIfNull(reqVO.getHyaline(), SocialWxQrcodeReqDTO.HYALINE)); + } catch (WxErrorException e) { + log.error("[getWxQrcode][reqVO({}) 获得小程序码失败]", reqVO, e); + throw exception(ErrorCodeConstants.SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR); + } + } + + @Override + @Cacheable(cacheNames = RedisKeyConstants.WXA_SUBSCRIBE_TEMPLATE, key = "#userType", + unless = "#result == null") + public List getSubscribeTemplateList(Integer userType) { + WxMaService service = getWxMaService(userType); + try { + WxMaSubscribeService subscribeService = service.getSubscribeService(); + return subscribeService.getTemplateList(); + } catch (WxErrorException e) { + log.error("[getSubscribeTemplate][userType({}) 获得小程序订阅消息模版]", userType, e); + throw exception(ErrorCodeConstants.SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR); + } + } + + @Override + public void sendSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO, String templateId, String openId) { + WxMaService service = getWxMaService(reqDTO.getUserType()); + try { + WxMaSubscribeService subscribeService = service.getSubscribeService(); + subscribeService.sendSubscribeMsg(buildMessageSendReqDTO(reqDTO, templateId, openId)); + } catch (WxErrorException e) { + log.error("[sendSubscribeMessage][reqVO({}) templateId({}) openId({}) 发送小程序订阅消息失败]", reqDTO, templateId, openId, e); + throw exception(ErrorCodeConstants.SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR); + } + } + + /** + * 构建发送消息请求参数 + * + * @param reqDTO 请求 + * @param templateId 模版编号 + * @param openId 会员 openId + * @return 微信小程序订阅消息请求参数 + */ + private WxMaSubscribeMessage buildMessageSendReqDTO(SocialWxaSubscribeMessageSendReqDTO reqDTO, + String templateId, String openId) { + // 设置订阅消息基本参数 + WxMaSubscribeMessage subscribeMessage = new WxMaSubscribeMessage().setLang(WxMaConstants.MiniProgramLang.ZH_CN) + .setMiniprogramState(miniprogramState).setTemplateId(templateId).setToUser(openId).setPage(reqDTO.getPage()); + // 设置具体消息参数 + Map messages = reqDTO.getMessages(); + if (CollUtil.isNotEmpty(messages)) { + reqDTO.getMessages().keySet().forEach(key -> findAndThen(messages, key, value -> + subscribeMessage.addData(new WxMaSubscribeMessage.MsgData(key, value)))); + } + return subscribeMessage; + } + + /** + * 获得 clientId + clientSecret 对应的 WxMpService 对象 + * + * @param userType 用户类型 + * @return WxMpService 对象 + */ + @VisibleForTesting + WxMaService getWxMaService(Integer userType) { + // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象 + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( + SocialTypeEnum.WECHAT_MINI_APP.getType(), userType); + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + return wxMaServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret()); + } + // 第二步,不存在 DB 配置项,则使用 application-*.yaml 对应的 WxMaService 对象 + return wxMaService; + } + + /** + * 创建 clientId + clientSecret 对应的 WxMaService 对象 + * + * @param clientId 微信小程序 appId + * @param clientSecret 微信小程序 secret + * @return WxMaService 对象 + */ + private WxMaService buildWxMaService(String clientId, String clientSecret) { + // 第一步,创建 WxMaRedisBetterConfigImpl 对象 + WxMaRedisBetterConfigImpl configStorage = new WxMaRedisBetterConfigImpl( + new RedisTemplateWxRedisOps(stringRedisTemplate), + wxMaProperties.getConfigStorage().getKeyPrefix()); + configStorage.setAppid(clientId); + configStorage.setSecret(clientSecret); + + // 第二步,创建 WxMpService 对象 + WxMaService service = new WxMaServiceImpl(); + service.setWxMaConfig(configStorage); + return service; + } + + // =================== 客户端管理 =================== + + @Override + public Long createSocialClient(SocialClientSaveReqVO createReqVO) { + // 校验重复 + validateSocialClientUnique(null, createReqVO.getUserType(), createReqVO.getSocialType()); + + // 插入 + SocialClientDO client = BeanUtils.toBean(createReqVO, SocialClientDO.class); + socialClientMapper.insert(client); + return client.getId(); + } + + @Override + public void updateSocialClient(SocialClientSaveReqVO updateReqVO) { + // 校验存在 + validateSocialClientExists(updateReqVO.getId()); + // 校验重复 + validateSocialClientUnique(updateReqVO.getId(), updateReqVO.getUserType(), updateReqVO.getSocialType()); + + // 更新 + SocialClientDO updateObj = BeanUtils.toBean(updateReqVO, SocialClientDO.class); + socialClientMapper.updateById(updateObj); + } + + @Override + public void deleteSocialClient(Long id) { + // 校验存在 + validateSocialClientExists(id); + // 删除 + socialClientMapper.deleteById(id); + } + + private void validateSocialClientExists(Long id) { + if (socialClientMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.SOCIAL_CLIENT_NOT_EXISTS); + } + } + + /** + * 校验社交应用是否重复,需要保证 userType + socialType 唯一 + * + * 原因是,不同端(userType)选择某个社交登录(socialType)时,需要通过 {@link #buildAuthRequest(Integer, Integer)} 构建对应的请求 + * + * @param id 编号 + * @param userType 用户类型 + * @param socialType 社交类型 + */ + private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) { + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( + socialType, userType); + if (client == null) { + return; + } + if (id == null // 新增时,说明重复 + || ObjUtil.notEqual(id, client.getId())) { // 更新时,如果 id 不一致,说明重复 + throw exception(ErrorCodeConstants.SOCIAL_CLIENT_UNIQUE); + } + } + + @Override + public SocialClientDO getSocialClient(Long id) { + return socialClientMapper.selectById(id); + } + + @Override + public PageResult getSocialClientPage(SocialClientPageReqVO pageReqVO) { + return socialClientMapper.selectPage(pageReqVO); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialUserService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialUserService.java new file mode 100644 index 0000000..bdd372b --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialUserService.java @@ -0,0 +1,93 @@ +package com.tashow.cloud.system.service.social; + +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserRespDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserDO; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserRespDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * 社交用户 Service 接口,例如说社交平台的授权登录 + * + * @author 芋道源码 + */ +public interface SocialUserService { + + /** + * 获得指定用户的社交用户列表 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 社交用户列表 + */ + List getSocialUserList(Long userId, Integer userType); + + /** + * 绑定社交用户 + * + * @param reqDTO 绑定信息 + * @return 社交用户 openid + */ + String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); + + /** + * 取消绑定社交用户 + * + * @param userId 用户编号 + * @param userType 全局用户类型 + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param openid 社交平台的 openid + */ + void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid); + + /** + * 获得社交用户,基于 userId + * + * @param userType 用户类型 + * @param userId 用户编号 + * @param socialType 社交平台的类型 + * @return 社交用户 + */ + SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType); + + /** + * 获得社交用户 + * + * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 + * + * @param userType 用户类型 + * @param socialType 社交平台的类型 + * @param code 授权码 + * @param state state + * @return 社交用户 + */ + SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state); + + // ==================== 社交用户 CRUD ==================== + + /** + * 获得社交用户 + * + * @param id 编号 + * @return 社交用户 + */ + SocialUserDO getSocialUser(Long id); + + /** + * 获得社交用户分页 + * + * @param pageReqVO 分页查询 + * @return 社交用户分页 + */ + PageResult getSocialUserPage(SocialUserPageReqVO pageReqVO); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialUserServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialUserServiceImpl.java new file mode 100644 index 0000000..0a6b468 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/social/SocialUserServiceImpl.java @@ -0,0 +1,177 @@ +package com.tashow.cloud.system.service.social; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserRespDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserBindDO; +import com.tashow.cloud.system.dal.dataobject.social.SocialUserDO; +import com.tashow.cloud.system.dal.mysql.social.SocialUserBindMapper; +import com.tashow.cloud.system.dal.mysql.social.SocialUserMapper; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserBindReqDTO; +import com.tashow.cloud.systemapi.api.social.dto.SocialUserRespDTO; +import com.tashow.cloud.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.systemapi.enums.social.SocialTypeEnum; +import com.xingyuv.jushauth.model.AuthUser; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotNull; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.util.Collections; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertSet; +import static com.tashow.cloud.common.util.json.JsonUtils.toJsonString; + +/** + * 社交用户 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class SocialUserServiceImpl implements SocialUserService { + + @Resource + private SocialUserBindMapper socialUserBindMapper; + @Resource + private SocialUserMapper socialUserMapper; + + @Resource + private SocialClientService socialClientService; + + @Override + public List getSocialUserList(Long userId, Integer userType) { + // 获得绑定 + List socialUserBinds = socialUserBindMapper.selectListByUserIdAndUserType(userId, userType); + if (CollUtil.isEmpty(socialUserBinds)) { + return Collections.emptyList(); + } + // 获得社交用户 + return socialUserMapper.selectBatchIds(convertSet(socialUserBinds, SocialUserBindDO::getSocialUserId)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String bindSocialUser(SocialUserBindReqDTO reqDTO) { + // 获得社交用户 + SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(), + reqDTO.getCode(), reqDTO.getState()); + Assert.notNull(socialUser, "社交用户不能为空"); + + // 社交用户可能之前绑定过别的用户,需要进行解绑 + socialUserBindMapper.deleteByUserTypeAndSocialUserId(reqDTO.getUserType(), socialUser.getId()); + + // 用户可能之前已经绑定过该社交类型,需要进行解绑 + socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(reqDTO.getUserType(), reqDTO.getUserId(), + socialUser.getType()); + + // 绑定当前登录的社交用户 + SocialUserBindDO socialUserBind = SocialUserBindDO.builder() + .userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) + .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); + socialUserBindMapper.insert(socialUserBind); + return socialUser.getOpenid(); + } + + @Override + public void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid) { + // 获得 openid 对应的 SocialUserDO 社交用户 + SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, openid); + if (socialUser == null) { + throw exception(ErrorCodeConstants.SOCIAL_USER_NOT_FOUND); + } + + // 获得对应的社交绑定关系 + socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(userType, userId, socialUser.getType()); + } + + @Override + public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) { + // 获得绑定用户 + SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserIdAndUserTypeAndSocialType(userId, userType, socialType); + if (socialUserBind == null) { + return null; + } + // 获得社交用户 + SocialUserDO socialUser = socialUserMapper.selectById(socialUserBind.getSocialUserId()); + Assert.notNull(socialUser, "社交用户不能为空"); + return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(), + socialUserBind.getUserId()); + } + + @Override + public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) { + // 获得社交用户 + SocialUserDO socialUser = authSocialUser(socialType, userType, code, state); + Assert.notNull(socialUser, "社交用户不能为空"); + + // 获得绑定用户 + SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, + socialUser.getId()); + return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(), + socialUserBind != null ? socialUserBind.getUserId() : null); + } + + /** + * 授权获得对应的社交用户 + * 如果授权失败,则会抛出 {@link ServiceException} 异常 + * + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param userType 用户类型 + * @param code 授权码 + * @param state state + * @return 授权用户 + */ + @NotNull + public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state) { + // 优先从 DB 中获取,因为 code 有且可以使用一次。 + // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次 + SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(socialType, code, state); + if (socialUser != null) { + return socialUser; + } + + // 请求获取 + AuthUser authUser = socialClientService.getAuthUser(socialType, userType, code, state); + Assert.notNull(authUser, "三方用户不能为空"); + + // 保存到 DB 中 + socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, authUser.getUuid()); + if (socialUser == null) { + socialUser = new SocialUserDO(); + } + socialUser.setType(socialType).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询 + .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken()))) + .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo())); + if (socialUser.getId() == null) { + socialUserMapper.insert(socialUser); + } else { + socialUserMapper.updateById(socialUser); + } + return socialUser; + } + + // ==================== 社交用户 CRUD ==================== + + @Override + public SocialUserDO getSocialUser(Long id) { + return socialUserMapper.selectById(id); + } + + @Override + public PageResult getSocialUserPage(SocialUserPageReqVO pageReqVO) { + return socialUserMapper.selectPage(pageReqVO); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantPackageService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantPackageService.java new file mode 100644 index 0000000..32e5855 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantPackageService.java @@ -0,0 +1,74 @@ +package com.tashow.cloud.system.service.tenant; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantPackageDO; + +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import jakarta.validation.Valid; +import java.util.List; + +/** + * 租户套餐 Service 接口 + * + * @author 芋道源码 + */ +public interface TenantPackageService { + + /** + * 创建租户套餐 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createTenantPackage(@Valid TenantPackageSaveReqVO createReqVO); + + /** + * 更新租户套餐 + * + * @param updateReqVO 更新信息 + */ + void updateTenantPackage(@Valid TenantPackageSaveReqVO updateReqVO); + + /** + * 删除租户套餐 + * + * @param id 编号 + */ + void deleteTenantPackage(Long id); + + /** + * 获得租户套餐 + * + * @param id 编号 + * @return 租户套餐 + */ + TenantPackageDO getTenantPackage(Long id); + + /** + * 获得租户套餐分页 + * + * @param pageReqVO 分页查询 + * @return 租户套餐分页 + */ + PageResult getTenantPackagePage(TenantPackagePageReqVO pageReqVO); + + /** + * 校验租户套餐 + * + * @param id 编号 + * @return 租户套餐 + */ + TenantPackageDO validTenantPackage(Long id); + + /** + * 获得指定状态的租户套餐列表 + * + * @param status 状态 + * @return 租户套餐 + */ + List getTenantPackageListByStatus(Integer status); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantPackageServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantPackageServiceImpl.java new file mode 100644 index 0000000..227c65c --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantPackageServiceImpl.java @@ -0,0 +1,142 @@ +package com.tashow.cloud.system.service.tenant; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantDO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantPackageDO; +import com.tashow.cloud.system.dal.mysql.tenant.TenantPackageMapper; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import com.google.common.annotations.VisibleForTesting; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.List; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.systemapi.enums.ErrorCodeConstants.TENANT_PACKAGE_NAME_DUPLICATE; + +/** + * 租户套餐 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class TenantPackageServiceImpl implements TenantPackageService { + + @Resource + private TenantPackageMapper tenantPackageMapper; + + @Resource + @Lazy // 避免循环依赖的报错 + private TenantService tenantService; + + @Override + public Long createTenantPackage(TenantPackageSaveReqVO createReqVO) { + // 校验套餐名是否重复 + validateTenantPackageNameUnique(null, createReqVO.getName()); + // 插入 + TenantPackageDO tenantPackage = BeanUtils.toBean(createReqVO, TenantPackageDO.class); + tenantPackageMapper.insert(tenantPackage); + // 返回 + return tenantPackage.getId(); + } + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + public void updateTenantPackage(TenantPackageSaveReqVO updateReqVO) { + // 校验存在 + TenantPackageDO tenantPackage = validateTenantPackageExists(updateReqVO.getId()); + // 校验套餐名是否重复 + validateTenantPackageNameUnique(updateReqVO.getId(), updateReqVO.getName()); + // 更新 + TenantPackageDO updateObj = BeanUtils.toBean(updateReqVO, TenantPackageDO.class); + tenantPackageMapper.updateById(updateObj); + // 如果菜单发生变化,则修改每个租户的菜单 + if (!CollUtil.isEqualList(tenantPackage.getMenuIds(), updateReqVO.getMenuIds())) { + List tenants = tenantService.getTenantListByPackageId(tenantPackage.getId()); + tenants.forEach(tenant -> tenantService.updateTenantRoleMenu(tenant.getId(), updateReqVO.getMenuIds())); + } + } + + @Override + public void deleteTenantPackage(Long id) { + // 校验存在 + validateTenantPackageExists(id); + // 校验正在使用 + validateTenantUsed(id); + // 删除 + tenantPackageMapper.deleteById(id); + } + + private TenantPackageDO validateTenantPackageExists(Long id) { + TenantPackageDO tenantPackage = tenantPackageMapper.selectById(id); + if (tenantPackage == null) { + throw exception(ErrorCodeConstants.TENANT_PACKAGE_NOT_EXISTS); + } + return tenantPackage; + } + + private void validateTenantUsed(Long id) { + if (tenantService.getTenantCountByPackageId(id) > 0) { + throw exception(ErrorCodeConstants.TENANT_PACKAGE_USED); + } + } + + @Override + public TenantPackageDO getTenantPackage(Long id) { + return tenantPackageMapper.selectById(id); + } + + @Override + public PageResult getTenantPackagePage(TenantPackagePageReqVO pageReqVO) { + return tenantPackageMapper.selectPage(pageReqVO); + } + + @Override + public TenantPackageDO validTenantPackage(Long id) { + TenantPackageDO tenantPackage = tenantPackageMapper.selectById(id); + if (tenantPackage == null) { + throw exception(ErrorCodeConstants.TENANT_PACKAGE_NOT_EXISTS); + } + if (tenantPackage.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { + throw exception(ErrorCodeConstants.TENANT_PACKAGE_DISABLE, tenantPackage.getName()); + } + return tenantPackage; + } + + @Override + public List getTenantPackageListByStatus(Integer status) { + return tenantPackageMapper.selectListByStatus(status); + } + + + @VisibleForTesting + void validateTenantPackageNameUnique(Long id, String name) { + if (StrUtil.isBlank(name)) { + return; + } + TenantPackageDO tenantPackage = tenantPackageMapper.selectByName(name); + if (tenantPackage == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的用户 + if (id == null) { + throw exception(ErrorCodeConstants.TENANT_PACKAGE_NAME_DUPLICATE); + } + if (!tenantPackage.getId().equals(id)) { + throw exception(ErrorCodeConstants.TENANT_PACKAGE_NAME_DUPLICATE); + } + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantService.java new file mode 100644 index 0000000..353f988 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantService.java @@ -0,0 +1,130 @@ +package com.tashow.cloud.system.service.tenant; + +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantDO; +import com.tashow.cloud.system.service.tenant.handler.TenantInfoHandler; +import com.tashow.cloud.system.service.tenant.handler.TenantMenuHandler; + +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import jakarta.validation.Valid; +import java.util.List; +import java.util.Set; + +/** + * 租户 Service 接口 + * + * @author 芋道源码 + */ +public interface TenantService { + + /** + * 创建租户 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createTenant(@Valid TenantSaveReqVO createReqVO); + + /** + * 更新租户 + * + * @param updateReqVO 更新信息 + */ + void updateTenant(@Valid TenantSaveReqVO updateReqVO); + + /** + * 更新租户的角色菜单 + * + * @param tenantId 租户编号 + * @param menuIds 菜单编号数组 + */ + void updateTenantRoleMenu(Long tenantId, Set menuIds); + + /** + * 删除租户 + * + * @param id 编号 + */ + void deleteTenant(Long id); + + /** + * 获得租户 + * + * @param id 编号 + * @return 租户 + */ + TenantDO getTenant(Long id); + + /** + * 获得租户分页 + * + * @param pageReqVO 分页查询 + * @return 租户分页 + */ + PageResult getTenantPage(TenantPageReqVO pageReqVO); + + /** + * 获得名字对应的租户 + * + * @param name 租户名 + * @return 租户 + */ + TenantDO getTenantByName(String name); + + /** + * 获得域名对应的租户 + * + * @param website 域名 + * @return 租户 + */ + TenantDO getTenantByWebsite(String website); + + /** + * 获得使用指定套餐的租户数量 + * + * @param packageId 租户套餐编号 + * @return 租户数量 + */ + Long getTenantCountByPackageId(Long packageId); + + /** + * 获得使用指定套餐的租户数组 + * + * @param packageId 租户套餐编号 + * @return 租户数组 + */ + List getTenantListByPackageId(Long packageId); + + /** + * 进行租户的信息处理逻辑 + * 其中,租户编号从 {@link TenantContextHolder} 上下文中获取 + * + * @param handler 处理器 + */ + void handleTenantInfo(TenantInfoHandler handler); + + /** + * 进行租户的菜单处理逻辑 + * 其中,租户编号从 {@link TenantContextHolder} 上下文中获取 + * + * @param handler 处理器 + */ + void handleTenantMenu(TenantMenuHandler handler); + + /** + * 获得所有租户 + * + * @return 租户编号数组 + */ + List getTenantIdList(); + + /** + * 校验租户是否合法 + * + * @param id 租户编号 + */ + void validTenant(Long id); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantServiceImpl.java new file mode 100644 index 0000000..5e76ff7 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/TenantServiceImpl.java @@ -0,0 +1,306 @@ +package com.tashow.cloud.system.service.tenant; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.date.DateUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import com.tashow.cloud.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import com.tashow.cloud.system.convert.tenant.TenantConvert; +import com.tashow.cloud.system.dal.dataobject.permission.MenuDO; +import com.tashow.cloud.system.dal.dataobject.permission.RoleDO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantDO; +import com.tashow.cloud.system.dal.dataobject.tenant.TenantPackageDO; +import com.tashow.cloud.system.dal.mysql.tenant.TenantMapper; +import com.tashow.cloud.systemapi.enums.permission.RoleCodeEnum; +import com.tashow.cloud.systemapi.enums.permission.RoleTypeEnum; +import com.tashow.cloud.system.service.permission.MenuService; +import com.tashow.cloud.system.service.permission.PermissionService; +import com.tashow.cloud.system.service.permission.RoleService; +import com.tashow.cloud.system.service.tenant.handler.TenantInfoHandler; +import com.tashow.cloud.system.service.tenant.handler.TenantMenuHandler; +import com.tashow.cloud.system.service.user.AdminUserService; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.tenant.config.TenantProperties; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.util.TenantUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static java.util.Collections.singleton; + +/** + * 租户 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class TenantServiceImpl implements TenantService { + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired(required = false) // 由于 yudao.tenant.enable 配置项,可以关闭多租户的功能,所以这里只能不强制注入 + private TenantProperties tenantProperties; + + @Resource + private TenantMapper tenantMapper; + + @Resource + private TenantPackageService tenantPackageService; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private AdminUserService userService; + @Resource + private RoleService roleService; + @Resource + private MenuService menuService; + @Resource + private PermissionService permissionService; + + @Override + public List getTenantIdList() { + List tenants = tenantMapper.selectList(); + return CollectionUtils.convertList(tenants, TenantDO::getId); + } + + @Override + public void validTenant(Long id) { + TenantDO tenant = getTenant(id); + if (tenant == null) { + throw exception(ErrorCodeConstants.TENANT_NOT_EXISTS); + } + if (tenant.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { + throw exception(ErrorCodeConstants.TENANT_DISABLE, tenant.getName()); + } + if (DateUtils.isExpired(tenant.getExpireTime())) { + throw exception(ErrorCodeConstants.TENANT_EXPIRE, tenant.getName()); + } + } + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + public Long createTenant(TenantSaveReqVO createReqVO) { + // 校验租户名称是否重复 + validTenantNameDuplicate(createReqVO.getName(), null); + // 校验租户域名是否重复 + validTenantWebsiteDuplicate(createReqVO.getWebsite(), null); + // 校验套餐被禁用 + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId()); + + // 创建租户 + TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class); + tenantMapper.insert(tenant); + // 创建租户的管理员 + TenantUtils.execute(tenant.getId(), () -> { + // 创建角色 + Long roleId = createRole(tenantPackage); + // 创建用户,并分配角色 + Long userId = createUser(roleId, createReqVO); + // 修改租户的管理员 + tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId)); + }); + return tenant.getId(); + } + + private Long createUser(Long roleId, TenantSaveReqVO createReqVO) { + // 创建用户 + Long userId = userService.createUser(TenantConvert.INSTANCE.convert02(createReqVO)); + // 分配角色 + permissionService.assignUserRole(userId, singleton(roleId)); + return userId; + } + + private Long createRole(TenantPackageDO tenantPackage) { + // 创建角色 + RoleSaveReqVO reqVO = new RoleSaveReqVO(); + reqVO.setName(RoleCodeEnum.TENANT_ADMIN.getName()).setCode(RoleCodeEnum.TENANT_ADMIN.getCode()) + .setSort(0).setRemark("系统自动生成"); + Long roleId = roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType()); + // 分配权限 + permissionService.assignRoleMenu(roleId, tenantPackage.getMenuIds()); + return roleId; + } + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + public void updateTenant(TenantSaveReqVO updateReqVO) { + // 校验存在 + TenantDO tenant = validateUpdateTenant(updateReqVO.getId()); + // 校验租户名称是否重复 + validTenantNameDuplicate(updateReqVO.getName(), updateReqVO.getId()); + // 校验租户域名是否重复 + validTenantWebsiteDuplicate(updateReqVO.getWebsite(), updateReqVO.getId()); + // 校验套餐被禁用 + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); + + // 更新租户 + TenantDO updateObj = BeanUtils.toBean(updateReqVO, TenantDO.class); + tenantMapper.updateById(updateObj); + // 如果套餐发生变化,则修改其角色的权限 + if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) { + updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds()); + } + } + + private void validTenantNameDuplicate(String name, Long id) { + TenantDO tenant = tenantMapper.selectByName(name); + if (tenant == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同名字的租户 + if (id == null) { + throw exception(ErrorCodeConstants.TENANT_NAME_DUPLICATE, name); + } + if (!tenant.getId().equals(id)) { + throw exception(ErrorCodeConstants.TENANT_NAME_DUPLICATE, name); + } + } + + private void validTenantWebsiteDuplicate(String website, Long id) { + if (StrUtil.isEmpty(website)) { + return; + } + TenantDO tenant = tenantMapper.selectByWebsite(website); + if (tenant == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同名字的租户 + if (id == null) { + throw exception(ErrorCodeConstants.TENANT_WEBSITE_DUPLICATE, website); + } + if (!tenant.getId().equals(id)) { + throw exception(ErrorCodeConstants.TENANT_WEBSITE_DUPLICATE, website); + } + } + + @Override + @DSTransactional + public void updateTenantRoleMenu(Long tenantId, Set menuIds) { + TenantUtils.execute(tenantId, () -> { + // 获得所有角色 + List roles = roleService.getRoleList(); + roles.forEach(role -> Assert.isTrue(tenantId.equals(role.getTenantId()), "角色({}/{}) 租户不匹配", + role.getId(), role.getTenantId(), tenantId)); // 兜底校验 + // 重新分配每个角色的权限 + roles.forEach(role -> { + // 如果是租户管理员,重新分配其权限为租户套餐的权限 + if (Objects.equals(role.getCode(), RoleCodeEnum.TENANT_ADMIN.getCode())) { + permissionService.assignRoleMenu(role.getId(), menuIds); + log.info("[updateTenantRoleMenu][租户管理员({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), menuIds); + return; + } + // 如果是其他角色,则去掉超过套餐的权限 + Set roleMenuIds = permissionService.getRoleMenuListByRoleId(role.getId()); + roleMenuIds = CollUtil.intersectionDistinct(roleMenuIds, menuIds); + permissionService.assignRoleMenu(role.getId(), roleMenuIds); + log.info("[updateTenantRoleMenu][角色({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), roleMenuIds); + }); + }); + } + + @Override + public void deleteTenant(Long id) { + // 校验存在 + validateUpdateTenant(id); + // 删除 + tenantMapper.deleteById(id); + } + + private TenantDO validateUpdateTenant(Long id) { + TenantDO tenant = tenantMapper.selectById(id); + if (tenant == null) { + throw exception(ErrorCodeConstants.TENANT_NOT_EXISTS); + } + // 内置租户,不允许删除 + if (isSystemTenant(tenant)) { + throw exception(ErrorCodeConstants.TENANT_CAN_NOT_UPDATE_SYSTEM); + } + return tenant; + } + + @Override + public TenantDO getTenant(Long id) { + return tenantMapper.selectById(id); + } + + @Override + public PageResult getTenantPage(TenantPageReqVO pageReqVO) { + return tenantMapper.selectPage(pageReqVO); + } + + @Override + public TenantDO getTenantByName(String name) { + return tenantMapper.selectByName(name); + } + + @Override + public TenantDO getTenantByWebsite(String website) { + return tenantMapper.selectByWebsite(website); + } + + @Override + public Long getTenantCountByPackageId(Long packageId) { + return tenantMapper.selectCountByPackageId(packageId); + } + + @Override + public List getTenantListByPackageId(Long packageId) { + return tenantMapper.selectListByPackageId(packageId); + } + + @Override + public void handleTenantInfo(TenantInfoHandler handler) { + // 如果禁用,则不执行逻辑 + if (isTenantDisable()) { + return; + } + // 获得租户 + TenantDO tenant = getTenant(TenantContextHolder.getRequiredTenantId()); + // 执行处理器 + handler.handle(tenant); + } + + @Override + public void handleTenantMenu(TenantMenuHandler handler) { + // 如果禁用,则不执行逻辑 + if (isTenantDisable()) { + return; + } + // 获得租户,然后获得菜单 + TenantDO tenant = getTenant(TenantContextHolder.getRequiredTenantId()); + Set menuIds; + if (isSystemTenant(tenant)) { // 系统租户,菜单是全量的 + menuIds = CollectionUtils.convertSet(menuService.getMenuList(), MenuDO::getId); + } else { + menuIds = tenantPackageService.getTenantPackage(tenant.getPackageId()).getMenuIds(); + } + // 执行处理器 + handler.handle(menuIds); + } + + private static boolean isSystemTenant(TenantDO tenant) { + return Objects.equals(tenant.getPackageId(), TenantDO.PACKAGE_ID_SYSTEM); + } + + private boolean isTenantDisable() { + return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable()); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/handler/TenantInfoHandler.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/handler/TenantInfoHandler.java new file mode 100644 index 0000000..4d6c689 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/handler/TenantInfoHandler.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.system.service.tenant.handler; + +import com.tashow.cloud.system.dal.dataobject.tenant.TenantDO; + +/** + * 租户信息处理 + * 目的:尽量减少租户逻辑耦合到系统中 + * + * @author 芋道源码 + */ +public interface TenantInfoHandler { + + /** + * 基于传入的租户信息,进行相关逻辑的执行 + * 例如说,创建用户时,超过最大账户配额 + * + * @param tenant 租户信息 + */ + void handle(TenantDO tenant); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/handler/TenantMenuHandler.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/handler/TenantMenuHandler.java new file mode 100644 index 0000000..e06aad9 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/tenant/handler/TenantMenuHandler.java @@ -0,0 +1,21 @@ +package com.tashow.cloud.system.service.tenant.handler; + +import java.util.Set; + +/** + * 租户菜单处理 + * 目的:尽量减少租户逻辑耦合到系统中 + * + * @author 芋道源码 + */ +public interface TenantMenuHandler { + + /** + * 基于传入的租户菜单【全】列表,进行相关逻辑的执行 + * 例如说,返回可分配菜单的时候,可以移除多余的 + * + * @param menuIds 菜单列表 + */ + void handle(Set menuIds); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/user/AdminUserService.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/user/AdminUserService.java new file mode 100644 index 0000000..3797715 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/user/AdminUserService.java @@ -0,0 +1,226 @@ +package com.tashow.cloud.system.service.user; + +import cn.hutool.core.collection.CollUtil; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthRegisterReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserImportExcelVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserImportRespVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserPageReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthRegisterReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserImportExcelVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserImportRespVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserPageReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserSaveReqVO; +import jakarta.validation.Valid; + +import java.io.InputStream; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 后台用户 Service 接口 + * + * @author 芋道源码 + */ +public interface AdminUserService { + + /** + * 创建用户 + * + * @param createReqVO 用户信息 + * @return 用户编号 + */ + Long createUser(@Valid UserSaveReqVO createReqVO); + + /** + * 注册用户 + * + * @param registerReqVO 用户信息 + * @return 用户编号 + */ + Long registerUser(@Valid AuthRegisterReqVO registerReqVO); + + /** + * 修改用户 + * + * @param updateReqVO 用户信息 + */ + void updateUser(@Valid UserSaveReqVO updateReqVO); + + /** + * 更新用户的最后登陆信息 + * + * @param id 用户编号 + * @param loginIp 登陆 IP + */ + void updateUserLogin(Long id, String loginIp); + + /** + * 修改用户个人信息 + * + * @param id 用户编号 + * @param reqVO 用户个人信息 + */ + void updateUserProfile(Long id, @Valid UserProfileUpdateReqVO reqVO); + + /** + * 修改用户个人密码 + * + * @param id 用户编号 + * @param reqVO 更新用户个人密码 + */ + void updateUserPassword(Long id, @Valid UserProfileUpdatePasswordReqVO reqVO); + + /** + * 更新用户头像 + * + * @param id 用户 id + * @param avatarFile 头像文件 + */ + String updateUserAvatar(Long id, InputStream avatarFile) throws Exception; + + /** + * 修改密码 + * + * @param id 用户编号 + * @param password 密码 + */ + void updateUserPassword(Long id, String password); + + /** + * 修改状态 + * + * @param id 用户编号 + * @param status 状态 + */ + void updateUserStatus(Long id, Integer status); + + /** + * 删除用户 + * + * @param id 用户编号 + */ + void deleteUser(Long id); + + /** + * 通过用户名查询用户 + * + * @param username 用户名 + * @return 用户对象信息 + */ + AdminUserDO getUserByUsername(String username); + + /** + * 通过手机号获取用户 + * + * @param mobile 手机号 + * @return 用户对象信息 + */ + AdminUserDO getUserByMobile(String mobile); + + /** + * 获得用户分页列表 + * + * @param reqVO 分页条件 + * @return 分页列表 + */ + PageResult getUserPage(UserPageReqVO reqVO); + + /** + * 通过用户 ID 查询用户 + * + * @param id 用户ID + * @return 用户对象信息 + */ + AdminUserDO getUser(Long id); + + /** + * 获得指定部门的用户数组 + * + * @param deptIds 部门数组 + * @return 用户数组 + */ + List getUserListByDeptIds(Collection deptIds); + + /** + * 获得指定岗位的用户数组 + * + * @param postIds 岗位数组 + * @return 用户数组 + */ + List getUserListByPostIds(Collection postIds); + + /** + * 获得用户列表 + * + * @param ids 用户编号数组 + * @return 用户列表 + */ + List getUserList(Collection ids); + + /** + * 校验用户们是否有效。如下情况,视为无效: + * 1. 用户编号不存在 + * 2. 用户被禁用 + * + * @param ids 用户编号数组 + */ + void validateUserList(Collection ids); + + /** + * 获得用户 Map + * + * @param ids 用户编号数组 + * @return 用户 Map + */ + default Map getUserMap(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return new HashMap<>(); + } + return CollectionUtils.convertMap(getUserList(ids), AdminUserDO::getId); + } + + /** + * 获得用户列表,基于昵称模糊匹配 + * + * @param nickname 昵称 + * @return 用户列表 + */ + List getUserListByNickname(String nickname); + + /** + * 批量导入用户 + * + * @param importUsers 导入用户列表 + * @param isUpdateSupport 是否支持更新 + * @return 导入结果 + */ + UserImportRespVO importUserList(List importUsers, boolean isUpdateSupport); + + /** + * 获得指定状态的用户们 + * + * @param status 状态 + * @return 用户们 + */ + List getUserListByStatus(Integer status); + + /** + * 判断密码是否匹配 + * + * @param rawPassword 未加密的密码 + * @param encodedPassword 加密后的密码 + * @return 是否匹配 + */ + boolean isPasswordMatch(String rawPassword, String encodedPassword); + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/user/AdminUserServiceImpl.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/user/AdminUserServiceImpl.java new file mode 100644 index 0000000..e54f141 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/service/user/AdminUserServiceImpl.java @@ -0,0 +1,531 @@ +package com.tashow.cloud.system.service.user; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.enums.CommonStatusEnum; +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.object.BeanUtils; +import com.tashow.cloud.common.util.validation.ValidationUtils; +import com.tashow.cloud.infraapi.api.config.ConfigApi; +import com.tashow.cloud.infraapi.api.file.FileApi; +import com.tashow.cloud.permission.core.util.DataPermissionUtils; +import com.tashow.cloud.system.controller.admin.auth.vo.AuthRegisterReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserImportExcelVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserImportRespVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserPageReqVO; +import com.tashow.cloud.system.controller.admin.user.vo.user.UserSaveReqVO; +import com.tashow.cloud.system.dal.dataobject.dept.DeptDO; +import com.tashow.cloud.system.dal.dataobject.dept.UserPostDO; +import com.tashow.cloud.system.dal.dataobject.user.AdminUserDO; +import com.tashow.cloud.system.dal.mysql.dept.UserPostMapper; +import com.tashow.cloud.system.dal.mysql.user.AdminUserMapper; +import com.tashow.cloud.system.service.dept.DeptService; +import com.tashow.cloud.system.service.dept.PostService; +import com.tashow.cloud.system.service.permission.PermissionService; +import com.tashow.cloud.system.service.tenant.TenantService; +import com.google.common.annotations.VisibleForTesting; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import com.tashow.cloud.systemapi.enums.ErrorCodeConstants; +import com.tashow.cloud.systemapi.enums.LogRecordConstants; +import jakarta.annotation.Resource; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.InputStream; +import java.time.LocalDateTime; +import java.util.*; + +import static com.tashow.cloud.common.exception.util.ServiceExceptionUtil.exception; +import static com.tashow.cloud.common.util.collection.CollectionUtils.*; + +/** + * 后台用户 Service 实现类 + * + * @author 芋道源码 + */ +@Service("adminUserService") +@Slf4j +public class AdminUserServiceImpl implements AdminUserService { + + static final String USER_INIT_PASSWORD_KEY = "system.user.init-password"; + + @Resource + private AdminUserMapper userMapper; + + @Resource + private DeptService deptService; + @Resource + private PostService postService; + @Resource + private PermissionService permissionService; + @Resource + private PasswordEncoder passwordEncoder; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private TenantService tenantService; + + @Resource + private UserPostMapper userPostMapper; + + @Resource + private FileApi fileApi; + @Resource + private ConfigApi configApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = LogRecordConstants.SYSTEM_USER_TYPE, subType = LogRecordConstants.SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}", + success = LogRecordConstants.SYSTEM_USER_CREATE_SUCCESS) + public Long createUser(UserSaveReqVO createReqVO) { + // 1.1 校验账户配合 + tenantService.handleTenantInfo(tenant -> { + long count = userMapper.selectCount(); + if (count >= tenant.getAccountCount()) { + throw exception(ErrorCodeConstants.USER_COUNT_MAX, tenant.getAccountCount()); + } + }); + // 1.2 校验正确性 + validateUserForCreateOrUpdate(null, createReqVO.getUsername(), + createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds()); + // 2.1 插入用户 + AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class); + user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 + user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码 + userMapper.insert(user); + // 2.2 插入关联岗位 + if (CollectionUtil.isNotEmpty(user.getPostIds())) { + userPostMapper.insertBatch(convertList(user.getPostIds(), + postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId))); + } + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("user", user); + return user.getId(); + } + + @Override + public Long registerUser(AuthRegisterReqVO registerReqVO) { + // 1.1 校验账户配合 + tenantService.handleTenantInfo(tenant -> { + long count = userMapper.selectCount(); + if (count >= tenant.getAccountCount()) { + throw exception(ErrorCodeConstants.USER_COUNT_MAX, tenant.getAccountCount()); + } + }); + // 1.2 校验正确性 + validateUserForCreateOrUpdate(null, registerReqVO.getUsername(), null, null, null, null); + + // 2. 插入用户 + AdminUserDO user = BeanUtils.toBean(registerReqVO, AdminUserDO.class); + user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 + user.setPassword(encodePassword(registerReqVO.getPassword())); // 加密密码 + userMapper.insert(user); + return user.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = LogRecordConstants.SYSTEM_USER_TYPE, subType = LogRecordConstants.SYSTEM_USER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = LogRecordConstants.SYSTEM_USER_UPDATE_SUCCESS) + public void updateUser(UserSaveReqVO updateReqVO) { + updateReqVO.setPassword(null); // 特殊:此处不更新密码 + // 1. 校验正确性 + AdminUserDO oldUser = validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(), + updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds()); + + // 2.1 更新用户 + AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class); + userMapper.updateById(updateObj); + // 2.2 更新岗位 + updateUserPost(updateReqVO, updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class)); + LogRecordContext.putVariable("user", oldUser); + } + + private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) { + Long userId = reqVO.getId(); + Set dbPostIds = convertSet(userPostMapper.selectListByUserId(userId), UserPostDO::getPostId); + // 计算新增和删除的岗位编号 + Set postIds = CollUtil.emptyIfNull(updateObj.getPostIds()); + Collection createPostIds = CollUtil.subtract(postIds, dbPostIds); + Collection deletePostIds = CollUtil.subtract(dbPostIds, postIds); + // 执行新增和删除。对于已经授权的岗位,不用做任何处理 + if (!CollectionUtil.isEmpty(createPostIds)) { + userPostMapper.insertBatch(convertList(createPostIds, + postId -> new UserPostDO().setUserId(userId).setPostId(postId))); + } + if (!CollectionUtil.isEmpty(deletePostIds)) { + userPostMapper.deleteByUserIdAndPostId(userId, deletePostIds); + } + } + + @Override + public void updateUserLogin(Long id, String loginIp) { + userMapper.updateById(new AdminUserDO().setId(id).setLoginIp(loginIp).setLoginDate(LocalDateTime.now())); + } + + @Override + public void updateUserProfile(Long id, UserProfileUpdateReqVO reqVO) { + // 校验正确性 + validateUserExists(id); + validateEmailUnique(id, reqVO.getEmail()); + validateMobileUnique(id, reqVO.getMobile()); + // 执行更新 + userMapper.updateById(BeanUtils.toBean(reqVO, AdminUserDO.class).setId(id)); + } + + @Override + public void updateUserPassword(Long id, UserProfileUpdatePasswordReqVO reqVO) { + // 校验旧密码密码 + validateOldPassword(id, reqVO.getOldPassword()); + // 执行更新 + AdminUserDO updateObj = new AdminUserDO().setId(id); + updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码 + userMapper.updateById(updateObj); + } + + @Override + public String updateUserAvatar(Long id, InputStream avatarFile) { + validateUserExists(id); + // 存储文件 + String avatar = fileApi.createFile(IoUtil.readBytes(avatarFile)); + // 更新路径 + AdminUserDO sysUserDO = new AdminUserDO(); + sysUserDO.setId(id); + sysUserDO.setAvatar(avatar); + userMapper.updateById(sysUserDO); + return avatar; + } + + @Override + @LogRecord(type = LogRecordConstants.SYSTEM_USER_TYPE, subType = LogRecordConstants.SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE, bizNo = "{{#id}}", + success = LogRecordConstants.SYSTEM_USER_UPDATE_PASSWORD_SUCCESS) + public void updateUserPassword(Long id, String password) { + // 1. 校验用户存在 + AdminUserDO user = validateUserExists(id); + + // 2. 更新密码 + AdminUserDO updateObj = new AdminUserDO(); + updateObj.setId(id); + updateObj.setPassword(encodePassword(password)); // 加密密码 + userMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("user", user); + LogRecordContext.putVariable("newPassword", updateObj.getPassword()); + } + + @Override + public void updateUserStatus(Long id, Integer status) { + // 校验用户存在 + validateUserExists(id); + // 更新状态 + AdminUserDO updateObj = new AdminUserDO(); + updateObj.setId(id); + updateObj.setStatus(status); + userMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = LogRecordConstants.SYSTEM_USER_TYPE, subType = LogRecordConstants.SYSTEM_USER_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = LogRecordConstants.SYSTEM_USER_DELETE_SUCCESS) + public void deleteUser(Long id) { + // 1. 校验用户存在 + AdminUserDO user = validateUserExists(id); + + // 2.1 删除用户 + userMapper.deleteById(id); + // 2.2 删除用户关联数据 + permissionService.processUserDeleted(id); + // 2.2 删除用户岗位 + userPostMapper.deleteByUserId(id); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("user", user); + } + + @Override + public AdminUserDO getUserByUsername(String username) { + return userMapper.selectByUsername(username); + } + + @Override + public AdminUserDO getUserByMobile(String mobile) { + return userMapper.selectByMobile(mobile); + } + + @Override + public PageResult getUserPage(UserPageReqVO reqVO) { + // 如果有角色编号,查询角色对应的用户编号 + Set userIds = reqVO.getRoleId() != null ? + permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId())) : null; + + // 分页查询 + return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId()), userIds); + } + + @Override + public AdminUserDO getUser(Long id) { + return userMapper.selectById(id); + } + + @Override + public List getUserListByDeptIds(Collection deptIds) { + if (CollUtil.isEmpty(deptIds)) { + return Collections.emptyList(); + } + return userMapper.selectListByDeptIds(deptIds); + } + + @Override + public List getUserListByPostIds(Collection postIds) { + if (CollUtil.isEmpty(postIds)) { + return Collections.emptyList(); + } + Set userIds = convertSet(userPostMapper.selectListByPostIds(postIds), UserPostDO::getUserId); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + return userMapper.selectBatchIds(userIds); + } + + @Override + public List getUserList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return userMapper.selectBatchIds(ids); + } + + @Override + public void validateUserList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得岗位信息 + List users = userMapper.selectBatchIds(ids); + Map userMap = CollectionUtils.convertMap(users, AdminUserDO::getId); + // 校验 + ids.forEach(id -> { + AdminUserDO user = userMap.get(id); + if (user == null) { + throw exception(ErrorCodeConstants.USER_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus())) { + throw exception(ErrorCodeConstants.USER_IS_DISABLE, user.getNickname()); + } + }); + } + + @Override + public List getUserListByNickname(String nickname) { + return userMapper.selectListByNickname(nickname); + } + + /** + * 获得部门条件:查询指定部门的子部门编号们,包括自身 + * + * @param deptId 部门编号 + * @return 部门编号集合 + */ + private Set getDeptCondition(Long deptId) { + if (deptId == null) { + return Collections.emptySet(); + } + Set deptIds = convertSet(deptService.getChildDeptList(deptId), DeptDO::getId); + deptIds.add(deptId); // 包括自身 + return deptIds; + } + + private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String mobile, String email, + Long deptId, Set postIds) { + // 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确 + return DataPermissionUtils.executeIgnore(() -> { + // 校验用户存在 + AdminUserDO user = validateUserExists(id); + // 校验用户名唯一 + validateUsernameUnique(id, username); + // 校验手机号唯一 + validateMobileUnique(id, mobile); + // 校验邮箱唯一 + validateEmailUnique(id, email); + // 校验部门处于开启状态 + deptService.validateDeptList(singleton(deptId)); + // 校验岗位处于开启状态 + postService.validatePostList(postIds); + return user; + }); + } + + @VisibleForTesting + AdminUserDO validateUserExists(Long id) { + if (id == null) { + return null; + } + AdminUserDO user = userMapper.selectById(id); + if (user == null) { + throw exception(ErrorCodeConstants.USER_NOT_EXISTS); + } + return user; + } + + @VisibleForTesting + void validateUsernameUnique(Long id, String username) { + if (StrUtil.isBlank(username)) { + return; + } + AdminUserDO user = userMapper.selectByUsername(username); + if (user == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的用户 + if (id == null) { + throw exception(ErrorCodeConstants.USER_USERNAME_EXISTS); + } + if (!user.getId().equals(id)) { + throw exception(ErrorCodeConstants.USER_USERNAME_EXISTS); + } + } + + @VisibleForTesting + void validateEmailUnique(Long id, String email) { + if (StrUtil.isBlank(email)) { + return; + } + AdminUserDO user = userMapper.selectByEmail(email); + if (user == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的用户 + if (id == null) { + throw exception(ErrorCodeConstants.USER_EMAIL_EXISTS); + } + if (!user.getId().equals(id)) { + throw exception(ErrorCodeConstants.USER_EMAIL_EXISTS); + } + } + + @VisibleForTesting + void validateMobileUnique(Long id, String mobile) { + if (StrUtil.isBlank(mobile)) { + return; + } + AdminUserDO user = userMapper.selectByMobile(mobile); + if (user == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的用户 + if (id == null) { + throw exception(ErrorCodeConstants.USER_MOBILE_EXISTS); + } + if (!user.getId().equals(id)) { + throw exception(ErrorCodeConstants.USER_MOBILE_EXISTS); + } + } + + /** + * 校验旧密码 + * @param id 用户 id + * @param oldPassword 旧密码 + */ + @VisibleForTesting + void validateOldPassword(Long id, String oldPassword) { + AdminUserDO user = userMapper.selectById(id); + if (user == null) { + throw exception(ErrorCodeConstants.USER_NOT_EXISTS); + } + if (!isPasswordMatch(oldPassword, user.getPassword())) { + throw exception(ErrorCodeConstants.USER_PASSWORD_FAILED); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入 + public UserImportRespVO importUserList(List importUsers, boolean isUpdateSupport) { + // 1.1 参数校验 + if (CollUtil.isEmpty(importUsers)) { + throw exception(ErrorCodeConstants.USER_IMPORT_LIST_IS_EMPTY); + } + // 1.2 初始化密码不能为空 + String initPassword = configApi.getConfigValueByKey(USER_INIT_PASSWORD_KEY).getCheckedData(); + if (StrUtil.isEmpty(initPassword)) { + throw exception(ErrorCodeConstants.USER_IMPORT_INIT_PASSWORD); + } + + // 2. 遍历,逐个创建 or 更新 + UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>()) + .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build(); + importUsers.forEach(importUser -> { + // 2.1.1 校验字段是否符合要求 + try { + ValidationUtils.validate(BeanUtils.toBean(importUser, UserSaveReqVO.class).setPassword(initPassword)); + } catch (ConstraintViolationException ex){ + respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage()); + return; + } + // 2.1.2 校验,判断是否有不符合的原因 + try { + validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(), + importUser.getDeptId(), null); + } catch (ServiceException ex) { + respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage()); + return; + } + + // 2.2.1 判断如果不存在,在进行插入 + AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername()); + if (existUser == null) { + userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class) + .setPassword(encodePassword(initPassword)).setPostIds(new HashSet<>())); // 设置默认密码及空岗位编号数组 + respVO.getCreateUsernames().add(importUser.getUsername()); + return; + } + // 2.2.2 如果存在,判断是否允许更新 + if (!isUpdateSupport) { + respVO.getFailureUsernames().put(importUser.getUsername(), ErrorCodeConstants.USER_USERNAME_EXISTS.getMsg()); + return; + } + AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class); + updateUser.setId(existUser.getId()); + userMapper.updateById(updateUser); + respVO.getUpdateUsernames().add(importUser.getUsername()); + }); + return respVO; + } + + @Override + public List getUserListByStatus(Integer status) { + return userMapper.selectListByStatus(status); + } + + @Override + public boolean isPasswordMatch(String rawPassword, String encodedPassword) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + /** + * 对密码进行加密 + * + * @param password 密码 + * @return 加密后的密码 + */ + private String encodePassword(String password) { + return passwordEncoder.encode(password); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/util/oauth2/OAuth2Utils.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/util/oauth2/OAuth2Utils.java new file mode 100644 index 0000000..cf291ab --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/util/oauth2/OAuth2Utils.java @@ -0,0 +1,103 @@ +package com.tashow.cloud.system.util.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.StrUtil; +import com.tashow.cloud.common.util.http.HttpUtils; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.*; + +/** + * OAuth2 相关的工具类 + * + * @author 芋道源码 + */ +public class OAuth2Utils { + + /** + * 构建授权码模式下,重定向的 URI + * + * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 getSuccessfulRedirect 方法 + * + * @param redirectUri 重定向 URI + * @param authorizationCode 授权码 + * @param state 状态 + * @return 授权码模式下的重定向 URI + */ + public static String buildAuthorizationCodeRedirectUri(String redirectUri, String authorizationCode, String state) { + Map query = new LinkedHashMap<>(); + query.put("code", authorizationCode); + if (state != null) { + query.put("state", state); + } + return HttpUtils.append(redirectUri, query, null, false); + } + + /** + * 构建简化模式下,重定向的 URI + * + * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 appendAccessToken 方法 + * + * @param redirectUri 重定向 URI + * @param accessToken 访问令牌 + * @param state 状态 + * @param expireTime 过期时间 + * @param scopes 授权范围 + * @param additionalInformation 附加信息 + * @return 简化授权模式下的重定向 URI + */ + public static String buildImplicitRedirectUri(String redirectUri, String accessToken, String state, LocalDateTime expireTime, + Collection scopes, Map additionalInformation) { + Map vars = new LinkedHashMap(); + Map keys = new HashMap(); + vars.put("access_token", accessToken); + vars.put("token_type", SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase()); + if (state != null) { + vars.put("state", state); + } + if (expireTime != null) { + vars.put("expires_in", getExpiresIn(expireTime)); + } + if (CollUtil.isNotEmpty(scopes)) { + vars.put("scope", buildScopeStr(scopes)); + } + if (CollUtil.isNotEmpty(additionalInformation)) { + for (String key : additionalInformation.keySet()) { + Object value = additionalInformation.get(key); + if (value != null) { + keys.put("extra_" + key, key); + vars.put("extra_" + key, value); + } + } + } + // Do not include the refresh token (even if there is one) + return HttpUtils.append(redirectUri, vars, keys, true); + } + + public static String buildUnsuccessfulRedirect(String redirectUri, String responseType, String state, + String error, String description) { + Map query = new LinkedHashMap(); + query.put("error", error); + query.put("error_description", description); + if (state != null) { + query.put("state", state); + } + return HttpUtils.append(redirectUri, query, null, !responseType.contains("code")); + } + + public static long getExpiresIn(LocalDateTime expireTime) { + return LocalDateTimeUtil.between(LocalDateTime.now(), expireTime, ChronoUnit.SECONDS); + } + + public static String buildScopeStr(Collection scopes) { + return CollUtil.join(scopes, " "); + } + + public static List buildScopes(String scope) { + return StrUtil.split(scope, ' '); + } + +} diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/util/package-info.java b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/util/package-info.java new file mode 100644 index 0000000..fd439a6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/java/com/tashow/cloud/system/util/package-info.java @@ -0,0 +1,4 @@ +/** + * 每个模块的 util 包,放专属当前模块的 Utils 工具类 + */ +package com.tashow.cloud.system.util; diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/META-INF/services/com.xingyuv.captcha.service.CaptchaCacheService b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/META-INF/services/com.xingyuv.captcha.service.CaptchaCacheService new file mode 100644 index 0000000..c6113e5 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/META-INF/services/com.xingyuv.captcha.service.CaptchaCacheService @@ -0,0 +1 @@ +com.tashow.cloud.system.framework.captcha.core.RedisCaptchaServiceImpl diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application-dev.yaml b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application-dev.yaml new file mode 100644 index 0000000..4c8dca6 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application-dev.yaml @@ -0,0 +1,184 @@ +--- #################### 注册中心 + 配置中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + username: # Nacos 账号 + password: # Nacos 密码 + discovery: # 【配置中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + metadata: + version: 1.0.0 # 服务实例的版本号,可用于灰度发布 + config: # 【注册中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + +--- #################### 数据库相关配置 #################### +spring: + # 数据源配置项 + autoconfigure: + exclude: + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 5 # 初始连接数 + min-idle: 10 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + username: root + password: 123456 + slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 + lazy: true # 开启懒加载,保证启动速度 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + data: + redis: + host: 400-infra.server.iocoder.cn # 地址 + port: 6379 # 端口 + database: 1 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +--- #################### MQ 消息队列相关配置 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv + +spring: + # RabbitMQ 配置项,对应 RabbitProperties 配置类 + rabbitmq: + host: 127.0.0.1 # RabbitMQ 服务的地址 + port: 5672 # RabbitMQ 服务的端口 + username: guest # RabbitMQ 服务的账号 + password: guest # RabbitMQ 服务的密码 + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔 + +--- #################### 定时任务相关配置 #################### +xxl: + job: + admin: + addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + # Spring Boot Admin Server 服务端的相关配置 + context-path: /admin # 配置 Spring + +# 日志文件配置 +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + +--- #################### 微信公众号、小程序相关配置 #################### +wx: + mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 + # app-id: wx041349c6f39b268b + # secret: 5abee519483bc9f8cb37ce280e814bd0 + app-id: wx5b23ba7a5589ecbb # 测试号 + secret: 2a7b3b20c537e52e74afd395eb85f61f + # 存储配置,解决 AccessToken 的跨节点的共享 + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wx # Redis Key 的前缀 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 + # appid: wx62056c0d5e8db250 + # secret: 333ae72f41552af1e998fe1f54e1584a + appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 + secret: 6f270509224a7ae1296bbf1c8cb97aed + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wa # Redis Key 的前缀 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + demo: true # 开启演示模式 + +justauth: + enabled: true + type: + DINGTALK: # 钉钉 + client-id: dingvrnreaje3yqvzhxg + client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI + ignore-check-redirect-uri: true + WECHAT_ENTERPRISE: # 企业微信 + client-id: wwd411c69a39ad2e54 + client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw + agent-id: 1000004 + ignore-check-redirect-uri: true + # noinspection SpringBootApplicationYaml + WECHAT_MINI_APP: # 微信小程序 + client-id: ${wx.miniapp.appid} + client-secret: ${wx.miniapp.secret} + ignore-check-redirect-uri: true + ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验 + WECHAT_MP: # 微信公众号 + client-id: ${wx.mp.app-id} + client-secret: ${wx.mp.secret} + ignore-check-redirect-uri: true + cache: + type: REDIS + prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application-local.yaml b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application-local.yaml new file mode 100644 index 0000000..d9d75f8 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application-local.yaml @@ -0,0 +1,211 @@ +--- #################### 注册中心 + 配置中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + username: # Nacos 账号 + password: # Nacos 密码 + discovery: # 【配置中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + metadata: + version: 1.0.0 # 服务实例的版本号,可用于灰度发布 + config: # 【注册中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + +--- #################### 数据库相关配置 #################### +spring: + # 数据源配置项 + autoconfigure: + exclude: + - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 1 # 初始连接数 + min-idle: 1 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 + # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 + # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro # SQLServer 连接的示例 + # url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 + username: root + password: 123456 + # username: sa # SQL Server 连接的示例 + # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W # SQL Server 连接的示例 + # username: SYSDBA # DM 连接的示例 + # password: SYSDBA # DM 连接的示例 + slave: # 模拟从库,可根据自己需要修改 + lazy: true # 开启懒加载,保证启动速度 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + data: + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +--- #################### MQ 消息队列相关配置 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv + +spring: + # RabbitMQ 配置项,对应 RabbitProperties 配置类 + rabbitmq: + host: 127.0.0.1 # RabbitMQ 服务的地址 + port: 5672 # RabbitMQ 服务的端口 + username: guest # RabbitMQ 服务的账号 + password: guest # RabbitMQ 服务的密码 + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔 + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + enabled: false # 是否开启调度中心,默认为 true 开启 + admin: + addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + +# 日志文件配置 +logging: + level: + # 配置自己写的 MyBatis Mapper 打印日志 + com.tashow.cloud: info +--- #################### 微信公众号、小程序相关配置 #################### +wx: + mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 + # app-id: wx041349c6f39b268b # 测试号(牛希尧提供的) + # secret: 5abee519483bc9f8cb37ce280e814bd0 + app-id: wx5b23ba7a5589ecbb # 测试号(自己的) + secret: 2a7b3b20c537e52e74afd395eb85f61f + # app-id: wxa69ab825b163be19 # 测试号(Kongdy 提供的) + # secret: bd4f9fab889591b62aeac0d7b8d8b4a0 + # 存储配置,解决 AccessToken 的跨节点的共享 + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wx # Redis Key 的前缀 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 + # appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的) + # secret: 333ae72f41552af1e998fe1f54e1584a + # appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 + # secret: 6f270509224a7ae1296bbf1c8cb97aed + # appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) + # secret: 4a1a04e07f6a4a0751b39c3064a92c8b + appid: wx66186af0759f47c9 # 测试号(puhui 提供的) + secret: 3218bcbd112cbc614c7264ceb20144ac + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wa # Redis Key 的前缀 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + env: # 多环境的配置项 + tag: ${HOSTNAME} + captcha: + enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试 + security: + mock-enable: true + access-log: # 访问日志的配置项 + enable: false + wxa-code: + env-version: develop # 小程序版本: 正式版为 "release";体验版为 "trial";开发版为 "develop" + wxa-subscribe-message: + miniprogram-state: developer # 跳转小程序类型:开发版为 “developer”;体验版为 “trial”为;正式版为 “formal” + +justauth: + enabled: true + type: + DINGTALK: # 钉钉 + client-id: dingvrnreaje3yqvzhxg + client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI + ignore-check-redirect-uri: true + WECHAT_ENTERPRISE: # 企业微信 + client-id: wwd411c69a39ad2e54 + client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw + agent-id: 1000004 + ignore-check-redirect-uri: true + # noinspection SpringBootApplicationYaml + WECHAT_MINI_APP: # 微信小程序 + client-id: ${wx.miniapp.appid} + client-secret: ${wx.miniapp.secret} + ignore-check-redirect-uri: true + ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验 + WECHAT_MP: # 微信公众号 + client-id: ${wx.mp.app-id} + client-secret: ${wx.mp.secret} + ignore-check-redirect-uri: true + cache: + type: REDIS + prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application.yaml b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application.yaml new file mode 100644 index 0000000..7244e05 --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/application.yaml @@ -0,0 +1,208 @@ +spring: + application: + name: system-server + + profiles: + active: local + + main: + allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 + allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务 + + config: + import: + - optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置 + - optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置 + + # Servlet 配置 + servlet: + # 文件上传相关配置项 + multipart: + max-file-size: 16MB # 单个文件大小 + max-request-size: 32MB # 设置总上传的文件大小 + + # Jackson 配置项 + jackson: + serialization: + write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳 + write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401 + write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳 + fail-on-empty-beans: false # 允许序列化无属性的 Bean + + # Cache 配置项 + cache: + type: REDIS + redis: + time-to-live: 1h # 设置过期时间为 1 小时 + +server: + port: 48081 + +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + +--- #################### 接口文档配置 #################### + +springdoc: + api-docs: + enabled: true # 1. 是否开启 Swagger 接文档的元数据 + path: /v3/api-docs + swagger-ui: + enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面 + path: /swagger-ui + default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档 + +knife4j: + enable: true # 2.2 是否开启 Swagger 文档的 Knife4j UI 界面 + setting: + language: zh_cn + +# MyBatis Plus 的配置项 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 + global-config: + db-config: + id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 + # id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库 + # id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 + # id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + banner: false # 关闭控制台的 Banner 打印 + type-aliases-package: ${yudao.info.base-package}.dal.dataobject + encryptor: + password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成 + +mybatis-plus-join: + banner: false # 关闭控制台的 Banner 打印 + +# Spring Data Redis 配置 +spring: + data: + redis: + repositories: + enabled: false # 项目未使用到 Spring Data Redis 的 Repository,所以直接禁用,保证启动速度 + +# VO 转换(数据翻译)相关 +easy-trans: + is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口 + +--- #################### RPC 远程调用相关配置 #################### + +--- #################### 消息队列相关 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + # Producer 配置项 + producer: + group: ${spring.application.name}_PRODUCER # 生产者分组 + +spring: + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + # Kafka Producer 配置项 + producer: + acks: 1 # 0-不应答。1-leader 应答。all-所有 leader 和 follower 应答。 + retries: 3 # 发送失败时,重试发送的次数 + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer # 消息的 value 的序列化 + # Kafka Consumer 配置项 + consumer: + auto-offset-reset: earliest # 设置消费者分组最初的消费进度为 earliest 。可参考博客 https://blog.csdn.net/lishuangzhe7047/article/details/74530417 理解 + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: '*' + # Kafka Consumer Listener 监听器配置 + listener: + missing-topics-fatal: false # 消费监听接口监听的主题不存在时,默认会报错。所以通过设置为 false ,解决报错 + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + executor: + appname: ${spring.application.name} # 执行器 AppName + logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径 + accessToken: default_token # 执行器通讯TOKEN + +--- #################### 验证码相关配置 #################### + +aj: + captcha: + jigsaw: classpath:images/jigsaw # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径 + pic-click: classpath:images/pic-click # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径 + cache-type: redis # 缓存 local/redis... + cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存 + timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行 + type: blockPuzzle # 验证码类型 default两种都实例化。 blockPuzzle 滑块拼图 clickWord 文字点选 + water-mark: 芋道源码 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode + interference-options: 0 # 滑动干扰项(0/1/2) + req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false + req-get-lock-limit: 5 # 验证失败5次,get接口锁定 + req-get-lock-seconds: 10 # 验证失败后,锁定时间间隔 + req-get-minute-limit: 30 # get 接口一分钟内请求数限制 + req-check-minute-limit: 60 # check 接口一分钟内请求数限制 + req-verify-minute-limit: 60 # verify 接口一分钟内请求数限制 + +--- #################### 芋道相关配置 #################### + +tashow: + info: + version: 1.0.0 + base-package: com.tashow.cloud.system + web: + admin-ui: + url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址 + xss: + enable: false + exclude-urls: # 如下 url,仅仅是为了演示,去掉配置也没关系 + - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 + swagger: + title: 管理后台 + description: 提供管理员管理的所有功能 + version: ${yudao.info.version} + tenant: # 多租户相关配置项 + enable: true + ignore-urls: + - /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号 + - /admin-api/system/tenant/get-by-website # 基于域名获取租户,不许带租户编号 + - /admin-api/system/captcha/get-image # 获取图片验证码,和租户无关 + - /admin-api/system/captcha/get # 获取图片验证码,和租户无关 + - /admin-api/system/captcha/check # 校验图片验证码,和租户无关 + - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号 + - /rpc-api/system/tenant/valid # 防止递归。避免调用 /rpc-api/system/tenant/valid 接口时,又去触发 /rpc-api/system/tenant/valid 去校验 + - /rpc-api/system/tenant/id-list # 获得租户列表的时候,无需传递租户编号 + - /rpc-api/system/oauth2/token/check # 访问令牌校验时,无需传递租户编号;主要解决上传文件的场景,前端不会传递 tenant-id! + ignore-tables: + - system_tenant + - system_tenant_package + - system_dict_data + - system_dict_type + - system_error_code + - system_menu + - system_sms_channel + - system_sms_template + - system_sms_log + - system_sensitive_word + - system_oauth2_client + - system_mail_account + - system_mail_template + - system_mail_log + - system_notify_template + ignore-caches: + - user_role_ids + - permission_menu_ids + - oauth_client + - notify_template + - mail_account + - mail_template + - sms_template + sms-code: # 短信验证码相关的配置项 + expire-times: 10m + send-frequency: 1m + send-maximum-quantity-per-day: 10 + begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 + end-code: 9999 # 这里配置 9999 的原因是,测试方便。 + +debug: false diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg1.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg1.png new file mode 100644 index 0000000..c481457 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg1.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg2.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg2.png new file mode 100644 index 0000000..bf8fb38 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg2.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg3.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg3.png new file mode 100644 index 0000000..f871d3d Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg3.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg4.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg4.png new file mode 100644 index 0000000..2e3d871 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg4.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg5.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg5.png new file mode 100644 index 0000000..fe383b7 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg5.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg6.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg6.png new file mode 100644 index 0000000..5024ceb Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg6.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg7.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg7.png new file mode 100644 index 0000000..efe76f8 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg7.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg8.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg8.png new file mode 100644 index 0000000..2727aa3 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg8.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg9.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg9.png new file mode 100644 index 0000000..4463aa2 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/original/bg9.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/1.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/1.png new file mode 100644 index 0000000..ef11324 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/1.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/10.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/10.png new file mode 100644 index 0000000..297e44c Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/10.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/11.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/11.png new file mode 100644 index 0000000..d9b1da8 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/11.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/12.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/12.png new file mode 100644 index 0000000..07e7313 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/12.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/13.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/13.png new file mode 100644 index 0000000..82c3dd9 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/13.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/14.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/14.png new file mode 100644 index 0000000..0b9a866 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/14.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/15.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/15.png new file mode 100644 index 0000000..86b0d1c Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/15.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/16.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/16.png new file mode 100644 index 0000000..e90a6e2 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/16.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/17.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/17.png new file mode 100644 index 0000000..a82cbc7 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/17.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/18.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/18.png new file mode 100644 index 0000000..d3f3cfd Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/18.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/19.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/19.png new file mode 100644 index 0000000..eb2855b Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/19.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/8.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/8.png new file mode 100644 index 0000000..3cb5ce1 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/8.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/9.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/9.png new file mode 100644 index 0000000..384d354 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/9.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/2.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/2.png new file mode 100644 index 0000000..baf3f06 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/2.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/3.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/3.png new file mode 100644 index 0000000..ccaf617 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/3.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/4.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/4.png new file mode 100644 index 0000000..7dab162 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/4.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg1.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg1.png new file mode 100644 index 0000000..14e7345 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg1.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg10.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg10.png new file mode 100644 index 0000000..1ea1d6d Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg10.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg2.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg2.png new file mode 100644 index 0000000..0edb329 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg2.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg3.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg3.png new file mode 100644 index 0000000..9167996 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg3.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg4.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg4.png new file mode 100644 index 0000000..e8e8e6c Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg4.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg5.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg5.png new file mode 100644 index 0000000..66a3181 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg5.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg6.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg6.png new file mode 100644 index 0000000..9b0f5d8 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg6.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg7.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg7.png new file mode 100644 index 0000000..db41c74 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg7.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg8.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg8.png new file mode 100644 index 0000000..3496813 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg8.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg9.png b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg9.png new file mode 100644 index 0000000..4e7b477 Binary files /dev/null and b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/images/pic-click/bg9.png differ diff --git a/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/logback-spring.xml b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..16f0c0f --- /dev/null +++ b/tashow-module/tashow-module-system/tashow-module-system-biz/src/main/resources/logback-spring.xml @@ -0,0 +1,76 @@ + + + + + + + + + +       + + + ${PATTERN_DEFAULT} + + + + + + + + + + ${PATTERN_DEFAULT} + + + + ${LOG_FILE} + + + ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} + + ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} + + ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} + + ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} + + ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30} + + + + + + 0 + + 256 + + + + + + + + ${PATTERN_DEFAULT} + + + + + + + + + + + + + + + + + + + + + + diff --git a/tashow-platform-framework/pom.xml b/tashow-platform-framework/pom.xml index d0899c2..35083f4 100644 --- a/tashow-platform-framework/pom.xml +++ b/tashow-platform-framework/pom.xml @@ -11,7 +11,21 @@ pom tashow-common + tashow-framework-web + tashow-framework-env + tashow-framework-ip + tashow-framework-job + tashow-framework-monitor + tashow-framework-mq + tashow-framework-protection + tashow-framework-rpc + tashow-framework-security + tashow-framework-tenant + tashow-framework-websocket tashow-data-permission + tashow-data-mybatis + tashow-data-redis + tashow-data-excel tashow-platform-framework diff --git a/tashow-platform-framework/tashow-common/src/main/java/com/tashow/cloud/common/util/collection/ArrayUtils.java b/tashow-platform-framework/tashow-common/src/main/java/com/tashow/cloud/common/util/collection/ArrayUtils.java index 45ac49b..d7454ea 100644 --- a/tashow-platform-framework/tashow-common/src/main/java/com/tashow/cloud/common/util/collection/ArrayUtils.java +++ b/tashow-platform-framework/tashow-common/src/main/java/com/tashow/cloud/common/util/collection/ArrayUtils.java @@ -8,7 +8,8 @@ import java.util.Collection; import java.util.function.Consumer; import java.util.function.Function; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; + /** * Array 工具类 diff --git a/tashow-platform-framework/tashow-common/src/main/java/com/tashow/cloud/common/util/http/HttpUtils.java b/tashow-platform-framework/tashow-common/src/main/java/com/tashow/cloud/common/util/http/HttpUtils.java index 73d8555..ec90edd 100644 --- a/tashow-platform-framework/tashow-common/src/main/java/com/tashow/cloud/common/util/http/HttpUtils.java +++ b/tashow-platform-framework/tashow-common/src/main/java/com/tashow/cloud/common/util/http/HttpUtils.java @@ -7,11 +7,11 @@ import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; -import jakarta.servlet.http.HttpServletRequest; import org.springframework.util.StringUtils; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; +import jakarta.servlet.http.HttpServletRequest; import java.net.URI; import java.nio.charset.Charset; import java.util.Map; diff --git a/tashow-platform-framework/tashow-common/src/test/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtilsTest.java b/tashow-platform-framework/tashow-common/src/test/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtilsTest.java deleted file mode 100644 index 0e44645..0000000 --- a/tashow-platform-framework/tashow-common/src/test/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtilsTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package cn.iocoder.yudao.framework.common.util.collection; - -import lombok.AllArgsConstructor; -import lombok.Data; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.function.BiFunction; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -/** - * {@link CollectionUtils} 的单元测试 - */ -public class CollectionUtilsTest { - - @Data - @AllArgsConstructor - private static class Dog { - - private Integer id; - private String name; - private String code; - - } - - @Test - public void testDiffList() { - // 准备参数 - Collection oldList = Arrays.asList( - new Dog(1, "花花", "hh"), - new Dog(2, "旺财", "wc") - ); - Collection newList = Arrays.asList( - new Dog(null, "花花2", "hh"), - new Dog(null, "小白", "xb") - ); - BiFunction sameFunc = (oldObj, newObj) -> { - boolean same = oldObj.getCode().equals(newObj.getCode()); - // 如果相等的情况下,需要设置下 id,后续好更新 - if (same) { - newObj.setId(oldObj.getId()); - } - return same; - }; - - // 调用 - List> result = CollectionUtils.diffList(oldList, newList, sameFunc); - // 断言 - assertEquals(result.size(), 3); - // 断言 create - assertEquals(result.get(0).size(), 1); - assertEquals(result.get(0).get(0), new Dog(null, "小白", "xb")); - // 断言 update - assertEquals(result.get(1).size(), 1); - assertEquals(result.get(1).get(0), new Dog(1, "花花2", "hh")); - // 断言 delete - assertEquals(result.get(2).size(), 1); - assertEquals(result.get(2).get(0), new Dog(2, "旺财", "wc")); - } - -} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/pom.xml b/tashow-platform-framework/tashow-data-excel/pom.xml similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/pom.xml rename to tashow-platform-framework/tashow-data-excel/pom.xml index 8ff79d6..b1060bb 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/pom.xml +++ b/tashow-platform-framework/tashow-data-excel/pom.xml @@ -3,22 +3,21 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} 4.0.0 - yudao-spring-boot-starter-excel + tashow-data-excel jar ${project.artifactId} Excel 拓展 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common @@ -29,15 +28,15 @@ - cn.iocoder.cloud - yudao-spring-boot-starter-rpc + com.tashow.cloud + tashow-framework-rpc true - cn.iocoder.cloud - yudao-module-system-api + com.tashow.cloud + tashow-module-system-api ${revision} @@ -71,8 +70,8 @@ - cn.iocoder.cloud - yudao-spring-boot-starter-biz-ip + com.tashow.cloud + tashow-framework-ip true diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/config/DictAutoConfiguration.java similarity index 63% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/config/DictAutoConfiguration.java index 8a6075e..7d8b452 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/config/DictAutoConfiguration.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.dict.config; +package com.tashow.cloud.excel.dict.config; -import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import com.tashow.cloud.excel.dict.core.DictFrameworkUtils; +import com.tashow.cloud.systemapi.api.dict.DictDataApi; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; @AutoConfiguration -public class YudaoDictAutoConfiguration { +public class DictAutoConfiguration { @Bean @SuppressWarnings("InstantiationOfUtilityClass") diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictRpcAutoConfiguration.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/config/DictRpcAutoConfiguration.java similarity index 66% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictRpcAutoConfiguration.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/config/DictRpcAutoConfiguration.java index 5a9c018..a7ad326 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictRpcAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/config/DictRpcAutoConfiguration.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.dict.config; +package com.tashow.cloud.excel.dict.config; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import com.tashow.cloud.systemapi.api.dict.DictDataApi; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.cloud.openfeign.EnableFeignClients; @@ -11,5 +11,5 @@ import org.springframework.cloud.openfeign.EnableFeignClients; */ @AutoConfiguration @EnableFeignClients(clients = DictDataApi.class) // 主要是引入相关的 API 服务 -public class YudaoDictRpcAutoConfiguration { +public class DictRpcAutoConfiguration { } diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/core/DictFrameworkUtils.java similarity index 91% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/core/DictFrameworkUtils.java index d964121..92a0e91 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/core/DictFrameworkUtils.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.dict.core; +package com.tashow.cloud.excel.dict.core; import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.common.util.cache.CacheUtils; +import com.tashow.cloud.systemapi.api.dict.DictDataApi; +import com.tashow.cloud.systemapi.api.dict.dto.DictDataRespDTO; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; diff --git a/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/package-info.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/package-info.java new file mode 100644 index 0000000..1ef27fe --- /dev/null +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/dict/package-info.java @@ -0,0 +1,6 @@ +/** + * 字典数据模块,提供 {@link com.tashow.cloud.excel.dict.core.DictFrameworkUtils} 工具类 + * + * 通过将字典缓存在内存中,保证性能 + */ +package com.tashow.cloud.excel.dict; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/DictFormat.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/annotations/DictFormat.java similarity index 86% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/DictFormat.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/annotations/DictFormat.java index 0d898b4..c364f8d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/DictFormat.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/annotations/DictFormat.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.excel.core.annotations; +package com.tashow.cloud.excel.excel.core.annotations; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/annotations/ExcelColumnSelect.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/annotations/ExcelColumnSelect.java index b4ff140..347c02e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/annotations/ExcelColumnSelect.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.excel.core.annotations; +package com.tashow.cloud.excel.excel.core.annotations; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/AreaConvert.java similarity index 89% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/AreaConvert.java index 9778b17..fbb5d56 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/AreaConvert.java @@ -1,13 +1,13 @@ -package cn.iocoder.yudao.framework.excel.core.convert; +package com.tashow.cloud.excel.excel.core.convert; import cn.hutool.core.convert.Convert; -import cn.iocoder.yudao.framework.ip.core.Area; -import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.data.ReadCellData; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.tashow.cloud.ip.core.Area; +import com.tashow.cloud.ip.core.utils.AreaUtils; import lombok.extern.slf4j.Slf4j; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/DictConvert.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/DictConvert.java index fc79585..5462bf3 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/DictConvert.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.excel.core.convert; +package com.tashow.cloud.excel.excel.core.convert; import cn.hutool.core.convert.Convert; -import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import com.tashow.cloud.excel.dict.core.DictFrameworkUtils; +import com.tashow.cloud.excel.excel.core.annotations.DictFormat; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.GlobalConfiguration; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/JsonConvert.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/JsonConvert.java similarity index 89% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/JsonConvert.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/JsonConvert.java index 0d4794e..653dfef 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/JsonConvert.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/JsonConvert.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.excel.core.convert; +package com.tashow.cloud.excel.excel.core.convert; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.tashow.cloud.common.util.json.JsonUtils; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.GlobalConfiguration; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MoneyConvert.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/MoneyConvert.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MoneyConvert.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/MoneyConvert.java index ee66fe7..6c8ab82 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MoneyConvert.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/convert/MoneyConvert.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.excel.core.convert; +package com.tashow.cloud.excel.excel.core.convert; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/function/ExcelColumnSelectFunction.java similarity index 89% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/function/ExcelColumnSelectFunction.java index 51953c4..07f4908 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/function/ExcelColumnSelectFunction.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.excel.core.function; +package com.tashow.cloud.excel.excel.core.function; import java.util.List; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/handler/SelectSheetWriteHandler.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/handler/SelectSheetWriteHandler.java index ef1eb65..057a262 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/handler/SelectSheetWriteHandler.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.excel.core.handler; +package com.tashow.cloud.excel.excel.core.handler; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; @@ -6,10 +6,10 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.hutool.poi.excel.ExcelUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; -import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; -import cn.iocoder.yudao.framework.excel.core.function.ExcelColumnSelectFunction; +import com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.excel.dict.core.DictFrameworkUtils; +import com.tashow.cloud.excel.excel.core.annotations.ExcelColumnSelect; +import com.tashow.cloud.excel.excel.core.function.ExcelColumnSelectFunction; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; @@ -25,7 +25,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; /** * 基于固定 sheet 实现下拉框 @@ -155,4 +155,4 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { writeSheetHolder.getSheet().addValidationData(validation); } -} \ No newline at end of file +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/util/ExcelUtils.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/util/ExcelUtils.java index f5c4b83..c344b3a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/core/util/ExcelUtils.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.excel.core.util; +package com.tashow.cloud.excel.excel.core.util; -import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; +import com.tashow.cloud.excel.excel.core.handler.SelectSheetWriteHandler; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.converters.longconverter.LongStringConverter; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/package-info.java similarity index 57% rename from tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java rename to tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/package-info.java index 53bc5c0..ba99a4c 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java +++ b/tashow-platform-framework/tashow-data-excel/src/main/java/com/tashow/cloud/excel/excel/package-info.java @@ -1,4 +1,4 @@ /** * 基于 EasyExcel 实现 Excel 相关的操作 */ -package cn.iocoder.yudao.framework.excel; +package com.tashow.cloud.excel.excel; diff --git a/tashow-platform-framework/tashow-data-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-data-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..b5e7b16 --- /dev/null +++ b/tashow-platform-framework/tashow-data-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.tashow.cloud.excel.dict.config.DictRpcAutoConfiguration +com.tashow.cloud.excel.dict.config.DictAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/pom.xml b/tashow-platform-framework/tashow-data-mybatis/pom.xml similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/pom.xml rename to tashow-platform-framework/tashow-data-mybatis/pom.xml index f694946..3630292 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/tashow-platform-framework/tashow-data-mybatis/pom.xml @@ -3,28 +3,27 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} 4.0.0 - yudao-spring-boot-starter-mybatis + tashow-data-mybatis jar ${project.artifactId} 数据库连接池、多数据源、事务、MyBatis 拓展 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common - cn.iocoder.cloud - yudao-spring-boot-starter-web + com.tashow.cloud + tashow-framework-web provided diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/config/DataSourceAutoConfiguration.java similarity index 90% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/config/DataSourceAutoConfiguration.java index 879a19a..07b2b8a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/config/DataSourceAutoConfiguration.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.datasource.config; +package com.tashow.cloud.mybatis.datasource.config; -import cn.iocoder.yudao.framework.datasource.core.filter.DruidAdRemoveFilter; import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties; +import com.tashow.cloud.mybatis.datasource.core.filter.DruidAdRemoveFilter; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -17,7 +17,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @AutoConfiguration @EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理 @EnableConfigurationProperties(DruidStatProperties.class) -public class YudaoDataSourceAutoConfiguration { +public class DataSourceAutoConfiguration { /** * 创建 DruidAdRemoveFilter 过滤器,过滤 common.js 的广告 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/enums/DataSourceEnum.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/core/enums/DataSourceEnum.java similarity index 91% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/enums/DataSourceEnum.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/core/enums/DataSourceEnum.java index c99a256..662d24e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/enums/DataSourceEnum.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/core/enums/DataSourceEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.datasource.core.enums; +package com.tashow.cloud.mybatis.datasource.core.enums; /** * 对应于多数据源中不同数据源配置 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/filter/DruidAdRemoveFilter.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/core/filter/DruidAdRemoveFilter.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/filter/DruidAdRemoveFilter.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/core/filter/DruidAdRemoveFilter.java index 18a86a8..5d4369c 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/filter/DruidAdRemoveFilter.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/core/filter/DruidAdRemoveFilter.java @@ -1,12 +1,14 @@ -package cn.iocoder.yudao.framework.datasource.core.filter; +package com.tashow.cloud.mybatis.datasource.core.filter; + + import com.alibaba.druid.util.Utils; -import org.springframework.web.filter.OncePerRequestFilter; - import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + import java.io.IOException; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/package-info.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/package-info.java similarity index 62% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/package-info.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/package-info.java index 8512891..58d9abc 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/package-info.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/datasource/package-info.java @@ -2,4 +2,4 @@ * 数据库连接池,采用 Druid * 多数据源,采用爆米花 */ -package cn.iocoder.yudao.framework.datasource; +package com.tashow.cloud.mybatis.datasource; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/config/IdTypeEnvironmentPostProcessor.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/config/IdTypeEnvironmentPostProcessor.java index 3a67b90..9b80f81 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/config/IdTypeEnvironmentPostProcessor.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.mybatis.config; +package com.tashow.cloud.mybatis.mybatis.config; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.IdType; +import com.tashow.cloud.common.util.collection.SetUtils; +import com.tashow.cloud.mybatis.mybatis.core.util.JdbcUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/config/MybatisAutoConfiguration.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/config/MybatisAutoConfiguration.java index ab29921..0163eb2 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/config/MybatisAutoConfiguration.java @@ -1,7 +1,6 @@ -package cn.iocoder.yudao.framework.mybatis.config; +package com.tashow.cloud.mybatis.mybatis.config; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; @@ -11,6 +10,7 @@ import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal; import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.tashow.cloud.mybatis.mybatis.core.handler.DefaultDBFieldHandler; import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -26,9 +26,9 @@ import java.util.concurrent.TimeUnit; * @author 芋道源码 */ @AutoConfiguration(before = MybatisPlusAutoConfiguration.class) // 目的:先于 MyBatis Plus 自动配置,避免 @MapperScan 可能扫描不到 Mapper 打印 warn 日志 -@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class, +@MapperScan(value = "${tashow.info.base-package}", annotationClass = Mapper.class, lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试 -public class YudaoMybatisAutoConfiguration { +public class MybatisAutoConfiguration { static { // 动态 SQL 智能优化支持本地缓存加速解析,更完善的租户复杂 XML 动态 SQL 支持,静态注入缓存 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/dataobject/BaseDO.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/dataobject/BaseDO.java index fc5f0a3..5f1ec6d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/dataobject/BaseDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.mybatis.core.dataobject; +package com.tashow.cloud.mybatis.mybatis.core.dataobject; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/enums/DbTypeEnum.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/enums/DbTypeEnum.java index 3929b71..d2839b6 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/enums/DbTypeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.mybatis.core.enums; +package com.tashow.cloud.mybatis.mybatis.core.enums; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.annotation.DbType; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/handler/DefaultDBFieldHandler.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/handler/DefaultDBFieldHandler.java index 94dada1..ea2a027 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/handler/DefaultDBFieldHandler.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.mybatis.core.handler; +package com.tashow.cloud.mybatis.mybatis.core.handler; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import org.apache.ibatis.reflection.MetaObject; import java.time.LocalDateTime; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/mapper/BaseMapperX.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/mapper/BaseMapperX.java index 01f2142..01bb70d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/mapper/BaseMapperX.java @@ -1,12 +1,6 @@ -package cn.iocoder.yudao.framework.mybatis.core.mapper; +package com.tashow.cloud.mybatis.mybatis.core.mapper; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; -import cn.iocoder.yudao.framework.common.pojo.SortingField; -import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; -import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -18,6 +12,12 @@ import com.baomidou.mybatisplus.extension.toolkit.Db; import com.github.yulichang.base.MPJBaseMapper; import com.github.yulichang.interfaces.MPJBaseJoin; import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.PageResult; +import com.tashow.cloud.common.pojo.SortablePageParam; +import com.tashow.cloud.common.pojo.SortingField; +import com.tashow.cloud.mybatis.mybatis.core.util.JdbcUtils; +import com.tashow.cloud.mybatis.mybatis.core.util.MyBatisUtils; import org.apache.ibatis.annotations.Param; import java.util.Collection; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/LambdaQueryWrapperX.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/LambdaQueryWrapperX.java index a728365..ac60b99 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/LambdaQueryWrapperX.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.mybatis.core.query; +package com.tashow.cloud.mybatis.mybatis.core.query; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.tashow.cloud.common.util.collection.ArrayUtils; import org.springframework.util.StringUtils; import java.util.Collection; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/MPJLambdaWrapperX.java similarity index 98% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/MPJLambdaWrapperX.java index 7950a2f..1863e1b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/MPJLambdaWrapperX.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.framework.mybatis.core.query; +package com.tashow.cloud.mybatis.mybatis.core.query; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import com.github.yulichang.toolkit.MPJWrappers; import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.tashow.cloud.common.util.collection.ArrayUtils; import org.springframework.util.StringUtils; import java.util.Collection; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/QueryWrapperX.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/QueryWrapperX.java index 087b1b8..aec8880 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/query/QueryWrapperX.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.mybatis.core.query; +package com.tashow.cloud.mybatis.mybatis.core.query; -import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.ArrayUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.tashow.cloud.mybatis.mybatis.core.util.JdbcUtils; import org.springframework.util.StringUtils; import java.util.Collection; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/EncryptTypeHandler.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/EncryptTypeHandler.java index 7ef0f4e..a7072e0 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/EncryptTypeHandler.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.mybatis.core.type; +package com.tashow.cloud.mybatis.mybatis.core.type; import cn.hutool.core.lang.Assert; import cn.hutool.crypto.SecureUtil; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerListTypeHandler.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/IntegerListTypeHandler.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerListTypeHandler.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/IntegerListTypeHandler.java index 18455ba..c6d0892 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerListTypeHandler.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/IntegerListTypeHandler.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.mybatis.core.type; +package com.tashow.cloud.mybatis.mybatis.core.type; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import com.tashow.cloud.common.util.string.StrUtils; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongListTypeHandler.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/LongListTypeHandler.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongListTypeHandler.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/LongListTypeHandler.java index 8c30f3d..eaa8a36 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongListTypeHandler.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/LongListTypeHandler.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.mybatis.core.type; +package com.tashow.cloud.mybatis.mybatis.core.type; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import com.tashow.cloud.common.util.string.StrUtils; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/StringListTypeHandler.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/StringListTypeHandler.java index 598a15e..b138579 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/type/StringListTypeHandler.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.mybatis.core.type; +package com.tashow.cloud.mybatis.mybatis.core.type; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/util/JdbcUtils.java similarity index 90% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/util/JdbcUtils.java index 0ee22db..aa1739c 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/util/JdbcUtils.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.mybatis.core.util; +package com.tashow.cloud.mybatis.mybatis.core.util; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.common.util.spring.SpringUtils; -import cn.iocoder.yudao.framework.mybatis.core.enums.DbTypeEnum; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.mybatisplus.annotation.DbType; +import com.tashow.cloud.common.util.object.ObjectUtils; +import com.tashow.cloud.common.util.spring.SpringUtils; +import com.tashow.cloud.mybatis.mybatis.core.enums.DbTypeEnum; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import javax.sql.DataSource; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/util/MyBatisUtils.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/util/MyBatisUtils.java index ccd9412..3f1443d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/core/util/MyBatisUtils.java @@ -1,16 +1,16 @@ -package cn.iocoder.yudao.framework.mybatis.core.util; +package com.tashow.cloud.mybatis.mybatis.core.util; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.SortingField; -import cn.iocoder.yudao.framework.mybatis.core.enums.DbTypeEnum; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.tashow.cloud.common.pojo.PageParam; +import com.tashow.cloud.common.pojo.SortingField; +import com.tashow.cloud.mybatis.mybatis.core.enums.DbTypeEnum; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/package-info.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/package-info.java similarity index 60% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/package-info.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/package-info.java index 50b1e85..64ce74e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/package-info.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/mybatis/package-info.java @@ -1,4 +1,4 @@ /** * 使用 MyBatis Plus 提升使用 MyBatis 的开发效率 */ -package cn.iocoder.yudao.framework.mybatis; +package com.tashow.cloud.mybatis.mybatis; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/config/TranslateAutoConfiguration.java similarity index 73% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/config/TranslateAutoConfiguration.java index bcc46b8..03ea639 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/config/TranslateAutoConfiguration.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.translate.config; +package com.tashow.cloud.mybatis.translate.config; -import cn.iocoder.yudao.framework.translate.core.TranslateUtils; import com.fhs.trans.service.impl.TransService; +import com.tashow.cloud.mybatis.translate.core.TranslateUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; @AutoConfiguration -public class YudaoTranslateAutoConfiguration { +public class TranslateAutoConfiguration { @Bean @SuppressWarnings({"InstantiationOfUtilityClass", "SpringJavaInjectionPointsAutowiringInspection"}) diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/core/TranslateUtils.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/core/TranslateUtils.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/core/TranslateUtils.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/core/TranslateUtils.java index 2974b0c..4b76b24 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/core/TranslateUtils.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/core/TranslateUtils.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.translate.core; +package com.tashow.cloud.mybatis.translate.core; import cn.hutool.core.collection.CollUtil; import com.fhs.core.trans.vo.VO; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/package-info.java b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/package-info.java similarity index 61% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/package-info.java rename to tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/package-info.java index f14914a..a24154e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/package-info.java +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/java/com/tashow/cloud/mybatis/translate/package-info.java @@ -1,4 +1,4 @@ /** * 使用 Easy-Trans 提升使用 VO 数据翻译的开发效率 */ -package cn.iocoder.yudao.framework.translate; +package com.tashow.cloud.mybatis.translate; diff --git a/tashow-platform-framework/tashow-data-mybatis/src/main/resources/META-INF/spring.factories b/tashow-platform-framework/tashow-data-mybatis/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..8ff75f4 --- /dev/null +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ + com.tashow.cloud.mybatis.mybatis.config.IdTypeEnvironmentPostProcessor diff --git a/tashow-platform-framework/tashow-data-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-data-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..9df82c2 --- /dev/null +++ b/tashow-platform-framework/tashow-data-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +com.tashow.cloud.mybatis.datasource.config.DataSourceAutoConfiguration +com.tashow.cloud.mybatis.mybatis.config.MybatisAutoConfiguration +com.tashow.cloud.mybatis.translate.config.TranslateAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot MyBatis 入门》.md b/tashow-platform-framework/tashow-data-mybatis/《芋道 Spring Boot MyBatis 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot MyBatis 入门》.md rename to tashow-platform-framework/tashow-data-mybatis/《芋道 Spring Boot MyBatis 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 多数据源(读写分离)入门》.md b/tashow-platform-framework/tashow-data-mybatis/《芋道 Spring Boot 多数据源(读写分离)入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 多数据源(读写分离)入门》.md rename to tashow-platform-framework/tashow-data-mybatis/《芋道 Spring Boot 多数据源(读写分离)入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 数据库连接池入门》.md b/tashow-platform-framework/tashow-data-mybatis/《芋道 Spring Boot 数据库连接池入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 数据库连接池入门》.md rename to tashow-platform-framework/tashow-data-mybatis/《芋道 Spring Boot 数据库连接池入门》.md diff --git a/tashow-platform-framework/tashow-data-permission/pom.xml b/tashow-platform-framework/tashow-data-permission/pom.xml index 014bd07..356471a 100644 --- a/tashow-platform-framework/tashow-data-permission/pom.xml +++ b/tashow-platform-framework/tashow-data-permission/pom.xml @@ -2,12 +2,12 @@ + 4.0.0 - tashow-platform-framework com.tashow.cloud + tashow-platform-framework ${revision} - 4.0.0 tashow-data-permission jar @@ -22,28 +22,28 @@ - cn.iocoder.cloud - yudao-spring-boot-starter-security + com.tashow.cloud + tashow-framework-security true - cn.iocoder.cloud - yudao-spring-boot-starter-mybatis + com.tashow.cloud + tashow-data-mybatis - cn.iocoder.cloud - yudao-spring-boot-starter-rpc + com.tashow.cloud + tashow-framework-rpc true - cn.iocoder.cloud - yudao-module-system-api + com.tashow.cloud + tashow-module-system-api ${revision} diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DataPermissionAutoConfiguration.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DataPermissionAutoConfiguration.java similarity index 60% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DataPermissionAutoConfiguration.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DataPermissionAutoConfiguration.java index 0fc7082..6cbc372 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DataPermissionAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DataPermissionAutoConfiguration.java @@ -1,10 +1,15 @@ -package com.tashow.cloud.datapermission.config; +package com.tashow.cloud.permission.config; -import com.tashow.cloud.datapermission.core.aop.DataPermissionAnnotationAdvisor; -import com.tashow.cloud.datapermission.core.db.DataPermissionRuleHandler; -import com.tashow.cloud.datapermission.core.rule.DataPermissionRule; -import com.tashow.cloud.datapermission.core.rule.DataPermissionRuleFactory; -import com.tashow.cloud.datapermission.core.rule.DataPermissionRuleFactoryImpl; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor; +import com.tashow.cloud.permission.core.rule.DataPermissionRuleFactory; +import com.tashow.cloud.permission.core.rule.DataPermissionRuleFactoryImpl; +import com.tashow.cloud.permission.core.aop.DataPermissionAnnotationAdvisor; +import com.tashow.cloud.permission.core.db.DataPermissionRuleHandler; +import com.tashow.cloud.permission.core.rule.DataPermissionRule; +import com.tashow.cloud.mybatis.mybatis.core.util.MyBatisUtils; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; import java.util.List; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DataPermissionRpcAutoConfiguration.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DataPermissionRpcAutoConfiguration.java similarity index 78% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DataPermissionRpcAutoConfiguration.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DataPermissionRpcAutoConfiguration.java index 3d259c8..29cadca 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DataPermissionRpcAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DataPermissionRpcAutoConfiguration.java @@ -1,13 +1,14 @@ -package com.tashow.cloud.datapermission.config; +package com.tashow.cloud.permission.config; -import com.tashow.cloud.datapermission.core.rpc.DataPermissionRequestInterceptor; -import com.tashow.cloud.datapermission.core.rpc.DataPermissionRpcWebFilter; +import com.tashow.cloud.permission.core.rpc.DataPermissionRequestInterceptor; +import com.tashow.cloud.permission.core.rpc.DataPermissionRpcWebFilter; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; -import static cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum.TENANT_CONTEXT_FILTER; +import static com.tashow.cloud.common.enums.WebFilterOrderEnum.TENANT_CONTEXT_FILTER; + /** * 数据权限针对 RPC 的自动配置类 diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DeptDataPermissionAutoConfiguration.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DeptDataPermissionAutoConfiguration.java similarity index 82% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DeptDataPermissionAutoConfiguration.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DeptDataPermissionAutoConfiguration.java index ea63f5e..cc57f7b 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/config/DeptDataPermissionAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/config/DeptDataPermissionAutoConfiguration.java @@ -1,10 +1,10 @@ -package com.tashow.cloud.datapermission.config; +package com.tashow.cloud.permission.config; import cn.hutool.extra.spring.SpringUtil; -import com.tashow.cloud.datapermission.core.rule.dept.DeptDataPermissionRule; -import com.tashow.cloud.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import com.tashow.cloud.permission.core.rule.dept.DeptDataPermissionRule; +import com.tashow.cloud.permission.core.rule.dept.DeptDataPermissionRuleCustomizer; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.systemapi.api.permission.PermissionApi; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/annotation/DataPermission.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/annotation/DataPermission.java similarity index 86% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/annotation/DataPermission.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/annotation/DataPermission.java index 1bc0a43..c48c7ed 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/annotation/DataPermission.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/annotation/DataPermission.java @@ -1,6 +1,6 @@ -package com.tashow.cloud.datapermission.core.annotation; +package com.tashow.cloud.permission.core.annotation; -import com.tashow.cloud.datapermission.core.rule.DataPermissionRule; +import com.tashow.cloud.permission.core.rule.DataPermissionRule; import java.lang.annotation.*; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionAnnotationAdvisor.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionAnnotationAdvisor.java similarity index 90% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionAnnotationAdvisor.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionAnnotationAdvisor.java index 71d1831..c18aa69 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionAnnotationAdvisor.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionAnnotationAdvisor.java @@ -1,6 +1,6 @@ -package com.tashow.cloud.datapermission.core.aop; +package com.tashow.cloud.permission.core.aop; -import com.tashow.cloud.datapermission.core.annotation.DataPermission; +import com.tashow.cloud.permission.core.annotation.DataPermission; import lombok.EqualsAndHashCode; import lombok.Getter; import org.aopalliance.aop.Advice; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionAnnotationInterceptor.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionAnnotationInterceptor.java similarity index 95% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionAnnotationInterceptor.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionAnnotationInterceptor.java index cfb71f0..a468960 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionAnnotationInterceptor.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionAnnotationInterceptor.java @@ -1,6 +1,6 @@ -package com.tashow.cloud.datapermission.core.aop; +package com.tashow.cloud.permission.core.aop; -import com.tashow.cloud.datapermission.core.annotation.DataPermission; +import com.tashow.cloud.permission.core.annotation.DataPermission; import lombok.Getter; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionContextHolder.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionContextHolder.java similarity index 93% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionContextHolder.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionContextHolder.java index ddf9d6a..58d51d4 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/aop/DataPermissionContextHolder.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/aop/DataPermissionContextHolder.java @@ -1,6 +1,6 @@ -package com.tashow.cloud.datapermission.core.aop; +package com.tashow.cloud.permission.core.aop; -import com.tashow.cloud.datapermission.core.annotation.DataPermission; +import com.tashow.cloud.permission.core.annotation.DataPermission; import com.alibaba.ttl.TransmittableThreadLocal; import java.util.LinkedList; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/db/DataPermissionRuleHandler.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/db/DataPermissionRuleHandler.java similarity index 88% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/db/DataPermissionRuleHandler.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/db/DataPermissionRuleHandler.java index 70c36a8..2fbf3fd 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/db/DataPermissionRuleHandler.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/db/DataPermissionRuleHandler.java @@ -1,9 +1,9 @@ -package com.tashow.cloud.datapermission.core.db; +package com.tashow.cloud.permission.core.db; import cn.hutool.core.collection.CollUtil; -import com.tashow.cloud.datapermission.core.rule.DataPermissionRule; -import com.tashow.cloud.datapermission.core.rule.DataPermissionRuleFactory; -import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import com.tashow.cloud.mybatis.mybatis.core.util.MyBatisUtils; +import com.tashow.cloud.permission.core.rule.DataPermissionRule; +import com.tashow.cloud.permission.core.rule.DataPermissionRuleFactory; import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler; import lombok.RequiredArgsConstructor; import net.sf.jsqlparser.expression.Expression; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rpc/DataPermissionRequestInterceptor.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rpc/DataPermissionRequestInterceptor.java similarity index 81% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rpc/DataPermissionRequestInterceptor.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rpc/DataPermissionRequestInterceptor.java index 0924466..3da4535 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rpc/DataPermissionRequestInterceptor.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rpc/DataPermissionRequestInterceptor.java @@ -1,7 +1,7 @@ -package com.tashow.cloud.datapermission.core.rpc; +package com.tashow.cloud.permission.core.rpc; -import com.tashow.cloud.datapermission.core.annotation.DataPermission; -import com.tashow.cloud.datapermission.core.aop.DataPermissionContextHolder; +import com.tashow.cloud.permission.core.annotation.DataPermission; +import com.tashow.cloud.permission.core.aop.DataPermissionContextHolder; import feign.RequestInterceptor; import feign.RequestTemplate; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rpc/DataPermissionRpcWebFilter.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rpc/DataPermissionRpcWebFilter.java similarity index 86% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rpc/DataPermissionRpcWebFilter.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rpc/DataPermissionRpcWebFilter.java index 7ccb375..cdba72b 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rpc/DataPermissionRpcWebFilter.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rpc/DataPermissionRpcWebFilter.java @@ -1,7 +1,7 @@ -package com.tashow.cloud.datapermission.core.rpc; +package com.tashow.cloud.permission.core.rpc; -import com.tashow.cloud.datapermission.core.aop.DataPermissionContextHolder; -import com.tashow.cloud.datapermission.core.util.DataPermissionUtils; +import com.tashow.cloud.permission.core.util.DataPermissionUtils; +import com.tashow.cloud.permission.core.aop.DataPermissionContextHolder; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRule.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRule.java similarity index 95% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRule.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRule.java index 18e98f2..ffc4afb 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRule.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRule.java @@ -1,4 +1,4 @@ -package com.tashow.cloud.datapermission.core.rule; +package com.tashow.cloud.permission.core.rule; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import net.sf.jsqlparser.expression.Alias; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRuleFactory.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRuleFactory.java similarity index 92% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRuleFactory.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRuleFactory.java index 1b919cc..65c3dae 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRuleFactory.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRuleFactory.java @@ -1,4 +1,4 @@ -package com.tashow.cloud.datapermission.core.rule; +package com.tashow.cloud.permission.core.rule; import java.util.List; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRuleFactoryImpl.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRuleFactoryImpl.java similarity index 91% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRuleFactoryImpl.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRuleFactoryImpl.java index 024d793..3a81cf4 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/DataPermissionRuleFactoryImpl.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/DataPermissionRuleFactoryImpl.java @@ -1,9 +1,9 @@ -package com.tashow.cloud.datapermission.core.rule; +package com.tashow.cloud.permission.core.rule; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; -import com.tashow.cloud.datapermission.core.annotation.DataPermission; -import com.tashow.cloud.datapermission.core.aop.DataPermissionContextHolder; +import com.tashow.cloud.permission.core.annotation.DataPermission; +import com.tashow.cloud.permission.core.aop.DataPermissionContextHolder; import lombok.RequiredArgsConstructor; import java.util.Collections; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/DeptDataPermissionRule.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/DeptDataPermissionRule.java similarity index 92% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/DeptDataPermissionRule.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/DeptDataPermissionRule.java index 8717f62..65ea201 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/DeptDataPermissionRule.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/DeptDataPermissionRule.java @@ -1,18 +1,18 @@ -package com.tashow.cloud.datapermission.core.rule.dept; +package com.tashow.cloud.permission.core.rule.dept; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import com.tashow.cloud.datapermission.core.rule.DataPermissionRule; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; -import cn.iocoder.yudao.framework.security.core.LoginUser; -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.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.mybatis.mybatis.core.util.MyBatisUtils; +import com.tashow.cloud.permission.core.rule.DataPermissionRule; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; +import com.tashow.cloud.systemapi.api.permission.PermissionApi; +import com.tashow.cloud.systemapi.api.permission.dto.DeptDataPermissionRespDTO; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/DeptDataPermissionRuleCustomizer.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/DeptDataPermissionRuleCustomizer.java similarity index 90% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/DeptDataPermissionRuleCustomizer.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/DeptDataPermissionRuleCustomizer.java index ba66b40..c26f74e 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/DeptDataPermissionRuleCustomizer.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/DeptDataPermissionRuleCustomizer.java @@ -1,4 +1,4 @@ -package com.tashow.cloud.datapermission.core.rule.dept; +package com.tashow.cloud.permission.core.rule.dept; /** * {@link DeptDataPermissionRule} 的自定义配置接口 diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/package-info.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/package-info.java similarity index 56% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/package-info.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/package-info.java index eaa07fc..d6579cb 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/rule/dept/package-info.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/rule/dept/package-info.java @@ -3,4 +3,4 @@ * * @author 芋道源码 */ -package com.tashow.cloud.datapermission.core.rule.dept; +package com.tashow.cloud.permission.core.rule.dept; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/util/DataPermissionUtils.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/util/DataPermissionUtils.java similarity index 89% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/util/DataPermissionUtils.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/util/DataPermissionUtils.java index ad28371..9318a71 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/core/util/DataPermissionUtils.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/core/util/DataPermissionUtils.java @@ -1,7 +1,7 @@ -package com.tashow.cloud.datapermission.core.util; +package com.tashow.cloud.permission.core.util; -import com.tashow.cloud.datapermission.core.annotation.DataPermission; -import com.tashow.cloud.datapermission.core.aop.DataPermissionContextHolder; +import com.tashow.cloud.permission.core.annotation.DataPermission; +import com.tashow.cloud.permission.core.aop.DataPermissionContextHolder; import lombok.SneakyThrows; import java.util.concurrent.Callable; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/package-info.java b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/package-info.java similarity index 65% rename from tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/package-info.java rename to tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/package-info.java index a431677..3ce447d 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/datapermission/package-info.java +++ b/tashow-platform-framework/tashow-data-permission/src/main/java/com/tashow/cloud/permission/package-info.java @@ -1,4 +1,4 @@ /** * 基于 JSqlParser 解析 SQL,增加数据权限的 WHERE 条件 */ -package com.tashow.cloud.datapermission; +package com.tashow.cloud.permission; diff --git a/tashow-platform-framework/tashow-data-permission/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-data-permission/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 414a746..95e116a 100644 --- a/tashow-platform-framework/tashow-data-permission/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/tashow-platform-framework/tashow-data-permission/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,3 +1,3 @@ -com.tashow.cloud.datapermission.config.DataPermissionAutoConfiguration -com.tashow.cloud.datapermission.config.DeptDataPermissionAutoConfiguration -com.tashow.cloud.datapermission.config.DataPermissionRpcAutoConfiguration +com.tashow.cloud.permission.config.DataPermissionAutoConfiguration +com.tashow.cloud.permission.config.DeptDataPermissionAutoConfiguration +com.tashow.cloud.permission.config.DataPermissionRpcAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/pom.xml b/tashow-platform-framework/tashow-data-redis/pom.xml similarity index 78% rename from tashow-platform-framework/yudao-spring-boot-starter-redis/pom.xml rename to tashow-platform-framework/tashow-data-redis/pom.xml index 5fea8a2..1ab70f3 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-redis/pom.xml +++ b/tashow-platform-framework/tashow-data-redis/pom.xml @@ -2,23 +2,22 @@ + 4.0.0 - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} - 4.0.0 - yudao-spring-boot-starter-redis + tashow-data-redis jar ${project.artifactId} Redis 封装拓展 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java b/tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/CacheAutoConfiguration.java similarity index 82% rename from tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java rename to tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/CacheAutoConfiguration.java index 9e84c4a..a8ec5b5 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/CacheAutoConfiguration.java @@ -1,9 +1,8 @@ -package cn.iocoder.yudao.framework.redis.config; +package com.tashow.cloud.redis.config; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager; +import com.tashow.cloud.redis.core.TimeoutRedisCacheManager; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.cache.CacheProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; @@ -19,15 +18,16 @@ import org.springframework.util.StringUtils; import java.util.Objects; -import static cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration.buildRedisSerializer; +import static com.tashow.cloud.redis.config.RedisAutoConfiguration.buildRedisSerializer; + /** * Cache 配置类,基于 Redis 实现 */ @AutoConfiguration -@EnableConfigurationProperties({CacheProperties.class, YudaoCacheProperties.class}) +@EnableConfigurationProperties({org.springframework.boot.autoconfigure.cache.CacheProperties.class, CacheProperties.class}) @EnableCaching -public class YudaoCacheAutoConfiguration { +public class CacheAutoConfiguration { /** * RedisCacheConfiguration Bean @@ -36,7 +36,7 @@ public class YudaoCacheAutoConfiguration { */ @Bean @Primary - public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) { + public RedisCacheConfiguration redisCacheConfiguration(org.springframework.boot.autoconfigure.cache.CacheProperties cacheProperties) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 设置使用 : 单冒号,而不是双 :: 冒号,避免 Redis Desktop Manager 多余空格 // 详细可见 https://blog.csdn.net/chuixue24/article/details/103928965 博客 @@ -54,7 +54,7 @@ public class YudaoCacheAutoConfiguration { RedisSerializationContext.SerializationPair.fromSerializer(buildRedisSerializer())); // 设置 CacheProperties.Redis 的属性 - CacheProperties.Redis redisProperties = cacheProperties.getRedis(); + org.springframework.boot.autoconfigure.cache.CacheProperties.Redis redisProperties = cacheProperties.getRedis(); if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } @@ -70,7 +70,7 @@ public class YudaoCacheAutoConfiguration { @Bean public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate, RedisCacheConfiguration redisCacheConfiguration, - YudaoCacheProperties yudaoCacheProperties) { + CacheProperties yudaoCacheProperties) { // 创建 RedisCacheWriter 对象 RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory()); RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory, diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheProperties.java b/tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/CacheProperties.java similarity index 79% rename from tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheProperties.java rename to tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/CacheProperties.java index c51219d..6ce9099 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheProperties.java +++ b/tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/CacheProperties.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.redis.config; +package com.tashow.cloud.redis.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -9,10 +9,10 @@ import org.springframework.validation.annotation.Validated; * * @author Wanwan */ -@ConfigurationProperties("yudao.cache") +@ConfigurationProperties("tashow.cache") @Data @Validated -public class YudaoCacheProperties { +public class CacheProperties { /** * {@link #redisScanBatchSize} 默认值 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java b/tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/RedisAutoConfiguration.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java rename to tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/RedisAutoConfiguration.java index 01eeb04..39a9ee7 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java +++ b/tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/config/RedisAutoConfiguration.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.redis.config; +package com.tashow.cloud.redis.config; import cn.hutool.core.util.ReflectUtil; import com.fasterxml.jackson.databind.ObjectMapper; @@ -14,7 +14,7 @@ import org.springframework.data.redis.serializer.RedisSerializer; * Redis 配置类 */ @AutoConfiguration(before = RedissonAutoConfigurationV2.class) // 目的:使用自己定义的 RedisTemplate Bean -public class YudaoRedisAutoConfiguration { +public class RedisAutoConfiguration { /** * 创建 RedisTemplate Bean,使用 JSON 序列化方式 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java b/tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/core/TimeoutRedisCacheManager.java similarity index 98% rename from tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java rename to tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/core/TimeoutRedisCacheManager.java index a835835..57280de 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java +++ b/tashow-platform-framework/tashow-data-redis/src/main/java/com/tashow/cloud/redis/core/TimeoutRedisCacheManager.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.redis.core; +package com.tashow.cloud.redis.core; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; diff --git a/tashow-platform-framework/tashow-data-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-data-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..bcaa8a2 --- /dev/null +++ b/tashow-platform-framework/tashow-data-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.tashow.cloud.redis.config.RedisAutoConfiguration +com.tashow.cloud.redis.config.CacheAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Cache 入门》.md b/tashow-platform-framework/tashow-data-redis/《芋道 Spring Boot Cache 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Cache 入门》.md rename to tashow-platform-framework/tashow-data-redis/《芋道 Spring Boot Cache 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Redis 入门》.md b/tashow-platform-framework/tashow-data-redis/《芋道 Spring Boot Redis 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Redis 入门》.md rename to tashow-platform-framework/tashow-data-redis/《芋道 Spring Boot Redis 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/pom.xml b/tashow-platform-framework/tashow-framework-env/pom.xml similarity index 85% rename from tashow-platform-framework/yudao-spring-boot-starter-env/pom.xml rename to tashow-platform-framework/tashow-framework-env/pom.xml index 2bf0efe..ea2eeb9 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/pom.xml +++ b/tashow-platform-framework/tashow-framework-env/pom.xml @@ -3,12 +3,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} 4.0.0 - yudao-spring-boot-starter-env + tashow-framework-env jar ${project.artifactId} @@ -16,7 +16,6 @@ 开发环境拓展,实现类似阿里的特性环境的能力 1. https://segmentfault.com/a/1190000018022987 - https://github.com/YunaiV/ruoyi-vue-pro 8 @@ -25,8 +24,8 @@ - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvEnvironmentPostProcessor.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvEnvironmentPostProcessor.java similarity index 86% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvEnvironmentPostProcessor.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvEnvironmentPostProcessor.java index 29d8991..d9d1180 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvEnvironmentPostProcessor.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvEnvironmentPostProcessor.java @@ -1,15 +1,16 @@ -package cn.iocoder.yudao.framework.env.config; +package com.tashow.cloud.env.config; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.framework.env.core.util.EnvUtils; +import com.tashow.cloud.common.util.collection.SetUtils; +import com.tashow.cloud.env.core.util.EnvUtils; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.core.env.ConfigurableEnvironment; import java.util.Set; -import static cn.iocoder.yudao.framework.env.core.util.EnvUtils.HOST_NAME_VALUE; +import static com.tashow.cloud.env.core.util.EnvUtils.HOST_NAME_VALUE; + /** * 多环境的 {@link EnvEnvironmentPostProcessor} 实现类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvProperties.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvProperties.java similarity index 62% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvProperties.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvProperties.java index 1c88ff2..a49755f 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/EnvProperties.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvProperties.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.env.config; +package com.tashow.cloud.env.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -8,11 +8,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * * @author 芋道源码 */ -@ConfigurationProperties(prefix = "yudao.env") +@ConfigurationProperties(prefix = "tashow.env") @Data public class EnvProperties { - public static final String TAG_KEY = "yudao.env.tag"; + public static final String TAG_KEY = "tashow.env.tag"; /** * 环境标签 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvRpcAutoConfiguration.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvRpcAutoConfiguration.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvRpcAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvRpcAutoConfiguration.java index b288f19..dd9ed4f 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvRpcAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvRpcAutoConfiguration.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.env.config; +package com.tashow.cloud.env.config; -import cn.iocoder.yudao.framework.env.core.fegin.EnvLoadBalancerClientFactory; -import cn.iocoder.yudao.framework.env.core.fegin.EnvRequestInterceptor; +import com.tashow.cloud.env.core.fegin.EnvLoadBalancerClientFactory; +import com.tashow.cloud.env.core.fegin.EnvRequestInterceptor; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -21,7 +21,7 @@ import java.util.List; */ @AutoConfiguration @EnableConfigurationProperties(EnvProperties.class) -public class YudaoEnvRpcAutoConfiguration { +public class EnvRpcAutoConfiguration { // ========== Feign 相关 ========== diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvWebAutoConfiguration.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvWebAutoConfiguration.java similarity index 81% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvWebAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvWebAutoConfiguration.java index 0dc1223..53560e3 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/config/YudaoEnvWebAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/config/EnvWebAutoConfiguration.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.env.config; +package com.tashow.cloud.env.config; -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import cn.iocoder.yudao.framework.env.core.web.EnvWebFilter; +import com.tashow.cloud.common.enums.WebFilterOrderEnum; +import com.tashow.cloud.env.core.web.EnvWebFilter; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -16,7 +16,7 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @EnableConfigurationProperties(EnvProperties.class) -public class YudaoEnvWebAutoConfiguration { +public class EnvWebAutoConfiguration { /** * 创建 {@link EnvWebFilter} Bean diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/context/EnvContextHolder.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/context/EnvContextHolder.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/context/EnvContextHolder.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/context/EnvContextHolder.java index a8eafc6..40f1565 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/context/EnvContextHolder.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/context/EnvContextHolder.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.env.core.context; +package com.tashow.cloud.env.core.context; import cn.hutool.core.collection.CollUtil; import com.alibaba.ttl.TransmittableThreadLocal; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvLoadBalancerClient.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvLoadBalancerClient.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvLoadBalancerClient.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvLoadBalancerClient.java index ac136e6..82d9552 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvLoadBalancerClient.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvLoadBalancerClient.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.framework.env.core.fegin; +package com.tashow.cloud.env.core.fegin; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.env.core.context.EnvContextHolder; -import cn.iocoder.yudao.framework.env.core.util.EnvUtils; import com.alibaba.cloud.nacos.balancer.NacosBalancer; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.env.core.context.EnvContextHolder; +import com.tashow.cloud.env.core.util.EnvUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.ObjectProvider; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvLoadBalancerClientFactory.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvLoadBalancerClientFactory.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvLoadBalancerClientFactory.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvLoadBalancerClientFactory.java index e6d0953..cb879ce 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvLoadBalancerClientFactory.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvLoadBalancerClientFactory.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.env.core.fegin; +package com.tashow.cloud.env.core.fegin; import org.springframework.cloud.client.ServiceInstance; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvRequestInterceptor.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvRequestInterceptor.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvRequestInterceptor.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvRequestInterceptor.java index 4c60eb5..4cd461d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/fegin/EnvRequestInterceptor.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/fegin/EnvRequestInterceptor.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.env.core.fegin; +package com.tashow.cloud.env.core.fegin; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.env.core.context.EnvContextHolder; -import cn.iocoder.yudao.framework.env.core.util.EnvUtils; +import com.tashow.cloud.env.core.context.EnvContextHolder; +import com.tashow.cloud.env.core.util.EnvUtils; import feign.RequestInterceptor; import feign.RequestTemplate; diff --git a/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/package-info.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/package-info.java new file mode 100644 index 0000000..ee6717d --- /dev/null +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/package-info.java @@ -0,0 +1 @@ +package com.tashow.cloud.env.core; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/util/EnvUtils.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/util/EnvUtils.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/util/EnvUtils.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/util/EnvUtils.java index b4e265e..8aebcec 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/util/EnvUtils.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/util/EnvUtils.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.env.core.util; +package com.tashow.cloud.env.core.util; -import cn.iocoder.yudao.framework.env.config.EnvProperties; +import com.tashow.cloud.env.config.EnvProperties; import feign.RequestTemplate; +import jakarta.servlet.http.HttpServletRequest; import lombok.SneakyThrows; import org.springframework.cloud.client.ServiceInstance; import org.springframework.core.env.Environment; -import jakarta.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.util.Objects; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/web/EnvWebFilter.java b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/web/EnvWebFilter.java similarity index 86% rename from tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/web/EnvWebFilter.java rename to tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/web/EnvWebFilter.java index 93964de..31fa82e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/web/EnvWebFilter.java +++ b/tashow-platform-framework/tashow-framework-env/src/main/java/com/tashow/cloud/env/core/web/EnvWebFilter.java @@ -1,14 +1,14 @@ -package cn.iocoder.yudao.framework.env.core.web; +package com.tashow.cloud.env.core.web; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.env.core.context.EnvContextHolder; -import cn.iocoder.yudao.framework.env.core.util.EnvUtils; -import org.springframework.web.filter.OncePerRequestFilter; - +import com.tashow.cloud.env.core.context.EnvContextHolder; +import com.tashow.cloud.env.core.util.EnvUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + import java.io.IOException; /** diff --git a/tashow-platform-framework/tashow-framework-env/src/main/resources/META-INF/spring.factories b/tashow-platform-framework/tashow-framework-env/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..7178c49 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-env/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ + com.tashow.cloud.env.config.EnvEnvironmentPostProcessor diff --git a/tashow-platform-framework/tashow-framework-env/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-framework-env/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..8858e5b --- /dev/null +++ b/tashow-platform-framework/tashow-framework-env/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.tashow.cloud.env.config.EnvWebAutoConfiguration +com.tashow.cloud.env.config.EnvRpcAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/pom.xml b/tashow-platform-framework/tashow-framework-ip/pom.xml similarity index 81% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-ip/pom.xml rename to tashow-platform-framework/tashow-framework-ip/pom.xml index d33f2eb..7eaa072 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/pom.xml +++ b/tashow-platform-framework/tashow-framework-ip/pom.xml @@ -2,13 +2,13 @@ + 4.0.0 - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} - 4.0.0 - yudao-spring-boot-starter-biz-ip + tashow-framework-ip jar ${project.artifactId} @@ -18,12 +18,11 @@ 2. 城市功能:查询城市编码对应的城市信息 基于 https://github.com/modood/Administrative-divisions-of-China 实现 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/Area.java similarity index 91% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java rename to tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/Area.java index 3027085..685a0de 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java +++ b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/Area.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.ip.core; +package com.tashow.cloud.ip.core; -import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.tashow.cloud.ip.core.enums.AreaTypeEnum; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/enums/AreaTypeEnum.java b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/enums/AreaTypeEnum.java similarity index 86% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/enums/AreaTypeEnum.java rename to tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/enums/AreaTypeEnum.java index 1698ad2..3aabdc4 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/enums/AreaTypeEnum.java +++ b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/enums/AreaTypeEnum.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.ip.core.enums; +package com.tashow.cloud.ip.core.enums; -import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import com.tashow.cloud.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/utils/AreaUtils.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java rename to tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/utils/AreaUtils.java index 8e27a31..500fd4c 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java +++ b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/utils/AreaUtils.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.ip.core.utils; +package com.tashow.cloud.ip.core.utils; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.text.csv.CsvRow; import cn.hutool.core.text.csv.CsvUtil; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.ip.core.Area; -import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import com.tashow.cloud.common.util.object.ObjectUtils; +import com.tashow.cloud.ip.core.Area; +import com.tashow.cloud.ip.core.enums.AreaTypeEnum; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -16,8 +16,9 @@ import java.util.List; import java.util.Map; import java.util.function.Function; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; +import static com.tashow.cloud.common.util.collection.CollectionUtils.findFirst; + /** * 区域工具类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/utils/IPUtils.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java rename to tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/utils/IPUtils.java index f74f848..2dfcc06 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java +++ b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/core/utils/IPUtils.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.ip.core.utils; +package com.tashow.cloud.ip.core.utils; import cn.hutool.core.io.resource.ResourceUtil; -import cn.iocoder.yudao.framework.ip.core.Area; +import com.tashow.cloud.ip.core.Area; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.lionsoul.ip2region.xdb.Searcher; diff --git a/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/package-info.java b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/package-info.java new file mode 100644 index 0000000..f1ecaa6 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-ip/src/main/java/com/tashow/cloud/ip/package-info.java @@ -0,0 +1,6 @@ +/** + * @Author liwq + * @Date 2025年04月16日 10:38 + * @Desc + */ +package com.tashow.cloud.ip; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv b/tashow-platform-framework/tashow-framework-ip/src/main/resources/area.csv similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv rename to tashow-platform-framework/tashow-framework-ip/src/main/resources/area.csv diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/ip2region.xdb b/tashow-platform-framework/tashow-framework-ip/src/main/resources/ip2region.xdb similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/ip2region.xdb rename to tashow-platform-framework/tashow-framework-ip/src/main/resources/ip2region.xdb diff --git a/tashow-platform-framework/yudao-spring-boot-starter-job/pom.xml b/tashow-platform-framework/tashow-framework-job/pom.xml similarity index 81% rename from tashow-platform-framework/yudao-spring-boot-starter-job/pom.xml rename to tashow-platform-framework/tashow-framework-job/pom.xml index 01b5ff1..7783350 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-job/pom.xml +++ b/tashow-platform-framework/tashow-framework-job/pom.xml @@ -2,23 +2,22 @@ + 4.0.0 - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} - 4.0.0 - yudao-spring-boot-starter-job + tashow-framework-job jar ${project.artifactId} 任务拓展,基于 XXL-Job 实现 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common diff --git a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java b/tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/AsyncAutoConfiguration.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/AsyncAutoConfiguration.java index bcf0e65..5aea1a8 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/AsyncAutoConfiguration.java @@ -1,11 +1,10 @@ -package cn.iocoder.yudao.framework.quartz.config; +package com.tashow.cloud.quartz.config; import com.alibaba.ttl.TtlRunnable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -14,7 +13,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; */ @AutoConfiguration @EnableAsync -public class YudaoAsyncAutoConfiguration { +public class AsyncAutoConfiguration { @Bean public BeanPostProcessor threadPoolTaskExecutorBeanPostProcessor() { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoXxlJobAutoConfiguration.java b/tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/XxlJobAutoConfiguration.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoXxlJobAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/XxlJobAutoConfiguration.java index 6fa99cc..8c6b9b6 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoXxlJobAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/XxlJobAutoConfiguration.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.quartz.config; +package com.tashow.cloud.quartz.config; import com.xxl.job.core.executor.XxlJobExecutor; import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; @@ -9,7 +9,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; /** @@ -23,7 +22,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; @EnableConfigurationProperties({XxlJobProperties.class}) @EnableScheduling // 开启 Spring 自带的定时任务 @Slf4j -public class YudaoXxlJobAutoConfiguration { +public class XxlJobAutoConfiguration { @Bean @ConditionalOnMissingBean diff --git a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/XxlJobProperties.java b/tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/XxlJobProperties.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/XxlJobProperties.java rename to tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/XxlJobProperties.java index e5955ee..1fc7157 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/XxlJobProperties.java +++ b/tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/config/XxlJobProperties.java @@ -1,12 +1,11 @@ -package cn.iocoder.yudao.framework.quartz.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.validation.annotation.Validated; +package com.tashow.cloud.quartz.config; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; /** * XXL-Job 配置类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java b/tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/package-info.java similarity index 72% rename from tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java rename to tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/package-info.java index 9781e82..60b8974 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java +++ b/tashow-platform-framework/tashow-framework-job/src/main/java/com/tashow/cloud/quartz/package-info.java @@ -2,4 +2,4 @@ * 1. 定时任务,基于 XXL-Job 实现。 * 2. 异步任务,采用 Spring Async 异步执行。 */ -package cn.iocoder.yudao.framework.quartz; +package com.tashow.cloud.quartz; diff --git a/tashow-platform-framework/tashow-framework-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-framework-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..d4b951c --- /dev/null +++ b/tashow-platform-framework/tashow-framework-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.tashow.cloud.quartz.config.XxlJobAutoConfiguration +com.tashow.cloud.quartz.config.AsyncAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 定时任务入门》.md b/tashow-platform-framework/tashow-framework-job/《芋道 Spring Boot 定时任务入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 定时任务入门》.md rename to tashow-platform-framework/tashow-framework-job/《芋道 Spring Boot 定时任务入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 异步任务入门》.md b/tashow-platform-framework/tashow-framework-job/《芋道 Spring Boot 异步任务入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 异步任务入门》.md rename to tashow-platform-framework/tashow-framework-job/《芋道 Spring Boot 异步任务入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/pom.xml b/tashow-platform-framework/tashow-framework-monitor/pom.xml similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/pom.xml rename to tashow-platform-framework/tashow-framework-monitor/pom.xml index 497aca6..2dd2592 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/pom.xml +++ b/tashow-platform-framework/tashow-framework-monitor/pom.xml @@ -2,23 +2,22 @@ + 4.0.0 - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} - 4.0.0 - yudao-spring-boot-starter-monitor + tashow-framework-monitor jar ${project.artifactId} 服务监控,提供链路追踪、日志服务、指标收集等等功能 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/MetricsAutoConfiguration.java similarity index 73% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/MetricsAutoConfiguration.java index 9b75d96..d2fde41 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/MetricsAutoConfiguration.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tracer.config; +package com.tashow.cloud.monitor.config; import io.micrometer.core.instrument.MeterRegistry; import org.springframework.beans.factory.annotation.Value; @@ -7,7 +7,6 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; /** * Metrics 配置类 @@ -16,8 +15,8 @@ import org.springframework.context.annotation.Configuration; */ @AutoConfiguration @ConditionalOnClass({MeterRegistryCustomizer.class}) -@ConditionalOnProperty(prefix = "yudao.metrics", value = "enable", matchIfMissing = true) // 允许使用 yudao.metrics.enable=false 禁用 Metrics -public class YudaoMetricsAutoConfiguration { +@ConditionalOnProperty(prefix = "tashow.metrics", value = "enable", matchIfMissing = true) // 允许使用 yudao.metrics.enable=false 禁用 Metrics +public class MetricsAutoConfiguration { @Bean public MeterRegistryCustomizer metricsCommonTags( diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/TracerAutoConfiguration.java similarity index 81% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/TracerAutoConfiguration.java index a3fa165..f013466 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/TracerAutoConfiguration.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.tracer.config; +package com.tashow.cloud.monitor.config; -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import cn.iocoder.yudao.framework.tracer.core.aop.BizTraceAspect; -import cn.iocoder.yudao.framework.tracer.core.filter.TraceFilter; +import com.tashow.cloud.common.enums.WebFilterOrderEnum; +import com.tashow.cloud.monitor.core.aop.BizTraceAspect; +import com.tashow.cloud.monitor.core.filter.TraceFilter; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -18,8 +18,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass(value = {BizTraceAspect.class}, name = "jakarta.servlet.Filter") @EnableConfigurationProperties(TracerProperties.class) -@ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true) -public class YudaoTracerAutoConfiguration { +@ConditionalOnProperty(prefix = "tashow.tracer", value = "enable", matchIfMissing = true) +public class TracerAutoConfiguration { // TODO @芋艿:重要。目前 opentracing 版本存在冲突,要么保证 skywalking,要么保证阿里云短信 sdk // @Bean diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerProperties.java b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/TracerProperties.java similarity index 67% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerProperties.java rename to tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/TracerProperties.java index 11d25a8..ebdbe3d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerProperties.java +++ b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/config/TracerProperties.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tracer.config; +package com.tashow.cloud.monitor.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -8,7 +8,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * * @author 麻薯 */ -@ConfigurationProperties("yudao.tracer") +@ConfigurationProperties("tashow.tracer") @Data public class TracerProperties { } diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/annotation/BizTrace.java b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/annotation/BizTrace.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/annotation/BizTrace.java rename to tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/annotation/BizTrace.java index 8b12140..97662ba 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/annotation/BizTrace.java +++ b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/annotation/BizTrace.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tracer.core.annotation; +package com.tashow.cloud.monitor.core.annotation; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/aop/BizTraceAspect.java similarity index 90% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java rename to tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/aop/BizTraceAspect.java index 3c3b9f3..825832e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java +++ b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/aop/BizTraceAspect.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.tracer.core.aop; +package com.tashow.cloud.monitor.core.aop; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.tracer.core.annotation.BizTrace; -import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; -import cn.iocoder.yudao.framework.tracer.core.util.TracerFrameworkUtils; +import com.tashow.cloud.common.util.spring.SpringExpressionUtils; +import com.tashow.cloud.monitor.core.annotation.BizTrace; +import com.tashow.cloud.monitor.core.util.TracerFrameworkUtils; import io.opentracing.Span; import io.opentracing.Tracer; import io.opentracing.tag.Tags; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/filter/TraceFilter.java b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/filter/TraceFilter.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/filter/TraceFilter.java rename to tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/filter/TraceFilter.java index e8d7ca1..0925c98 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/filter/TraceFilter.java +++ b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/filter/TraceFilter.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.tracer.core.filter; - -import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; -import org.springframework.web.filter.OncePerRequestFilter; +package com.tashow.cloud.monitor.core.filter; +import com.tashow.cloud.common.util.monitor.TracerUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + import java.io.IOException; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/util/TracerFrameworkUtils.java b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/util/TracerFrameworkUtils.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/util/TracerFrameworkUtils.java rename to tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/util/TracerFrameworkUtils.java index 51323e7..9ed6cbd 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/util/TracerFrameworkUtils.java +++ b/tashow-platform-framework/tashow-framework-monitor/src/main/java/com/tashow/cloud/monitor/core/util/TracerFrameworkUtils.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tracer.core.util; +package com.tashow.cloud.monitor.core.util; import io.opentracing.Span; import io.opentracing.tag.Tags; diff --git a/tashow-platform-framework/tashow-framework-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-framework-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..0a9b037 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.tashow.cloud.monitor.config.TracerAutoConfiguration +com.tashow.cloud.monitor.config.MetricsAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md b/tashow-platform-framework/tashow-framework-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md rename to tashow-platform-framework/tashow-framework-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md b/tashow-platform-framework/tashow-framework-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md rename to tashow-platform-framework/tashow-framework-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md b/tashow-platform-framework/tashow-framework-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md rename to tashow-platform-framework/tashow-framework-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/pom.xml b/tashow-platform-framework/tashow-framework-mq/pom.xml similarity index 79% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/pom.xml rename to tashow-platform-framework/tashow-framework-mq/pom.xml index 2291ca7..7e331ec 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/pom.xml +++ b/tashow-platform-framework/tashow-framework-mq/pom.xml @@ -2,24 +2,23 @@ + 4.0.0 - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} - 4.0.0 - yudao-spring-boot-starter-mq + tashow-framework-mq jar ${project.artifactId} 消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-spring-boot-starter-redis + com.tashow.cloud + tashow-data-redis diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/config/RabbitMQAutoConfiguration.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/config/RabbitMQAutoConfiguration.java index af14673..f161527 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/config/RabbitMQAutoConfiguration.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.mq.rabbitmq.config; +package com.tashow.cloud.mq.rabbitmq.config; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; @@ -15,7 +15,7 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @Slf4j @ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate") -public class YudaoRabbitMQAutoConfiguration { +public class RabbitMQAutoConfiguration { /** * Jackson2JsonMessageConverter Bean:使用 jackson 序列化消息 diff --git a/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/core/package-info.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/core/package-info.java new file mode 100644 index 0000000..8de99aa --- /dev/null +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,无特殊逻辑 + */ +package com.tashow.cloud.mq.rabbitmq.core; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/package-info.java similarity index 50% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/package-info.java index 9f6032c..ce65891 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/rabbitmq/package-info.java @@ -1,4 +1,4 @@ /** * 消息队列,基于 RabbitMQ 提供 */ -package cn.iocoder.yudao.framework.mq.rabbitmq; +package com.tashow.cloud.mq.rabbitmq; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/config/RedisMQConsumerAutoConfiguration.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/config/RedisMQConsumerAutoConfiguration.java index d02e84b..c26f4d2 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/config/RedisMQConsumerAutoConfiguration.java @@ -1,14 +1,14 @@ -package cn.iocoder.yudao.framework.mq.redis.config; +package com.tashow.cloud.mq.redis.config; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.system.SystemUtil; -import cn.iocoder.yudao.framework.common.enums.DocumentEnum; -import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; -import cn.iocoder.yudao.framework.mq.redis.core.job.RedisPendingMessageResendJob; -import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessageListener; -import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener; -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import com.tashow.cloud.common.enums.DocumentEnum; +import com.tashow.cloud.mq.redis.core.RedisMQTemplate; +import com.tashow.cloud.mq.redis.core.job.RedisPendingMessageResendJob; +import com.tashow.cloud.mq.redis.core.pubsub.AbstractRedisChannelMessageListener; +import com.tashow.cloud.mq.redis.core.stream.AbstractRedisStreamMessageListener; +import com.tashow.cloud.redis.config.RedisAutoConfiguration; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Value; @@ -37,8 +37,8 @@ import java.util.Properties; */ @Slf4j @EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息 -@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) -public class YudaoRedisMQConsumerAutoConfiguration { +@AutoConfiguration(after = RedisAutoConfiguration.class) +public class RedisMQConsumerAutoConfiguration { /** * 创建 Redis Pub/Sub 广播消费的容器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQProducerAutoConfiguration.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/config/RedisMQProducerAutoConfiguration.java similarity index 64% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQProducerAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/config/RedisMQProducerAutoConfiguration.java index c1950c4..0b2a62a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQProducerAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/config/RedisMQProducerAutoConfiguration.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.mq.redis.config; +package com.tashow.cloud.mq.redis.config; -import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; -import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import com.tashow.cloud.mq.redis.core.RedisMQTemplate; +import com.tashow.cloud.mq.redis.core.interceptor.RedisMessageInterceptor; +import com.tashow.cloud.redis.config.RedisAutoConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; @@ -16,8 +16,8 @@ import java.util.List; * @author 芋道源码 */ @Slf4j -@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) -public class YudaoRedisMQProducerAutoConfiguration { +@AutoConfiguration(after = RedisAutoConfiguration.class) +public class RedisMQProducerAutoConfiguration { @Bean public RedisMQTemplate redisMQTemplate(StringRedisTemplate redisTemplate, diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/RedisMQTemplate.java similarity index 83% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/RedisMQTemplate.java index 5755ffa..6d79c41 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/RedisMQTemplate.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.mq.redis.core; +package com.tashow.cloud.mq.redis.core; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; -import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; -import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessage; -import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessage; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.mq.redis.core.interceptor.RedisMessageInterceptor; +import com.tashow.cloud.mq.redis.core.message.AbstractRedisMessage; +import com.tashow.cloud.mq.redis.core.pubsub.AbstractRedisChannelMessage; +import com.tashow.cloud.mq.redis.core.stream.AbstractRedisStreamMessage; import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.data.redis.connection.stream.RecordId; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/interceptor/RedisMessageInterceptor.java similarity index 79% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/interceptor/RedisMessageInterceptor.java index dbcee7f..3cea3ff 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/interceptor/RedisMessageInterceptor.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.mq.redis.core.interceptor; +package com.tashow.cloud.mq.redis.core.interceptor; -import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import com.tashow.cloud.mq.redis.core.message.AbstractRedisMessage; /** * {@link AbstractRedisMessage} 消息拦截器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/job/RedisPendingMessageResendJob.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/job/RedisPendingMessageResendJob.java index b84f17c..7ddd81d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/job/RedisPendingMessageResendJob.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.mq.redis.core.job; +package com.tashow.cloud.mq.redis.core.job; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; -import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener; +import com.tashow.cloud.mq.redis.core.RedisMQTemplate; +import com.tashow.cloud.mq.redis.core.stream.AbstractRedisStreamMessageListener; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/message/AbstractRedisMessage.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/message/AbstractRedisMessage.java index ee40814..546934a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/message/AbstractRedisMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.mq.redis.core.message; +package com.tashow.cloud.mq.redis.core.message; import lombok.Data; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/pubsub/AbstractRedisChannelMessage.java similarity index 78% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/pubsub/AbstractRedisChannelMessage.java index d5ea5b9..3a46d92 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/pubsub/AbstractRedisChannelMessage.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.mq.redis.core.pubsub; +package com.tashow.cloud.mq.redis.core.pubsub; -import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tashow.cloud.mq.redis.core.message.AbstractRedisMessage; /** * Redis Channel Message 抽象类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java index fd7c910..b64a550 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.mq.redis.core.pubsub; +package com.tashow.cloud.mq.redis.core.pubsub; import cn.hutool.core.util.TypeUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; -import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; -import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.mq.redis.core.RedisMQTemplate; +import com.tashow.cloud.mq.redis.core.interceptor.RedisMessageInterceptor; +import com.tashow.cloud.mq.redis.core.message.AbstractRedisMessage; import lombok.Setter; import lombok.SneakyThrows; import org.springframework.data.redis.connection.Message; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessage.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/stream/AbstractRedisStreamMessage.java similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessage.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/stream/AbstractRedisStreamMessage.java index 9017e08..d254d84 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessage.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/stream/AbstractRedisStreamMessage.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.mq.redis.core.stream; +package com.tashow.cloud.mq.redis.core.stream; -import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.tashow.cloud.mq.redis.core.message.AbstractRedisMessage; /** * Redis Stream Message 抽象类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessageListener.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/stream/AbstractRedisStreamMessageListener.java similarity index 90% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessageListener.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/stream/AbstractRedisStreamMessageListener.java index 3e656af..bf30a9b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessageListener.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/core/stream/AbstractRedisStreamMessageListener.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.mq.redis.core.stream; +package com.tashow.cloud.mq.redis.core.stream; import cn.hutool.core.util.TypeUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; -import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; -import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.mq.redis.core.RedisMQTemplate; +import com.tashow.cloud.mq.redis.core.interceptor.RedisMessageInterceptor; +import com.tashow.cloud.mq.redis.core.message.AbstractRedisMessage; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/package-info.java similarity index 73% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java rename to tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/package-info.java index 6621fc1..cc39879 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java +++ b/tashow-platform-framework/tashow-framework-mq/src/main/java/com/tashow/cloud/mq/redis/package-info.java @@ -3,4 +3,4 @@ * 1. 基于 Pub/Sub 实现广播消费 * 2. 基于 Stream 实现集群消费 */ -package cn.iocoder.yudao.framework.mq.redis; +package com.tashow.cloud.mq.redis; diff --git a/tashow-platform-framework/tashow-framework-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-framework-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..ea037a6 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +com.tashow.cloud.mq.redis.config.RedisMQProducerAutoConfiguration +com.tashow.cloud.mq.redis.config.RedisMQConsumerAutoConfiguration +com.tashow.cloud.mq.rabbitmq.config.RabbitMQAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md b/tashow-platform-framework/tashow-framework-mq/《芋道 Spring Boot 事件机制 Event 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md rename to tashow-platform-framework/tashow-framework-mq/《芋道 Spring Boot 事件机制 Event 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md b/tashow-platform-framework/tashow-framework-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md rename to tashow-platform-framework/tashow-framework-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md b/tashow-platform-framework/tashow-framework-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md rename to tashow-platform-framework/tashow-framework-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md b/tashow-platform-framework/tashow-framework-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md rename to tashow-platform-framework/tashow-framework-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/pom.xml b/tashow-platform-framework/tashow-framework-protection/pom.xml similarity index 70% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/pom.xml rename to tashow-platform-framework/tashow-framework-protection/pom.xml index 8b95cd0..1553785 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/pom.xml +++ b/tashow-platform-framework/tashow-framework-protection/pom.xml @@ -2,31 +2,30 @@ + 4.0.0 - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} - 4.0.0 - yudao-spring-boot-starter-protection + tashow-framework-protection jar ${project.artifactId} 服务保证,提供分布式锁、幂等、限流、熔断等等功能 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-spring-boot-starter-web + com.tashow.cloud + tashow-framework-web provided - cn.iocoder.cloud - yudao-spring-boot-starter-redis + com.tashow.cloud + tashow-data-redis diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/config/IdempotentConfiguration.java similarity index 58% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/config/IdempotentConfiguration.java index de74963..784bbad 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/config/IdempotentConfiguration.java @@ -1,20 +1,20 @@ -package cn.iocoder.yudao.framework.idempotent.config; +package com.tashow.cloud.protection.idempotent.config; -import cn.iocoder.yudao.framework.idempotent.core.aop.IdempotentAspect; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO; +import com.tashow.cloud.protection.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.aop.IdempotentAspect; +import com.tashow.cloud.protection.idempotent.core.keyresolver.IdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.redis.IdempotentRedisDAO; +import com.tashow.cloud.redis.config.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.core.StringRedisTemplate; import java.util.List; -@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) -public class YudaoIdempotentConfiguration { +@AutoConfiguration(after = RedisAutoConfiguration.class) +public class IdempotentConfiguration { @Bean public IdempotentAspect idempotentAspect(List keyResolvers, IdempotentRedisDAO idempotentRedisDAO) { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/annotation/Idempotent.java similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/annotation/Idempotent.java index cd6add8..2598d72 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/annotation/Idempotent.java @@ -1,9 +1,10 @@ -package cn.iocoder.yudao.framework.idempotent.core.annotation; +package com.tashow.cloud.protection.idempotent.core.annotation; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.keyresolver.IdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/aop/IdempotentAspect.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/aop/IdempotentAspect.java index 11ff765..3fbcc60 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/aop/IdempotentAspect.java @@ -1,16 +1,18 @@ -package cn.iocoder.yudao.framework.idempotent.core.aop; +package com.tashow.cloud.protection.idempotent.core.aop; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO; +import cn.hutool.core.lang.Assert; +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.keyresolver.IdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.keyresolver.IdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.redis.IdempotentRedisDAO; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.springframework.util.Assert; import java.util.List; import java.util.Map; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/IdempotentKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/IdempotentKeyResolver.java similarity index 62% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/IdempotentKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/IdempotentKeyResolver.java index 1617570..2d90fb2 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/IdempotentKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/IdempotentKeyResolver.java @@ -1,6 +1,7 @@ -package cn.iocoder.yudao.framework.idempotent.core.keyresolver; +package com.tashow.cloud.protection.idempotent.core.keyresolver; -import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; import org.aspectj.lang.JoinPoint; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java similarity index 68% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java index 7b5e145..9dfb3e8 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java @@ -1,9 +1,10 @@ -package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl; +package com.tashow.cloud.protection.idempotent.core.keyresolver.impl; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; -import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.keyresolver.IdempotentKeyResolver; import org.aspectj.lang.JoinPoint; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java index 665d327..195361d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java @@ -1,8 +1,9 @@ -package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl; +package com.tashow.cloud.protection.idempotent.core.keyresolver.impl; import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.keyresolver.IdempotentKeyResolver; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.DefaultParameterNameDiscoverer; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java similarity index 73% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java index 2fa91ff..0a58eef 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl; +package com.tashow.cloud.protection.idempotent.core.keyresolver.impl; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; -import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import com.tashow.cloud.protection.idempotent.core.annotation.Idempotent; +import com.tashow.cloud.protection.idempotent.core.keyresolver.IdempotentKeyResolver; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import org.aspectj.lang.JoinPoint; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/redis/IdempotentRedisDAO.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/redis/IdempotentRedisDAO.java index a8d981d..2c4293b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/core/redis/IdempotentRedisDAO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.idempotent.core.redis; +package com.tashow.cloud.protection.idempotent.core.redis; import lombok.AllArgsConstructor; import org.springframework.data.redis.core.StringRedisTemplate; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/package-info.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/package-info.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/package-info.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/package-info.java index 8cad5fc..87ae469 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/package-info.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/idempotent/package-info.java @@ -9,4 +9,4 @@ * 此时,我们偏向使用 Lock4j 组件。原则上,一个组件只提供一种单一的能力。 * 2. 考虑到组件的通用性,我们并未像 it4alla/idempotent 组件一样使用 Redisson RMap 结构,而是直接使用 Redis 的 String 数据格式。 */ -package cn.iocoder.yudao.framework.idempotent; +package com.tashow.cloud.protection.idempotent; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/config/Lock4jConfiguration.java similarity index 68% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/config/Lock4jConfiguration.java index f9b883c..02cc9cd 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/config/Lock4jConfiguration.java @@ -1,14 +1,15 @@ -package cn.iocoder.yudao.framework.lock4j.config; +package com.tashow.cloud.protection.lock4j.config; -import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy; import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration; +import com.tashow.cloud.protection.lock4j.core.DefaultLockFailureStrategy; +import com.tashow.cloud.protection.lock4j.core.DefaultLockFailureStrategy; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; @AutoConfiguration(before = LockAutoConfiguration.class) @ConditionalOnClass(name = "com.baomidou.lock.annotation.Lock4j") -public class YudaoLock4jConfiguration { +public class Lock4jConfiguration { @Bean public DefaultLockFailureStrategy lockFailureStrategy() { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/core/DefaultLockFailureStrategy.java similarity index 74% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/core/DefaultLockFailureStrategy.java index 2cea08b..17b742d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/core/DefaultLockFailureStrategy.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.lock4j.core; +package com.tashow.cloud.protection.lock4j.core; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import com.tashow.cloud.common.exception.ServiceException; import com.baomidou.lock.LockFailureStrategy; +import com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Method; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/core/Lock4jRedisKeyConstants.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/core/Lock4jRedisKeyConstants.java index 693d052..2dc9695 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/core/Lock4jRedisKeyConstants.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.lock4j.core; +package com.tashow.cloud.protection.lock4j.core; /** * Lock4j Redis Key 枚举类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/package-info.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/package-info.java similarity index 66% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/package-info.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/package-info.java index 267b951..627b698 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/package-info.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/lock4j/package-info.java @@ -1,4 +1,4 @@ /** * 分布式锁组件,使用 https://gitee.com/baomidou/lock4j 开源项目 */ -package cn.iocoder.yudao.framework.lock4j; +package com.tashow.cloud.protection.lock4j; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/config/RateLimiterConfiguration.java similarity index 72% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/config/RateLimiterConfiguration.java index 68b910f..0ad87a8 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/config/RateLimiterConfiguration.java @@ -1,18 +1,18 @@ -package cn.iocoder.yudao.framework.ratelimiter.config; +package com.tashow.cloud.protection.ratelimiter.config; -import cn.iocoder.yudao.framework.ratelimiter.core.aop.RateLimiterAspect; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.*; -import cn.iocoder.yudao.framework.ratelimiter.core.redis.RateLimiterRedisDAO; -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import com.tashow.cloud.protection.ratelimiter.core.aop.RateLimiterAspect; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl.*; +import com.tashow.cloud.redis.config.RedisAutoConfiguration; +import com.tashow.cloud.protection.ratelimiter.core.redis.RateLimiterRedisDAO; import org.redisson.api.RedissonClient; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; import java.util.List; -@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) -public class YudaoRateLimiterConfiguration { +@AutoConfiguration(after = RedisAutoConfiguration.class) +public class RateLimiterConfiguration { @Bean public RateLimiterAspect rateLimiterAspect(List keyResolvers, RateLimiterRedisDAO rateLimiterRedisDAO) { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/annotation/RateLimiter.java similarity index 65% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/annotation/RateLimiter.java index 417c4d6..f38237d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/annotation/RateLimiter.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.annotation; +package com.tashow.cloud.protection.ratelimiter.core.annotation; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.ClientIpRateLimiterKeyResolver; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.DefaultRateLimiterKeyResolver; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.ServerNodeRateLimiterKeyResolver; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.UserRateLimiterKeyResolver; +import com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants; +import com.tashow.cloud.protection.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl.DefaultRateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl.UserRateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl.ClientIpRateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl.ServerNodeRateLimiterKeyResolver; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/aop/RateLimiterAspect.java similarity index 79% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/aop/RateLimiterAspect.java index 6ede62b..44f18e6 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/aop/RateLimiterAspect.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.aop; +package com.tashow.cloud.protection.ratelimiter.core.aop; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; -import cn.iocoder.yudao.framework.ratelimiter.core.redis.RateLimiterRedisDAO; +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants; +import com.tashow.cloud.common.util.collection.CollectionUtils; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.annotation.RateLimiter; +import com.tashow.cloud.protection.ratelimiter.core.redis.RateLimiterRedisDAO; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java similarity index 71% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java index 44d7bdf..fc698b0 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver; +package com.tashow.cloud.protection.ratelimiter.core.keyresolver; -import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import com.tashow.cloud.protection.ratelimiter.core.annotation.RateLimiter; import org.aspectj.lang.JoinPoint; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java similarity index 70% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java index 8d6253c..bb7fdbc 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; +package com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.protection.ratelimiter.core.annotation.RateLimiter; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; import org.aspectj.lang.JoinPoint; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java similarity index 74% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java index 236ea45..7f25e44 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; +package com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; -import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.annotation.RateLimiter; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; import org.aspectj.lang.JoinPoint; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java index 118581e..e676c50 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java @@ -1,8 +1,9 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; +package com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl; import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.annotation.RateLimiter; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.DefaultParameterNameDiscoverer; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java similarity index 67% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java index 300a4d2..114e512 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java @@ -1,10 +1,12 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; +package com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.system.SystemUtil; -import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.annotation.RateLimiter; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.protection.ratelimiter.core.annotation.RateLimiter; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; import org.aspectj.lang.JoinPoint; /** @@ -24,4 +26,4 @@ public class ServerNodeRateLimiterKeyResolver implements RateLimiterKeyResolver return SecureUtil.md5(methodName + argsStr + serverNode); } -} \ No newline at end of file +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java similarity index 73% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java index a8d1c3a..cea96c4 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; +package com.tashow.cloud.protection.ratelimiter.core.keyresolver.impl; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; -import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; -import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import com.tashow.cloud.protection.ratelimiter.core.annotation.RateLimiter; +import com.tashow.cloud.protection.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import org.aspectj.lang.JoinPoint; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/redis/RateLimiterRedisDAO.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/redis/RateLimiterRedisDAO.java index fc1378f..4592189 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/core/redis/RateLimiterRedisDAO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.ratelimiter.core.redis; +package com.tashow.cloud.protection.ratelimiter.core.redis; import lombok.AllArgsConstructor; import org.redisson.api.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/package-info.java similarity index 65% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/package-info.java index 36a408c..0dd7fbc 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/ratelimiter/package-info.java @@ -1,4 +1,4 @@ /** * 限流组件,基于 Redisson {@link org.redisson.api.RRateLimiter} 限流实现 */ -package cn.iocoder.yudao.framework.ratelimiter; \ No newline at end of file +package com.tashow.cloud.protection.ratelimiter; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/config/YudaoApiSignatureAutoConfiguration.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/config/ApiSignatureAutoConfiguration.java similarity index 60% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/config/YudaoApiSignatureAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/config/ApiSignatureAutoConfiguration.java index 7c68424..fcf1394 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/config/YudaoApiSignatureAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/config/ApiSignatureAutoConfiguration.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.signature.config; +package com.tashow.cloud.protection.signature.config; -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; -import cn.iocoder.yudao.framework.signature.core.aop.ApiSignatureAspect; -import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO; +import com.tashow.cloud.protection.signature.core.redis.ApiSignatureRedisDAO; +import com.tashow.cloud.protection.signature.core.aop.ApiSignatureAspect; +import com.tashow.cloud.redis.config.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.core.StringRedisTemplate; @@ -12,8 +12,8 @@ import org.springframework.data.redis.core.StringRedisTemplate; * * @author Zhougang */ -@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) -public class YudaoApiSignatureAutoConfiguration { +@AutoConfiguration(after = RedisAutoConfiguration.class) +public class ApiSignatureAutoConfiguration { @Bean public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO) { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/annotation/ApiSignature.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/annotation/ApiSignature.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/annotation/ApiSignature.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/annotation/ApiSignature.java index 281bcec..3a715db 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/annotation/ApiSignature.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/annotation/ApiSignature.java @@ -1,6 +1,7 @@ -package cn.iocoder.yudao.framework.signature.core.annotation; +package com.tashow.cloud.protection.signature.core.annotation; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; + +import com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants; import java.lang.annotation.*; import java.util.concurrent.TimeUnit; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/aop/ApiSignatureAspect.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/aop/ApiSignatureAspect.java index c1c78ac..f204dab 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/aop/ApiSignatureAspect.java @@ -1,14 +1,14 @@ -package cn.iocoder.yudao.framework.signature.core.aop; +package com.tashow.cloud.protection.signature.core.aop; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.DigestUtil; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature; -import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO; +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.protection.signature.core.annotation.ApiSignature; +import com.tashow.cloud.protection.signature.core.redis.ApiSignatureRedisDAO; import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -21,7 +21,8 @@ import java.util.Objects; import java.util.SortedMap; import java.util.TreeMap; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; + /** * 拦截声明了 {@link ApiSignature} 注解的方法,实现签名 @@ -165,4 +166,4 @@ public class ApiSignatureAspect { return sortedMap; } -} \ No newline at end of file +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/redis/ApiSignatureRedisDAO.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/redis/ApiSignatureRedisDAO.java index 11fe384..c3c41c1 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/core/redis/ApiSignatureRedisDAO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.signature.core.redis; +package com.tashow.cloud.protection.signature.core.redis; import lombok.AllArgsConstructor; import org.springframework.data.redis.core.StringRedisTemplate; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/package-info.java b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/package-info.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/package-info.java rename to tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/package-info.java index 4ebd87a..689d9c8 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/package-info.java +++ b/tashow-platform-framework/tashow-framework-protection/src/main/java/com/tashow/cloud/protection/signature/package-info.java @@ -3,4 +3,4 @@ * * @see - yudao-platform-framework - cn.iocoder.cloud + com.tashow.cloud + tashow-platform-framework ${revision} 4.0.0 - yudao-spring-boot-starter-rpc + tashow-framework-rpc jar ${project.artifactId} OpenFeign:提供 RESTful API 的调用 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common diff --git a/tashow-platform-framework/tashow-framework-rpc/src/main/java/com/tashow/cloud/rpc/config/package-info.java b/tashow-platform-framework/tashow-framework-rpc/src/main/java/com/tashow/cloud/rpc/config/package-info.java new file mode 100644 index 0000000..ff499d0 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-rpc/src/main/java/com/tashow/cloud/rpc/config/package-info.java @@ -0,0 +1,4 @@ +/** + * 占坑 TODO + */ +package com.tashow.cloud.rpc.config; diff --git a/tashow-platform-framework/tashow-framework-rpc/src/main/java/com/tashow/cloud/rpc/core/package-info.java b/tashow-platform-framework/tashow-framework-rpc/src/main/java/com/tashow/cloud/rpc/core/package-info.java new file mode 100644 index 0000000..be165b7 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-rpc/src/main/java/com/tashow/cloud/rpc/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占坑 TODO + */ +package com.tashow.cloud.rpc.core; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-rpc/《芋道 Spring Boot 声明式调用 Feign 入门》.md b/tashow-platform-framework/tashow-framework-rpc/《芋道 Spring Boot 声明式调用 Feign 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-rpc/《芋道 Spring Boot 声明式调用 Feign 入门》.md rename to tashow-platform-framework/tashow-framework-rpc/《芋道 Spring Boot 声明式调用 Feign 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-rpc/《芋道 Spring Cloud 声明式调用 Feign 入门》.md b/tashow-platform-framework/tashow-framework-rpc/《芋道 Spring Cloud 声明式调用 Feign 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-rpc/《芋道 Spring Cloud 声明式调用 Feign 入门》.md rename to tashow-platform-framework/tashow-framework-rpc/《芋道 Spring Cloud 声明式调用 Feign 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/pom.xml b/tashow-platform-framework/tashow-framework-security/pom.xml similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-security/pom.xml rename to tashow-platform-framework/tashow-framework-security/pom.xml index ea8d5cb..58d2021 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/pom.xml +++ b/tashow-platform-framework/tashow-framework-security/pom.xml @@ -3,12 +3,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} 4.0.0 - yudao-spring-boot-starter-security + tashow-framework-security jar ${project.artifactId} @@ -16,12 +16,11 @@ 1. security:用户的认证、权限的校验,实现「谁」可以做「什么事」 2. operatelog:操作日志,实现「谁」在「什么时间」对「什么」做了「什么事」 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common @@ -32,8 +31,8 @@ - cn.iocoder.cloud - yudao-spring-boot-starter-web + com.tashow.cloud + tashow-framework-web @@ -49,15 +48,15 @@ - cn.iocoder.cloud - yudao-spring-boot-starter-rpc + com.tashow.cloud + tashow-framework-rpc true - cn.iocoder.cloud - yudao-module-system-api + com.tashow.cloud + tashow-module-system-api ${revision} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogConfiguration.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/config/OperateLogConfiguration.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogConfiguration.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/config/OperateLogConfiguration.java index eda6a14..e69a2ba 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogConfiguration.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/config/OperateLogConfiguration.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.operatelog.config; +package com.tashow.cloud.security.operatelog.config; -import cn.iocoder.yudao.framework.operatelog.core.service.LogRecordServiceImpl; import com.mzt.logapi.service.ILogRecordService; import com.mzt.logapi.starter.annotation.EnableLogRecord; +import com.tashow.cloud.security.operatelog.core.service.LogRecordServiceImpl; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; @@ -16,7 +16,7 @@ import org.springframework.context.annotation.Primary; @EnableLogRecord(tenant = "") // 貌似用不上 tenant 这玩意给个空好啦 @AutoConfiguration @Slf4j -public class YudaoOperateLogConfiguration { +public class OperateLogConfiguration { @Bean @Primary diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogRpcAutoConfiguration.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/config/OperateLogRpcAutoConfiguration.java similarity index 65% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogRpcAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/config/OperateLogRpcAutoConfiguration.java index 6518b7d..bbe48fc 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogRpcAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/config/OperateLogRpcAutoConfiguration.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.operatelog.config; +package com.tashow.cloud.security.operatelog.config; -import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; +import com.tashow.cloud.systemapi.api.logger.OperateLogApi; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.cloud.openfeign.EnableFeignClients; @@ -11,5 +11,5 @@ import org.springframework.cloud.openfeign.EnableFeignClients; */ @AutoConfiguration @EnableFeignClients(clients = {OperateLogApi.class}) // 主要是引入相关的 API 服务 -public class YudaoOperateLogRpcAutoConfiguration { +public class OperateLogRpcAutoConfiguration { } diff --git a/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/core/package-info.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/core/package-info.java new file mode 100644 index 0000000..92fe6f3 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位,无特殊作用 + */ +package com.tashow.cloud.security.operatelog.core; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/core/service/LogRecordServiceImpl.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/core/service/LogRecordServiceImpl.java index 68cdf65..026613a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/core/service/LogRecordServiceImpl.java @@ -1,13 +1,13 @@ -package cn.iocoder.yudao.framework.operatelog.core.service; +package com.tashow.cloud.security.operatelog.core.service; -import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; -import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import com.tashow.cloud.systemapi.api.logger.OperateLogApi; +import com.tashow.cloud.systemapi.api.logger.dto.OperateLogCreateReqDTO; import com.mzt.logapi.beans.LogRecord; import com.mzt.logapi.service.ILogRecordService; +import com.tashow.cloud.common.util.monitor.TracerUtils; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; @@ -88,4 +88,4 @@ public class LogRecordServiceImpl implements ILogRecordService { throw new UnsupportedOperationException("使用 OperateLogApi 进行操作日志的查询"); } -} \ No newline at end of file +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/package-info.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/package-info.java similarity index 63% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/package-info.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/package-info.java index c90139b..23bd5b1 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/package-info.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/operatelog/package-info.java @@ -4,4 +4,4 @@ * * @author HUIHUI */ -package cn.iocoder.yudao.framework.operatelog; +package com.tashow.cloud.security.operatelog; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/AuthorizeRequestsCustomizer.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/AuthorizeRequestsCustomizer.java similarity index 89% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/AuthorizeRequestsCustomizer.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/AuthorizeRequestsCustomizer.java index 1b6bf68..7d1a6f7 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/AuthorizeRequestsCustomizer.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/AuthorizeRequestsCustomizer.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.security.config; +package com.tashow.cloud.security.security.config; -import cn.iocoder.yudao.framework.web.config.WebProperties; +import com.tashow.cloud.web.web.config.WebProperties; import jakarta.annotation.Resource; import org.springframework.core.Ordered; import org.springframework.security.config.Customizer; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityAutoConfiguration.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityAutoConfiguration.java index 6941645..f782d3f 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityAutoConfiguration.java @@ -1,14 +1,14 @@ -package cn.iocoder.yudao.framework.security.config; +package com.tashow.cloud.security.security.config; -import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy; -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.AuthenticationEntryPointImpl; -import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService; -import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkServiceImpl; -import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; -import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import com.tashow.cloud.systemapi.api.oauth2.OAuth2TokenApi; +import com.tashow.cloud.systemapi.api.permission.PermissionApi; +import com.tashow.cloud.security.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy; +import com.tashow.cloud.security.security.core.filter.TokenAuthenticationFilter; +import com.tashow.cloud.security.security.core.handler.AccessDeniedHandlerImpl; +import com.tashow.cloud.security.security.core.handler.AuthenticationEntryPointImpl; +import com.tashow.cloud.security.security.core.service.SecurityFrameworkService; +import com.tashow.cloud.security.security.core.service.SecurityFrameworkServiceImpl; +import com.tashow.cloud.web.web.core.handler.GlobalExceptionHandler; import jakarta.annotation.Resource; import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -24,7 +24,7 @@ import org.springframework.security.web.access.AccessDeniedHandler; /** * Spring Security 自动配置类,主要用于相关组件的配置 * - * 注意,不能和 {@link YudaoWebSecurityConfigurerAdapter} 用一个,原因是会导致初始化报错。 + * 注意,不能和 {@link WebSecurityConfigurerAdapter} 用一个,原因是会导致初始化报错。 * 参见 https://stackoverflow.com/questions/53847050/spring-boot-delegatebuilder-cannot-be-null-on-autowiring-authenticationmanager 文档。 * * @author 芋道源码 @@ -32,7 +32,7 @@ import org.springframework.security.web.access.AccessDeniedHandler; @AutoConfiguration @AutoConfigureOrder(-1) // 目的:先于 Spring Security 自动配置,避免一键改包后,org.* 基础包无法生效 @EnableConfigurationProperties(SecurityProperties.class) -public class YudaoSecurityAutoConfiguration { +public class SecurityAutoConfiguration { @Resource private SecurityProperties securityProperties; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityProperties.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityProperties.java index 936e447..407b691 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityProperties.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.security.config; +package com.tashow.cloud.security.security.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityRpcAutoConfiguration.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityRpcAutoConfiguration.java similarity index 63% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityRpcAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityRpcAutoConfiguration.java index f39cc2a..15b3369 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityRpcAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/SecurityRpcAutoConfiguration.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.security.config; +package com.tashow.cloud.security.security.config; -import cn.iocoder.yudao.framework.security.core.rpc.LoginUserRequestInterceptor; -import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import com.tashow.cloud.systemapi.api.oauth2.OAuth2TokenApi; +import com.tashow.cloud.systemapi.api.permission.PermissionApi; +import com.tashow.cloud.security.security.core.rpc.LoginUserRequestInterceptor; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; @@ -15,7 +15,7 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @EnableFeignClients(clients = {OAuth2TokenApi.class, // 主要是引入相关的 API 服务 PermissionApi.class}) -public class YudaoSecurityRpcAutoConfiguration { +public class SecurityRpcAutoConfiguration { @Bean public LoginUserRequestInterceptor loginUserRequestInterceptor() { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/WebSecurityConfigurerAdapter.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/WebSecurityConfigurerAdapter.java index 68ae1b3..72307b1 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/config/WebSecurityConfigurerAdapter.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.security.config; +package com.tashow.cloud.security.security.config; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; -import cn.iocoder.yudao.framework.web.config.WebProperties; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import com.tashow.cloud.security.security.core.filter.TokenAuthenticationFilter; +import com.tashow.cloud.web.web.config.WebProperties; import jakarta.annotation.Resource; import jakarta.annotation.security.PermitAll; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -35,7 +35,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static com.tashow.cloud.common.util.collection.CollectionUtils.convertList; /** * 自定义的 Spring Security 配置适配器实现 @@ -45,7 +45,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @AutoConfiguration @AutoConfigureOrder(-1) // 目的:先于 Spring Security 自动配置,避免一键改包后,org.* 基础包无法生效 @EnableMethodSecurity(securedEnabled = true) -public class YudaoWebSecurityConfigurerAdapter { +public class WebSecurityConfigurerAdapter { @Resource private WebProperties webProperties; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/LoginUser.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/LoginUser.java index e23c3a7..dc967b9 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/LoginUser.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.security.core; +package com.tashow.cloud.security.security.core; import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java index 1bdbe71..f8950ef 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.security.core.context; +package com.tashow.cloud.security.security.core.context; import com.alibaba.ttl.TransmittableThreadLocal; import org.springframework.security.core.context.SecurityContext; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/filter/TokenAuthenticationFilter.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/filter/TokenAuthenticationFilter.java index 88ce4e1..6c400a8 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/filter/TokenAuthenticationFilter.java @@ -1,18 +1,18 @@ -package cn.iocoder.yudao.framework.security.core.filter; +package com.tashow.cloud.security.security.core.filter; import cn.hutool.core.util.ObjectUtil; 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.util.json.JsonUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.security.config.SecurityProperties; -import cn.iocoder.yudao.framework.security.core.LoginUser; -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.util.WebFrameworkUtils; -import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; -import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.systemapi.api.oauth2.OAuth2TokenApi; +import com.tashow.cloud.systemapi.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import com.tashow.cloud.security.security.config.SecurityProperties; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; +import com.tashow.cloud.web.web.core.handler.GlobalExceptionHandler; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/handler/AccessDeniedHandlerImpl.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/handler/AccessDeniedHandlerImpl.java index 0ec5262..17110a2 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/handler/AccessDeniedHandlerImpl.java @@ -1,9 +1,8 @@ -package cn.iocoder.yudao.framework.security.core.handler; +package com.tashow.cloud.security.security.core.handler; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; @@ -15,7 +14,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN; +import static com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN; + /** * 访问一个需要认证的 URL 资源,已经认证(登录)但是没有权限的情况下,返回 {@link GlobalErrorCodeConstants#FORBIDDEN} 错误码。 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/handler/AuthenticationEntryPointImpl.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/handler/AuthenticationEntryPointImpl.java index 9d9caa6..2c90a2e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/handler/AuthenticationEntryPointImpl.java @@ -1,8 +1,7 @@ -package cn.iocoder.yudao.framework.security.core.handler; +package com.tashow.cloud.security.security.core.handler; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.servlet.ServletUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; @@ -12,7 +11,8 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED; +import static com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED; + /** * 访问一个需要认证的 URL 资源,但是此时自己尚未认证(登录)的情况下,返回 {@link GlobalErrorCodeConstants#UNAUTHORIZED} 错误码,从而使前端重定向到登录页 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/rpc/LoginUserRequestInterceptor.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/rpc/LoginUserRequestInterceptor.java similarity index 80% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/rpc/LoginUserRequestInterceptor.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/rpc/LoginUserRequestInterceptor.java index afa8fd0..a1dce4a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/rpc/LoginUserRequestInterceptor.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/rpc/LoginUserRequestInterceptor.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.security.core.rpc; +package com.tashow.cloud.security.security.core.rpc; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; import feign.RequestInterceptor; import feign.RequestTemplate; import lombok.extern.slf4j.Slf4j; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkService.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/service/SecurityFrameworkService.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkService.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/service/SecurityFrameworkService.java index bf2f7f3..f134a28 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkService.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/service/SecurityFrameworkService.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.security.core.service; +package com.tashow.cloud.security.security.core.service; /** * Security 框架 Service 接口,定义权限相关的校验操作 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkServiceImpl.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/service/SecurityFrameworkServiceImpl.java similarity index 85% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkServiceImpl.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/service/SecurityFrameworkServiceImpl.java index ffa64a0..8fe7c4d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkServiceImpl.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/service/SecurityFrameworkServiceImpl.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.security.core.service; +package com.tashow.cloud.security.security.core.service; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; -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 com.tashow.cloud.common.core.KeyValue; +import com.tashow.cloud.systemapi.api.permission.PermissionApi; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; import lombok.AllArgsConstructor; import lombok.SneakyThrows; @@ -14,8 +14,8 @@ import java.time.Duration; import java.util.Arrays; import java.util.List; -import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildCache; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static com.tashow.cloud.common.util.cache.CacheUtils.buildCache; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.getLoginUserId; /** * 默认的 {@link SecurityFrameworkService} 实现类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/util/SecurityFrameworkUtils.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/util/SecurityFrameworkUtils.java index bb0ed94..e21610c 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/core/util/SecurityFrameworkUtils.java @@ -1,9 +1,10 @@ -package cn.iocoder.yudao.framework.security.core.util; +package com.tashow.cloud.security.security.core.util; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.lang.Nullable; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -12,7 +13,6 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.util.StringUtils; -import jakarta.servlet.http.HttpServletRequest; import java.util.Collections; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/package-info.java b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/package-info.java similarity index 68% rename from tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/package-info.java rename to tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/package-info.java index dc95b4e..69b5126 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/package-info.java +++ b/tashow-platform-framework/tashow-framework-security/src/main/java/com/tashow/cloud/security/security/package-info.java @@ -4,4 +4,4 @@ * * @author 芋道源码 */ -package cn.iocoder.yudao.framework.security; +package com.tashow.cloud.security.security; diff --git a/tashow-platform-framework/tashow-framework-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-framework-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..8a0e38f --- /dev/null +++ b/tashow-platform-framework/tashow-framework-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,5 @@ +com.tashow.cloud.security.security.config.SecurityRpcAutoConfiguration +com.tashow.cloud.security.security.config.SecurityAutoConfiguration +com.tashow.cloud.security.security.config.WebSecurityConfigurerAdapter +com.tashow.cloud.security.operatelog.config.OperateLogConfiguration +com.tashow.cloud.security.operatelog.config.OperateLogRpcAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/《芋道 Spring Boot 安全框架 Spring Security 入门》.md b/tashow-platform-framework/tashow-framework-security/《芋道 Spring Boot 安全框架 Spring Security 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-security/《芋道 Spring Boot 安全框架 Spring Security 入门》.md rename to tashow-platform-framework/tashow-framework-security/《芋道 Spring Boot 安全框架 Spring Security 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/pom.xml b/tashow-platform-framework/tashow-framework-tenant/pom.xml similarity index 67% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/pom.xml rename to tashow-platform-framework/tashow-framework-tenant/pom.xml index 7b95048..46c64e9 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/pom.xml +++ b/tashow-platform-framework/tashow-framework-tenant/pom.xml @@ -3,59 +3,58 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - yudao-platform-framework - cn.iocoder.cloud + com.tashow.cloud + tashow-platform-framework ${revision} 4.0.0 - yudao-spring-boot-starter-biz-tenant + tashow-framework-tenant jar ${project.artifactId} 多租户 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common - cn.iocoder.cloud - yudao-spring-boot-starter-security + com.tashow.cloud + tashow-framework-security - cn.iocoder.cloud - yudao-spring-boot-starter-mybatis + com.tashow.cloud + tashow-data-mybatis - cn.iocoder.cloud - yudao-spring-boot-starter-redis + com.tashow.cloud + tashow-data-redis - cn.iocoder.cloud - yudao-spring-boot-starter-rpc + com.tashow.cloud + tashow-framework-rpc true - cn.iocoder.cloud - yudao-spring-boot-starter-job + com.tashow.cloud + tashow-framework-job true - cn.iocoder.cloud - yudao-spring-boot-starter-mq + com.tashow.cloud + tashow-framework-mq true diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantAutoConfiguration.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantAutoConfiguration.java index cd3b365..f1a2c3a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantAutoConfiguration.java @@ -1,24 +1,24 @@ -package cn.iocoder.yudao.framework.tenant.config; +package com.tashow.cloud.tenant.config; -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; -import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; -import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; -import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect; -import cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq.TenantRabbitMQInitializer; -import cn.iocoder.yudao.framework.tenant.core.mq.redis.TenantRedisMessageInterceptor; -import cn.iocoder.yudao.framework.tenant.core.mq.rocketmq.TenantRocketMQInitializer; -import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; -import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; -import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; -import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkServiceImpl; -import cn.iocoder.yudao.framework.tenant.core.web.TenantContextWebFilter; -import cn.iocoder.yudao.framework.web.config.WebProperties; -import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; -import cn.iocoder.yudao.module.system.api.tenant.TenantApi; +import com.tashow.cloud.common.enums.WebFilterOrderEnum; +import com.tashow.cloud.mybatis.mybatis.core.util.MyBatisUtils; +import com.tashow.cloud.redis.config.CacheProperties; +import com.tashow.cloud.systemapi.api.tenant.TenantApi; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.tashow.cloud.tenant.core.aop.TenantIgnoreAspect; +import com.tashow.cloud.tenant.core.db.TenantDatabaseInterceptor; +import com.tashow.cloud.tenant.core.job.TenantJobAspect; +import com.tashow.cloud.tenant.core.mq.rabbitmq.TenantRabbitMQInitializer; +import com.tashow.cloud.tenant.core.mq.redis.TenantRedisMessageInterceptor; +import com.tashow.cloud.tenant.core.mq.rocketmq.TenantRocketMQInitializer; +import com.tashow.cloud.tenant.core.redis.TenantRedisCacheManager; +import com.tashow.cloud.tenant.core.security.TenantSecurityWebFilter; +import com.tashow.cloud.tenant.core.service.TenantFrameworkService; +import com.tashow.cloud.tenant.core.service.TenantFrameworkServiceImpl; +import com.tashow.cloud.tenant.core.web.TenantContextWebFilter; +import com.tashow.cloud.web.web.config.WebProperties; +import com.tashow.cloud.web.web.core.handler.GlobalExceptionHandler; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -37,9 +37,9 @@ import org.springframework.data.redis.core.RedisTemplate; import java.util.Objects; @AutoConfiguration -@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true) // 允许使用 yudao.tenant.enable=false 禁用多租户 +@ConditionalOnProperty(prefix = "tashow.tenant", value = "enable", matchIfMissing = true) // 允许使用 yudao.tenant.enable=false 禁用多租户 @EnableConfigurationProperties(TenantProperties.class) -public class YudaoTenantAutoConfiguration { +public class TenantAutoConfiguration { @Bean public TenantFrameworkService tenantFrameworkService(TenantApi tenantApi) { @@ -105,7 +105,7 @@ public class YudaoTenantAutoConfiguration { * 为什么要单独一个配置类呢?如果直接把 TenantRedisMessageInterceptor Bean 的初始化放外面,会报 RedisMessageInterceptor 类不存在的错误 */ @Configuration - @ConditionalOnClass(name = "cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate") + @ConditionalOnClass(name = "com.tashow.cloud.mq.redis.core.RedisMQTemplate") public static class TenantRedisMQAutoConfiguration { @Bean @@ -133,7 +133,7 @@ public class YudaoTenantAutoConfiguration { @Primary // 引入租户时,tenantRedisCacheManager 为主 Bean public RedisCacheManager tenantRedisCacheManager(RedisTemplate redisTemplate, RedisCacheConfiguration redisCacheConfiguration, - YudaoCacheProperties yudaoCacheProperties, + CacheProperties yudaoCacheProperties, TenantProperties tenantProperties) { // 创建 RedisCacheWriter 对象 RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory()); diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantProperties.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantProperties.java index b0c0217..4beca50 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantProperties.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tenant.config; +package com.tashow.cloud.tenant.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -11,7 +11,7 @@ import java.util.Set; * * @author 芋道源码 */ -@ConfigurationProperties(prefix = "yudao.tenant") +@ConfigurationProperties(prefix = "tashow.tenant") @Data public class TenantProperties { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantRpcAutoConfiguration.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantRpcAutoConfiguration.java similarity index 68% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantRpcAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantRpcAutoConfiguration.java index 71c3806..35447a9 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantRpcAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/config/TenantRpcAutoConfiguration.java @@ -1,17 +1,17 @@ -package cn.iocoder.yudao.framework.tenant.config; +package com.tashow.cloud.tenant.config; -import cn.iocoder.yudao.framework.tenant.core.rpc.TenantRequestInterceptor; -import cn.iocoder.yudao.module.system.api.tenant.TenantApi; +import com.tashow.cloud.systemapi.api.tenant.TenantApi; +import com.tashow.cloud.tenant.core.rpc.TenantRequestInterceptor; +import com.tashow.cloud.tenant.core.rpc.TenantRequestInterceptor; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; @AutoConfiguration @ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true) // 允许使用 yudao.tenant.enable=false 禁用多租户 @EnableFeignClients(clients = TenantApi.class) // 主要是引入相关的 API 服务 -public class YudaoTenantRpcAutoConfiguration { +public class TenantRpcAutoConfiguration { @Bean public TenantRequestInterceptor tenantRequestInterceptor() { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnore.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/aop/TenantIgnore.java similarity index 91% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnore.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/aop/TenantIgnore.java index f2fec50..e6be0b7 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnore.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/aop/TenantIgnore.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tenant.core.aop; +package com.tashow.cloud.tenant.core.aop; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/aop/TenantIgnoreAspect.java similarity index 84% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/aop/TenantIgnoreAspect.java index b7d0fa3..182095f 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/aop/TenantIgnoreAspect.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.tenant.core.aop; +package com.tashow.cloud.tenant.core.aop; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.util.TenantUtils; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/context/TenantContextHolder.java similarity index 90% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/context/TenantContextHolder.java index caf2a01..704a9f9 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/context/TenantContextHolder.java @@ -1,8 +1,7 @@ -package cn.iocoder.yudao.framework.tenant.core.context; +package com.tashow.cloud.tenant.core.context; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.enums.DocumentEnum; import com.alibaba.ttl.TransmittableThreadLocal; +import com.tashow.cloud.common.enums.DocumentEnum; /** * 多租户上下文 Holder diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/db/TenantBaseDO.java similarity index 71% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/db/TenantBaseDO.java index f4f0ea5..405e8d8 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/db/TenantBaseDO.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.tenant.core.db; +package com.tashow.cloud.tenant.core.db; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.tashow.cloud.mybatis.mybatis.core.dataobject.BaseDO; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/db/TenantDatabaseInterceptor.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/db/TenantDatabaseInterceptor.java index 8f1c8ac..0f3672f 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/db/TenantDatabaseInterceptor.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.tenant.core.db; +package com.tashow.cloud.tenant.core.db; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.tenant.config.TenantProperties; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils; +import com.tashow.cloud.tenant.config.TenantProperties; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/job/TenantJob.java similarity index 84% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/job/TenantJob.java index 23474bb..72c01d5 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/job/TenantJob.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tenant.core.job; +package com.tashow.cloud.tenant.core.job; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/job/TenantJobAspect.java similarity index 91% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/job/TenantJobAspect.java index 07bbdee..60797e2 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/job/TenantJobAspect.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.framework.tenant.core.job; +package com.tashow.cloud.tenant.core.job; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.tenant.core.service.TenantFrameworkService; +import com.tashow.cloud.tenant.core.util.TenantUtils; import com.xxl.job.core.context.XxlJobContext; import com.xxl.job.core.context.XxlJobHelper; import lombok.RequiredArgsConstructor; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java index 8bf7cc1..71896db 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tenant.core.mq.kafka; +package com.tashow.cloud.tenant.core.mq.kafka; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java index 8ded801..b55e215 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.tenant.core.mq.kafka; +package com.tashow.cloud.tenant.core.mq.kafka; import cn.hutool.core.util.ReflectUtil; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; import org.apache.kafka.clients.producer.ProducerInterceptor; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.clients.producer.RecordMetadata; @@ -10,7 +10,8 @@ import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; import java.util.Map; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * Kafka 消息队列的多租户 {@link ProducerInterceptor} 实现类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java similarity index 91% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java index b856ce9..e8f0ecd 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq; +package com.tashow.cloud.tenant.core.mq.rabbitmq; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.BeansException; @@ -20,4 +20,4 @@ public class TenantRabbitMQInitializer implements BeanPostProcessor { return bean; } -} \ No newline at end of file +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java similarity index 82% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java index 3e6969c..74a42fa 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java @@ -1,13 +1,14 @@ -package cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq; +package com.tashow.cloud.tenant.core.mq.rabbitmq; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; import org.apache.kafka.clients.producer.ProducerInterceptor; import org.springframework.amqp.AmqpException; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessagePostProcessor; import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * RabbitMQ 消息队列的多租户 {@link ProducerInterceptor} 实现类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/redis/TenantRedisMessageInterceptor.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/redis/TenantRedisMessageInterceptor.java similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/redis/TenantRedisMessageInterceptor.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/redis/TenantRedisMessageInterceptor.java index f6b7747..e4f6e91 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/redis/TenantRedisMessageInterceptor.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/redis/TenantRedisMessageInterceptor.java @@ -1,11 +1,12 @@ -package cn.iocoder.yudao.framework.tenant.core.mq.redis; +package com.tashow.cloud.tenant.core.mq.redis; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; -import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.mq.redis.core.interceptor.RedisMessageInterceptor; +import com.tashow.cloud.mq.redis.core.message.AbstractRedisMessage; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; + +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; /** * 多租户 {@link AbstractRedisMessage} 拦截器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java similarity index 86% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java index d9d7334..83b4f5b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq; +package com.tashow.cloud.tenant.core.mq.rocketmq; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; import org.apache.rocketmq.client.hook.ConsumeMessageContext; import org.apache.rocketmq.client.hook.ConsumeMessageHook; import org.apache.rocketmq.common.message.MessageExt; @@ -10,7 +10,8 @@ import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; import java.util.List; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * RocketMQ 消息队列的多租户 {@link ConsumeMessageHook} 实现类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java index 7f12ac5..601ede5 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq; +package com.tashow.cloud.tenant.core.mq.rocketmq; import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl; @@ -50,4 +50,4 @@ public class TenantRocketMQInitializer implements BeanPostProcessor { consumerImpl.registerConsumeMessageHook(new TenantRocketMQConsumeMessageHook()); } -} \ No newline at end of file +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java similarity index 80% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java index 4f03074..fc99bcb 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java @@ -1,10 +1,11 @@ -package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq; +package com.tashow.cloud.tenant.core.mq.rocketmq; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; import org.apache.rocketmq.client.hook.SendMessageContext; import org.apache.rocketmq.client.hook.SendMessageHook; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * RocketMQ 消息队列的多租户 {@link SendMessageHook} 实现类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/redis/TenantRedisCacheManager.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/redis/TenantRedisCacheManager.java index 68a2a3e..7b3f679 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/redis/TenantRedisCacheManager.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.tenant.core.redis; +package com.tashow.cloud.tenant.core.redis; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.redis.core.TimeoutRedisCacheManager; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.Cache; import org.springframework.data.redis.cache.RedisCacheConfiguration; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/rpc/TenantRequestInterceptor.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/rpc/TenantRequestInterceptor.java similarity index 67% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/rpc/TenantRequestInterceptor.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/rpc/TenantRequestInterceptor.java index ac82fb9..8200cbd 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/rpc/TenantRequestInterceptor.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/rpc/TenantRequestInterceptor.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.framework.tenant.core.rpc; +package com.tashow.cloud.tenant.core.rpc; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; import feign.RequestInterceptor; import feign.RequestTemplate; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * Tenant 的 RequestInterceptor 实现类:Feign 请求时,将 {@link TenantContextHolder} 设置到 header 中,继续透传给被调用的服务 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/security/TenantSecurityWebFilter.java similarity index 84% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/security/TenantSecurityWebFilter.java index 146b9cd..f6c20d6 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/security/TenantSecurityWebFilter.java @@ -1,17 +1,17 @@ -package cn.iocoder.yudao.framework.tenant.core.security; +package com.tashow.cloud.tenant.core.security; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import cn.iocoder.yudao.framework.tenant.config.TenantProperties; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; -import cn.iocoder.yudao.framework.web.config.WebProperties; -import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter; -import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; +import com.tashow.cloud.tenant.config.TenantProperties; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.service.TenantFrameworkService; +import com.tashow.cloud.web.web.config.WebProperties; +import com.tashow.cloud.web.web.core.filter.ApiRequestFilter; +import com.tashow.cloud.web.web.core.handler.GlobalExceptionHandler; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/service/TenantFrameworkService.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/service/TenantFrameworkService.java index 2ca474d..a830ad1 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/service/TenantFrameworkService.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.tenant.core.service; +package com.tashow.cloud.tenant.core.service; import java.util.List; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/service/TenantFrameworkServiceImpl.java similarity index 82% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/service/TenantFrameworkServiceImpl.java index abeecab..8fec264 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/service/TenantFrameworkServiceImpl.java @@ -1,8 +1,7 @@ -package cn.iocoder.yudao.framework.tenant.core.service; +package com.tashow.cloud.tenant.core.service; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; -import cn.iocoder.yudao.module.system.api.tenant.TenantApi; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.systemapi.api.tenant.TenantApi; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import lombok.RequiredArgsConstructor; @@ -11,7 +10,8 @@ import lombok.SneakyThrows; import java.time.Duration; import java.util.List; -import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; +import static com.tashow.cloud.common.util.cache.CacheUtils.buildAsyncReloadingCache; + /** * Tenant 框架 Service 实现类 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/util/TenantUtils.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/util/TenantUtils.java index 7ec9c69..23bd2d9 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/util/TenantUtils.java @@ -1,11 +1,12 @@ -package cn.iocoder.yudao.framework.tenant.core.util; +package com.tashow.cloud.tenant.core.util; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; import java.util.Map; import java.util.concurrent.Callable; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * 多租户 Util diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/web/TenantContextWebFilter.java similarity index 84% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/web/TenantContextWebFilter.java index 41b7b4d..3e7c42b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/com/tashow/cloud/tenant/core/web/TenantContextWebFilter.java @@ -1,13 +1,13 @@ -package cn.iocoder.yudao.framework.tenant.core.web; - -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; -import org.springframework.web.filter.OncePerRequestFilter; +package com.tashow.cloud.tenant.core.web; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + import java.io.IOException; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java b/tashow-platform-framework/tashow-framework-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java rename to tashow-platform-framework/tashow-framework-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java index de330fd..3a73860 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java @@ -21,8 +21,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Arrays; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import com.tashow.cloud.tenant.core.util.TenantUtils; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; @@ -32,7 +31,8 @@ import org.springframework.messaging.Message; import org.springframework.messaging.handler.HandlerMethod; import org.springframework.util.ObjectUtils; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * Extension of {@link HandlerMethod} that invokes the underlying method with diff --git a/tashow-platform-framework/tashow-framework-tenant/src/main/resources/META-INF/spring.factories b/tashow-platform-framework/tashow-framework-tenant/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..ddf705c --- /dev/null +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ + com.tashow.cloud.tenant.core.mq.kafka.TenantKafkaEnvironmentPostProcessor diff --git a/tashow-platform-framework/tashow-framework-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-framework-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..3ec3751 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.tashow.cloud.tenant.config.TenantRpcAutoConfiguration +com.tashow.cloud.tenant.config.TenantAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/pom.xml b/tashow-platform-framework/tashow-framework-web/pom.xml similarity index 78% rename from tashow-platform-framework/yudao-spring-boot-starter-web/pom.xml rename to tashow-platform-framework/tashow-framework-web/pom.xml index 14c2e3d..e4882da 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/pom.xml +++ b/tashow-platform-framework/tashow-framework-web/pom.xml @@ -2,23 +2,22 @@ + 4.0.0 - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} - 4.0.0 - yudao-spring-boot-starter-web + tashow-framework-web jar ${project.artifactId} Web 框架,全局异常、API 日志、脱敏、错误码等 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common @@ -56,20 +55,20 @@ - cn.iocoder.cloud - yudao-spring-boot-starter-rpc + com.tashow.cloud + tashow-framework-rpc true - cn.iocoder.cloud - yudao-module-infra-api + com.tashow.cloud + tashow-module-infra-api ${revision} - cn.iocoder.cloud - yudao-module-system-api + com.tashow.cloud + tashow-module-system-api ${revision} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogAutoConfiguration.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/config/ApiLogAutoConfiguration.java similarity index 67% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/config/ApiLogAutoConfiguration.java index 56bc18a..fb5d57a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/config/ApiLogAutoConfiguration.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.framework.apilog.config; +package com.tashow.cloud.web.apilog.config; -import cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter; -import cn.iocoder.yudao.framework.apilog.core.interceptor.ApiAccessLogInterceptor; -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import cn.iocoder.yudao.framework.web.config.WebProperties; -import cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration; -import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi; +import com.tashow.cloud.infraapi.api.logger.ApiAccessLogApi; +import com.tashow.cloud.common.enums.WebFilterOrderEnum; +import com.tashow.cloud.web.apilog.core.filter.ApiAccessLogFilter; +import com.tashow.cloud.web.apilog.core.interceptor.ApiAccessLogInterceptor; +import com.tashow.cloud.web.web.config.WebAutoConfiguration; +import com.tashow.cloud.web.web.config.WebProperties; import jakarta.servlet.Filter; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -15,14 +15,14 @@ import org.springframework.context.annotation.Bean; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -@AutoConfiguration(after = YudaoWebAutoConfiguration.class) -public class YudaoApiLogAutoConfiguration implements WebMvcConfigurer { +@AutoConfiguration(after = WebAutoConfiguration.class) +public class ApiLogAutoConfiguration implements WebMvcConfigurer { /** * 创建 ApiAccessLogFilter Bean,记录 API 请求日志 */ @Bean - @ConditionalOnProperty(prefix = "yudao.access-log", value = "enable", matchIfMissing = true) // 允许使用 yudao.access-log.enable=false 禁用访问日志 + @ConditionalOnProperty(prefix = "tashow.access-log", value = "enable", matchIfMissing = true) // 允许使用 yudao.access-log.enable=false 禁用访问日志 @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") public FilterRegistrationBean apiAccessLogFilter(WebProperties webProperties, @Value("${spring.application.name}") String applicationName, diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogRpcAutoConfiguration.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/config/ApiLogRpcAutoConfiguration.java similarity index 60% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogRpcAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/config/ApiLogRpcAutoConfiguration.java index 80b41cd..a745878 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogRpcAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/config/ApiLogRpcAutoConfiguration.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.apilog.config; +package com.tashow.cloud.web.apilog.config; -import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi; -import cn.iocoder.yudao.module.infra.api.logger.ApiErrorLogApi; +import com.tashow.cloud.infraapi.api.logger.ApiAccessLogApi; +import com.tashow.cloud.infraapi.api.logger.ApiErrorLogApi; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.cloud.openfeign.EnableFeignClients; @@ -12,5 +12,5 @@ import org.springframework.cloud.openfeign.EnableFeignClients; */ @AutoConfiguration @EnableFeignClients(clients = {ApiAccessLogApi.class, ApiErrorLogApi.class}) // 主要是引入相关的 API 服务 -public class YudaoApiLogRpcAutoConfiguration { +public class ApiLogRpcAutoConfiguration { } diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/annotation/ApiAccessLog.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/annotation/ApiAccessLog.java index fe93ef6..2d7365b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/annotation/ApiAccessLog.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.apilog.core.annotation; +package com.tashow.cloud.web.apilog.core.annotation; -import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; +import com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/enums/OperateTypeEnum.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/enums/OperateTypeEnum.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/enums/OperateTypeEnum.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/enums/OperateTypeEnum.java index a7f0055..35f7697 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/enums/OperateTypeEnum.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/enums/OperateTypeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.apilog.core.enums; +package com.tashow.cloud.web.apilog.core.enums; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/filter/ApiAccessLogFilter.java similarity index 89% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/filter/ApiAccessLogFilter.java index fed2ca8..d2f83c5 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/filter/ApiAccessLogFilter.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.apilog.core.filter; +package com.tashow.cloud.web.apilog.core.filter; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; @@ -7,19 +7,19 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.web.config.WebProperties; -import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; -import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi; -import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; +import com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.common.util.monitor.TracerUtils; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.infraapi.api.logger.ApiAccessLogApi; +import com.tashow.cloud.infraapi.api.logger.dto.ApiAccessLogCreateReqDTO; import com.fasterxml.jackson.databind.JsonNode; +import com.tashow.cloud.web.apilog.core.annotation.ApiAccessLog; +import com.tashow.cloud.web.apilog.core.enums.OperateTypeEnum; +import com.tashow.cloud.web.web.config.WebProperties; +import com.tashow.cloud.web.web.core.filter.ApiRequestFilter; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.FilterChain; @@ -36,8 +36,8 @@ import java.time.temporal.ChronoUnit; import java.util.Iterator; import java.util.Map; -import static cn.iocoder.yudao.framework.apilog.core.interceptor.ApiAccessLogInterceptor.ATTRIBUTE_HANDLER_METHOD; -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static com.tashow.cloud.common.util.json.JsonUtils.toJsonString; +import static com.tashow.cloud.web.apilog.core.interceptor.ApiAccessLogInterceptor.ATTRIBUTE_HANDLER_METHOD; /** * API 访问日志 Filter @@ -190,7 +190,7 @@ public class ApiAccessLogFilter extends ApiRequestFilter { MapUtil.removeAny(map, sanitizeKeys); } MapUtil.removeAny(map, SANITIZE_KEYS); - return JsonUtils.toJsonString(map); + return toJsonString(map); } private static String sanitizeJson(String jsonString, String[] sanitizeKeys) { @@ -200,7 +200,7 @@ public class ApiAccessLogFilter extends ApiRequestFilter { try { JsonNode rootNode = JsonUtils.parseTree(jsonString); sanitizeJson(rootNode, sanitizeKeys); - return JsonUtils.toJsonString(rootNode); + return toJsonString(rootNode); } catch (Exception e) { // 脱敏失败的情况下,直接忽略异常,避免影响用户请求 log.error("[sanitizeJson][脱敏({}) 发生异常]", jsonString, e); @@ -216,7 +216,7 @@ public class ApiAccessLogFilter extends ApiRequestFilter { try { JsonNode rootNode = JsonUtils.parseTree(jsonString); sanitizeJson(rootNode.get("data"), sanitizeKeys); // 只处理 data 字段,不处理 code、msg 字段,避免错误被脱敏掉 - return JsonUtils.toJsonString(rootNode); + return toJsonString(rootNode); } catch (Exception e) { // 脱敏失败的情况下,直接忽略异常,避免影响用户请求 log.error("[sanitizeJson][脱敏({}) 发生异常]", jsonString, e); diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/interceptor/ApiAccessLogInterceptor.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/interceptor/ApiAccessLogInterceptor.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/interceptor/ApiAccessLogInterceptor.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/interceptor/ApiAccessLogInterceptor.java index 7d6b456..9f35424 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/interceptor/ApiAccessLogInterceptor.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/core/interceptor/ApiAccessLogInterceptor.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.framework.apilog.core.interceptor; +package com.tashow.cloud.web.apilog.core.interceptor; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.common.util.spring.SpringUtils; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.common.util.spring.SpringUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/package-info.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/package-info.java similarity index 85% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/package-info.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/package-info.java index cb93f3d..f35e3d1 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/package-info.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/apilog/package-info.java @@ -5,4 +5,4 @@ * * @author 芋道源码 */ -package cn.iocoder.yudao.framework.apilog; +package com.tashow.cloud.web.apilog; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/config/YudaoBannerAutoConfiguration.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/config/YudaoBannerAutoConfiguration.java similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/config/YudaoBannerAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/config/YudaoBannerAutoConfiguration.java index a8b6678..7612e35 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/config/YudaoBannerAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/config/YudaoBannerAutoConfiguration.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.banner.config; +package com.tashow.cloud.web.banner.config; -import cn.iocoder.yudao.framework.banner.core.BannerApplicationRunner; +import com.tashow.cloud.web.banner.core.BannerApplicationRunner; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/core/BannerApplicationRunner.java similarity index 98% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/core/BannerApplicationRunner.java index 6c01b94..3dc3a5e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/core/BannerApplicationRunner.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.banner.core; +package com.tashow.cloud.web.banner.core; import cn.hutool.core.thread.ThreadUtil; import lombok.extern.slf4j.Slf4j; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/package-info.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/package-info.java similarity index 72% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/package-info.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/package-info.java index aba7268..85be471 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/package-info.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/banner/package-info.java @@ -3,4 +3,4 @@ * * @author 芋道源码 */ -package cn.iocoder.yudao.framework.banner; +package com.tashow.cloud.web.banner; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/annotation/DesensitizeBy.java similarity index 74% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/annotation/DesensitizeBy.java index 1e252c0..d7dbb68 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/annotation/DesensitizeBy.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.framework.desensitize.core.base.annotation; +package com.tashow.cloud.web.desensitize.core.base.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; -import cn.iocoder.yudao.framework.desensitize.core.base.serializer.StringDesensitizeSerializer; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.tashow.cloud.web.desensitize.core.base.handler.DesensitizationHandler; +import com.tashow.cloud.web.desensitize.core.base.serializer.StringDesensitizeSerializer; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/handler/DesensitizationHandler.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/handler/DesensitizationHandler.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/handler/DesensitizationHandler.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/handler/DesensitizationHandler.java index b15e356..692e134 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/handler/DesensitizationHandler.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/handler/DesensitizationHandler.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.desensitize.core.base.handler; +package com.tashow.cloud.web.desensitize.core.base.handler; import cn.hutool.core.util.ReflectUtil; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/serializer/StringDesensitizeSerializer.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/serializer/StringDesensitizeSerializer.java index 2c15a74..f932a21 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/base/serializer/StringDesensitizeSerializer.java @@ -1,18 +1,18 @@ -package cn.iocoder.yudao.framework.desensitize.core.base.serializer; +package com.tashow.cloud.web.desensitize.core.base.serializer; import cn.hutool.core.annotation.AnnotationUtil; import cn.hutool.core.lang.Singleton; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.ContextualSerializer; import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.base.handler.DesensitizationHandler; import lombok.Getter; import lombok.Setter; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/EmailDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/annotation/EmailDesensitize.java similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/EmailDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/annotation/EmailDesensitize.java index 87d9df6..e6c5a38 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/EmailDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/annotation/EmailDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.regex.annotation; +package com.tashow.cloud.web.desensitize.core.regex.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.regex.handler.EmailDesensitizationHandler; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.regex.handler.EmailDesensitizationHandler; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/RegexDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/annotation/RegexDesensitize.java similarity index 78% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/RegexDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/annotation/RegexDesensitize.java index 83ab69a..1ed76b5 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/RegexDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/annotation/RegexDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.regex.annotation; +package com.tashow.cloud.web.desensitize.core.regex.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.regex.handler.DefaultRegexDesensitizationHandler; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.regex.handler.DefaultRegexDesensitizationHandler; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java similarity index 82% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java index 6ae1a50..a828f2a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.desensitize.core.regex.handler; +package com.tashow.cloud.web.desensitize.core.regex.handler; -import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; -import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; +import com.tashow.cloud.common.util.spring.SpringExpressionUtils; +import com.tashow.cloud.web.desensitize.core.base.handler.DesensitizationHandler; import java.lang.annotation.Annotation; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java index debbe63..0aada4a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.regex.handler; +package com.tashow.cloud.web.desensitize.core.regex.handler; -import cn.iocoder.yudao.framework.desensitize.core.regex.annotation.RegexDesensitize; +import com.tashow.cloud.web.desensitize.core.regex.annotation.RegexDesensitize; /** * {@link RegexDesensitize} 的正则脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/EmailDesensitizationHandler.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/EmailDesensitizationHandler.java similarity index 72% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/EmailDesensitizationHandler.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/EmailDesensitizationHandler.java index 8d1867a..bb22ee3 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/EmailDesensitizationHandler.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/regex/handler/EmailDesensitizationHandler.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.regex.handler; +package com.tashow.cloud.web.desensitize.core.regex.handler; -import cn.iocoder.yudao.framework.desensitize.core.regex.annotation.EmailDesensitize; +import com.tashow.cloud.web.desensitize.core.regex.annotation.EmailDesensitize; /** * {@link EmailDesensitize} 的脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/BankCardDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/BankCardDesensitize.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/BankCardDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/BankCardDesensitize.java index 297d7c8..3334c21 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/BankCardDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/BankCardDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; +package com.tashow.cloud.web.desensitize.core.slider.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.slider.handler.BankCardDesensitization; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.slider.handler.BankCardDesensitization; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/CarLicenseDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/CarLicenseDesensitize.java similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/CarLicenseDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/CarLicenseDesensitize.java index ef94185..8b41545 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/CarLicenseDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/CarLicenseDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; +package com.tashow.cloud.web.desensitize.core.slider.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.slider.handler.CarLicenseDesensitization; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.slider.handler.CarLicenseDesensitization; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/ChineseNameDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/ChineseNameDesensitize.java similarity index 75% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/ChineseNameDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/ChineseNameDesensitize.java index 5679727..9f41f87 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/ChineseNameDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/ChineseNameDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; +package com.tashow.cloud.web.desensitize.core.slider.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.slider.handler.ChineseNameDesensitization; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.slider.handler.ChineseNameDesensitization; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/FixedPhoneDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/FixedPhoneDesensitize.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/FixedPhoneDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/FixedPhoneDesensitize.java index b225155..8c6af1b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/FixedPhoneDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/FixedPhoneDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; +package com.tashow.cloud.web.desensitize.core.slider.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.slider.handler.FixedPhoneDesensitization; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.slider.handler.FixedPhoneDesensitization; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/IdCardDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/IdCardDesensitize.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/IdCardDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/IdCardDesensitize.java index df1cac0..1f3b774 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/IdCardDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/IdCardDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; +package com.tashow.cloud.web.desensitize.core.slider.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.slider.handler.IdCardDesensitization; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.slider.handler.IdCardDesensitization; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/MobileDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/MobileDesensitize.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/MobileDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/MobileDesensitize.java index b3e3492..4b3e94d 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/MobileDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/MobileDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; +package com.tashow.cloud.web.desensitize.core.slider.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.slider.handler.MobileDesensitization; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.slider.handler.MobileDesensitization; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/PasswordDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/PasswordDesensitize.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/PasswordDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/PasswordDesensitize.java index e70b8ac..1ce1398 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/PasswordDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/PasswordDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; +package com.tashow.cloud.web.desensitize.core.slider.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.slider.handler.PasswordDesensitization; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.slider.handler.PasswordDesensitization; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/SliderDesensitize.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/SliderDesensitize.java similarity index 79% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/SliderDesensitize.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/SliderDesensitize.java index 886eedd..c0b5298 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/SliderDesensitize.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/annotation/SliderDesensitize.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; +package com.tashow.cloud.web.desensitize.core.slider.annotation; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.slider.handler.DefaultDesensitizationHandler; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.tashow.cloud.web.desensitize.core.base.annotation.DesensitizeBy; +import com.tashow.cloud.web.desensitize.core.slider.handler.DefaultDesensitizationHandler; import java.lang.annotation.*; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java similarity index 90% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java index 7b56329..7a724a8 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; -import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; +import com.tashow.cloud.common.util.spring.SpringExpressionUtils; +import com.tashow.cloud.web.desensitize.core.base.handler.DesensitizationHandler; import java.lang.annotation.Annotation; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/BankCardDesensitization.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/BankCardDesensitization.java similarity index 80% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/BankCardDesensitization.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/BankCardDesensitization.java index 79797e5..3a71c91 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/BankCardDesensitization.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/BankCardDesensitization.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.BankCardDesensitize; +import com.tashow.cloud.web.desensitize.core.slider.annotation.BankCardDesensitize; /** * {@link BankCardDesensitize} 的脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/CarLicenseDesensitization.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/CarLicenseDesensitization.java similarity index 80% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/CarLicenseDesensitization.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/CarLicenseDesensitization.java index 1029ee2..0da8c24 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/CarLicenseDesensitization.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/CarLicenseDesensitization.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.CarLicenseDesensitize; +import com.tashow.cloud.web.desensitize.core.slider.annotation.CarLicenseDesensitize; /** * {@link CarLicenseDesensitize} 的脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/ChineseNameDesensitization.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/ChineseNameDesensitization.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/ChineseNameDesensitization.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/ChineseNameDesensitization.java index f71dac0..b403323 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/ChineseNameDesensitization.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/ChineseNameDesensitization.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.ChineseNameDesensitize; +import com.tashow.cloud.web.desensitize.core.slider.annotation.ChineseNameDesensitize; /** * {@link ChineseNameDesensitize} 的脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/DefaultDesensitizationHandler.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/DefaultDesensitizationHandler.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/DefaultDesensitizationHandler.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/DefaultDesensitizationHandler.java index bdb282d..40166ca 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/DefaultDesensitizationHandler.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/DefaultDesensitizationHandler.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.SliderDesensitize; +import com.tashow.cloud.web.desensitize.core.slider.annotation.SliderDesensitize; /** * {@link SliderDesensitize} 的脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/FixedPhoneDesensitization.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/FixedPhoneDesensitization.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/FixedPhoneDesensitization.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/FixedPhoneDesensitization.java index 53412e4..26cb9d2 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/FixedPhoneDesensitization.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/FixedPhoneDesensitization.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.FixedPhoneDesensitize; +import com.tashow.cloud.web.desensitize.core.slider.annotation.FixedPhoneDesensitize; /** * {@link FixedPhoneDesensitize} 的脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/IdCardDesensitization.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/IdCardDesensitization.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/IdCardDesensitization.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/IdCardDesensitization.java index 4bb8915..96f5083 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/IdCardDesensitization.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/IdCardDesensitization.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.IdCardDesensitize; +import com.tashow.cloud.web.desensitize.core.slider.annotation.IdCardDesensitize; /** * {@link IdCardDesensitize} 的脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/MobileDesensitization.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/MobileDesensitization.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/MobileDesensitization.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/MobileDesensitization.java index 5796d13..c9a95f5 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/MobileDesensitization.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/MobileDesensitization.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.MobileDesensitize; +import com.tashow.cloud.web.desensitize.core.slider.annotation.MobileDesensitize; /** * {@link MobileDesensitize} 的脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/PasswordDesensitization.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/PasswordDesensitization.java similarity index 77% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/PasswordDesensitization.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/PasswordDesensitization.java index 8c6d120..bcfbbcb 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/PasswordDesensitization.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/core/slider/handler/PasswordDesensitization.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.desensitize.core.slider.handler; +package com.tashow.cloud.web.desensitize.core.slider.handler; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.PasswordDesensitize; +import com.tashow.cloud.web.desensitize.core.slider.annotation.PasswordDesensitize; /** * {@link PasswordDesensitize} 的码脱敏处理器 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/package-info.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/package-info.java similarity index 66% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/package-info.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/package-info.java index bfe0187..2c81459 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/package-info.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/desensitize/package-info.java @@ -1,4 +1,4 @@ /** * 脱敏组件:支持 JSON 返回数据时,将邮箱、手机等字段进行脱敏 */ -package cn.iocoder.yudao.framework.desensitize; +package com.tashow.cloud.web.desensitize; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/jackson/config/JacksonAutoConfiguration.java similarity index 83% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/jackson/config/JacksonAutoConfiguration.java index c62f0a0..070715f 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/jackson/config/JacksonAutoConfiguration.java @@ -1,16 +1,16 @@ -package cn.iocoder.yudao.framework.jackson.config; +package com.tashow.cloud.web.jackson.config; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer; -import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer; -import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.common.util.json.databind.NumberSerializer; +import com.tashow.cloud.common.util.json.databind.TimestampLocalDateTimeDeserializer; +import com.tashow.cloud.common.util.json.databind.TimestampLocalDateTimeSerializer; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; @@ -22,7 +22,7 @@ import java.util.List; @AutoConfiguration @Slf4j -public class YudaoJacksonAutoConfiguration { +public class JacksonAutoConfiguration { @Bean @SuppressWarnings("InstantiationOfUtilityClass") diff --git a/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/jackson/core/package-info.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/jackson/core/package-info.java new file mode 100644 index 0000000..e788384 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/jackson/core/package-info.java @@ -0,0 +1 @@ +package com.tashow.cloud.web.jackson.core; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/config/SwaggerAutoConfiguration.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/config/SwaggerAutoConfiguration.java index 093303e..b743e11 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/config/SwaggerAutoConfiguration.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.swagger.config; +package com.tashow.cloud.web.swagger.config; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; @@ -31,7 +31,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import static com.tashow.cloud.web.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * Swagger 自动配置类,基于 OpenAPI + Springdoc 实现。 @@ -46,7 +47,7 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ @ConditionalOnClass({OpenAPI.class}) @EnableConfigurationProperties(SwaggerProperties.class) @ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true) // 设置为 false 时,禁用 -public class YudaoSwaggerAutoConfiguration { +public class SwaggerAutoConfiguration { // ========== 全局 OpenAPI 配置 ========== diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/SwaggerProperties.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/config/SwaggerProperties.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/SwaggerProperties.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/config/SwaggerProperties.java index 5374d3a..512b5aa 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/SwaggerProperties.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/config/SwaggerProperties.java @@ -1,9 +1,8 @@ -package cn.iocoder.yudao.framework.swagger.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; +package com.tashow.cloud.web.swagger.config; import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; /** * Swagger 配置属性 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/package-info.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/package-info.java similarity index 66% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/package-info.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/package-info.java index 5eb7822..35e0f40 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/package-info.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/swagger/package-info.java @@ -3,4 +3,4 @@ * * @author 芋道源码 */ -package cn.iocoder.yudao.framework.swagger; +package com.tashow.cloud.web.swagger; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/config/WebAutoConfiguration.java similarity index 89% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/config/WebAutoConfiguration.java index c2e9393..ad26e57 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/config/WebAutoConfiguration.java @@ -1,12 +1,14 @@ -package cn.iocoder.yudao.framework.web.config; +package com.tashow.cloud.web.web.config; -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter; -import cn.iocoder.yudao.framework.web.core.filter.DemoFilter; -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.util.WebFrameworkUtils; -import cn.iocoder.yudao.module.infra.api.logger.ApiErrorLogApi; +import com.tashow.cloud.common.enums.WebFilterOrderEnum; +import com.tashow.cloud.infraapi.api.logger.ApiErrorLogApi; +import com.tashow.cloud.web.web.core.filter.CacheRequestBodyFilter; +import com.tashow.cloud.web.web.core.filter.DemoFilter; +import com.tashow.cloud.web.web.core.handler.GlobalExceptionHandler; +import com.tashow.cloud.web.web.core.handler.GlobalResponseBodyHandler; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; +import jakarta.annotation.Resource; +import jakarta.servlet.Filter; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -25,12 +27,9 @@ import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import jakarta.annotation.Resource; -import jakarta.servlet.Filter; - @AutoConfiguration @EnableConfigurationProperties(WebProperties.class) -public class YudaoWebAutoConfiguration implements WebMvcConfigurer { +public class WebAutoConfiguration implements WebMvcConfigurer { @Resource private WebProperties webProperties; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/config/WebProperties.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/config/WebProperties.java index 8091e9a..6c32a34 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/config/WebProperties.java @@ -1,5 +1,8 @@ -package cn.iocoder.yudao.framework.web.config; +package com.tashow.cloud.web.web.config; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -7,10 +10,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; - @ConfigurationProperties(prefix = "yudao.web") @Validated @Data @@ -37,7 +36,7 @@ public class WebProperties { * 意义:通过该前缀,避免 Swagger、Actuator 意外通过 Nginx 暴露出来给外部,带来安全性问题 * 这样,Nginx 只需要配置转发到 /api/* 的所有接口即可。 * - * @see YudaoWebAutoConfiguration#configurePathMatch(PathMatchConfigurer) + * @see WebAutoConfiguration#configurePathMatch(PathMatchConfigurer) */ @NotEmpty(message = "API 前缀不能为空") private String prefix; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/ApiRequestFilter.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/ApiRequestFilter.java index 7b064e8..0123feb 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/ApiRequestFilter.java @@ -1,12 +1,11 @@ -package cn.iocoder.yudao.framework.web.core.filter; +package com.tashow.cloud.web.web.core.filter; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.web.config.WebProperties; +import com.tashow.cloud.web.web.config.WebProperties; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.web.filter.OncePerRequestFilter; -import jakarta.servlet.http.HttpServletRequest; - /** * 过滤 /admin-api、/app-api 等 API 请求的过滤器 * diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyFilter.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/CacheRequestBodyFilter.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyFilter.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/CacheRequestBodyFilter.java index 9071998..11245da 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyFilter.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/CacheRequestBodyFilter.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.web.core.filter; - -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import org.springframework.web.filter.OncePerRequestFilter; +package com.tashow.cloud.web.web.core.filter; +import com.tashow.cloud.common.util.servlet.ServletUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + import java.io.IOException; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyWrapper.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/CacheRequestBodyWrapper.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyWrapper.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/CacheRequestBodyWrapper.java index 8e80fa5..af6fb2c 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyWrapper.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/CacheRequestBodyWrapper.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.framework.web.core.filter; - -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +package com.tashow.cloud.web.web.core.filter; +import com.tashow.cloud.common.util.servlet.ServletUtils; import jakarta.servlet.ReadListener; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; + import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/DemoFilter.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/DemoFilter.java similarity index 74% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/DemoFilter.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/DemoFilter.java index eece304..4ec53f0 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/DemoFilter.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/filter/DemoFilter.java @@ -1,16 +1,16 @@ -package cn.iocoder.yudao.framework.web.core.filter; +package com.tashow.cloud.web.web.core.filter; 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.web.core.util.WebFrameworkUtils; -import org.springframework.web.filter.OncePerRequestFilter; - +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + +import static com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants.DEMO_DENY; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.DEMO_DENY; /** * 演示 Filter,禁止用户发起写操作,避免影响测试数据 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/handler/GlobalExceptionHandler.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/handler/GlobalExceptionHandler.java index 8d63724..31f77a3 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/handler/GlobalExceptionHandler.java @@ -1,21 +1,21 @@ -package cn.iocoder.yudao.framework.web.core.handler; +package com.tashow.cloud.web.web.core.handler; import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.JakartaServletUtil; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; -import cn.iocoder.yudao.module.infra.api.logger.ApiErrorLogApi; -import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; +import com.tashow.cloud.common.exception.ServiceException; +import com.tashow.cloud.common.exception.util.ServiceExceptionUtil; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.common.util.collection.SetUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.common.util.monitor.TracerUtils; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.infraapi.api.logger.ApiErrorLogApi; +import com.tashow.cloud.infraapi.api.logger.dto.ApiErrorLogCreateReqDTO; import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; @@ -40,12 +40,8 @@ import java.time.LocalDateTime; import java.util.Map; import java.util.Set; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.METHOD_NOT_ALLOWED; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_FOUND; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED; +import static com.tashow.cloud.common.exception.enums.GlobalErrorCodeConstants.*; + /** * 全局异常处理器,将 Exception 翻译成 CommonResult + 对应的异常编号 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalResponseBodyHandler.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/handler/GlobalResponseBodyHandler.java similarity index 86% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalResponseBodyHandler.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/handler/GlobalResponseBodyHandler.java index 90da742..d86ca76 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalResponseBodyHandler.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/handler/GlobalResponseBodyHandler.java @@ -1,7 +1,8 @@ -package cn.iocoder.yudao.framework.web.core.handler; +package com.tashow.cloud.web.web.core.handler; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.web.apilog.core.filter.ApiAccessLogFilter; +import com.tashow.cloud.web.web.core.util.WebFrameworkUtils; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; @@ -18,7 +19,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; * 原因是,GlobalResponseBodyHandler 本质上是 AOP,它不应该改变 Controller 返回的数据结构 * * 目前,GlobalResponseBodyHandler 的主要作用是,记录 Controller 的返回结果, - * 方便 {@link cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter} 记录访问日志 + * 方便 {@link ApiAccessLogFilter} 记录访问日志 */ @ControllerAdvice public class GlobalResponseBodyHandler implements ResponseBodyAdvice { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/util/WebFrameworkUtils.java similarity index 90% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/util/WebFrameworkUtils.java index 83c07f3..333c172 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/core/util/WebFrameworkUtils.java @@ -1,20 +1,17 @@ -package cn.iocoder.yudao.framework.web.core.util; +package com.tashow.cloud.web.web.core.util; import cn.hutool.core.util.NumberUtil; -import cn.hutool.extra.servlet.ServletUtil; -import cn.iocoder.yudao.framework.common.enums.RpcConstants; -import cn.iocoder.yudao.framework.common.enums.TerminalEnum; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.web.config.WebProperties; +import com.tashow.cloud.common.enums.RpcConstants; +import com.tashow.cloud.common.enums.TerminalEnum; +import com.tashow.cloud.common.enums.UserTypeEnum; +import com.tashow.cloud.common.pojo.CommonResult; +import com.tashow.cloud.web.web.config.WebProperties; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.http.HttpServletRequest; - /** * 专属于 web 包的工具类 * @@ -32,7 +29,7 @@ public class WebFrameworkUtils { /** * 终端的 Header * - * @see cn.iocoder.yudao.framework.common.enums.TerminalEnum + * @see TerminalEnum */ public static final String HEADER_TERMINAL = "terminal"; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/package-info.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/package-info.java similarity index 52% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/package-info.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/package-info.java index 43b70eb..79c7df1 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/package-info.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/web/package-info.java @@ -1,4 +1,4 @@ /** * 针对 SpringMVC 的基础封装 */ -package cn.iocoder.yudao.framework.web; +package com.tashow.cloud.web.web; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/XssProperties.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/config/XssProperties.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/XssProperties.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/config/XssProperties.java index c914b04..5739bad 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/XssProperties.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/config/XssProperties.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.xss.config; +package com.tashow.cloud.web.xss.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/config/YudaoXssAutoConfiguration.java similarity index 84% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/config/YudaoXssAutoConfiguration.java index 99b6a44..a75bbb6 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/config/YudaoXssAutoConfiguration.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.framework.xss.config; +package com.tashow.cloud.web.xss.config; -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import cn.iocoder.yudao.framework.xss.core.clean.JsoupXssCleaner; -import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner; -import cn.iocoder.yudao.framework.xss.core.filter.XssFilter; -import cn.iocoder.yudao.framework.xss.core.json.XssStringJsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; +import com.tashow.cloud.common.enums.WebFilterOrderEnum; +import com.tashow.cloud.web.xss.core.clean.JsoupXssCleaner; +import com.tashow.cloud.web.xss.core.clean.XssCleaner; +import com.tashow.cloud.web.xss.core.filter.XssFilter; +import com.tashow.cloud.web.xss.core.json.XssStringJsonDeserializer; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -17,7 +17,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.util.PathMatcher; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import static cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration.createFilterBean; +import static com.tashow.cloud.web.web.config.WebAutoConfiguration.createFilterBean; + @AutoConfiguration @EnableConfigurationProperties(XssProperties.class) diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/JsoupXssCleaner.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/clean/JsoupXssCleaner.java similarity index 97% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/JsoupXssCleaner.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/clean/JsoupXssCleaner.java index 4cbc907..280065a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/JsoupXssCleaner.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/clean/JsoupXssCleaner.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.xss.core.clean; +package com.tashow.cloud.web.xss.core.clean; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/XssCleaner.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/clean/XssCleaner.java similarity index 83% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/XssCleaner.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/clean/XssCleaner.java index 529bc64..b9eba68 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/XssCleaner.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/clean/XssCleaner.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.xss.core.clean; +package com.tashow.cloud.web.xss.core.clean; /** * 对 html 文本中的有 Xss 风险的数据进行清理 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssFilter.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/filter/XssFilter.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssFilter.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/filter/XssFilter.java index d33086a..250db1f 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssFilter.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/filter/XssFilter.java @@ -1,15 +1,15 @@ -package cn.iocoder.yudao.framework.xss.core.filter; - -import cn.iocoder.yudao.framework.xss.config.XssProperties; -import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner; -import lombok.AllArgsConstructor; -import org.springframework.util.PathMatcher; -import org.springframework.web.filter.OncePerRequestFilter; +package com.tashow.cloud.web.xss.core.filter; +import com.tashow.cloud.web.xss.config.XssProperties; +import com.tashow.cloud.web.xss.core.clean.XssCleaner; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +import org.springframework.util.PathMatcher; +import org.springframework.web.filter.OncePerRequestFilter; + import java.io.IOException; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssRequestWrapper.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/filter/XssRequestWrapper.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssRequestWrapper.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/filter/XssRequestWrapper.java index 427eb9b..6eec5da 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssRequestWrapper.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/filter/XssRequestWrapper.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.framework.xss.core.filter; - -import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner; +package com.tashow.cloud.web.xss.core.filter; +import com.tashow.cloud.web.xss.core.clean.XssCleaner; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; + import java.util.LinkedHashMap; import java.util.Map; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/json/XssStringJsonDeserializer.java similarity index 91% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/json/XssStringJsonDeserializer.java index 047b19d..22ba522 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/core/json/XssStringJsonDeserializer.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.xss.core.json; +package com.tashow.cloud.web.xss.core.json; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.xss.config.XssProperties; -import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StringDeserializer; +import com.tashow.cloud.common.util.servlet.ServletUtils; +import com.tashow.cloud.web.xss.config.XssProperties; +import com.tashow.cloud.web.xss.core.clean.XssCleaner; import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/package-info.java b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/package-info.java similarity index 73% rename from tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/package-info.java rename to tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/package-info.java index c6e46f0..bdb71ae 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/package-info.java +++ b/tashow-platform-framework/tashow-framework-web/src/main/java/com/tashow/cloud/web/xss/package-info.java @@ -3,4 +3,4 @@ * * XSS 说明:https://tech.meituan.com/2018/09/27/fe-security.html */ -package cn.iocoder.yudao.framework.xss; +package com.tashow.cloud.web.xss; diff --git a/tashow-platform-framework/tashow-framework-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-framework-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..61841e4 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,6 @@ +com.tashow.cloud.web.apilog.config.ApiLogAutoConfiguration +com.tashow.cloud.web.jackson.config.JacksonAutoConfiguration +com.tashow.cloud.web.swagger.config.SwaggerAutoConfiguration +com.tashow.cloud.web.web.config.WebAutoConfiguration +com.tashow.cloud.web.apilog.config.ApiLogRpcAutoConfiguration +com.tashow.cloud.web.banner.config.BannerAutoConfiguration diff --git a/tashow-platform-framework/tashow-framework-web/src/main/resources/banner.txt b/tashow-platform-framework/tashow-framework-web/src/main/resources/banner.txt new file mode 100644 index 0000000..39a441d --- /dev/null +++ b/tashow-platform-framework/tashow-framework-web/src/main/resources/banner.txt @@ -0,0 +1,17 @@ +芋道源码 http://www.iocoder.cn +Application Version: ${yudao.info.version} +Spring Boot Version: ${spring-boot.version} + +.__ __. ______ .______ __ __ _______ +| \ | | / __ \ | _ \ | | | | / _____| +| \| | | | | | | |_) | | | | | | | __ +| . ` | | | | | | _ < | | | | | | |_ | +| |\ | | `--' | | |_) | | `--' | | |__| | +|__| \__| \______/ |______/ \______/ \______| + +███╗ ██╗ ██████╗ ██████╗ ██╗ ██╗ ██████╗ +████╗ ██║██╔═══██╗ ██╔══██╗██║ ██║██╔════╝ +██╔██╗ ██║██║ ██║ ██████╔╝██║ ██║██║ ███╗ +██║╚██╗██║██║ ██║ ██╔══██╗██║ ██║██║ ██║ +██║ ╚████║╚██████╔╝ ██████╔╝╚██████╔╝╚██████╔╝ +╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot API 接口文档 Swagger 入门》.md b/tashow-platform-framework/tashow-framework-web/《芋道 Spring Boot API 接口文档 Swagger 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot API 接口文档 Swagger 入门》.md rename to tashow-platform-framework/tashow-framework-web/《芋道 Spring Boot API 接口文档 Swagger 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot SpringMVC 入门》.md b/tashow-platform-framework/tashow-framework-web/《芋道 Spring Boot SpringMVC 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot SpringMVC 入门》.md rename to tashow-platform-framework/tashow-framework-web/《芋道 Spring Boot SpringMVC 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/pom.xml b/tashow-platform-framework/tashow-framework-websocket/pom.xml similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/pom.xml rename to tashow-platform-framework/tashow-framework-websocket/pom.xml index 48d1924..10b75c9 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/pom.xml +++ b/tashow-platform-framework/tashow-framework-websocket/pom.xml @@ -3,23 +3,22 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - cn.iocoder.cloud - yudao-platform-framework + com.tashow.cloud + tashow-platform-framework ${revision} 4.0.0 - yudao-spring-boot-starter-websocket + tashow-framework-websocket jar ${project.artifactId} WebSocket 框架,支持多节点的广播 - https://github.com/YunaiV/ruoyi-vue-pro - cn.iocoder.cloud - yudao-common + com.tashow.cloud + tashow-common @@ -28,8 +27,8 @@ 因为 websocket 和 LoginUser 当前登录的用户有一定的相关性,具体可见 WebSocketSessionManagerImpl 逻辑。 如果让 security 拓展 websocket 的话,会导致 websocket 组件的封装很散,进而增大理解成本。 --> - cn.iocoder.cloud - yudao-spring-boot-starter-security + com.tashow.cloud + tashow-framework-security provided @@ -40,8 +39,8 @@ - cn.iocoder.cloud - yudao-spring-boot-starter-mq + com.tashow.cloud + tashow-framework-mq org.springframework.kafka @@ -64,8 +63,8 @@ - cn.iocoder.cloud - yudao-spring-boot-starter-biz-tenant + com.tashow.cloud + tashow-framework-tenant provided diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/YudaoWebSocketAutoConfiguration.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/config/WebSocketAutoConfiguration.java similarity index 73% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/YudaoWebSocketAutoConfiguration.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/config/WebSocketAutoConfiguration.java index 3aded88..639719a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/YudaoWebSocketAutoConfiguration.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/config/WebSocketAutoConfiguration.java @@ -1,23 +1,23 @@ -package cn.iocoder.yudao.framework.websocket.config; +package com.tashow.cloud.websocket.config; -import cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQConsumerAutoConfiguration; -import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; -import cn.iocoder.yudao.framework.websocket.core.handler.JsonWebSocketMessageHandler; -import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; -import cn.iocoder.yudao.framework.websocket.core.security.LoginUserHandshakeInterceptor; -import cn.iocoder.yudao.framework.websocket.core.security.WebSocketAuthorizeRequestsCustomizer; -import cn.iocoder.yudao.framework.websocket.core.sender.kafka.KafkaWebSocketMessageConsumer; -import cn.iocoder.yudao.framework.websocket.core.sender.kafka.KafkaWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.local.LocalWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq.RabbitMQWebSocketMessageConsumer; -import cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq.RabbitMQWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.redis.RedisWebSocketMessageConsumer; -import cn.iocoder.yudao.framework.websocket.core.sender.redis.RedisWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.rocketmq.RocketMQWebSocketMessageConsumer; -import cn.iocoder.yudao.framework.websocket.core.sender.rocketmq.RocketMQWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionHandlerDecorator; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManagerImpl; +import com.tashow.cloud.mq.redis.config.RedisMQConsumerAutoConfiguration; +import com.tashow.cloud.mq.redis.core.RedisMQTemplate; +import com.tashow.cloud.websocket.core.handler.JsonWebSocketMessageHandler; +import com.tashow.cloud.websocket.core.listener.WebSocketMessageListener; +import com.tashow.cloud.websocket.core.security.LoginUserHandshakeInterceptor; +import com.tashow.cloud.websocket.core.security.WebSocketAuthorizeRequestsCustomizer; +import com.tashow.cloud.websocket.core.sender.kafka.KafkaWebSocketMessageConsumer; +import com.tashow.cloud.websocket.core.sender.kafka.KafkaWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.local.LocalWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.rabbitmq.RabbitMQWebSocketMessageConsumer; +import com.tashow.cloud.websocket.core.sender.rabbitmq.RabbitMQWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.redis.RedisWebSocketMessageConsumer; +import com.tashow.cloud.websocket.core.sender.redis.RedisWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.rocketmq.RocketMQWebSocketMessageConsumer; +import com.tashow.cloud.websocket.core.sender.rocketmq.RocketMQWebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionHandlerDecorator; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManagerImpl; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.amqp.core.TopicExchange; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -40,11 +40,11 @@ import java.util.List; * * @author xingyu4j */ -@AutoConfiguration(before = YudaoRedisMQConsumerAutoConfiguration.class) // before YudaoRedisMQConsumerAutoConfiguration 的原因是,需要保证 RedisWebSocketMessageConsumer 先创建,才能创建 RedisMessageListenerContainer +@AutoConfiguration(before = RedisMQConsumerAutoConfiguration.class) // before YudaoRedisMQConsumerAutoConfiguration 的原因是,需要保证 RedisWebSocketMessageConsumer 先创建,才能创建 RedisMessageListenerContainer @EnableWebSocket // 开启 websocket @ConditionalOnProperty(prefix = "yudao.websocket", value = "enable", matchIfMissing = true) // 允许使用 yudao.websocket.enable=false 禁用 websocket @EnableConfigurationProperties(WebSocketProperties.class) -public class YudaoWebSocketAutoConfiguration { +public class WebSocketAutoConfiguration { @Bean public WebSocketConfigurer webSocketConfigurer(HandshakeInterceptor[] handshakeInterceptors, @@ -85,7 +85,7 @@ public class YudaoWebSocketAutoConfiguration { // ==================== Sender 相关 ==================== @Configuration - @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "local") + @ConditionalOnProperty(prefix = "tashow.websocket", name = "sender-type", havingValue = "local") public class LocalWebSocketMessageSenderConfiguration { @Bean @@ -96,7 +96,7 @@ public class YudaoWebSocketAutoConfiguration { } @Configuration - @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "redis") + @ConditionalOnProperty(prefix = "tashow.websocket", name = "sender-type", havingValue = "redis") public class RedisWebSocketMessageSenderConfiguration { @Bean @@ -114,7 +114,7 @@ public class YudaoWebSocketAutoConfiguration { } @Configuration - @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "rocketmq") + @ConditionalOnProperty(prefix = "tashow.websocket", name = "sender-type", havingValue = "rocketmq") public class RocketMQWebSocketMessageSenderConfiguration { @Bean @@ -162,7 +162,7 @@ public class YudaoWebSocketAutoConfiguration { } @Configuration - @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "kafka") + @ConditionalOnProperty(prefix = "tashow.websocket", name = "sender-type", havingValue = "kafka") public class KafkaWebSocketMessageSenderConfiguration { @Bean @@ -180,4 +180,4 @@ public class YudaoWebSocketAutoConfiguration { } -} \ No newline at end of file +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/WebSocketProperties.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/config/WebSocketProperties.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/WebSocketProperties.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/config/WebSocketProperties.java index f1d84f7..3f6ce34 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/WebSocketProperties.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/config/WebSocketProperties.java @@ -1,18 +1,17 @@ -package cn.iocoder.yudao.framework.websocket.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.validation.annotation.Validated; +package com.tashow.cloud.websocket.config; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; /** * WebSocket 配置项 * * @author xingyu4j */ -@ConfigurationProperties("yudao.websocket") +@ConfigurationProperties("tashow.websocket") @Data @Validated public class WebSocketProperties { diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/handler/JsonWebSocketMessageHandler.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/handler/JsonWebSocketMessageHandler.java index 120f529..ff97818 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/handler/JsonWebSocketMessageHandler.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.framework.websocket.core.handler; +package com.tashow.cloud.websocket.core.handler; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.TypeUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; -import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; -import cn.iocoder.yudao.framework.websocket.core.message.JsonWebSocketMessage; -import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.tenant.core.util.TenantUtils; +import com.tashow.cloud.websocket.core.listener.WebSocketMessageListener; +import com.tashow.cloud.websocket.core.message.JsonWebSocketMessage; +import com.tashow.cloud.websocket.core.util.WebSocketFrameworkUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/listener/WebSocketMessageListener.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/listener/WebSocketMessageListener.java similarity index 80% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/listener/WebSocketMessageListener.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/listener/WebSocketMessageListener.java index f3a62cc..b6453ba 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/listener/WebSocketMessageListener.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/listener/WebSocketMessageListener.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.websocket.core.listener; +package com.tashow.cloud.websocket.core.listener; -import cn.iocoder.yudao.framework.websocket.core.message.JsonWebSocketMessage; +import com.tashow.cloud.websocket.core.message.JsonWebSocketMessage; import org.springframework.web.socket.WebSocketSession; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/message/JsonWebSocketMessage.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/message/JsonWebSocketMessage.java similarity index 69% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/message/JsonWebSocketMessage.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/message/JsonWebSocketMessage.java index 0a55cd6..fada656 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/message/JsonWebSocketMessage.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/message/JsonWebSocketMessage.java @@ -1,6 +1,7 @@ -package cn.iocoder.yudao.framework.websocket.core.message; +package com.tashow.cloud.websocket.core.message; -import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; +import com.tashow.cloud.websocket.core.listener.WebSocketMessageListener; +import com.tashow.cloud.websocket.core.listener.WebSocketMessageListener; import lombok.Data; import java.io.Serializable; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/security/LoginUserHandshakeInterceptor.java similarity index 79% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/security/LoginUserHandshakeInterceptor.java index 3a31825..160ecda 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/security/LoginUserHandshakeInterceptor.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.framework.websocket.core.security; +package com.tashow.cloud.websocket.core.security; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.security.security.core.filter.TokenAuthenticationFilter; +import com.tashow.cloud.security.security.core.util.SecurityFrameworkUtils; +import com.tashow.cloud.websocket.core.util.WebSocketFrameworkUtils; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java index f260dfc..d74170a 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.framework.websocket.core.security; +package com.tashow.cloud.websocket.core.security; -import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; -import cn.iocoder.yudao.framework.websocket.config.WebSocketProperties; +import com.tashow.cloud.security.security.config.AuthorizeRequestsCustomizer; +import com.tashow.cloud.websocket.config.WebSocketProperties; import lombok.RequiredArgsConstructor; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/AbstractWebSocketMessageSender.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/AbstractWebSocketMessageSender.java index 9309fd2..427ea13 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/AbstractWebSocketMessageSender.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.framework.websocket.core.sender; +package com.tashow.cloud.websocket.core.sender; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.websocket.core.message.JsonWebSocketMessage; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.common.util.json.JsonUtils; +import com.tashow.cloud.websocket.core.message.JsonWebSocketMessage; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.socket.TextMessage; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/WebSocketMessageSender.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/WebSocketMessageSender.java similarity index 92% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/WebSocketMessageSender.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/WebSocketMessageSender.java index 9f75ad5..b5a4a98 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/WebSocketMessageSender.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/WebSocketMessageSender.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.websocket.core.sender; +package com.tashow.cloud.websocket.core.sender; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.tashow.cloud.common.util.json.JsonUtils; /** * WebSocket 消息的发送器接口 diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessage.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessage.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessage.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessage.java index 5a4cf53..9ba2d90 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessage.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.kafka; +package com.tashow.cloud.websocket.core.sender.kafka; import lombok.Data; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java index 4b255b9..44b13c2 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.kafka; +package com.tashow.cloud.websocket.core.sender.kafka; import lombok.RequiredArgsConstructor; import org.springframework.amqp.rabbit.annotation.RabbitHandler; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java index 47bb598..ccbd632 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.kafka; +package com.tashow.cloud.websocket.core.sender.kafka; -import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.websocket.core.sender.AbstractWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; import lombok.extern.slf4j.Slf4j; import org.springframework.kafka.core.KafkaTemplate; diff --git a/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/local/LocalWebSocketMessageSender.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/local/LocalWebSocketMessageSender.java new file mode 100644 index 0000000..44d839e --- /dev/null +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/local/LocalWebSocketMessageSender.java @@ -0,0 +1,23 @@ +package com.tashow.cloud.websocket.core.sender.local; + +import com.tashow.cloud.websocket.core.sender.AbstractWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.websocket.core.sender.AbstractWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; + +/** + * 本地的 {@link WebSocketMessageSender} 实现类 + * + * 注意:仅仅适合单机场景!!! + * + * @author 芋道源码 + */ +public class LocalWebSocketMessageSender extends AbstractWebSocketMessageSender { + + public LocalWebSocketMessageSender(WebSocketSessionManager sessionManager) { + super(sessionManager); + } + +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java similarity index 88% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java index 80a4bc1..b1ee0cf 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq; +package com.tashow.cloud.websocket.core.sender.rabbitmq; import lombok.Data; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java similarity index 95% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java index 59e3824..9de0e64 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq; +package com.tashow.cloud.websocket.core.sender.rabbitmq; import lombok.RequiredArgsConstructor; import org.springframework.amqp.core.ExchangeTypes; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java similarity index 80% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java index 065a5d6..fe76103 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java @@ -1,8 +1,11 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq; +package com.tashow.cloud.websocket.core.sender.rabbitmq; -import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.websocket.core.sender.AbstractWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.websocket.core.sender.AbstractWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.TopicExchange; import org.springframework.amqp.rabbit.core.RabbitTemplate; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessage.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessage.java similarity index 76% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessage.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessage.java index fb9ea0c..68d694b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessage.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessage.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.redis; +package com.tashow.cloud.websocket.core.sender.redis; -import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessage; +import com.tashow.cloud.mq.redis.core.pubsub.AbstractRedisChannelMessage; import lombok.Data; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java similarity index 80% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java index abce006..0991062 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.redis; +package com.tashow.cloud.websocket.core.sender.redis; -import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessageListener; +import com.tashow.cloud.mq.redis.core.pubsub.AbstractRedisChannelMessageListener; import lombok.RequiredArgsConstructor; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageSender.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessageSender.java similarity index 82% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageSender.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessageSender.java index d6004ac..d31e5a1 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageSender.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/redis/RedisWebSocketMessageSender.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.redis; +package com.tashow.cloud.websocket.core.sender.redis; -import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; -import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.mq.redis.core.RedisMQTemplate; +import com.tashow.cloud.websocket.core.sender.AbstractWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; import lombok.extern.slf4j.Slf4j; /** diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java similarity index 87% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java index 91570e3..acda3aa 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.rocketmq; +package com.tashow.cloud.websocket.core.sender.rocketmq; import lombok.Data; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java index ab2e2c4..09c012e 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.rocketmq; +package com.tashow.cloud.websocket.core.sender.rocketmq; import lombok.RequiredArgsConstructor; import org.apache.rocketmq.spring.annotation.MessageModel; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java similarity index 80% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java index ed059ba..d097156 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java @@ -1,8 +1,11 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.rocketmq; +package com.tashow.cloud.websocket.core.sender.rocketmq; -import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.websocket.core.sender.AbstractWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; +import com.tashow.cloud.websocket.core.sender.AbstractWebSocketMessageSender; +import com.tashow.cloud.websocket.core.sender.WebSocketMessageSender; +import com.tashow.cloud.websocket.core.session.WebSocketSessionManager; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.spring.core.RocketMQTemplate; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionHandlerDecorator.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionHandlerDecorator.java similarity index 96% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionHandlerDecorator.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionHandlerDecorator.java index 600a4dd..1aa2e8b 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionHandlerDecorator.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionHandlerDecorator.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.websocket.core.session; +package com.tashow.cloud.websocket.core.session; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketHandler; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManager.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionManager.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManager.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionManager.java index ad1de23..4d14267 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManager.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionManager.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.websocket.core.session; +package com.tashow.cloud.websocket.core.session; import org.springframework.web.socket.WebSocketSession; @@ -50,4 +50,4 @@ public interface WebSocketSessionManager { */ Collection getSessionList(Integer userType, Long userId); -} \ No newline at end of file +} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManagerImpl.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionManagerImpl.java similarity index 94% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManagerImpl.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionManagerImpl.java index 6dba898..532f920 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManagerImpl.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/session/WebSocketSessionManagerImpl.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.framework.websocket.core.session; +package com.tashow.cloud.websocket.core.session; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; +import com.tashow.cloud.security.security.core.LoginUser; +import com.tashow.cloud.tenant.core.context.TenantContextHolder; +import com.tashow.cloud.websocket.core.util.WebSocketFrameworkUtils; import org.springframework.web.socket.WebSocketSession; import java.util.ArrayList; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/util/WebSocketFrameworkUtils.java b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/util/WebSocketFrameworkUtils.java similarity index 93% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/util/WebSocketFrameworkUtils.java rename to tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/util/WebSocketFrameworkUtils.java index 58cdedc..adab697 100644 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/util/WebSocketFrameworkUtils.java +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/java/com/tashow/cloud/websocket/core/util/WebSocketFrameworkUtils.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.websocket.core.util; +package com.tashow.cloud.websocket.core.util; -import cn.iocoder.yudao.framework.security.core.LoginUser; +import com.tashow.cloud.security.security.core.LoginUser; import org.springframework.web.socket.WebSocketSession; import java.util.Map; diff --git a/tashow-platform-framework/tashow-framework-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/tashow-framework-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..ce42960 --- /dev/null +++ b/tashow-platform-framework/tashow-framework-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.tashow.cloud.websocket.config.WebSocketAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/《芋道 Spring Boot WebSocket 入门》.md b/tashow-platform-framework/tashow-framework-websocket/《芋道 Spring Boot WebSocket 入门》.md similarity index 100% rename from tashow-platform-framework/yudao-spring-boot-starter-websocket/《芋道 Spring Boot WebSocket 入门》.md rename to tashow-platform-framework/tashow-framework-websocket/《芋道 Spring Boot WebSocket 入门》.md diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/package-info.java deleted file mode 100644 index 9d422f5..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/package-info.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * IP 拓展,支持如下功能: - * - * 1. IP 功能:查询 IP 对应的城市信息 - * 基于 https://gitee.com/lionsoul/ip2region 实现 - * 2. 城市功能:查询城市编码对应的城市信息 - * 基于 https://github.com/modood/Administrative-divisions-of-China 实现 - * - * @author 芋道源码 - */ -package cn.iocoder.yudao.framework.ip; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java deleted file mode 100644 index aa22cdb..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java +++ /dev/null @@ -1,17 +0,0 @@ -/** - * 多租户,支持如下层面: - * 1. DB:基于 MyBatis Plus 多租户的功能实现。 - * 2. Redis:通过在 Redis Key 上拼接租户编号的方式,进行隔离。 - * 3. Web:请求 HTTP API 时,解析 Header 的 tenant-id 租户编号,添加到租户上下文。 - * 4. Security:校验当前登陆的用户,是否越权访问其它租户的数据。 - * 5. Job:在 JobHandler 执行任务时,会按照每个租户,都独立并行执行一次。 - * 6. MQ:在 Producer 发送消息时,Header 带上 tenant-id 租户编号;在 Consumer 消费消息时,将 Header 的 tenant-id 租户编号,添加到租户上下文。 - * 7. Async:异步需要保证 ThreadLocal 的传递性,通过使用阿里开源的 TransmittableThreadLocal 实现。相关的改造点,可见: - * 1)Spring Async: - * {@link cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration#threadPoolTaskExecutorBeanPostProcessor()} - * 2)Spring Security: - * TransmittableThreadLocalSecurityContextHolderStrategy - * 和 YudaoSecurityAutoConfiguration#securityContextHolderMethodInvokingFactoryBean() 方法 - * - */ -package cn.iocoder.yudao.framework.tenant; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories b/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories deleted file mode 100644 index a495842..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=\ - cn.iocoder.yudao.framework.tenant.core.mq.kafka.TenantKafkaEnvironmentPostProcessor diff --git a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 26f472e..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -cn.iocoder.yudao.framework.tenant.config.YudaoTenantRpcAutoConfiguration -cn.iocoder.yudao.framework.tenant.config.YudaoTenantAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/package-info.java deleted file mode 100644 index 9ef9a1d..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/core/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.framework.env.core; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/package-info.java deleted file mode 100644 index 20d1d3a..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/java/cn/iocoder/yudao/framework/env/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 开发环境拓展,实现类似阿里的特性环境的能力 - * 1. https://segmentfault.com/a/1190000018022987 - * - * @author 芋道源码 - */ -package cn.iocoder.yudao.framework.env; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring.factories b/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 6df9601..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=\ - cn.iocoder.yudao.framework.env.config.EnvEnvironmentPostProcessor diff --git a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 8bb162e..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-env/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -cn.iocoder.yudao.framework.env.config.YudaoEnvWebAutoConfiguration -cn.iocoder.yudao.framework.env.config.YudaoEnvRpcAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java deleted file mode 100644 index fd87fda..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 字典数据模块,提供 {@link cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils} 工具类 - * - * 通过将字典缓存在内存中,保证性能 - */ -package cn.iocoder.yudao.framework.dict; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index c135368..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -cn.iocoder.yudao.framework.dict.config.YudaoDictRpcAutoConfiguration -cn.iocoder.yudao.framework.dict.config.YudaoDictAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index a3a316d..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -cn.iocoder.yudao.framework.quartz.config.YudaoXxlJobAutoConfiguration -cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java deleted file mode 100644 index 43ee5e4..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 使用 SkyWalking 组件,作为链路追踪、日志中心。 - * - * @author 芋道源码 - */ -package cn.iocoder.yudao.framework.tracer; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 581832f..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -cn.iocoder.yudao.framework.tracer.config.YudaoTracerAutoConfiguration -cn.iocoder.yudao.framework.tracer.config.YudaoMetricsAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java deleted file mode 100644 index 3b716cb..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种 - */ -package cn.iocoder.yudao.framework.mq; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java deleted file mode 100644 index 2773b58..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 占位符,无特殊逻辑 - */ -package cn.iocoder.yudao.framework.mq.rabbitmq.core; \ No newline at end of file diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 4b98f61..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,3 +0,0 @@ -cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQProducerAutoConfiguration -cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQConsumerAutoConfiguration -cn.iocoder.yudao.framework.mq.rabbitmq.config.YudaoRabbitMQAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories b/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories deleted file mode 100644 index eb172e4..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=\ - cn.iocoder.yudao.framework.mybatis.config.IdTypeEnvironmentPostProcessor diff --git a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 4a4eb95..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,3 +0,0 @@ -cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration -cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration -cn.iocoder.yudao.framework.translate.config.YudaoTranslateAutoConfiguration \ No newline at end of file diff --git a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index abca513..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-protection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,4 +0,0 @@ -cn.iocoder.yudao.framework.idempotent.config.YudaoIdempotentConfiguration -cn.iocoder.yudao.framework.lock4j.config.YudaoLock4jConfiguration -cn.iocoder.yudao.framework.ratelimiter.config.YudaoRateLimiterConfiguration -cn.iocoder.yudao.framework.signature.config.YudaoApiSignatureAutoConfiguration \ No newline at end of file diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/package-info.java deleted file mode 100644 index bd8a5d3..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 采用 Spring Data Redis 操作 Redis,底层使用 Redisson 作为客户端 - */ -package cn.iocoder.yudao.framework.redis; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 49724a4..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration -cn.iocoder.yudao.framework.redis.config.YudaoCacheAutoConfiguration diff --git a/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/config/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/config/package-info.java deleted file mode 100644 index 516acc5..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/config/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 占坑 TODO - */ -package cn.iocoder.yudao.framework.rpc.config; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/core/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/core/package-info.java deleted file mode 100644 index e8e4946..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/core/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 占坑 TODO - */ -package cn.iocoder.yudao.framework.rpc.core; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/package-info.java deleted file mode 100644 index 4441019..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-rpc/src/main/java/cn/iocoder/yudao/framework/rpc/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * OpenFeign:提供 RESTful API 的调用 - * - * @author 芋道源码 - */ -package cn.iocoder.yudao.framework.rpc; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java deleted file mode 100644 index 97ce4ea..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 占位,无特殊作用 - */ -package cn.iocoder.yudao.framework.operatelog.core; \ No newline at end of file diff --git a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index ef08215..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,5 +0,0 @@ -cn.iocoder.yudao.framework.security.config.YudaoSecurityRpcAutoConfiguration -cn.iocoder.yudao.framework.security.config.YudaoSecurityAutoConfiguration -cn.iocoder.yudao.framework.security.config.YudaoWebSecurityConfigurerAdapter -cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogConfiguration -cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogRpcAutoConfiguration \ No newline at end of file diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/package-info.java deleted file mode 100644 index 261b508..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.framework.jackson.core; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/package-info.java deleted file mode 100644 index 2dc5316..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Web 框架,全局异常、API 日志等 - */ -package cn.iocoder.yudao.framework; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index a751bb4..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,6 +0,0 @@ -cn.iocoder.yudao.framework.apilog.config.YudaoApiLogAutoConfiguration -cn.iocoder.yudao.framework.jackson.config.YudaoJacksonAutoConfiguration -cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration -cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration -cn.iocoder.yudao.framework.apilog.config.YudaoApiLogRpcAutoConfiguration -cn.iocoder.yudao.framework.banner.config.YudaoBannerAutoConfiguration \ No newline at end of file diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/DesensitizeTest.java b/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/DesensitizeTest.java deleted file mode 100644 index c2a107f..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/DesensitizeTest.java +++ /dev/null @@ -1,100 +0,0 @@ -package cn.iocoder.yudao.framework.desensitize.core; - -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.desensitize.core.regex.annotation.EmailDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.regex.annotation.RegexDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.annotation.Address; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.BankCardDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.CarLicenseDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.ChineseNameDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.FixedPhoneDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.IdCardDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.PasswordDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.MobileDesensitize; -import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.SliderDesensitize; -import lombok.Data; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * {@link DesensitizeTest} 的单元测试 - */ -@ExtendWith(MockitoExtension.class) -public class DesensitizeTest { - - @Test - public void test() { - // 准备参数 - DesensitizeDemo desensitizeDemo = new DesensitizeDemo(); - desensitizeDemo.setNickname("芋道源码"); - desensitizeDemo.setBankCard("9988002866797031"); - desensitizeDemo.setCarLicense("粤A66666"); - desensitizeDemo.setFixedPhone("01086551122"); - desensitizeDemo.setIdCard("530321199204074611"); - desensitizeDemo.setPassword("123456"); - desensitizeDemo.setPhoneNumber("13248765917"); - desensitizeDemo.setSlider1("ABCDEFG"); - desensitizeDemo.setSlider2("ABCDEFG"); - desensitizeDemo.setSlider3("ABCDEFG"); - desensitizeDemo.setEmail("1@email.com"); - desensitizeDemo.setRegex("你好,我是芋道源码"); - desensitizeDemo.setAddress("北京市海淀区上地十街10号"); - desensitizeDemo.setOrigin("芋道源码"); - - // 调用 - DesensitizeDemo d = JsonUtils.parseObject(JsonUtils.toJsonString(desensitizeDemo), DesensitizeDemo.class); - // 断言 - assertNotNull(d); - assertEquals("芋***", d.getNickname()); - assertEquals("998800********31", d.getBankCard()); - assertEquals("粤A6***6", d.getCarLicense()); - assertEquals("0108*****22", d.getFixedPhone()); - assertEquals("530321**********11", d.getIdCard()); - assertEquals("******", d.getPassword()); - assertEquals("132****5917", d.getPhoneNumber()); - assertEquals("#######", d.getSlider1()); - assertEquals("ABC*EFG", d.getSlider2()); - assertEquals("*******", d.getSlider3()); - assertEquals("1****@email.com", d.getEmail()); - assertEquals("你好,我是*", d.getRegex()); - assertEquals("北京市海淀区上地十街10号*", d.getAddress()); - assertEquals("芋道源码", d.getOrigin()); - } - - @Data - public static class DesensitizeDemo { - - @ChineseNameDesensitize - private String nickname; - @BankCardDesensitize - private String bankCard; - @CarLicenseDesensitize - private String carLicense; - @FixedPhoneDesensitize - private String fixedPhone; - @IdCardDesensitize - private String idCard; - @PasswordDesensitize - private String password; - @MobileDesensitize - private String phoneNumber; - @SliderDesensitize(prefixKeep = 6, suffixKeep = 1, replacer = "#") - private String slider1; - @SliderDesensitize(prefixKeep = 3, suffixKeep = 3) - private String slider2; - @SliderDesensitize(prefixKeep = 10) - private String slider3; - @EmailDesensitize - private String email; - @RegexDesensitize(regex = "芋道源码", replacer = "*") - private String regex; - @Address - private String address; - private String origin; - - } - -} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/annotation/Address.java b/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/annotation/Address.java deleted file mode 100644 index 735d25b..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/annotation/Address.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.framework.desensitize.core.annotation; - -import cn.iocoder.yudao.framework.desensitize.core.DesensitizeTest; -import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; -import cn.iocoder.yudao.framework.desensitize.core.handler.AddressHandler; -import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 地址 - * - * 用于 {@link DesensitizeTest} 测试使用 - * - * @author gaibu - */ -@Documented -@Target({ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotationsInside -@DesensitizeBy(handler = AddressHandler.class) -public @interface Address { - - String replacer() default "*"; - -} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/handler/AddressHandler.java b/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/handler/AddressHandler.java deleted file mode 100644 index 7a8455f..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/handler/AddressHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.framework.desensitize.core.handler; - -import cn.iocoder.yudao.framework.desensitize.core.DesensitizeTest; -import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; -import cn.iocoder.yudao.framework.desensitize.core.annotation.Address; - -/** - * {@link Address} 的脱敏处理器 - * - * 用于 {@link DesensitizeTest} 测试使用 - */ -public class AddressHandler implements DesensitizationHandler

{ - - @Override - public String desensitize(String origin, Address annotation) { - return origin + annotation.replacer(); - } - -} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/local/LocalWebSocketMessageSender.java b/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/local/LocalWebSocketMessageSender.java deleted file mode 100644 index 66640ef..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/local/LocalWebSocketMessageSender.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.framework.websocket.core.sender.local; - -import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; - -/** - * 本地的 {@link WebSocketMessageSender} 实现类 - * - * 注意:仅仅适合单机场景!!! - * - * @author 芋道源码 - */ -public class LocalWebSocketMessageSender extends AbstractWebSocketMessageSender { - - public LocalWebSocketMessageSender(WebSocketSessionManager sessionManager) { - super(sessionManager); - } - -} diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/package-info.java b/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/package-info.java deleted file mode 100644 index 97bc5f9..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * WebSocket 框架,支持多节点的广播 - */ -package cn.iocoder.yudao.framework.websocket; diff --git a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 6260e40..0000000 --- a/tashow-platform-framework/yudao-spring-boot-starter-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -cn.iocoder.yudao.framework.websocket.config.YudaoWebSocketAutoConfiguration \ No newline at end of file