Merge remote-tracking branch 'origin/master' into feature/vue3

# Conflicts:
#	yudao-dependencies/pom.xml
This commit is contained in:
xingyu 2022-11-26 13:07:51 +08:00
commit 693288d33d
19 changed files with 309 additions and 908 deletions

View File

@ -35,7 +35,7 @@
* 工作流使用 Flowable支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式
* 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验
* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款
* 集成阿里云、腾讯云、云片等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务
* 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务
* 集成报表设计器,支持数据报表、图形报表、打印设计等
| 项目名 | 说明 | 传说门 |
@ -90,12 +90,12 @@
| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |
| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、云等主流短信平台 |
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |
| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |
| | 通知公告 | 系统通知公告信息发布维护 |
| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |
| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |
| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |
### 工作流程

View File

@ -1245,7 +1245,6 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (62, 0, '未处理', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (63, 1, '已处理', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (64, 2, '已忽略', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (65, 1, '云片', 'YUN_PIAN', 'system_sms_channel_code', 0, 'success', '', NULL, '1', '2021-04-05 01:05:14', '1', '2022-02-16 10:09:55', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (66, 2, '阿里云', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2022-02-16 10:09:52', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (67, 1, '验证码', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (68, 2, '通知', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', b'0');
@ -2277,7 +2276,6 @@ CREATE TABLE `system_sms_channel` (
-- Records of system_sms_channel
-- ----------------------------
BEGIN;
INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道', 'YUN_PIAN', 0, '呵呵呵哒', '1555a14277cb8a608cf45a9e6a80d510', NULL, 'http://vdwapu.natappfree.cc/admin-api/system/sms/callback/yunpian', '', '2021-03-31 06:12:20', '1', '2022-02-23 16:48:44', b'0');
INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'Ballcat', 'ALIYUN', 0, '啦啦啦', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2021-04-14 00:08:37', b'0');
INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', b'0');
INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6, '测试演示', 'DEBUG_DING_TALK', 0, NULL, '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2022-04-10 23:07:59', '1', '2022-06-19 00:33:54', b'0');

View File

@ -2454,7 +2454,6 @@ INSERT INTO "SYSTEM_DICT_DATA" ("ID", "SORT", "LABEL", "VALUE", "DICT_TYPE", "ST
INSERT INTO "SYSTEM_DICT_DATA" ("ID", "SORT", "LABEL", "VALUE", "DICT_TYPE", "STATUS", "COLOR_TYPE", "CSS_CLASS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('62', '0', '未处理', '0', 'infra_api_error_log_process_status', '0', 'primary', NULL, NULL, NULL, TO_DATE('2021-02-26 07:07:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-16 20:14:17', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_DATA" ("ID", "SORT", "LABEL", "VALUE", "DICT_TYPE", "STATUS", "COLOR_TYPE", "CSS_CLASS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('63', '1', '已处理', '1', 'infra_api_error_log_process_status', '0', 'success', NULL, NULL, NULL, TO_DATE('2021-02-26 07:07:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-16 20:14:08', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_DATA" ("ID", "SORT", "LABEL", "VALUE", "DICT_TYPE", "STATUS", "COLOR_TYPE", "CSS_CLASS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('64', '2', '已忽略', '2', 'infra_api_error_log_process_status', '0', 'danger', NULL, NULL, NULL, TO_DATE('2021-02-26 07:07:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-16 20:14:14', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_DATA" ("ID", "SORT", "LABEL", "VALUE", "DICT_TYPE", "STATUS", "COLOR_TYPE", "CSS_CLASS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('65', '1', '云片', 'YUN_PIAN', 'system_sms_channel_code', '0', 'success', NULL, NULL, '1', TO_DATE('2021-04-05 01:05:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-16 10:09:55', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_DATA" ("ID", "SORT", "LABEL", "VALUE", "DICT_TYPE", "STATUS", "COLOR_TYPE", "CSS_CLASS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('66', '2', '阿里云', 'ALIYUN', 'system_sms_channel_code', '0', 'primary', NULL, NULL, '1', TO_DATE('2021-04-05 01:05:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-16 10:09:52', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_DATA" ("ID", "SORT", "LABEL", "VALUE", "DICT_TYPE", "STATUS", "COLOR_TYPE", "CSS_CLASS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('67', '1', '验证码', '1', 'system_sms_template_type', '0', 'warning', NULL, NULL, '1', TO_DATE('2021-04-05 21:50:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-16 12:48:30', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_DATA" ("ID", "SORT", "LABEL", "VALUE", "DICT_TYPE", "STATUS", "COLOR_TYPE", "CSS_CLASS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('68', '2', '通知', '2', 'system_sms_template_type', '0', 'primary', NULL, NULL, '1', TO_DATE('2021-04-05 21:51:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-16 12:48:27', 'SYYYY-MM-DD HH24:MI:SS'), '0');
@ -3845,7 +3844,6 @@ COMMENT ON TABLE "SYSTEM_SMS_CHANNEL" IS '短信渠道';
-- ----------------------------
-- Records of SYSTEM_SMS_CHANNEL
-- ----------------------------
INSERT INTO "SYSTEM_SMS_CHANNEL" ("ID", "SIGNATURE", "CODE", "STATUS", "REMARK", "API_KEY", "API_SECRET", "CALLBACK_URL", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('1', '芋道', 'YUN_PIAN', '0', '呵呵呵哒', '1555a14277cb8a608cf45a9e6a80d510', NULL, 'http://vdwapu.natappfree.cc/admin-api/system/sms/callback/yunpian', NULL, TO_DATE('2021-03-31 06:12:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-23 16:48:44', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_SMS_CHANNEL" ("ID", "SIGNATURE", "CODE", "STATUS", "REMARK", "API_KEY", "API_SECRET", "CALLBACK_URL", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('2', 'Ballcat', 'ALIYUN', '0', '啦啦啦', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, NULL, TO_DATE('2021-03-31 11:53:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2021-04-14 00:08:37', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_SMS_CHANNEL" ("ID", "SIGNATURE", "CODE", "STATUS", "REMARK", "API_KEY", "API_SECRET", "CALLBACK_URL", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('4', '测试渠道', 'DEBUG_DING_TALK', '0', '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', TO_DATE('2021-04-13 00:23:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2021-04-14 00:07:10', 'SYYYY-MM-DD HH24:MI:SS'), '0');
COMMIT;

View File

@ -2267,7 +2267,6 @@ INSERT INTO "system_dict_data" ("id", "sort", "label", "value", "dict_type", "st
INSERT INTO "system_dict_data" ("id", "sort", "label", "value", "dict_type", "status", "color_type", "css_class", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (62, 0, '未处理', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', 0);
INSERT INTO "system_dict_data" ("id", "sort", "label", "value", "dict_type", "status", "color_type", "css_class", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (63, 1, '已处理', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', 0);
INSERT INTO "system_dict_data" ("id", "sort", "label", "value", "dict_type", "status", "color_type", "css_class", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (64, 2, '已忽略', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', 0);
INSERT INTO "system_dict_data" ("id", "sort", "label", "value", "dict_type", "status", "color_type", "css_class", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (65, 1, '云片', 'YUN_PIAN', 'system_sms_channel_code', 0, 'success', '', NULL, '1', '2021-04-05 01:05:14', '1', '2022-02-16 10:09:55', 0);
INSERT INTO "system_dict_data" ("id", "sort", "label", "value", "dict_type", "status", "color_type", "css_class", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (66, 2, '阿里云', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2022-02-16 10:09:52', 0);
INSERT INTO "system_dict_data" ("id", "sort", "label", "value", "dict_type", "status", "color_type", "css_class", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (67, 1, '验证码', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', 0);
INSERT INTO "system_dict_data" ("id", "sort", "label", "value", "dict_type", "status", "color_type", "css_class", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (68, 2, '通知', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', 0);
@ -3519,7 +3518,6 @@ COMMENT ON TABLE "system_sms_channel" IS '短信渠道';
-- Records of system_sms_channel
-- ----------------------------
BEGIN;
INSERT INTO "system_sms_channel" ("id", "signature", "code", "status", "remark", "api_key", "api_secret", "callback_url", "creator", "create_time", "updater", "update_time", "deleted") VALUES (1, '芋道', 'YUN_PIAN', 0, '呵呵呵哒', '1555a14277cb8a608cf45a9e6a80d510', NULL, 'http://vdwapu.natappfree.cc/admin-api/system/sms/callback/yunpian', '', '2021-03-31 06:12:20', '1', '2022-02-23 16:48:44', 0);
INSERT INTO "system_sms_channel" ("id", "signature", "code", "status", "remark", "api_key", "api_secret", "callback_url", "creator", "create_time", "updater", "update_time", "deleted") VALUES (2, 'Ballcat', 'ALIYUN', 0, '啦啦啦', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2021-04-14 00:08:37', 0);
INSERT INTO "system_sms_channel" ("id", "signature", "code", "status", "remark", "api_key", "api_secret", "callback_url", "creator", "create_time", "updater", "update_time", "deleted") VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', 0);
INSERT INTO "system_sms_channel" ("id", "signature", "code", "status", "remark", "api_key", "api_secret", "callback_url", "creator", "create_time", "updater", "update_time", "deleted") VALUES (6, '测试演示', 'DEBUG_DING_TALK', 0, NULL, '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2022-04-10 23:07:59', '1', '2022-04-10 23:07:59', 0);

View File

@ -5545,11 +5545,7 @@ GO
INSERT INTO [dbo].[system_dict_data] ([id], [sort], [label], [value], [dict_type], [status], [color_type], [css_class], [remark], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'63', N'1', N'已处理', N'1', N'infra_api_error_log_process_status', N'0', N'success', N'', NULL, N'', N'2021-02-26 07:07:26.0000000', N'1', N'2022-02-16 20:14:08.0000000', N'0')
GO
INSERT INTO [dbo].[system_dict_data] ([id], [sort], [label], [value], [dict_type], [status], [color_type], [css_class], [remark], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'64', N'2', N'已忽略', N'2', N'infra_api_error_log_process_status', N'0', N'danger', N'', NULL, N'', N'2021-02-26 07:07:34.0000000', N'1', N'2022-02-16 20:14:14.0000000', N'0')
GO
INSERT INTO [dbo].[system_dict_data] ([id], [sort], [label], [value], [dict_type], [status], [color_type], [css_class], [remark], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'65', N'1', N'云片', N'YUN_PIAN', N'system_sms_channel_code', N'0', N'success', N'', NULL, N'1', N'2021-04-05 01:05:14.0000000', N'1', N'2022-02-16 10:09:55.0000000', N'0')
GO
INSERT INTO [dbo].[system_dict_data] ([id], [sort], [label], [value], [dict_type], [status], [color_type], [css_class], [remark], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'66', N'2', N'阿里云', N'ALIYUN', N'system_sms_channel_code', N'0', N'primary', N'', NULL, N'1', N'2021-04-05 01:05:26.0000000', N'1', N'2022-02-16 10:09:52.0000000', N'0')
GO
@ -9623,9 +9619,6 @@ GO
SET IDENTITY_INSERT [dbo].[system_sms_channel] ON
GO
INSERT INTO [dbo].[system_sms_channel] ([id], [signature], [code], [status], [remark], [api_key], [api_secret], [callback_url], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'1', N'芋道', N'YUN_PIAN', N'0', N'呵呵呵哒', N'1555a14277cb8a608cf45a9e6a80d510', NULL, N'http://vdwapu.natappfree.cc/admin-api/system/sms/callback/yunpian', N'', N'2021-03-31 06:12:20.0000000', N'1', N'2022-02-23 16:48:44.0000000', N'0')
GO
INSERT INTO [dbo].[system_sms_channel] ([id], [signature], [code], [status], [remark], [api_key], [api_secret], [callback_url], [creator], [create_time], [updater], [update_time], [deleted]) VALUES (N'2', N'Ballcat', N'ALIYUN', N'0', N'啦啦啦', N'LTAI5tCnKso2uG3kJ5gRav88', N'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, N'', N'2021-03-31 11:53:10.0000000', N'1', N'2021-04-14 00:08:37.0000000', N'0')
GO

View File

@ -61,7 +61,6 @@
<aliyun-java-sdk-core.version>4.6.2</aliyun-java-sdk-core.version>
<aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
<tencentcloud-sdk-java.version>3.1.634</tencentcloud-sdk-java.version>
<yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
<justauth.version>1.4.0</justauth.version>
<jimureport.version>1.5.3</jimureport.version>
<xercesImpl.version>2.12.2</xercesImpl.version>
@ -522,11 +521,6 @@
</dependency>
<!-- SMS SDK begin -->
<dependency>
<groupId>com.yunpian.sdk</groupId>
<artifactId>yunpian-java-sdk</artifactId>
<version>${yunpian-java-sdk.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>

View File

@ -12,7 +12,7 @@
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>短信拓展,支持阿里云、云片、腾讯云</description>
<description>短信拓展,支持阿里云、腾讯云</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<dependencies>
@ -64,11 +64,6 @@
<!-- 三方云服务相关 -->
<!-- SMS SDK begin -->
<dependency>
<groupId>com.yunpian.sdk</groupId>
<artifactId>yunpian-java-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>

View File

@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.yudao.framework.sms.core.client.impl.aliyun.AliyunSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.debug.DebugDingTalkSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.tencent.TencentSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j;
@ -80,7 +79,6 @@ public class SmsClientFactoryImpl implements SmsClientFactory {
// 创建客户端
switch (channelEnum) {
case ALIYUN: return new AliyunSmsClient(properties);
case YUN_PIAN: return new YunpianSmsClient(properties);
case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
case TENCENT: return new TencentSmsClient(properties);
}

View File

@ -1,210 +0,0 @@
package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting;
import com.yunpian.sdk.YunpianClient;
import com.yunpian.sdk.constant.YunpianConstant;
import com.yunpian.sdk.model.Result;
import com.yunpian.sdk.model.Template;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
/**
* 云片短信客户端的实现类
*
* @author zzf
* @since 9:48 2021/3/5
*/
@Slf4j
public class YunpianSmsClient extends AbstractSmsClient {
/**
* 云信短信客户端
*/
private volatile YunpianClient client;
public YunpianSmsClient(SmsChannelProperties properties) {
super(properties, new YunpianSmsCodeMapping());
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
}
@Override
public void doInit() {
YunpianClient oldClient = client;
// 初始化新的客户端
YunpianClient newClient = new YunpianClient(properties.getApiKey());
newClient.init();
this.client = newClient;
// 销毁老的客户端
if (oldClient != null) {
oldClient.close();
}
}
@Override
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
return invoke(() -> {
Map<String, String> request = new HashMap<>();
request.put(YunpianConstant.MOBILE, mobile);
request.put(YunpianConstant.TPL_ID, apiTemplateId);
request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams));
request.put(YunpianConstant.UID, String.valueOf(sendLogId));
request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl());
return client.sms().tpl_single_send(request);
}, response -> new SmsSendRespDTO().setSerialNo(String.valueOf(response.getSid())));
}
private static String formatTplValue(List<KeyValue<String, Object>> templateParams) {
if (CollUtil.isEmpty(templateParams)) {
return "";
}
// 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化
StringJoiner joiner = new StringJoiner("&");
templateParams.forEach(param -> joiner.add(String.format("#%s#=%s", param.getKey(),
URLUtil.encode(String.valueOf(param.getValue())))));
return joiner.toString();
}
@Override
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
return statuses.stream().map(status -> {
SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
resp.setSuccess(Objects.equals(status.getReportStatus(), "SUCCESS"));
resp.setErrorCode(status.getErrorMsg()).setErrorMsg(status.getErrorDetail());
resp.setMobile(status.getMobile()).setReceiveTime(status.getUserReceiveTime());
resp.setSerialNo(String.valueOf(status.getSid())).setLogId(status.getUid());
return resp;
}).collect(Collectors.toList());
}
@Override
protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable {
return invoke(() -> {
if (!NumberUtil.isNumber(apiTemplateId)) {
throw new IllegalArgumentException("云片的 API 模板编号必须为整数");
}
Map<String, String> request = new HashMap<>();
request.put(YunpianConstant.APIKEY, properties.getApiKey());
request.put(YunpianConstant.TPL_ID, apiTemplateId);
return client.tpl().get(request);
}, response -> {
Template template = response.get(0);
return new SmsTemplateRespDTO().setId(String.valueOf(template.getTpl_id())).setContent(template.getTpl_content())
.setAuditStatus(convertSmsTemplateAuditStatus(template.getCheck_status())).setAuditReason(template.getReason());
});
}
@VisibleForTesting
Integer convertSmsTemplateAuditStatus(String checkStatus) {
switch (checkStatus) {
case "CHECKING": return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
case "SUCCESS": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
case "FAIL": return SmsTemplateAuditStatusEnum.FAIL.getStatus();
default: throw new IllegalArgumentException(String.format("未知审核状态(%s)", checkStatus));
}
}
@VisibleForTesting
<T, R> SmsCommonResult<R> invoke(Supplier<Result<T>> requestConsumer, Function<T, R> responseConsumer) throws Throwable {
// 执行请求
Result<T> result = requestConsumer.get();
if (result.getThrowable() != null) {
throw result.getThrowable();
}
// 解析结果
R data = null;
if (result.getData() != null) {
data = responseConsumer.apply(result.getData());
}
// 拼接结果
return SmsCommonResult.build(String.valueOf(result.getCode()), formatResultMsg(result), null, data, codeMapping);
}
private static String formatResultMsg(Result<?> sendResult) {
if (StrUtil.isEmpty(sendResult.getDetail())) {
return sendResult.getMsg();
}
return sendResult.getMsg() + " => " + sendResult.getDetail();
}
/**
* 短信接收状态
*
* 参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档
*
* @author 芋道源码
*/
@Data
public static class SmsReceiveStatus {
/**
* 接收状态
*
* 目前仅有 SUCCESS / FAIL所以使用 Boolean 接收
*/
@JsonProperty("report_status")
private String reportStatus;
/**
* 接收手机号
*/
private String mobile;
/**
* 运营商返回的代码"DB:0103"
*
* 由于不同运营商信息不同此字段仅供参考
*/
@JsonProperty("error_msg")
private String errorMsg;
/**
* 运营商反馈代码的中文解释
*
* 默认不推送此字段如需推送请联系客服
*/
@JsonProperty("error_detail")
private String errorDetail;
/**
* 短信编号
*/
private Long sid;
/**
* 用户自定义 id
*
* 这里我们传递的是 SysSmsLogDO 的日志编号
*/
private Long uid;
/**
* 用户接收时间
*/
@JsonProperty("user_receive_time")
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private LocalDateTime userReceiveTime;
}
}

View File

@ -1,59 +0,0 @@
package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
import static com.yunpian.sdk.constant.Code.*;
/**
* 云片的 SmsCodeMapping 实现类
* <p>
* 参见 https://www.yunpian.com/official/document/sms/zh_CN/returnvalue_common 文档
*
* @author 芋道源码
*/
public class YunpianSmsCodeMapping implements SmsCodeMapping {
@Override
public ErrorCode apply(String apiCode) {
int code = Integer.parseInt(apiCode);
switch (code) {
case OK:
return SUCCESS;
case ARGUMENT_MISSING:
return SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR;
case BAD_ARGUMENT_FORMAT:
return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR;
case TPL_NOT_FOUND:
case TPL_NOT_VALID:
return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID;
case MONEY_NOT_ENOUGH:
return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH;
case BLACK_WORD:
return SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID;
case DUP_IN_SHORT_TIME:
case TOO_MANY_TIME_IN_5:
case DAY_LIMIT_PER_MOBILE:
case HOUR_LIMIT_PER_MOBILE:
return SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL;
case BLACK_PHONE_FILTER:
return SmsFrameworkErrorCodeConstants.SMS_MOBILE_BLACK;
case SIGN_NOT_MATCH:
case BAD_SIGN_FORMAT:
case SIGN_NOT_VALID:
return SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID;
case BAD_API_KEY:
return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID;
case API_NOT_ALLOWED:
return SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY;
case IP_NOT_ALLOWED:
return SmsFrameworkErrorCodeConstants.SMS_IP_DENY;
default:
break;
}
return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
}
}

View File

@ -15,7 +15,6 @@ import lombok.Getter;
public enum SmsChannelEnum {
DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"),
YUN_PIAN("YUN_PIAN", "云片"),
ALIYUN("ALIYUN", "阿里云"),
TENCENT("TENCENT", "腾讯云"),
// HUA_WEI("HUA_WEI", "华为云"),

View File

@ -16,7 +16,6 @@ public interface SmsFrameworkErrorCodeConstants {
// ========== 权限 / 限流等相关 2001000100 ==========
ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限");
// 云片可以配置 IP 白名单只有在白名单中才可以发送短信
ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信");
// 阿里云将短信发送频率限制在正常的业务限流范围内默认短信验证码使用同一签名对同一个手机号验证码支持 1 / 分钟5 / 小时累计 10 /

View File

@ -1,53 +0,0 @@
package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
/**
* {@link YunpianSmsClient} 的集成测试
*/
public class YunpianSmsClientIntegrationTest {
private static YunpianSmsClient smsClient;
@BeforeAll
public static void init() {
// 创建配置类
SmsChannelProperties properties = new SmsChannelProperties();
properties.setId(1L);
properties.setSignature("芋道");
properties.setCode(SmsChannelEnum.YUN_PIAN.getCode());
properties.setApiKey("1555a14277cb8a608cf45a9e6a80d510");
// 创建客户端
smsClient = new YunpianSmsClient(properties);
smsClient.init();
}
@Test
public void testSendSms() {
List<KeyValue<String, Object>> templateParams = new ArrayList<>();
templateParams.add(new KeyValue<>("code", "1024"));
templateParams.add(new KeyValue<>("operation", "嘿嘿"));
// SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams);
SmsCommonResult<SmsSendRespDTO> result = smsClient.sendSms(1L, "15601691399", "4383920", templateParams);
System.out.println(result);
}
@Test
public void testGetSmsTemplate() {
String apiTemplateId = "4383920";
SmsCommonResult<SmsTemplateRespDTO> result = smsClient.getSmsTemplate(apiTemplateId);
System.out.println(result);
}
}

View File

@ -1,202 +0,0 @@
package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian;
import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import com.google.common.collect.Lists;
import com.yunpian.sdk.YunpianClient;
import com.yunpian.sdk.api.SmsApi;
import com.yunpian.sdk.api.TplApi;
import com.yunpian.sdk.constant.YunpianConstant;
import com.yunpian.sdk.model.Result;
import com.yunpian.sdk.model.SmsSingleSend;
import com.yunpian.sdk.model.Template;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static com.yunpian.sdk.constant.Code.OK;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* {@link YunpianSmsClient} 的单元测试
*
* @author 芋道源码
*/
public class YunpianSmsClientTest extends BaseMockitoUnitTest {
private final SmsChannelProperties properties = new SmsChannelProperties()
.setApiKey(randomString()); // 随机一个 apiKey避免构建报错
@InjectMocks
private final YunpianSmsClient smsClient = new YunpianSmsClient(properties);
@Mock
private YunpianClient client;
@Test
public void testDoInit() {
// 准备参数
// mock 方法
// 调用
smsClient.doInit();
// 断言
assertNotEquals(client, ReflectUtil.getFieldValue(smsClient, "client"));
verify(client, times(1)).close();
}
@Test
@SuppressWarnings("unchecked")
public void testDoSendSms() throws Throwable {
// 准备参数
Long sendLogId = randomLongId();
String mobile = randomString();
String apiTemplateId = randomString();
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
// mock sms 方法
SmsApi smsApi = mock(SmsApi.class);
when(client.sms()).thenReturn(smsApi);
// mock tpl_single_send 方法
Map<String, String> request = new HashMap<>();
request.put(YunpianConstant.MOBILE, mobile);
request.put(YunpianConstant.TPL_ID, apiTemplateId);
request.put(YunpianConstant.TPL_VALUE, "#code#=1234&#op#=login");
request.put(YunpianConstant.UID, String.valueOf(sendLogId));
request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl());
Result<SmsSingleSend> responseResult = randomPojo(Result.class, SmsSingleSend.class,
o -> o.setCode(OK)); // API 发送成功的 code
when(smsApi.tpl_single_send(eq(request))).thenReturn(responseResult);
// 调用
SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile,
apiTemplateId, templateParams);
// 断言
assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
assertNull(result.getApiRequestId());
// 断言结果
assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo());
}
@Test
public void testDoParseSmsReceiveStatus() throws Throwable {
// 准备参数
String text = "[{\"sid\":9527,\"uid\":1024,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"}]";
// mock 方法
// 调用
// 断言
// 调用
List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text);
// 断言
assertEquals(1, statuses.size());
assertTrue(statuses.get(0).getSuccess());
assertEquals("", statuses.get(0).getErrorCode());
assertNull(statuses.get(0).getErrorMsg());
assertEquals("15205201314", statuses.get(0).getMobile());
assertEquals(LocalDateTime.of(2014, 3, 17, 22, 55, 21), statuses.get(0).getReceiveTime());
assertEquals("9527", statuses.get(0).getSerialNo());
assertEquals(1024L, statuses.get(0).getLogId());
}
@Test
@SuppressWarnings("unchecked")
public void testDoGetSmsTemplate() throws Throwable {
// 准备参数
String apiTemplateId = String.valueOf(randomLongId());
// mock tpl 方法
TplApi tplApi = mock(TplApi.class);
when(client.tpl()).thenReturn(tplApi);
// mock get 方法
Map<String, String> request = new HashMap<>();
request.put(YunpianConstant.APIKEY, properties.getApiKey());
request.put(YunpianConstant.TPL_ID, apiTemplateId);
Result<List<Template>> responseResult = randomPojo(Result.class, List.class, o -> {
o.setCode(OK); // API 发送成功的 code
o.setData(randomPojoList(Template.class, t -> t.setCheck_status("SUCCESS")));
});
when(tplApi.get(eq(request))).thenReturn(responseResult);
// 调用
SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId);
// 断言
assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
assertNull(result.getApiRequestId());
// 断言结果
Template template = responseResult.getData().get(0);
assertEquals(template.getTpl_id().toString(), result.getData().getId());
assertEquals(template.getTpl_content(), result.getData().getContent());
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
assertEquals(template.getReason(), result.getData().getAuditReason());
}
@Test
public void testConvertSmsTemplateAuditStatus() {
assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(),
smsClient.convertSmsTemplateAuditStatus("CHECKING"));
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
smsClient.convertSmsTemplateAuditStatus("SUCCESS"));
assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(),
smsClient.convertSmsTemplateAuditStatus("FAIL"));
assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus("test"),
"未知审核状态(test)");
}
@Test
public void testInvoke_throwable() {
// 准备参数
Supplier<Result<Object>> requestConsumer =
() -> new Result<>().setThrowable(new NullPointerException());
// mock 方法
// 调用并断言异常
assertThrows(NullPointerException.class,
() -> smsClient.invoke(requestConsumer, null));
}
@Test
@SuppressWarnings("unchecked")
public void testInvoke_success() throws Throwable {
// 准备参数
Result<SmsSingleSend> responseResult = randomPojo(Result.class, SmsSingleSend.class, o -> o.setCode(OK));
Supplier<Result<SmsSingleSend>> requestConsumer = () -> responseResult;
Function<SmsSingleSend, SmsSendRespDTO> responseConsumer =
smsSingleSend -> new SmsSendRespDTO().setSerialNo(String.valueOf(responseResult.getData().getSid()));
// mock 方法
// 调用
SmsCommonResult<SmsSendRespDTO> result = smsClient.invoke(requestConsumer, responseConsumer);
// 断言
assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
assertNull(result.getApiRequestId());
assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo());
}
}

View File

@ -1,44 +0,0 @@
package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import static com.yunpian.sdk.constant.Code.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link YunpianSmsCodeMapping} 的单元测试
*
* @author 芋道源码
*/
class YunpianSmsCodeMappingTest extends BaseMockitoUnitTest {
@InjectMocks
private YunpianSmsCodeMapping codeMapping;
@Test
public void testApply() {
assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply(String.valueOf(OK)));
Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply(String.valueOf(ARGUMENT_MISSING)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply(String.valueOf(BAD_ARGUMENT_FORMAT)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply(String.valueOf(MONEY_NOT_ENOUGH)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply(String.valueOf(TPL_NOT_FOUND)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply(String.valueOf(TPL_NOT_VALID)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(DUP_IN_SHORT_TIME)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(TOO_MANY_TIME_IN_5)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(DAY_LIMIT_PER_MOBILE)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(HOUR_LIMIT_PER_MOBILE)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_BLACK, codeMapping.apply(String.valueOf(BLACK_PHONE_FILTER)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(SIGN_NOT_MATCH)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(SIGN_NOT_VALID)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(BAD_SIGN_FORMAT)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply(String.valueOf(BAD_API_KEY)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply(String.valueOf(API_NOT_ALLOWED)));
assertEquals(SmsFrameworkErrorCodeConstants.SMS_IP_DENY, codeMapping.apply(String.valueOf(IP_NOT_ALLOWED)));
}
}

View File

@ -1,17 +1,14 @@
package cn.iocoder.yudao.module.system.controller.admin.sms;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@ -28,17 +25,6 @@ public class SmsCallbackController {
@Resource
private SmsSendService smsSendService;
@PostMapping("/yunpian")
@PermitAll
@ApiOperation(value = "云片短信的回调", notes = "参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档")
@ApiImplicitParam(name = "sms_status", value = "发送状态", required = true, example = "[{具体内容}]", dataTypeClass = String.class)
@OperateLog(enable = false)
public String receiveYunpianSmsStatus(@RequestParam("sms_status") String smsStatus) throws Throwable {
String text = URLUtil.decode(smsStatus); // decode 解码参数因为它被 encode
smsSendService.receiveSmsStatus(SmsChannelEnum.YUN_PIAN.getCode(), text);
return "SUCCESS"; // 约定返回 SUCCESS 为成功
}
@PostMapping("/aliyun")
@PermitAll
@ApiOperation(value = "阿里云短信的回调", notes = "参见 https://help.aliyun.com/document_detail/120998.html 文档")

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.job;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Component
@TenantJob // 标记多租户
public class DemoJob implements JobHandler {
@Resource
private AdminUserMapper adminUserMapper;
@Override
public String execute(String param) throws Exception {
System.out.println("当前租户:" + TenantContextHolder.getTenantId());
List<AdminUserDO> users = adminUserMapper.selectList();
return "用户数量:" + users.size();
}
}

View File

@ -30,22 +30,6 @@ public class SmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest {
@MockBean
private AdminUserService userService;
@Test
public void testSendSingleSms_yunpianSuccess() {
// 参数准备
String mobile = "15601691399";
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
String templateCode = "test_01";
Map<String, Object> templateParams = MapUtil.<String, Object>builder()
.put("operation", "登录").put("code", "1234").build();
// 调用
smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
// 等待 MQ 消费
ThreadUtil.sleep(1, TimeUnit.HOURS);
}
@Test
public void testSendSingleSms_aliyunSuccess() {
// 参数准备

View File

@ -78,7 +78,7 @@ spring:
# Quartz 配置项,对应 QuartzProperties 配置类
spring:
quartz:
auto-startup: false # 本地开发环境,尽量不要开启 Job
auto-startup: true # 本地开发环境,尽量不要开启 Job
scheduler-name: schedulerName # Scheduler 名字。默认为 schedulerName
job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。
wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true