|
| 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 | +``` |
0 commit comments