Skip to content

Commit 27a0a3a

Browse files
authored
[Core] [DataSet] Support notify (#788)
2 parents ceca620 + 4db1135 commit 27a0a3a

File tree

6 files changed

+300
-3
lines changed

6 files changed

+300
-3
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
USE `datacap`;
2+
3+
ALTER TABLE `datacap_source_query`
4+
ADD COLUMN `format` VARCHAR(100) DEFAULT 'Json';

core/datacap-service/src/main/java/io/edurt/datacap/service/audit/AuditPluginHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.inject.Injector;
44
import io.edurt.datacap.common.enums.State;
55
import io.edurt.datacap.common.response.CommonResponse;
6+
import io.edurt.datacap.common.utils.CodeUtils;
67
import io.edurt.datacap.common.utils.DateUtils;
78
import io.edurt.datacap.common.utils.SpiUtils;
89
import io.edurt.datacap.file.FileFilter;
@@ -33,7 +34,6 @@
3334
import java.nio.file.Files;
3435
import java.sql.Timestamp;
3536
import java.time.LocalDateTime;
36-
import java.util.UUID;
3737
import java.util.concurrent.ExecutorService;
3838
import java.util.concurrent.Executors;
3939

@@ -94,14 +94,15 @@ protected void handlerPlugin(final JoinPoint joinPoint, final PluginAuditEntity
9494
ExecuteEntity executeEntity = (ExecuteEntity) joinPoint.getArgs()[0];
9595
pluginAudit.setContent(executeEntity.getContent());
9696
pluginAudit.setMode(executeEntity.getMode());
97+
pluginAudit.setFormat(executeEntity.getFormat());
9798
this.sourceRepository.findById(Long.valueOf(executeEntity.getName()))
9899
.ifPresent(pluginAudit::setSource);
99100
}
100101
UserEntity user = UserDetailsService.getUser();
101102
pluginAudit.setUser(user);
102103
pluginAudit.setUpdateTime(Timestamp.valueOf(LocalDateTime.now()));
103104
pluginAudit.setElapsed(pluginAudit.getUpdateTime().getTime() - pluginAudit.getCreateTime().getTime());
104-
pluginAudit.setCode(UUID.randomUUID().toString().replace("-", ""));
105+
pluginAudit.setCode(CodeUtils.generateCode(false));
105106
this.pluginAuditRepository.save(pluginAudit);
106107

107108
ExecutorService service = Executors.newSingleThreadExecutor();

core/datacap-service/src/main/java/io/edurt/datacap/service/entity/PluginAuditEntity.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ public class PluginAuditEntity
5252
@Column(name = "home")
5353
private String home;
5454

55+
@Column(name = "format")
56+
private String format;
57+
5558
@ManyToOne
5659
@JoinColumn(name = "plugin_id")
5760
@JsonIncludeProperties(value = {"id", "name", "type", "code"})

core/datacap-spi/src/main/java/io/edurt/datacap/spi/adapter/Adapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ default List<Object> handlerFormatter(Injector injector, String format, List<Str
2222
request.setColumns(columns);
2323

2424
FileResponse response = file.format(request);
25-
Preconditions.checkArgument(Boolean.TRUE.equals(response.getSuccessful()), "Not support format: %s", format);
25+
Preconditions.checkArgument(Boolean.TRUE.equals(response.getSuccessful()), response.getMessage(), format);
2626
return response.getColumns();
2727
})
2828
.orElseThrow(() -> new IllegalArgumentException("Unsupported format: " + format));
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
---
2+
title: 自定义 Notify 通知器
3+
---
4+
5+
DataCap 支持自定义通知器,使用者可以编写自己的通知器集成到 DataCap 中。该文档主要讲解如何快速集成一个通知器到 DataCap 系统中。
6+
7+
该模块我们主要使用到的是 `notify` 模块内的代码,我们本文使用钉钉通知器来做示例。
8+
9+
### 项目配置
10+
11+
---
12+
13+
新建项目后在 `pom.xml` 文件中增加以下内容:
14+
15+
```xml
16+
<dependencies>
17+
<dependency>
18+
<groupId>io.edurt.datacap</groupId>
19+
<artifactId>datacap-notify-spi</artifactId>
20+
<version>${project.version}</version>
21+
</dependency>
22+
</dependencies>
23+
```
24+
我们添加 `datacap-notify-spi` 依赖,这样我们就可以实现集成通知器。
25+
26+
### 模块加载器
27+
28+
---
29+
30+
```kotlin
31+
package io.edurt.datacap.notify.dingtalk
32+
33+
import com.google.inject.multibindings.Multibinder
34+
import io.edurt.datacap.notify.Notify
35+
import io.edurt.datacap.notify.NotifyModule
36+
37+
class DingTalkModule : NotifyModule()
38+
{
39+
override fun configure()
40+
{
41+
Multibinder.newSetBinder(this.binder(), Notify::class.java)
42+
.addBinding()
43+
.to(DingTalkNotify::class.java)
44+
}
45+
}
46+
```
47+
48+
### 通知器
49+
50+
---
51+
52+
```kotlin
53+
package io.edurt.datacap.notify.dingtalk
54+
55+
import io.edurt.datacap.notify.Notify
56+
import io.edurt.datacap.notify.model.NotifyRequest
57+
import io.edurt.datacap.notify.model.NotifyResponse
58+
59+
class DingTalkNotify : Notify
60+
{
61+
override fun send(request: NotifyRequest): NotifyResponse
62+
{
63+
return DingTalkUtils.send(request)
64+
}
65+
}
66+
```
67+
68+
在转换器中我们只需要实现以下两个方法:
69+
70+
- `fun send(request: NotifyRequest): NotifyResponse` 用于实现发送器执行逻辑
71+
72+
### `DingTalkUtils` 工具类
73+
74+
---
75+
76+
```kotlin
77+
package io.edurt.datacap.notify.dingtalk
78+
79+
import io.edurt.datacap.common.utils.JsonUtils
80+
import io.edurt.datacap.common.utils.SignUtils
81+
import io.edurt.datacap.lib.http.HttpClient
82+
import io.edurt.datacap.lib.http.HttpConfigure
83+
import io.edurt.datacap.lib.http.HttpMethod
84+
import io.edurt.datacap.notify.NotifyType
85+
import io.edurt.datacap.notify.dingtalk.model.ReturnModel
86+
import io.edurt.datacap.notify.dingtalk.model.TextModel
87+
import io.edurt.datacap.notify.model.NotifyRequest
88+
import io.edurt.datacap.notify.model.NotifyResponse
89+
import org.apache.commons.lang3.StringUtils.isNotEmpty
90+
import org.slf4j.Logger
91+
import org.slf4j.LoggerFactory.getLogger
92+
93+
object DingTalkUtils
94+
{
95+
private val log: Logger = getLogger(DingTalkUtils::class.java)
96+
97+
@JvmStatic
98+
fun send(request: NotifyRequest): NotifyResponse
99+
{
100+
val configure = HttpConfigure()
101+
configure.autoConnected = false
102+
configure.retry = 0
103+
configure.protocol = "https"
104+
configure.host = "oapi.dingtalk.com"
105+
configure.port = 443
106+
configure.path = "robot/send"
107+
configure.method = HttpMethod.POST
108+
109+
val params = mutableMapOf("access_token" to request.access)
110+
if (isNotEmpty(request.secret))
111+
{
112+
val signResponse = SignUtils.sign(request.secret)
113+
log.info("Sign response: ${JsonUtils.toJSON(signResponse)}")
114+
params["sign"] = signResponse.sign
115+
params["timestamp"] = signResponse.timestamp.toString()
116+
}
117+
configure.params = params
118+
log.info("Notify request params: ${JsonUtils.toJSON(params)}")
119+
120+
val text = TextModel()
121+
text.content = request.content
122+
configure.body = JsonUtils.toJSON(mapOf("text" to text, "msgtype" to formatMessageType(request)))
123+
log.info("Notify request body: ${configure.body}")
124+
125+
val client = HttpClient(configure)
126+
val returnModel = JsonUtils.toObject(client.execute(), ReturnModel::class.java)
127+
val response = NotifyResponse()
128+
if (returnModel.code == 0)
129+
{
130+
response.successful = true
131+
response.message = null
132+
}
133+
else
134+
{
135+
response.successful = false
136+
response.message = returnModel.message
137+
}
138+
return response
139+
}
140+
141+
private fun formatMessageType(request: NotifyRequest): String
142+
{
143+
if (request.type == NotifyType.TEXT)
144+
{
145+
return "text"
146+
}
147+
else
148+
{
149+
return "markdown"
150+
}
151+
}
152+
}
153+
```
154+
155+
在工具类中我们主要实现发送钉钉消息操作。
156+
157+
### `Notify SPI` 加载器
158+
159+
---
160+
161+
`resources` 源目录下添加 `META-INF``services` 目录,格式为 `resources/META-INF/services`,创建 `io.edurt.datacap.fs.FsModule` 文件,内容如下
162+
163+
```kotlin
164+
io.edurt.datacap.notify.dingtalk.DingTalkModule
165+
```
166+
167+
> 通过以上内容我们实现了 DingTalk 通知器的支持。我们只需要在要使用 DingTalk 通知器器的地方引用该模块即可。比如我们在 server 模块中使用到该模块,则在 server/pom.xml 文件中增加以下内容
168+
169+
```xml
170+
<dependency>
171+
<groupId>io.edurt.datacap</groupId>
172+
<artifactId>datacap-notify-dingtalk</artifactId>
173+
<version>${project.version}</version>
174+
</dependency>
175+
```
176+
177+
### `DingTalk Utils` 测试
178+
179+
```kotlin
180+
package io.edurt.datacap.notify.dingtalk
181+
182+
import io.edurt.datacap.notify.model.NotifyRequest
183+
import org.junit.Assert
184+
import org.junit.Before
185+
import org.junit.Test
186+
187+
class DingTalkUtilsTest
188+
{
189+
private val request: NotifyRequest = NotifyRequest()
190+
191+
@Before
192+
fun before()
193+
{
194+
request.access = "ACCESS"
195+
request.content = "Test Message"
196+
request.secret = "SECRET"
197+
}
198+
199+
@Test
200+
fun testSend()
201+
{
202+
Assert.assertFalse(
203+
DingTalkUtils.send(request)
204+
.successful
205+
)
206+
}
207+
}
208+
```
209+
210+
### `DingTalk Module` 测试
211+
212+
```kotlin
213+
package io.edurt.datacap.notify.dingtalk
214+
215+
import com.google.inject.Guice
216+
import com.google.inject.Injector
217+
import com.google.inject.Key
218+
import com.google.inject.TypeLiteral
219+
import io.edurt.datacap.notify.Notify
220+
import io.edurt.datacap.notify.NotifyManager
221+
import org.junit.Assert.assertNotNull
222+
import org.junit.Before
223+
import org.junit.Test
224+
225+
class DingTalkModuleTest
226+
{
227+
private val name = "DingTalk"
228+
private var injector: Injector? = null
229+
230+
@Before
231+
fun before()
232+
{
233+
injector = Guice.createInjector(NotifyManager())
234+
}
235+
236+
@Test
237+
fun test()
238+
{
239+
val notify: Notify? = injector?.getInstance(Key.get(object : TypeLiteral<Set<Notify>>()
240+
{}))
241+
?.first { it.name() == name }
242+
assertNotNull(notify)
243+
}
244+
}
245+
```
246+
247+
### `DingTalk SPI` 测试
248+
249+
```kotlin
250+
package io.edurt.datacap.notify.dingtalk
251+
252+
import com.google.inject.Guice
253+
import com.google.inject.Injector
254+
import com.google.inject.Key
255+
import com.google.inject.TypeLiteral
256+
import io.edurt.datacap.notify.Notify
257+
import io.edurt.datacap.notify.NotifyManager
258+
import io.edurt.datacap.notify.model.NotifyRequest
259+
import org.junit.Assert.assertNotNull
260+
import org.junit.Before
261+
import org.junit.Test
262+
263+
class DingTalkNotifyTest
264+
{
265+
private val name = "DingTalk"
266+
private var injector: Injector? = null
267+
private val request: NotifyRequest = NotifyRequest()
268+
269+
@Before
270+
fun before()
271+
{
272+
injector = Guice.createInjector(NotifyManager())
273+
274+
request.access = "ACCESS"
275+
request.content = "Test Message"
276+
request.secret = "SECRET"
277+
}
278+
279+
@Test
280+
fun test()
281+
{
282+
val notify: Notify? = injector?.getInstance(Key.get(object : TypeLiteral<Set<Notify>>()
283+
{}))
284+
?.first { it.name() == name }
285+
assertNotNull(notify?.send(request))
286+
}
287+
}
288+
```

docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ nav:
252252
- developer/plugin/kotlin/home.md
253253
- developer/filesystem/home.md
254254
- developer/file/kotlin/home.md
255+
- developer/notify/kotlin/home.md
255256
- Other:
256257
- developer/pipeline/home.md
257258
- useCases.md

0 commit comments

Comments
 (0)