sms4j-oa-plugin支持钉钉

This commit is contained in:
zhangyang 2023-10-18 22:44:56 +08:00
parent e2fde737bf
commit 2d65ffe0e1
22 changed files with 650 additions and 0 deletions

View File

@ -21,6 +21,7 @@
<module>sms4j-spring-boot-example</module>
<module>sms4j-javase-plugin</module>
<module>sms4j-Email-plugin</module>
<module>sms4j-oa-plugin</module>
</modules>
<!-- 开源协议 Apache 2.0 -->

78
sms4j-oa-plugin/pom.xml Normal file
View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>pom</packaging>
<artifactId>sms4j-oa-plugin</artifactId>
<modules>
<module>sms4j-oa-comm</module>
<module>sms4j-oa-api</module>
<module>sms4j-oa-core</module>
</modules>
<name>sms4j-oa-plugin</name>
<description>sms4j-oa-plugin</description>
<properties>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-comm</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
<version>${sunactivation.version}</version>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>${jakarta.activation.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-cron</artifactId>
<version>${hutool.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.feishu.openplatform</groupId>-->
<!-- <artifactId>feishu-sdk-java</artifactId>-->
<!-- <version>${feishu.openplatform.version}</version>-->
<!-- </dependency>-->
</dependencies>
</dependencyManagement>
</project>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-plugin</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-oa-api</artifactId>
<name>sms4j-oa-api</name>
<description>sms4j-oa-api</description>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-comm</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
package org.dromara.oa.api;
import org.dromara.oa.comm.entity.Request;
import org.dromara.oa.comm.entity.Response;
import org.dromara.oa.comm.enums.MessageType;
public interface OaSender {
Response sender(Request request, MessageType messageType);
}

View File

@ -0,0 +1,10 @@
package org.dromara.oa.api;
import org.dromara.oa.comm.entity.Request;
import org.dromara.oa.comm.entity.Response;
import org.dromara.oa.comm.enums.MessageType;
public interface OaSender {
Response Sender(Request request, MessageType messageType);
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-plugin</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-oa-comm</artifactId>
<name>sms4j-oa-comm</name>
<description>sms4j-oa-comm</description>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-cron</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,20 @@
package org.dromara.oa.comm.config;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@Builder
@ToString
@Getter
@EqualsAndHashCode
public class OaConfig {
private String OaType;
private String tokenId;
private String sign;
}

View File

@ -0,0 +1,21 @@
package org.dromara.oa.comm.entity;
import lombok.Data;
import java.util.List;
@Data
public class Request {
// 标题
private String title;
// 消息内容
private String content;
private List<String> phones;
// oa类型
private String oaType;
}

View File

@ -0,0 +1,19 @@
package org.dromara.oa.comm.entity;
import lombok.Data;
@Data
public class Response {
/**
* 响应码
*/
private String code;
/**
* 响应消息
*/
private String message;
/**
* 响应数据
*/
private String data;
}

View File

@ -0,0 +1,15 @@
package org.dromara.oa.comm.entity;
import lombok.Data;
@Data
public class SignTimesTamp {
String sign;
Long timestamp;
public SignTimesTamp(String newSign, Long timestamp) {
this.sign = newSign;
this.timestamp = timestamp;
}
}

View File

@ -0,0 +1,21 @@
package org.dromara.oa.comm.enums;
public enum MessageType {
// text 类型
TEXT("text"),
// md 格式
MARKDOWN("markdown"),
// link 格式
LINK("link");
MessageType(String name) {
this.name = name;
}
private final String name;
public String getName() {
return name;
}
}

View File

@ -0,0 +1,25 @@
package org.dromara.oa.comm.enums;
public enum OaType {
DINGTALK("dingding", "https://oapi.dingtalk.com/robot/send?access_token=", true),
WETALK("wetalk", "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=", true),
BYTETALK("feishu", "https://open.feishu.cn/open-apis/bot/v2/hook/", true),
;
private String type;
private String robotUrl;
OaType(String type, String robotUrl, boolean enabled) {
this.type = type;
this.robotUrl = robotUrl;
}
public String getType() {
return type;
}
public String getUrl() {
return robotUrl;
}
}

View File

@ -0,0 +1,12 @@
package org.dromara.oa.comm.errors;
public class OaException extends RuntimeException{
public OaException() {
super();
}
public OaException(String message) {
super(message);
}
}

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-plugin</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-oa-core</artifactId>
<name>sms4j-oa-core</name>
<description>sms4j-oa-core</description>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-json</artifactId>
<version>5.8.18</version>
<scope>compile</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.feishu.openplatform</groupId>-->
<!-- <artifactId>feishu-sdk-java</artifactId>-->
<!-- </dependency>-->
</dependencies>
</project>

View File

@ -0,0 +1,38 @@
package org.dromara.oa.core.factory;
import org.dromara.oa.comm.config.OaConfig;
import org.dromara.oa.comm.errors.OaException;
import org.dromara.oa.core.service.OaBuild;
import org.dromara.oa.core.service.SenderImpl;
import java.util.HashMap;
import java.util.Map;
public class OaFactory {
private static final Map<Object, OaConfig> configs = new HashMap<>();
/**
* createMailClient
* <p>从工厂获取一个OA发送实例
* @param key 配置的标识key
*/
public static SenderImpl createSender(Object key) {
try {
return OaBuild.build(configs.get(key));
} catch (Exception e) {
throw new OaException(e.getMessage());
}
}
/**
* set
* <p>将一个配置对象交给工厂
* @param key 标识
* @param config 配置对象
*/
public static void put(Object key, OaConfig config){
configs.put(key, config);
}
}

View File

@ -0,0 +1,22 @@
package org.dromara.oa.core.service;
import lombok.Data;
import org.dromara.oa.comm.config.OaConfig;
@Data
public class OaBuild {
private String OaType;
private OaConfig config;
public OaBuild(OaConfig config) {
this.config = config;
this.OaType = getOaType();
}
public static SenderImpl build(OaConfig config) {
return SenderImpl.NewSender(new OaBuild(config));
}
}

View File

@ -0,0 +1,120 @@
package org.dromara.oa.core.service;
import org.dromara.oa.api.OaSender;
import org.dromara.oa.comm.entity.Request;
import org.dromara.oa.comm.entity.Response;
import org.dromara.oa.comm.enums.MessageType;
import org.dromara.oa.comm.errors.OaException;
import org.dromara.oa.core.support.HttpClientImpl;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import cn.hutool.json.JSONObject;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import static org.dromara.oa.comm.enums.MessageType.*;
import static org.dromara.oa.comm.enums.OaType.DINGTALK;
public class SenderImpl implements OaSender {
private static Logger logger = Logger.getLogger("oaLog");
private OaBuild oaBuild;
private HttpClientImpl httpClient = new HttpClientImpl();
public SenderImpl() {
}
public SenderImpl(OaBuild oaBuild) {
this.oaBuild = oaBuild;
}
public static SenderImpl NewSender(OaBuild oaBuild){
return new SenderImpl(oaBuild);
}
@Override
public Response sender(Request request, MessageType messageType) {
StringBuilder webhook = new StringBuilder();
webhook.append(DINGTALK.getUrl());
webhook.append(oaBuild.getConfig().getTokenId());
if (request.getOaType().equals(DINGTALK.getType())) {
// todo 等待完善钉钉和飞书的sign
webhook.append(sign(oaBuild.getConfig().getSign()));
}
JSONObject message = createMessage(request, messageType);
try {
String post = httpClient.post(webhook, getHeaders(), message);
logger.info("请求返回结果:" + post);
} catch (Exception e) {
logger.warning("请求失败问题:" + e.getMessage());
throw new OaException(e.getMessage());
}
return new Response();
}
public static Map<String, String> getHeaders() {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return headers;
}
public static String sign(String secret) {
Long timestamp = System.currentTimeMillis();
String stringToSign = timestamp + "\n" + secret;
Mac mac = null;
try {
mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException(e);
}
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
String sign = null;
try {
sign = URLEncoder.encode(new String(Base64.getEncoder().encode(signData)),StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return "&timestamp=" + timestamp + "&sign=" + sign;
}
public static JSONObject createMessage(Request request, MessageType messageType) {
JSONObject message = new JSONObject();
if (messageType == TEXT){
message.set("msgtype", "text");
JSONObject text = new JSONObject();
text.set("content", request.getContent());
JSONObject at = new JSONObject();
at.set("atMobiles", request.getPhones());
message.set("at", at);
message.set("text", text);
} else if (messageType == LINK) {
message.set("msgtype", "link");
JSONObject link = new JSONObject();
link.set("text", request.getContent());
link.set("title", request.getTitle());
message.set("link", link);
} else if (messageType == MARKDOWN) {
message.set("msgtype", "markdown");
JSONObject markdown = new JSONObject();
markdown.set("text", request.getContent());
markdown.set("title", request.getTitle());
JSONObject at = new JSONObject();
at.set("atMobiles", request.getPhones());
message.set("at", at);
message.set("markdown", markdown);
}
return message;
}
}

View File

@ -0,0 +1,26 @@
package org.dromara.oa.core.support;
import java.util.Map;
public abstract class AbstractHttpClient implements MsgHttpClient{
@Override
public String get(String url) {
return null;
}
@Override
public String get(String url, Map<String, String> headers) {
return null;
}
@Override
public String post(String url) {
return null;
}
@Override
public String post(String url, Map<String, String> headers) {
return null;
}
}

View File

@ -0,0 +1,20 @@
package org.dromara.oa.core.support;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import java.util.Map;
public class HttpClientImpl extends AbstractHttpClient{
@Override
public <T> String post(StringBuilder url, Map<String, String> headers, T message) throws Exception {
// 构建请求体
String payload = "{\"msgtype\":\"text\",\"text\":{\"content\":\"This HertzBeat 通知\"},\"at\":{\"isAtAll\":false}}";
// 发送POST请求
HttpResponse response = HttpRequest.post(url.toString())
.headerMap(headers, true)
.body(message.toString())
.execute();
return response.body();
}
}

View File

@ -0,0 +1,17 @@
package org.dromara.oa.core.support;
import java.util.Map;
public interface MsgHttpClient {
String get(String url);
String get(String url, Map<String, String> headers);
String post(String url);
String post(String url, Map<String, String> headers);
<T> String post(StringBuilder url, Map<String, String> headers, T message) throws Exception;
}

View File

@ -29,6 +29,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>

View File

@ -0,0 +1,56 @@
package org.dromara.sms4j.example;
import lombok.extern.slf4j.Slf4j;
import org.dromara.oa.comm.config.OaConfig;
import org.dromara.oa.comm.entity.Request;
import org.dromara.oa.comm.enums.MessageType;
import org.dromara.oa.comm.enums.OaType;
import org.dromara.oa.core.factory.OaFactory;
import org.dromara.oa.core.service.SenderImpl;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
@Slf4j
@SpringBootTest
public class SmsOaTest {
/**
* 填测试手机号
*/
private static final String PHONE = "";
/**
* 填access_token
*/
private static final String TOKENID = "";
/**
* 填secret
*/
private static final String SIGN = "";
/**
* 填oa的key
* value是一个OaConfig
*/
private static final String oaKey = "";
@Test
public void oaDingTalkTest() {
OaFactory.put(oaKey, OaConfig.builder()
.OaType(OaType.DINGTALK.getType())
.tokenId(TOKENID)
.sign(SIGN).build());
SenderImpl alarm = OaFactory.createSender(oaKey);
Request request = new Request();
request.setOaType(OaType.DINGTALK.getType());
ArrayList<String> phones = new ArrayList<>();
phones.add(PHONE);
request.setPhones(phones);
request.setContent("测试消息");
request.setTitle("测试消息标题");
alarm.sender(request, MessageType.TEXT);
}
}