1 Commits

Author SHA1 Message Date
0c98628d03 Merge pull request 'dev-2025' (#2) from dev-2025 into main
Reviewed-on: #2
2025-04-11 16:37:08 +08:00
16 changed files with 29 additions and 515 deletions

View File

@@ -1,110 +0,0 @@
# 钉钉通知集成说明
## 功能概述
本项目已成功集成钉钉机器人通知功能,与现有的 ServerChan3 通知系统并存,提供多渠道消息通知能力。
## 新增文件
### 1. 配置类
- `src/main/kotlin/com/pomelotea/hoperun/sign/config/DingTalkConfig.kt` - 钉钉配置类
### 2. 数据模型
- `src/main/kotlin/com/pomelotea/hoperun/sign/api/model/DingTalkNotifyRequest.kt` - 钉钉消息请求/响应模型
### 3. 通知助手
- `src/main/kotlin/com/pomelotea/hoperun/sign/notify/DingTalkNotifyHelper.kt` - 钉钉通知助手类
### 4. 统一通知服务
- `src/main/kotlin/com/pomelotea/hoperun/sign/service/NotificationService.kt` - 统一管理多种通知方式
## 配置说明
### application-dev.yml 配置
```yaml
dingtalk:
enabled: false # 是否启用钉钉通知
webhook: https://oapi.dingtalk.com/robot/send?access_token=YOUR_ACCESS_TOKEN
secret: YOUR_SECRET # 钉钉机器人密钥(可选)
```
### 获取钉钉机器人信息
1. 在钉钉群中添加"自定义机器人"
2. 安全设置选择"加签",获取密钥
3. 获取 Webhook 地址
4. 将配置信息填入 `application-dev.yml`
## API 接口
### 测试接口
- `GET /api/daka/test/dingtalk` - 测试钉钉通知
- `GET /api/daka/test/serverchan` - 测试ServerChan3通知
- `GET /api/daka/test/all` - 测试所有通知方式
### 使用示例
```bash
# 测试钉钉通知
curl http://localhost:8982/api/daka/test/dingtalk
# 测试ServerChan3通知
curl http://localhost:8982/api/daka/test/serverchan
# 测试所有通知
curl http://localhost:8982/api/daka/test/all
```
## 编程接口
### NotificationService 使用
```kotlin
@Autowired
private lateinit var notificationService: NotificationService
// 发送所有类型的通知
notificationService.sendAllNotifications("标题", "内容")
// 只发送钉钉通知
val response = notificationService.sendDingTalkNotification("标题", "内容")
// 只发送ServerChan3通知
val response = notificationService.sendServerChanNotification("标题", "内容")
// 发送钉钉文本消息
val response = notificationService.sendDingTalkText("纯文本消息")
// 发送钉钉Markdown消息
val response = notificationService.sendDingTalkMarkdown("标题", "**Markdown** 内容")
```
## 功能特性
### 消息类型支持
- **文本消息**: 简单文本内容
- **Markdown消息**: 支持丰富的格式化内容
### 安全特性
- 支持钉钉机器人加签验证
- 自动URL签名生成
- 错误处理和日志记录
### 智能切换
- 自动检测配置有效性
- 支持同时启用多种通知方式
- 配置错误时自动跳过对应通知
## 使用建议
1. **开发测试**: 先使用测试接口验证配置正确性
2. **生产部署**: 确保 `enabled: true` 并填入正确的 webhook 和 secret
3. **消息格式**: 建议使用 Markdown 格式,支持更丰富的展示效果
4. **监控日志**: 关注应用日志,及时发现通知发送问题
## 注意事项
1. 确保钉钉机器人在群中有发送消息权限
2. Webhook 地址不要泄露到公开仓库
3. 消息发送频率不要超过钉钉限制通常每分钟最多20条
4. 建议在生产环境中配置错误重试机制

View File

@@ -1,4 +1,4 @@
FROM openjdk:8u212-jre-alpine FROM openjdk:8-jre
LABEL name="hoperun-custom-sign" LABEL name="hoperun-custom-sign"
MAINTAINER li@2ha.me MAINTAINER li@2ha.me
WORKDIR / WORKDIR /

61
pom.xml
View File

@@ -21,7 +21,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.code.style>official</kotlin.code.style> <kotlin.code.style>official</kotlin.code.style>
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
<kotlin.version>2.2.0</kotlin.version> <kotlin.version>2.0.20</kotlin.version>
</properties> </properties>
<build> <build>
@@ -44,6 +44,26 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
@@ -69,34 +89,6 @@
<jvmTarget>1.8</jvmTarget> <jvmTarget>1.8</jvmTarget>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
@@ -131,17 +123,6 @@
<artifactId>jsoup</artifactId> <artifactId>jsoup</artifactId>
<version>1.15.3</version> <version>1.15.3</version>
</dependency> </dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<distributionManagement> <distributionManagement>

View File

@@ -131,11 +131,6 @@ under the License.
<passphrase>optional; leave empty if not used.</passphrase> <passphrase>optional; leave empty if not used.</passphrase>
</server> </server>
--> -->
<server>
<id>mirror-all</id>
<username>jimlee</username>
<password>wysnih-dybbyQ-0rigti</password>
</server>
<server> <server>
<id>2ha</id> <id>2ha</id>
<username>jimlee</username> <username>jimlee</username>
@@ -181,7 +176,7 @@ under the License.
<id>mirror-all</id> <id>mirror-all</id>
<mirrorOf>*</mirrorOf> <mirrorOf>*</mirrorOf>
<name>2ha mirror</name> <name>2ha mirror</name>
<url>https://maven.2ha.me/repository/maven-public/</url> <url>https://2ha.me:18082/repository/maven-public/</url>
</mirror> </mirror>
</mirrors> </mirrors>
@@ -277,7 +272,7 @@ under the License.
<repository> <repository>
<id>2ha</id> <id>2ha</id>
<name>2ha.me nexus private</name> <name>2ha.me nexus private</name>
<url>https://maven.2ha.me/repository/maven-public/</url> <url>https://2ha.me:18082/repository/maven-public/</url>
<releases> <releases>
<enabled>true</enabled> <enabled>true</enabled>
</releases> </releases>
@@ -289,12 +284,12 @@ under the License.
<repository> <repository>
<id>maven-releases</id> <id>maven-releases</id>
<name>Nexus Release Repository</name> <name>Nexus Release Repository</name>
<url>https://maven.2ha.me/repository/private/</url> <url>https://2ha.me:18082/repository/private/</url>
</repository> </repository>
<repository> <repository>
<id>maven-snapshots</id> <id>maven-snapshots</id>
<name>Nexus Snapshot Repository</name> <name>Nexus Snapshot Repository</name>
<url>https://maven.2ha.me/repository/private/</url> <url>https://2ha.me:18082/repository/private/</url>
</repository> </repository>
</repositories> </repositories>
</profile> </profile>

View File

@@ -4,7 +4,6 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.boot.SpringApplication import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@@ -16,7 +15,6 @@ import java.util.*
* 启动入口 * 启动入口
**/ **/
@SpringBootApplication @SpringBootApplication
@ConfigurationPropertiesScan
open class DakaApplication open class DakaApplication
val <T : Any> T.logger: Logger val <T : Any> T.logger: Logger

View File

@@ -8,15 +8,12 @@ import com.pomelotea.hoperun.sign.config.HoperunUserConfig.deviceMap
import com.pomelotea.hoperun.sign.config.HoperunUserConfig.getUserConfig import com.pomelotea.hoperun.sign.config.HoperunUserConfig.getUserConfig
import com.pomelotea.hoperun.sign.config.HoperunUserConfig.userConfigMap import com.pomelotea.hoperun.sign.config.HoperunUserConfig.userConfigMap
import com.pomelotea.hoperun.sign.config.UserConfig import com.pomelotea.hoperun.sign.config.UserConfig
import com.pomelotea.hoperun.sign.notify.ServerChan3NotifyHelper
import com.pomelotea.hoperun.sign.service.NotificationService
import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler
import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler.Companion.dakaQueue import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler.Companion.dakaQueue
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.* import org.springframework.web.bind.annotation.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@@ -32,14 +29,12 @@ import java.util.*
@RestController @RestController
@RequestMapping("/api/daka") @RequestMapping("/api/daka")
class HoperunSignController( class HoperunSignController {
@field:Autowired private val notificationService: NotificationService
) {
init { init {
AutoDakaScheduler(notificationService) AutoDakaScheduler()
// AutoRenewSessionScheduler() // AutoRenewSessionScheduler()
val yxl = UserConfig( val yxl = UserConfig(
project_id = "U2103S000112", project_id = "U2103S000112",

View File

@@ -1,25 +0,0 @@
package com.pomelotea.hoperun.sign.api.model
data class DingTalkNotifyRequest(
val msgtype: String = "text",
val text: TextContent
)
data class TextContent(
val content: String
)
data class DingTalkNotifyResponse(
val errcode: Int,
val errmsg: String
)
data class MarkdownContent(
val title: String,
val text: String
)
data class DingTalkMarkdownRequest(
val msgtype: String = "markdown",
val markdown: MarkdownContent
)

View File

@@ -1,14 +0,0 @@
package com.pomelotea.hoperun.sign.api.model
data class ScNotifyRequest(
val title: String,
val desp: String?,
val tags: String? = null,
val short: String? = null
)
data class ScNotifyResponse(
val code: Int,
val message: String,
val data: String?
)

View File

@@ -1,12 +0,0 @@
package com.pomelotea.hoperun.sign.config
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component
@Component
@ConfigurationProperties(prefix = "dingtalk")
class DingTalkConfig {
lateinit var webhook: String
lateinit var secret: String
var enabled: Boolean = false
}

View File

@@ -1,11 +0,0 @@
package com.pomelotea.hoperun.sign.config
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component
@Component
@ConfigurationProperties(prefix = "sc3")
class ServerChan3Config {
lateinit var uid: String
lateinit var sendKey: String
}

View File

@@ -1,100 +0,0 @@
package com.pomelotea.hoperun.sign.notify
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.pomelotea.hoperun.sign.api.model.DingTalkMarkdownRequest
import com.pomelotea.hoperun.sign.api.model.DingTalkNotifyRequest
import com.pomelotea.hoperun.sign.api.model.DingTalkNotifyResponse
import com.pomelotea.hoperun.sign.api.model.MarkdownContent
import com.pomelotea.hoperun.sign.common.client
import com.pomelotea.hoperun.sign.config.DingTalkConfig
import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler.Companion.logger
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.springframework.stereotype.Service
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.util.Base64
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import kotlin.experimental.and
@Service
open class DingTalkNotifyHelper(
private val dingTalkConfig: DingTalkConfig
) {
fun sendText(content: String): DingTalkNotifyResponse {
if (!dingTalkConfig.enabled) {
logger.info("钉钉通知未启用,跳过发送消息")
return DingTalkNotifyResponse(0, "钉钉通知未启用")
}
val request = DingTalkNotifyRequest(
text = com.pomelotea.hoperun.sign.api.model.TextContent(content)
)
return sendRequest(request)
}
fun sendMarkdown(title: String, content: String): DingTalkNotifyResponse {
if (!dingTalkConfig.enabled) {
logger.info("钉钉通知未启用,跳过发送消息")
return DingTalkNotifyResponse(0, "钉钉通知未启用")
}
val request = DingTalkMarkdownRequest(
markdown = MarkdownContent(title, content)
)
return sendRequest(request)
}
private fun sendRequest(request: Any): DingTalkNotifyResponse {
try {
val url = generateSignedUrl()
val jsonBody = JSON.toJSONString(request)
logger.info("发送钉钉消息: $jsonBody")
val httpRequest = Request.Builder()
.url(url)
.post(jsonBody.toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull()))
.build()
val response = client.newCall(httpRequest).execute()
val responseBody = response.body?.string()
logger.info("钉钉响应: $responseBody")
return JSONObject.parseObject(responseBody, DingTalkNotifyResponse::class.java)
} catch (e: Exception) {
logger.error("发送钉钉消息失败", e)
return DingTalkNotifyResponse(-1, "发送钉钉消息失败: ${e.message}")
}
}
private fun generateSignedUrl(): String {
val webhook = dingTalkConfig.webhook
val secret = dingTalkConfig.secret
if (secret.isEmpty()) {
return webhook
}
val timestamp = System.currentTimeMillis()
val sign = generateSign(timestamp.toString(), secret)
return "$webhook&timestamp=$timestamp&sign=$sign"
}
private fun generateSign(timestamp: String, secret: String): String {
val stringToSign = "$timestamp\n$secret"
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(secret.toByteArray(StandardCharsets.UTF_8), "HmacSHA256"))
val signData = mac.doFinal(stringToSign.toByteArray(StandardCharsets.UTF_8))
val sign = Base64.getEncoder().encodeToString(signData)
return URLEncoder.encode(sign, StandardCharsets.UTF_8.name())
}
}

View File

@@ -1,31 +0,0 @@
package com.pomelotea.hoperun.sign.notify
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.pomelotea.hoperun.sign.api.model.ScNotifyRequest
import com.pomelotea.hoperun.sign.api.model.ScNotifyResponse
import com.pomelotea.hoperun.sign.common.client
import com.pomelotea.hoperun.sign.config.ServerChan3Config
import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler.Companion.logger
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.springframework.stereotype.Service
@Service
open class ServerChan3NotifyHelper(
private val serverChan3Config: ServerChan3Config
) {
fun push(req: ScNotifyRequest): ScNotifyResponse {
val notifyRequest = Request.Builder()
.url("https://${serverChan3Config.uid}.push.ft07.com/send/${serverChan3Config.sendKey}.send")
.post(
JSON.toJSONString(req)
.toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull())
)
.build()
val result: String? = client.newCall(notifyRequest).execute().body?.string()
return JSONObject.parseObject(result, ScNotifyResponse::class.java)
}
}

View File

@@ -1,21 +1,11 @@
package com.pomelotea.hoperun.sign.scheduler package com.pomelotea.hoperun.sign.scheduler
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.pomelotea.hoperun.sign.api.DakaResponse import com.pomelotea.hoperun.sign.api.DakaResponse
import com.pomelotea.hoperun.sign.api.model.ScNotifyRequest
import com.pomelotea.hoperun.sign.api.model.ScNotifyResponse
import com.pomelotea.hoperun.sign.common.* import com.pomelotea.hoperun.sign.common.*
import com.pomelotea.hoperun.sign.config.HoperunUserConfig import com.pomelotea.hoperun.sign.config.HoperunUserConfig
import com.pomelotea.hoperun.sign.config.UserConfig import com.pomelotea.hoperun.sign.config.UserConfig
import com.pomelotea.hoperun.sign.notify.ServerChan3NotifyHelper
import com.pomelotea.hoperun.sign.service.NotificationService
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.* import java.util.*
@@ -31,9 +21,7 @@ import java.util.concurrent.TimeUnit
* date 2023-03-22 14:50 * date 2023-03-22 14:50
* 自动打卡定时任务 * 自动打卡定时任务
**/ **/
open class AutoDakaScheduler( class AutoDakaScheduler {
private val notificationService: NotificationService
) {
val timeThreadPool: ScheduledExecutorService = Executors.newScheduledThreadPool(1) val timeThreadPool: ScheduledExecutorService = Executors.newScheduledThreadPool(1)
val schedulerThreadPool: ScheduledExecutorService = Executors.newScheduledThreadPool(10) val schedulerThreadPool: ScheduledExecutorService = Executors.newScheduledThreadPool(10)
@@ -57,19 +45,6 @@ open class AutoDakaScheduler(
if (daka == null) { if (daka == null) {
daka = generateDakaInfo(v, dakaDate) daka = generateDakaInfo(v, dakaDate)
dakaQueue.add(daka) dakaQueue.add(daka)
notificationService.sendDingTalkNotification(
"#### 【 $dakaDate 】添加打卡任务!",
"""
#### 【 $dakaDate 】添加打卡任务!
**************************************************
##### 工号: ${daka.employeeNo}
##### 上班卡: ${daka.beginTime}
##### 下班卡: ${daka.endTime}
**************************************************
"""
)
logger.info("添加打卡任务: ${v.username}, $daka") logger.info("添加打卡任务: ${v.username}, $daka")
} }
} }
@@ -121,28 +96,7 @@ open class AutoDakaScheduler(
beginTime(employeeNo = daka.employeeNo, date = daka.dakaDate, time = daka.beginTime) beginTime(employeeNo = daka.employeeNo, date = daka.dakaDate, time = daka.beginTime)
if (resp.result != "success") { if (resp.result != "success") {
logger.error("打上班卡失败") logger.error("打上班卡失败")
notificationService.sendDingTalkNotification(
title = "${daka.dakaDate} 】打上班卡失败",
"""
#### 【 ${daka.dakaDate} 】打上班卡失败!
**************************************************
##### 工号: ${daka.employeeNo}
##### 上班卡: ${daka.beginTime}
##### 下班卡: ${daka.endTime}
**************************************************
"""
)
} else { } else {
notificationService.sendDingTalkNotification(
title = "打上班卡成功:${daka.employeeNo}:DATE:${daka.dakaDate}:TIME:${daka.beginTime}",
"""
#### 【 ${daka.dakaDate} 】打上班卡成功!
**************************************************
##### 工号: ${daka.employeeNo}
##### 时间: ${daka.beginTime}
**************************************************
"""
)
logger.info("打上班卡成功") logger.info("打上班卡成功")
} }
} catch (e: Exception) { } catch (e: Exception) {
@@ -162,26 +116,7 @@ open class AutoDakaScheduler(
val resp: DakaResponse = endTime(employeeNo = daka.employeeNo, date = daka.dakaDate, time = daka.endTime) val resp: DakaResponse = endTime(employeeNo = daka.employeeNo, date = daka.dakaDate, time = daka.endTime)
if (resp.result != "success") { if (resp.result != "success") {
logger.error("打下班卡失败") logger.error("打下班卡失败")
notificationService.sendDingTalkNotification(
title = "打下班卡失败:${daka.employeeNo}:DATE:${daka.dakaDate}:TIME:${daka.endTime}",
"""
#### 【 ${daka.dakaDate} 】打下班卡失败!
**************************************************
##### 工号: ${daka.employeeNo}
##### 上班卡: ${daka.beginTime}
##### 下班卡: ${daka.endTime}
**************************************************
""" )
} else { } else {
notificationService.sendDingTalkNotification(
title = "打下班卡成功:${daka.employeeNo}:DATE:${daka.dakaDate}:TIME:${daka.endTime}",
"""
#### 【 ${daka.dakaDate} 】打下班卡成功!
**************************************************
##### 工号: ${daka.employeeNo}
##### 时间: ${daka.endTime}
**************************************************
""" )
logger.info("打下班卡成功") logger.info("打下班卡成功")
} }
} catch (e: Exception) { } catch (e: Exception) {

View File

@@ -1,70 +0,0 @@
package com.pomelotea.hoperun.sign.service
import com.pomelotea.hoperun.sign.api.model.ScNotifyRequest
import com.pomelotea.hoperun.sign.api.model.ScNotifyResponse
import com.pomelotea.hoperun.sign.api.model.DingTalkNotifyResponse
import com.pomelotea.hoperun.sign.config.DingTalkConfig
import com.pomelotea.hoperun.sign.config.ServerChan3Config
import com.pomelotea.hoperun.sign.notify.DingTalkNotifyHelper
import com.pomelotea.hoperun.sign.notify.ServerChan3NotifyHelper
import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler.Companion.logger
import org.springframework.stereotype.Service
@Service
open class NotificationService(
private val serverChan3NotifyHelper: ServerChan3NotifyHelper,
private val dingTalkNotifyHelper: DingTalkNotifyHelper,
private val serverChan3Config: ServerChan3Config,
private val dingTalkConfig: DingTalkConfig
) {
fun sendAllNotifications(title: String, content: String) {
// 发送 ServerChan3 通知
try {
val scResponse = sendServerChanNotification(title, content)
logger.info("ServerChan3 通知发送结果: ${scResponse.message}")
} catch (e: Exception) {
logger.error("ServerChan3 通知发送失败", e)
}
// 发送钉钉通知
try {
val dtResponse = sendDingTalkNotification(title, content)
logger.info("钉钉通知发送结果: ${dtResponse.errmsg}")
} catch (e: Exception) {
logger.error("钉钉通知发送失败", e)
}
}
fun sendServerChanNotification(title: String, content: String): ScNotifyResponse {
val request = ScNotifyRequest(title = title, desp = content)
return serverChan3NotifyHelper.push(request)
}
fun sendDingTalkNotification(title: String, content: String): DingTalkNotifyResponse {
// 如果内容包含markdown格式使用markdown类型消息
return if (content.contains("**") || content.contains("#") || content.contains("*")) {
dingTalkNotifyHelper.sendMarkdown(title, content)
} else {
dingTalkNotifyHelper.sendText("$title\n\n$content")
}
}
fun sendDingTalkText(text: String): DingTalkNotifyResponse {
return dingTalkNotifyHelper.sendText(text)
}
fun sendDingTalkMarkdown(title: String, content: String): DingTalkNotifyResponse {
return dingTalkNotifyHelper.sendMarkdown(title, content)
}
fun isServerChanEnabled(): Boolean {
return serverChan3Config.uid.isNotEmpty() && serverChan3Config.sendKey.isNotEmpty()
}
fun isDingTalkEnabled(): Boolean {
return dingTalkConfig.enabled &&
dingTalkConfig.webhook.isNotEmpty() &&
!dingTalkConfig.webhook.contains("YOUR_ACCESS_TOKEN")
}
}

View File

@@ -9,11 +9,3 @@ hoperun:
latitudeShort: "30.140219809955912" latitudeShort: "30.140219809955912"
qingUa: "Qing/0.9.113" qingUa: "Qing/0.9.113"
sc3:
uid: 7248
send-key: sctp7248ta-yehg0lpo6cr9xl6ikqwbpn4l
dingtalk:
enabled: true
webhook: https://oapi.dingtalk.com/robot/send?access_token=6925880a1b7379b2fb393b5336dd75155f37189a7912981b568b08316bfd7b9e
secret:

View File

@@ -37,12 +37,3 @@ hoperun:
"projectcode": "U2103S000112" "projectcode": "U2103S000112"
"projectname": "JRKF-浙江网商-技术服务外包" "projectname": "JRKF-浙江网商-技术服务外包"
"device": "Android 12;Redmi;M2007J3SC;deviceId:OAIDe7fa6084205e9a22d8f6f71bc91893ff;deviceName:Android" "device": "Android 12;Redmi;M2007J3SC;deviceId:OAIDe7fa6084205e9a22d8f6f71bc91893ff;deviceName:Android"
sc3:
uid: 7248
send-key: sctp7248ta-yehg0lpo6cr9xl6ikqwbpn4l
dingtalk:
enabled: true
webhook: https://oapi.dingtalk.com/robot/send?access_token=6925880a1b7379b2fb393b5336dd75155f37189a7912981b568b08316bfd7b9e
secret: