1111
1212## 一、设计概述
1313
14- 本设计在DSS工作流sendemail节点现有邮件发送功能的基础上,新增飞书消息发送能力。采用"后置增强"模式,在邮件发送成功后,根据配置和参数决定是否执行飞书发送 ,对现有代码侵入最小。
14+ 本设计在DSS工作流sendemail节点现有邮件发送功能的基础上,新增飞书消息发送能力。采用"后置增强"模式,在邮件发送成功后,根据节点参数和飞书接收者决定是否执行飞书发送 ,对现有代码侵入最小。
1515
1616---
1717
@@ -64,14 +64,15 @@ SendEmailRefExecutionOperation.execute(requestRef)
6464 +--> sendEmailAppConnHooks.preSend()
6565 +--> emailSender.send(email) <-- Step 1: 邮件发送
6666 |
67- +--> if (FeishuConfig.isEnabled
67+ +--> 从runtimeMap读取sendFeishu
68+ +--> if (sendFeishu == true
6869 | && email.getFeishuTo != null
6970 | && email.getFeishuTo.trim.nonEmpty)
7071 | |
7172 | +--> FeishuMessageSender.send(email) <-- Step 2: 飞书发送
7273 | |
7374 | +--> FeishuConfig.validate() <-- 配置校验
74- | +--> 解析feishuTo(逗号分隔 )
75+ | +--> 解析feishuTo(分号分隔 )
7576 | +--> FeishuClient.sendTextMessage() (主题通知)
7677 | +--> uploadAttachment() * N (附件上传)
7778 | | +--> FeishuClient.uploadFile()
@@ -95,20 +96,20 @@ public interface Email {
9596 // ... 原有方法 ...
9697
9798 /**
98- * 获取飞书接收者open_id列表(逗号分隔 )
99+ * 获取飞书接收者open_id列表(分号分隔 )
99100 */
100101 String getFeishuTo ();
101102
102103 /**
103104 * 设置飞书接收者open_id列表
104- * @param feishuTo 逗号分隔的open_id字符串
105+ * @param feishuTo 分号分隔的open_id字符串
105106 */
106107 void setFeishuTo (String feishuTo );
107108}
108109```
109110
110111** 设计决策** :
111- - feishuTo与to/cc/bcc字段对齐,采用逗号分隔的字符串格式
112+ - feishuTo与to/cc/bcc字段对齐,采用分号分隔的字符串格式
112113- 不使用独立的FeishuEmail子接口,避免接口膨胀
113114- 默认值为null(AbstractEmail中),运行时由AbstractEmailGenerator从runtimeMap读取并设置为空字符串
114115
@@ -132,25 +133,23 @@ class AbstractEmail extends Email {
132133
133134** 文件** : ` SendEmailAppConnConfiguration.scala `
134135
135- ** 新增配置项 ** :
136+ ** 新增系统连接配置项 ** :
136137
137138| 配置键 | 类型 | 默认值 | 说明 |
138139| -------| ------| -------| ------|
139- | wds.dss.appconn.feishu.enabled | Boolean | false | 飞书发送全局开关 |
140140| wds.dss.appconn.feishu.app.id | String | "" | 飞书应用App ID |
141141| wds.dss.appconn.feishu.app.secret | String | "" | 飞书应用App Secret |
142142| wds.dss.appconn.feishu.api.base.url | String | https://open.feishu.cn/open-apis | 飞书API基础地址 |
143143
144144``` scala
145- val FEISHU_ENABLED = CommonVars (" wds.dss.appconn.feishu.enabled" , false )
146145val FEISHU_APP_ID = CommonVars (" wds.dss.appconn.feishu.app.id" , " " )
147146val FEISHU_APP_SECRET = CommonVars (" wds.dss.appconn.feishu.app.secret" , " " )
148147val FEISHU_API_BASE_URL = CommonVars (" wds.dss.appconn.feishu.api.base.url" , " https://open.feishu.cn/open-apis" )
149148```
150149
151150** 设计决策** :
152- - 所有配置项通过CommonVars管理 ,与现有邮件配置风格一致
153- - 默认关闭飞书功能,确保升级兼容性
151+ - 连接配置项通过CommonVars管理 ,与现有邮件配置风格一致
152+ - 是否发送飞书不放在配置文件中,由sendemail节点参数 ` sendFeishu ` 控制
154153- 支持自定义api.base.url,便于代理部署场景
155154
156155### 3.4 FeishuConfig配置校验
@@ -161,24 +160,22 @@ val FEISHU_API_BASE_URL = CommonVars("wds.dss.appconn.feishu.api.base.url", "htt
161160
162161``` scala
163162object FeishuConfig extends Logging {
164- def isEnabled : Boolean = SendEmailAppConnConfiguration .FEISHU_ENABLED .getValue
165163 def getAppId : String = SendEmailAppConnConfiguration .FEISHU_APP_ID .getValue
166164 def getAppSecret : String = SendEmailAppConnConfiguration .FEISHU_APP_SECRET .getValue
167165 def getApiBaseUrl : String = SendEmailAppConnConfiguration .FEISHU_API_BASE_URL .getValue
168166
169167 def validate (): Unit = {
170- if (isEnabled) {
171- if (getAppId.isEmpty)
172- throw new IllegalArgumentException (" Feishu is enabled but app.id is not configured." )
173- if (getAppSecret.isEmpty)
174- throw new IllegalArgumentException (" Feishu is enabled but app.secret is not configured." )
175- }
168+ if (getAppId.isEmpty)
169+ throw new IllegalArgumentException (" Feishu app.id is not configured." )
170+ if (getAppSecret.isEmpty)
171+ throw new IllegalArgumentException (" Feishu app.secret is not configured." )
176172 }
177173}
178174```
179175
180176** 校验逻辑** :
181- - 仅在enabled=true时校验appId和appSecret
177+ - FeishuConfig只负责连接配置读取和校验,不负责判断节点是否发送飞书
178+ - 仅当节点sendFeishu=true且feishuTo非空、实际进入飞书发送流程时调用validate()
182179- 校验失败抛出IllegalArgumentException(快速失败,不做静默降级)
183180- 不校验apiBaseUrl(默认值可用,自定义地址由用户自行保证正确性)
184181
@@ -274,7 +271,7 @@ send(email: Email): Unit
274271 |
275272 +--> 1. 校验feishuTo(null/空/纯空格 -> 跳过)
276273 +--> 2. FeishuConfig.validate()(配置校验)
277- +--> 3. 解析接收者: feishuTo.split(", ").map(_.trim).filter(_.nonEmpty)
274+ +--> 3. 解析接收者: feishuTo.split("; ").map(_.trim).filter(_.nonEmpty)
278275 +--> 4. 发送主题文本消息
279276 | for each receiver:
280277 | FeishuClient.sendTextMessage(receiver, "open_id", "[DSS邮件通知] " + subject)
@@ -326,15 +323,21 @@ override def execute(requestRef): ExecutionResponseRef = {
326323 // Step 1: 发送邮件
327324 Utils .tryCatch {
328325 emailSender.send(email)
329- }(putErrorMsg(" 发送邮件失败!" , _))
326+ } { t =>
327+ return putErrorMsg(" 发送邮件失败!" , t)
328+ }
330329
331330 // Step 2: 发送到飞书(可选)
332- if (FeishuConfig .isEnabled && email.getFeishuTo != null && email.getFeishuTo.trim.nonEmpty) {
333- logger.info(s " Feishu sending is enabled and feishuTo is configured: ${email.getFeishuTo}" )
331+ val runtimeMap = requestRef.getExecutionRequestRefContext.getRuntimeMap
332+ val sendFeishu = Option (runtimeMap.get(" sendFeishu" )).exists(_.toString.equalsIgnoreCase(" true" ))
333+ if (sendFeishu && email.getFeishuTo != null && email.getFeishuTo.trim.nonEmpty) {
334+ logger.info(s " Feishu sending is selected and feishuTo is configured: ${email.getFeishuTo}" )
334335 Utils .tryCatch {
335336 FeishuMessageSender .send(email)
336337 logger.info(" Feishu sending completed successfully." )
337- }(putErrorMsg(" 飞书发送失败!" , _))
338+ } { t =>
339+ return putErrorMsg(" 飞书发送失败!" , t)
340+ }
338341 }
339342
340343 new ExecutionResponseRefBuilder ().success()
@@ -343,7 +346,7 @@ override def execute(requestRef): ExecutionResponseRef = {
343346
344347** 关键设计决策** :
345348- 飞书发送在邮件发送之后执行(邮件失败直接return,不走飞书)
346- - 飞书发送条件:enabled =true AND feishuTo非null AND feishuTo.trim非空
349+ - 飞书发送条件:sendFeishu =true AND feishuTo非null AND feishuTo.trim非空
347350- 飞书发送失败时,节点标记为失败(不静默忽略)
348351- 使用Utils.tryCatch包装,保持与邮件发送一致的异常处理风格
349352
@@ -402,13 +405,12 @@ email.setFeishuTo(feishuTo)
402405
403406| 字段 | 类型 | 默认值 | 说明 |
404407| ------| ------| -------| ------|
405- | feishuTo | String | null(AbstractEmail中)/ ""(Generator设置后) | 飞书接收者open_id列表,逗号分隔 |
408+ | feishuTo | String | null(AbstractEmail中)/ ""(Generator设置后) | 飞书接收者open_id列表,分号分隔 |
406409
407410### 5.2 配置数据模型
408411
409412| 配置键 | CommonVars变量 | 类型 | 默认值 |
410413| -------| ---------------| ------| -------|
411- | wds.dss.appconn.feishu.enabled | FEISHU_ENABLED | Boolean | false |
412414| wds.dss.appconn.feishu.app.id | FEISHU_APP_ID | String | "" |
413415| wds.dss.appconn.feishu.app.secret | FEISHU_APP_SECRET | String | "" |
414416| wds.dss.appconn.feishu.api.base.url | FEISHU_API_BASE_URL | String | https://open.feishu.cn/open-apis |
@@ -443,8 +445,7 @@ email.setFeishuTo(feishuTo)
443445在 ` appconn.properties ` 中添加以下配置:
444446
445447``` properties
446- # 飞书发送功能(默认关闭,启用前需配置appId和appSecret)
447- wds.dss.appconn.feishu.enabled =true
448+ # 飞书连接配置(是否发送飞书由sendemail节点参数sendFeishu控制)
448449wds.dss.appconn.feishu.app.id =cli_xxxxxxxxxxxx
449450wds.dss.appconn.feishu.app.secret =xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
450451# 自定义API地址(可选,默认为飞书官方地址)
@@ -453,10 +454,11 @@ wds.dss.appconn.feishu.app.secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
453454
454455### 6.3 sendemail节点配置
455456
456- 在工作流sendemail节点的参数中,新增feishuTo字段 :
457+ 在工作流sendemail节点的参数中,新增sendFeishu和feishuTo字段 :
457458
458459```
459- feishuTo=ou_xxxxxxxxxxxxxxxx,ou_yyyyyyyyyyyyyyyy
460+ sendFeishu=true
461+ feishuTo=ou_xxxxxxxxxxxxxxxx;ou_yyyyyyyyyyyyyyyy
460462```
461463
462464---
@@ -480,3 +482,5 @@ feishuTo=ou_xxxxxxxxxxxxxxxx,ou_yyyyyyyyyyyyyyyy
480482| Token安全 | 内存缓存,不持久化到磁盘 |
481483| 接收者验证 | 依赖飞书平台验证open_id有效性,无效ID返回错误 |
482484| 网络安全 | 支持HTTPS(默认),支持自定义代理地址 |
485+
486+
0 commit comments