diff --git a/pom.xml b/pom.xml index c870b0c8..ef22415f 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,7 @@ sms4j-spring-boot-example sms4j-javase-plugin sms4j-Email-plugin + sms4j-oa-plugin diff --git a/sms4j-oa-plugin/pom.xml b/sms4j-oa-plugin/pom.xml new file mode 100644 index 00000000..3999ddea --- /dev/null +++ b/sms4j-oa-plugin/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + org.dromara.sms4j + sms4j + ${revision} + ../pom.xml + + + pom + sms4j-oa-plugin + + + sms4j-oa-comm + sms4j-oa-api + sms4j-oa-core + + + sms4j-oa-plugin + sms4j-oa-plugin + + + + + + + + + + org.dromara.sms4j + sms4j-oa-api + ${revision} + + + + org.dromara.sms4j + sms4j-oa-comm + ${revision} + + + + org.dromara.sms4j + sms4j-oa-core + ${revision} + + + + + com.sun.activation + javax.activation + ${sunactivation.version} + + + + jakarta.activation + jakarta.activation-api + ${jakarta.activation.version} + + + cn.hutool + hutool-cron + ${hutool.version} + + + + + + org.springframework.boot + spring-boot-configuration-processor + ${spring.boot.version} + true + + + + org.springframework.boot + spring-boot-starter + ${spring.boot.version} + + + + + + + + + + + + diff --git a/sms4j-oa-plugin/sms4j-oa-api/pom.xml b/sms4j-oa-plugin/sms4j-oa-api/pom.xml new file mode 100644 index 00000000..690793c0 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-api/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + + org.dromara.sms4j + sms4j-oa-plugin + ${revision} + ../pom.xml + + + sms4j-oa-api + + sms4j-oa-api + sms4j-oa-api + + + + + + + + + org.dromara.sms4j + sms4j-oa-comm + + + diff --git a/sms4j-oa-plugin/sms4j-oa-api/src/main/java/org/dromara/oa/api/OaSender.java b/sms4j-oa-plugin/sms4j-oa-api/src/main/java/org/dromara/oa/api/OaSender.java new file mode 100644 index 00000000..8b079c36 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-api/src/main/java/org/dromara/oa/api/OaSender.java @@ -0,0 +1,23 @@ +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 { + + /** + * 获取通知webhook实例唯一标识 + */ + String getConfigId(); + + /** + * 获取供应商标识 + */ + String getSupplier(); + + /** + * 发送消息 + */ + Response sender(Request request, MessageType messageType); +} diff --git a/sms4j-oa-plugin/sms4j-oa-api/src/test/java/org/dromara/oa/api/OaSender.java b/sms4j-oa-plugin/sms4j-oa-api/src/test/java/org/dromara/oa/api/OaSender.java new file mode 100644 index 00000000..b745dfd3 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-api/src/test/java/org/dromara/oa/api/OaSender.java @@ -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); +} diff --git a/sms4j-oa-plugin/sms4j-oa-comm/pom.xml b/sms4j-oa-plugin/sms4j-oa-comm/pom.xml new file mode 100644 index 00000000..41002a0a --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + org.dromara.sms4j + sms4j-oa-plugin + ${revision} + ../pom.xml + + + sms4j-oa-comm + sms4j-oa-comm + sms4j-oa-comm + + + + + + + + + + + + + cn.hutool + hutool-cron + + + + cn.hutool + hutool-http + + + + diff --git a/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/config/OaSupplierConfig.java b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/config/OaSupplierConfig.java new file mode 100644 index 00000000..215ae747 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/config/OaSupplierConfig.java @@ -0,0 +1,23 @@ +package org.dromara.oa.comm.config; + +/** + * @author dongfeng + * @date 2023-10-19 13:36 + */ +public interface OaSupplierConfig { + + /** + * 获取配置标识名(唯一) + */ + String getConfigId(); + + /** + * 获取供应商 + */ + String getSupplier(); + + /** + * 获取是否使用 + */ + Boolean getIsEnable(); +} diff --git a/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/content/OaContent.java b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/content/OaContent.java new file mode 100644 index 00000000..ad24c74e --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/content/OaContent.java @@ -0,0 +1,26 @@ +package org.dromara.oa.comm.content; + +/** + * @author dongfeng + * @date 2023-10-22 13:50 + */ +public class OaContent { + /** + * 供应商配置键名 + */ + public static final String SUPPLIER_KEY = "supplier"; + + /** + * 钉钉 + */ + public static final String DINGTALK = "dingding"; + /** + * 飞书 + */ + public static final String BYTETALK = "feishu"; + /** + * 微信 + */ + public static final String WETALK = "wetalk"; + +} diff --git a/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/Request.java b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/Request.java new file mode 100644 index 00000000..a1e6ee95 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/Request.java @@ -0,0 +1,27 @@ +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 phoneList; + + private List userIdList; + + private List userNamesList; + + private Boolean isNoticeAll = false; + + // oa类型 + private String oaType; + +} diff --git a/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/Response.java b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/Response.java new file mode 100644 index 00000000..66ef8db7 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/Response.java @@ -0,0 +1,23 @@ +package org.dromara.oa.comm.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Response { + /** + * 是否成功 + */ + private boolean success; + + /** + * 厂商原返回体 + */ + private Object data; + + /** + * 配置标识名 如未配置取对应渠道名例如 + */ + private String oaConfigId; +} diff --git a/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/SignTimesTamp.java b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/SignTimesTamp.java new file mode 100644 index 00000000..f8806bc6 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/entity/SignTimesTamp.java @@ -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; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/enums/MessageType.java b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/enums/MessageType.java new file mode 100644 index 00000000..49dffc47 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/enums/MessageType.java @@ -0,0 +1,22 @@ +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; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/enums/OaType.java b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/enums/OaType.java new file mode 100644 index 00000000..2b807eb1 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/enums/OaType.java @@ -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; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/errors/OaException.java b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/errors/OaException.java new file mode 100644 index 00000000..d3a19e49 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-comm/src/main/java/org/dromara/oa/comm/errors/OaException.java @@ -0,0 +1,12 @@ +package org.dromara.oa.comm.errors; + +public class OaException extends RuntimeException { + + public OaException() { + super(); + } + + public OaException(String message) { + super(message); + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/pom.xml b/sms4j-oa-plugin/sms4j-oa-core/pom.xml new file mode 100644 index 00000000..d29874d6 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + org.dromara.sms4j + sms4j-oa-plugin + ${revision} + ../pom.xml + + + sms4j-oa-core + sms4j-oa-core + sms4j-oa-core + + + + + + + + org.dromara.sms4j + sms4j-oa-api + + + org.slf4j + slf4j-api + + + com.sun.activation + javax.activation + + + + jakarta.activation + jakarta.activation-api + + + com.sun.mail + javax.mail + + + cn.hutool + hutool-json + 5.8.18 + compile + + + + + + + + + + + org.springframework.boot + spring-boot-configuration-processor + ${spring.boot.version} + true + + + + org.springframework.boot + spring-boot-starter + + + + + + diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/config/ByteTalkConfig.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/config/ByteTalkConfig.java new file mode 100644 index 00000000..7208bea8 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/config/ByteTalkConfig.java @@ -0,0 +1,18 @@ +package org.dromara.oa.core.byteTalk.config; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.oa.comm.enums.OaType; +import org.dromara.oa.core.provider.config.OaBaseConfig; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ByteTalkConfig extends OaBaseConfig { + + private final String requestUrl = OaType.BYTETALK.getUrl(); + + @Override + public String getSupplier() { + return OaType.BYTETALK.getType(); + } +} \ No newline at end of file diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/config/ByteTalkFactory.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/config/ByteTalkFactory.java new file mode 100644 index 00000000..a92a1d99 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/config/ByteTalkFactory.java @@ -0,0 +1,40 @@ +package org.dromara.oa.core.byteTalk.config; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.oa.comm.content.OaContent; +import org.dromara.oa.core.byteTalk.service.ByteTalkOaImpl; +import org.dromara.oa.core.provider.factory.AbstractProviderFactory; + +/** + * @author dongfeng + * @description 飞书通知对象建造 + * @date 2023-10-22 21:00 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ByteTalkFactory extends AbstractProviderFactory { + private static final ByteTalkFactory INSTANCE = new ByteTalkFactory(); + + /** + * 建造一个飞书通知对象实现 + */ + @Override + public ByteTalkOaImpl createSmsOa(ByteTalkConfig byteTalkConfig) { + return new ByteTalkOaImpl(byteTalkConfig); + } + + @Override + public String getSupplier() { + return OaContent.BYTETALK; + } + + /** + * 获取建造者实例 + * + * @return 建造者实例 + */ + public static ByteTalkFactory instance() { + return INSTANCE; + } + +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/service/ByteTalkOaImpl.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/service/ByteTalkOaImpl.java new file mode 100644 index 00000000..1da5b306 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/service/ByteTalkOaImpl.java @@ -0,0 +1,70 @@ +package org.dromara.oa.core.byteTalk.service; + +import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; +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.enums.OaType; +import org.dromara.oa.comm.errors.OaException; +import org.dromara.oa.core.byteTalk.config.ByteTalkConfig; +import org.dromara.oa.core.byteTalk.utils.ByteTalkBuilder; +import org.dromara.oa.core.provider.service.AbstractOaBlend; +import org.dromara.oa.core.support.HttpClientImpl; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.dromara.oa.comm.enums.OaType.BYTETALK; + +/** + * @author dongfeng + * @date 2023-10-22 21:01 + */ +@Slf4j +public class ByteTalkOaImpl extends AbstractOaBlend { + + private HttpClientImpl httpClient = new HttpClientImpl(); + + public ByteTalkOaImpl(ByteTalkConfig config) { + super(config); + } + + @Override + public String getSupplier() { + return OaType.BYTETALK.getType(); + } + + @Override + public Response sender(Request request, MessageType messageType) { + + if (Objects.isNull(request.getContent())) { + throw new OaException("消息体content不能为空"); + } + StringBuilder webhook = new StringBuilder(); + JSONObject message = null; + ByteTalkConfig config = getConfig(); + webhook.append(BYTETALK.getUrl()); + webhook.append(config.getTokenId()); + long now = System.currentTimeMillis() / 1000; + String sign = ByteTalkBuilder.byteTalkSign(config.getSign(), now); + message = ByteTalkBuilder.createByteTalkMessage(request, messageType, sign, now); + String post; + try { + post = httpClient.post(webhook, getHeaders(), message); + log.info("请求返回结果:" + post); + } catch (Exception e) { + log.warn("请求失败问题:" + e.getMessage()); + throw new OaException(e.getMessage()); + } + // 后续解析响应体提取errorCode判断是否成功 + return new Response(true, post, config.getConfigId()); + } + + public static Map getHeaders() { + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + return headers; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/utils/ByteTalkBuilder.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/utils/ByteTalkBuilder.java new file mode 100644 index 00000000..d29d7361 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/byteTalk/utils/ByteTalkBuilder.java @@ -0,0 +1,62 @@ +package org.dromara.oa.core.byteTalk.utils; + +import cn.hutool.json.JSONObject; +import org.dromara.oa.comm.entity.Request; +import org.dromara.oa.comm.enums.MessageType; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.List; + +import static org.dromara.oa.comm.enums.MessageType.TEXT; + +/** + * @author dongfeng + * @description 飞书通知签名和信息构建 + * @date 2023-10-19 13:07 + */ +public class ByteTalkBuilder { + + public static String byteTalkSign(String secret, Long timestamp) { + //把timestamp+"\n"+密钥当做签名字符串 + String stringToSign = timestamp + "\n" + secret; + //使用HmacSHA256算法计算签名 + Mac mac = null; + try { + mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw new RuntimeException(e); + } + byte[] signData = mac.doFinal(new byte[]{}); + return new String(Base64.getEncoder().encode(signData)); + } + + + public static JSONObject createByteTalkMessage(Request request, MessageType messageType, String sign, Long timestamp) { + JSONObject message = new JSONObject(); + if (messageType == TEXT) { + message.set("msg_type", "text"); + message.set("timestamp", timestamp); + message.set("sign", sign); + StringBuilder content = new StringBuilder(); + List userNamesList = request.getUserNamesList(); + Boolean isNoticeAll = request.getIsNoticeAll(); + if (isNoticeAll) { + content.append("所有人"); + } + userNamesList.forEach(l -> { + content.append("").append(l).append(""); + }); + content.append(request.getContent()); + JSONObject text = new JSONObject(); + text.set("text", content); + message.set("content", text); + } + return message; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaBlendsInitializer.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaBlendsInitializer.java new file mode 100644 index 00000000..5ef7626b --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaBlendsInitializer.java @@ -0,0 +1,69 @@ +package org.dromara.oa.core.config; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.oa.api.OaSender; +import org.dromara.oa.comm.config.OaSupplierConfig; +import org.dromara.oa.comm.content.OaContent; +import org.dromara.oa.core.byteTalk.config.ByteTalkFactory; +import org.dromara.oa.core.dingTalk.config.DingTalkFactory; +import org.dromara.oa.core.provider.factory.BaseProviderFactory; +import org.dromara.oa.core.provider.factory.OaFactory; +import org.dromara.oa.core.provider.factory.ProviderFactoryHolder; +import org.dromara.oa.core.weTalk.config.WeTalkFactory; + +import java.util.List; +import java.util.Map; + +/** + * @author dongfeng + * @description 注册工厂, 读取yaml配置并根据配置生成对象 + * @date 2023-10-22 12:39 + */ + +@Slf4j +public class OaBlendsInitializer { + private List> factoryList; + + private final Map> blends; + + public OaBlendsInitializer(Map> oas + ) { + this.blends = oas; + onApplicationEvent(); + } + + public void onApplicationEvent() { + registerDefaultFactory(); + // 解析供应商配置 + for (String configId : blends.keySet()) { + Map configMap = blends.get(configId); + if (Boolean.FALSE.equals(configMap.get("isEnable"))) { + continue; + } + Object supplierObj = configMap.get(OaContent.SUPPLIER_KEY); + String supplier = supplierObj == null ? "" : String.valueOf(supplierObj); + supplier = StrUtil.isEmpty(supplier) ? configId : supplier; + BaseProviderFactory providerFactory = (BaseProviderFactory) ProviderFactoryHolder.requireForSupplier(supplier); + if (providerFactory == null) { + log.warn("创建\"{}\"的通知webhook服务失败,未找到供应商为\"{}\"的服务", configId, supplier); + continue; + } + configMap.put("configId", configId); + JSONObject configJson = new JSONObject(configMap); + OaSupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass()); + OaFactory.createAndRegisterOaSender(supplierConfig); + } + } + + /** + * 注册默认工厂实例 + */ + private void registerDefaultFactory() { + ProviderFactoryHolder.registerFactory(DingTalkFactory.instance()); + ProviderFactoryHolder.registerFactory(ByteTalkFactory.instance()); + ProviderFactoryHolder.registerFactory(WeTalkFactory.instance()); + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaSupplierConfig.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaSupplierConfig.java new file mode 100644 index 00000000..184429d6 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaSupplierConfig.java @@ -0,0 +1,31 @@ +package org.dromara.oa.core.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author dongfeng + * @date 2023-10-22 12:50 + */ +public class OaSupplierConfig { + /** + * 注入配置 + */ + @Bean + @ConfigurationProperties(prefix = "sms.oas") + @ConditionalOnProperty(prefix = "sms", name = "config-type", havingValue = "yaml") + protected Map> oas() { + return new LinkedHashMap<>(); + } + + + @Bean + protected OaBlendsInitializer smsOasInitializer( + Map> oas) { + return new OaBlendsInitializer(oas); + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/config/DingTalkConfig.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/config/DingTalkConfig.java new file mode 100644 index 00000000..41761c22 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/config/DingTalkConfig.java @@ -0,0 +1,22 @@ +package org.dromara.oa.core.dingTalk.config; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.oa.comm.enums.OaType; +import org.dromara.oa.core.provider.config.OaBaseConfig; + + +/** + * @author dongfeng + * @date 2023-10-19 13:38 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class DingTalkConfig extends OaBaseConfig { + private final String requestUrl = OaType.DINGTALK.getUrl(); + + @Override + public String getSupplier() { + return OaType.DINGTALK.getType(); + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/config/DingTalkFactory.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/config/DingTalkFactory.java new file mode 100644 index 00000000..a80408f1 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/config/DingTalkFactory.java @@ -0,0 +1,40 @@ +package org.dromara.oa.core.dingTalk.config; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.oa.comm.content.OaContent; +import org.dromara.oa.core.dingTalk.service.DingTalkOaImpl; +import org.dromara.oa.core.provider.factory.AbstractProviderFactory; + +/** + * @author dongfeng + * @description 钉钉通知对象建造 + * @date 2023-10-22 21:00 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DingTalkFactory extends AbstractProviderFactory { + private static final DingTalkFactory INSTANCE = new DingTalkFactory(); + + /** + * 建造一个钉钉通知实现 + */ + @Override + public DingTalkOaImpl createSmsOa(DingTalkConfig dingTalkConfig) { + return new DingTalkOaImpl(dingTalkConfig); + } + + @Override + public String getSupplier() { + return OaContent.DINGTALK; + } + + /** + * 获取建造者实例 + * + * @return 建造者实例 + */ + public static DingTalkFactory instance() { + return INSTANCE; + } + +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/service/DingTalkOaImpl.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/service/DingTalkOaImpl.java new file mode 100644 index 00000000..2d002d7a --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/service/DingTalkOaImpl.java @@ -0,0 +1,76 @@ +package org.dromara.oa.core.dingTalk.service; + +import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; +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.enums.OaType; +import org.dromara.oa.comm.errors.OaException; +import org.dromara.oa.core.dingTalk.config.DingTalkConfig; +import org.dromara.oa.core.dingTalk.utils.DingTalkBuilder; +import org.dromara.oa.core.provider.service.AbstractOaBlend; +import org.dromara.oa.core.support.HttpClientImpl; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.dromara.oa.comm.enums.OaType.DINGTALK; + +/** + * @author dongfeng + * @date 2023-10-22 21:01 + */ +@Slf4j +public class DingTalkOaImpl extends AbstractOaBlend { + + private HttpClientImpl httpClient = new HttpClientImpl(); + + /** + * 建造一个微信通知对象服务 + */ + public DingTalkOaImpl(DingTalkConfig config) { + super(config); + } + + @Override + public String getSupplier() { + return OaType.DINGTALK.getType(); + } + + @Override + public Response sender(Request request, MessageType messageType) { + + if (Objects.isNull(request.getContent())) { + throw new OaException("消息体content不能为空"); + } + StringBuilder webhook = new StringBuilder(); + JSONObject message = null; + DingTalkConfig config = getConfig(); + webhook.append(DINGTALK.getUrl()); + webhook.append(config.getTokenId()); + String sign = config.getSign(); + if (!Objects.isNull(sign)) { + sign = DingTalkBuilder.sign(sign); + webhook.append(sign); + } + message = DingTalkBuilder.createMessage(request, messageType); + String post; + try { + post = httpClient.post(webhook, getHeaders(), message); + log.info("请求返回结果:" + post); + } catch (Exception e) { + log.warn("请求失败问题:" + e.getMessage()); + throw new OaException(e.getMessage()); + } + // 后续解析响应体提取errorCode判断是否成功 + return new Response(true, post, config.getConfigId()); + } + + public static Map getHeaders() { + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + return headers; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/utils/DingTalkBuilder.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/utils/DingTalkBuilder.java new file mode 100644 index 00000000..e23aadf8 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/dingTalk/utils/DingTalkBuilder.java @@ -0,0 +1,70 @@ +package org.dromara.oa.core.dingTalk.utils; + +import cn.hutool.json.JSONObject; +import org.dromara.oa.comm.entity.Request; +import org.dromara.oa.comm.enums.MessageType; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +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 static org.dromara.oa.comm.enums.MessageType.MARKDOWN; +import static org.dromara.oa.comm.enums.MessageType.TEXT; + +/** + * @author dongfeng + * @description 钉钉通知签名和信息构建 + * @date 2023-10-19 13:07 + */ +public class DingTalkBuilder { + 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 "×tamp=" + 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.getPhoneList()); + at.set("isAtAll", request.getIsNoticeAll()); + message.set("at", at); + message.set("text", text); + } 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.getPhoneList()); + message.set("at", at); + message.set("markdown", markdown); + } + return message; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/config/OaBaseConfig.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/config/OaBaseConfig.java new file mode 100644 index 00000000..68ba0e45 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/config/OaBaseConfig.java @@ -0,0 +1,26 @@ +package org.dromara.oa.core.provider.config; + +import lombok.Data; +import org.dromara.oa.comm.config.OaSupplierConfig; + +@Data +public abstract class OaBaseConfig implements OaSupplierConfig { + /** + * 供应商 + */ + private String supplier; + + + /** + * 获取配置标识名(唯一) + */ + private String configId; + + private String tokenId; + + private String sign; + + private Boolean isEnable = true; + +} + diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/AbstractProviderFactory.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/AbstractProviderFactory.java new file mode 100644 index 00000000..3281c24d --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/AbstractProviderFactory.java @@ -0,0 +1,33 @@ +package org.dromara.oa.core.provider.factory; + +import org.dromara.oa.api.OaSender; +import org.dromara.oa.comm.config.OaSupplierConfig; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +public abstract class AbstractProviderFactory implements BaseProviderFactory { + + private Class configClass; + + public AbstractProviderFactory() { + Type genericSuperclass = getClass().getGenericSuperclass(); + if (genericSuperclass instanceof ParameterizedType) { + ParameterizedType paramType = (ParameterizedType) genericSuperclass; + Type[] typeArguments = paramType.getActualTypeArguments(); + if (typeArguments.length > 1 && typeArguments[1] instanceof Class) { + configClass = (Class) typeArguments[1]; + } + } + } + + /** + * 获取配置类 + * + * @return 配置类 + */ + public Class getConfigClass() { + return configClass; + } + +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/BaseProviderFactory.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/BaseProviderFactory.java new file mode 100644 index 00000000..d16765d4 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/BaseProviderFactory.java @@ -0,0 +1,30 @@ +package org.dromara.oa.core.provider.factory; + +import org.dromara.oa.api.OaSender; +import org.dromara.oa.comm.config.OaSupplierConfig; + +public interface BaseProviderFactory { + + /** + * 创建通知webhook实现对象 + * + * @param c 通知webhook配置对象 + * @return 通知webhook实现对象 + */ + S createSmsOa(C c); + + /** + * 获取配置类 + * + * @return 配置类 + */ + Class getConfigClass(); + + /** + * 获取供应商 + * + * @return 供应商 + */ + String getSupplier(); + +} \ No newline at end of file diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/OaFactory.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/OaFactory.java new file mode 100644 index 00000000..487ae81a --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/OaFactory.java @@ -0,0 +1,53 @@ +package org.dromara.oa.core.provider.factory; + +import org.dromara.oa.api.OaSender; +import org.dromara.oa.comm.config.OaSupplierConfig; +import org.dromara.oa.comm.errors.OaException; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class OaFactory { + private final static Map configs = new ConcurrentHashMap<>(); + + /** + *

创建各个厂商的实现类 + * + * @param config 通知webhook配置 + */ + public static void createAndRegisterOaSender(OaSupplierConfig config) { + OaSender oaSender = createAndGetOa(config); + register(oaSender); + } + + /** + * 注册通知webhook服务对象 + * + * @param smsBlend 通知webhook服务对象 + */ + public static void register(OaSender smsBlend) { + if (smsBlend == null) { + throw new OaException("通知webhook服务对象不能为空"); + } + configs.put(smsBlend.getConfigId(), smsBlend); + } + + public static OaSender createAndGetOa(OaSupplierConfig config) { + BaseProviderFactory factory = ProviderFactoryHolder.requireForSupplier(config.getSupplier()); + if (factory == null) { + throw new OaException("不支持当前供应商配置"); + } + return factory.createSmsOa(config); + } + + /** + * 通过configId获取通知webhook服务对象 + * + * @param configId 唯一标识 + * @return 返回通知webhook服务对象。如果未找到则返回null + */ + public static OaSender getSmsOaBlend(String configId) { + return configs.get(configId); + } + +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/ProviderFactoryHolder.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/ProviderFactoryHolder.java new file mode 100644 index 00000000..02270949 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/factory/ProviderFactoryHolder.java @@ -0,0 +1,43 @@ +package org.dromara.oa.core.provider.factory; + +import cn.hutool.core.collection.CollUtil; +import org.dromara.oa.api.OaSender; +import org.dromara.oa.comm.config.OaSupplierConfig; +import org.dromara.oa.comm.errors.OaException; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author dongfeng + * @date 2023-10-22 21:12 + */ +public class ProviderFactoryHolder { + + + private static final Map> factories = new ConcurrentHashMap<>(); + + public static void registerFactory(BaseProviderFactory factory) { + if (factory == null) { + throw new OaException("注册供应商工厂失败,工厂实例不能为空"); + } + factories.put(factory.getSupplier(), factory); + } + + public static void registerFactory(List> factoryList) { + if (CollUtil.isEmpty(factoryList)) { + return; + } + for (BaseProviderFactory factory : factoryList) { + if (factory == null) { + continue; + } + registerFactory(factory); + } + } + + public static BaseProviderFactory requireForSupplier(String supplier) { + return factories.getOrDefault(supplier, null); + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/service/AbstractOaBlend.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/service/AbstractOaBlend.java new file mode 100644 index 00000000..f8dbe026 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/provider/service/AbstractOaBlend.java @@ -0,0 +1,27 @@ +package org.dromara.oa.core.provider.service; + +import cn.hutool.core.util.StrUtil; +import lombok.Getter; +import org.dromara.oa.api.OaSender; +import org.dromara.oa.comm.config.OaSupplierConfig; + +/** + * @author dongfeng + * @date 2023-10-22 21:03 + */ +public abstract class AbstractOaBlend implements OaSender { + + @Getter + private final String configId; + + private final C config; + + protected AbstractOaBlend(C config) { + this.configId = StrUtil.isEmpty(config.getConfigId()) ? getSupplier() : config.getConfigId(); + this.config = config; + } + + protected C getConfig() { + return config; + } +} \ No newline at end of file diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/AbstractHttpClient.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/AbstractHttpClient.java new file mode 100644 index 00000000..49d2f234 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/AbstractHttpClient.java @@ -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 headers) { + return null; + } + + @Override + public String post(String url) { + return null; + } + + @Override + public String post(String url, Map headers) { + return null; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/HttpClientImpl.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/HttpClientImpl.java new file mode 100644 index 00000000..7b6f72a7 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/HttpClientImpl.java @@ -0,0 +1,19 @@ +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 String post(StringBuilder url, Map headers, T message) throws Exception { + // 构建请求体 + // 发送POST请求 + HttpResponse response = HttpRequest.post(url.toString()) + .headerMap(headers, true) + .body(message.toString()) + .execute(); + return response.body(); + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/MsgHttpClient.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/MsgHttpClient.java new file mode 100644 index 00000000..cb84e146 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/support/MsgHttpClient.java @@ -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 headers); + + String post(String url); + + String post(String url, Map headers); + + String post(StringBuilder url, Map headers, T message) throws Exception; + +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/config/WeTalkConfig.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/config/WeTalkConfig.java new file mode 100644 index 00000000..88b045b8 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/config/WeTalkConfig.java @@ -0,0 +1,18 @@ +package org.dromara.oa.core.weTalk.config; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.oa.comm.enums.OaType; +import org.dromara.oa.core.provider.config.OaBaseConfig; + +@Data +@EqualsAndHashCode(callSuper = true) +public class WeTalkConfig extends OaBaseConfig { + + private final String requestUrl = OaType.WETALK.getUrl(); + + @Override + public String getSupplier() { + return OaType.WETALK.getType(); + } +} \ No newline at end of file diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/config/WeTalkFactory.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/config/WeTalkFactory.java new file mode 100644 index 00000000..3a1969ef --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/config/WeTalkFactory.java @@ -0,0 +1,40 @@ +package org.dromara.oa.core.weTalk.config; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.oa.comm.content.OaContent; +import org.dromara.oa.core.provider.factory.AbstractProviderFactory; +import org.dromara.oa.core.weTalk.service.WeTalkOaImpl; + +/** + * @author dongfeng + * @description 微信通知对象建造 + * @date 2023-10-22 21:00 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class WeTalkFactory extends AbstractProviderFactory { + private static final WeTalkFactory INSTANCE = new WeTalkFactory(); + + /** + * 建造一个微信通知服务 + */ + @Override + public WeTalkOaImpl createSmsOa(WeTalkConfig weTalkConfig) { + return new WeTalkOaImpl(weTalkConfig); + } + + @Override + public String getSupplier() { + return OaContent.WETALK; + } + + /** + * 获取建造者实例 + * + * @return 建造者实例 + */ + public static WeTalkFactory instance() { + return INSTANCE; + } + +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/service/WeTalkOaImpl.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/service/WeTalkOaImpl.java new file mode 100644 index 00000000..bc800521 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/service/WeTalkOaImpl.java @@ -0,0 +1,68 @@ +package org.dromara.oa.core.weTalk.service; + +import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; +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.enums.OaType; +import org.dromara.oa.comm.errors.OaException; +import org.dromara.oa.core.provider.service.AbstractOaBlend; +import org.dromara.oa.core.support.HttpClientImpl; +import org.dromara.oa.core.weTalk.config.WeTalkConfig; +import org.dromara.oa.core.weTalk.utils.WeTalkBuilder; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.dromara.oa.comm.enums.OaType.WETALK; + +/** + * @author dongfeng + * @date 2023-10-22 21:01 + */ +@Slf4j +public class WeTalkOaImpl extends AbstractOaBlend { + + private HttpClientImpl httpClient = new HttpClientImpl(); + + public WeTalkOaImpl(WeTalkConfig config) { + super(config); + } + + @Override + public String getSupplier() { + return OaType.WETALK.getType(); + } + + @Override + public Response sender(Request request, MessageType messageType) { + + if (Objects.isNull(request.getContent())) { + throw new OaException("消息体content不能为空"); + } + StringBuilder webhook = new StringBuilder(); + JSONObject message = null; + WeTalkConfig config = getConfig(); + webhook.append(WETALK.getUrl()); + webhook.append(config.getTokenId()); + message = WeTalkBuilder.createWeTalkMessage(request, messageType); + String post; + try { + post = httpClient.post(webhook, getHeaders(), message); + log.info("请求返回结果:" + post); + } catch (Exception e) { + log.warn("请求失败问题:" + e.getMessage()); + throw new OaException(e.getMessage()); + } + // 后续解析响应体提取errorCode判断是否成功 + return new Response(true, post, config.getConfigId()); + } + + public static Map getHeaders() { + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + return headers; + } +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/utils/WeTalkBuilder.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/utils/WeTalkBuilder.java new file mode 100644 index 00000000..11046292 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/weTalk/utils/WeTalkBuilder.java @@ -0,0 +1,56 @@ +package org.dromara.oa.core.weTalk.utils; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; +import org.dromara.oa.comm.entity.Request; +import org.dromara.oa.comm.enums.MessageType; + +import java.util.List; + +import static org.dromara.oa.comm.enums.MessageType.MARKDOWN; +import static org.dromara.oa.comm.enums.MessageType.TEXT; + +/** + * @author dongfeng + * @description 微信通知签名和信息构建 + * @date 2023-10-19 13:07 + */ +public class WeTalkBuilder { + + + public static JSONObject createWeTalkMessage(Request request, MessageType messageType) { + + JSONObject message = new JSONObject(); + if (messageType == TEXT) { + message.set("msgtype", "text"); + JSONObject text = new JSONObject(); + text.set("content", request.getContent()); + boolean isContain = false; + List userIdList = request.getUserIdList(); + List phoneList = request.getPhoneList(); + Boolean isNoticeAll = request.getIsNoticeAll(); + if (!ObjectUtil.isNull(userIdList)) { + if (isNoticeAll) { + userIdList.add("@all"); + isContain = true; + } + text.set("mentioned_list", userIdList.toArray()); + } + if (!ObjectUtil.isNull(phoneList)) { + if (isNoticeAll && !isContain) { + phoneList.add("@all"); + } + text.set("mentioned_mobile_list", phoneList.toArray()); + } + message.set("text", text); + } else if (messageType == MARKDOWN) { + message.set("msgtype", "markdown"); + JSONObject markdown = new JSONObject(); + markdown.set("content", request.getContent()); + markdown.set("title", request.getTitle()); + message.set("markdown", markdown); + } + return message; + } + +} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/META-INF/spring.factories b/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..9157acc8 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.dromara.oa.core.config.OaSupplierConfig diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..9dc50ba4 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.oa.core.config.OaSupplierConfig diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/application.properties b/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/sms4j-spring-boot-example/pom.xml b/sms4j-spring-boot-example/pom.xml index a54f8118..fdf7cbea 100644 --- a/sms4j-spring-boot-example/pom.xml +++ b/sms4j-spring-boot-example/pom.xml @@ -29,6 +29,11 @@ spring-boot-starter-test test + + org.dromara.sms4j + sms4j-oa-core + ${revision} + org.dromara.sms4j sms4j-spring-boot-starter diff --git a/sms4j-spring-boot-example/src/main/resources/application.yml b/sms4j-spring-boot-example/src/main/resources/application.yml index e212bec1..61b6e526 100644 --- a/sms4j-spring-boot-example/src/main/resources/application.yml +++ b/sms4j-spring-boot-example/src/main/resources/application.yml @@ -59,4 +59,18 @@ sms: #模板ID template-id: pub_verif_short # 模版名称 - templateName: code \ No newline at end of file + templateName: code + + oas: + oaDingTalkByYaml: # configId + isEnable: true # 表示该配置是否生效(默认生效,false表示不生效) + supplier: dingding # 厂商标识 + tokenId: 您的accessKey + sign: 您的sign + oaByteTalkByYaml: # configId + supplier: feishu # 厂商标识 + tokenId: 您的accessKey + sign: 您的sign + oaWeTalkByYaml: + supplier: wetalk # 厂商标识 + tokenId: 您的sign \ No newline at end of file diff --git a/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsOaTest.java b/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsOaTest.java new file mode 100644 index 00000000..d7b4bcdb --- /dev/null +++ b/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsOaTest.java @@ -0,0 +1,165 @@ +package org.dromara.sms4j.example; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.oa.api.OaSender; +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.byteTalk.config.ByteTalkConfig; +import org.dromara.oa.core.dingTalk.config.DingTalkConfig; +import org.dromara.oa.core.provider.factory.OaFactory; +import org.dromara.oa.core.weTalk.config.WeTalkConfig; +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 = ""; + + @Test + public void oaDingTalkTest() { + String key = "oaDingTalk"; + DingTalkConfig dingTalkConfig = new DingTalkConfig(); + dingTalkConfig.setConfigId(key); + dingTalkConfig.setSign(SIGN); + dingTalkConfig.setTokenId(TOKENID); +// OaFactory.createAndRegisterOaSender(dingTalkConfig); + OaSender alarm = OaFactory.createAndGetOa(dingTalkConfig); + Request request = new Request(); + ArrayList phones = new ArrayList<>(); + phones.add(PHONE); + request.setPhoneList(phones); + request.setIsNoticeAll(true); + request.setContent("测试消息"); + request.setTitle("测试消息标题"); + alarm.sender(request, MessageType.TEXT); + + // 测试markdown,无法@ +// request.setContent("#### 杭州天气 @150XXXXXXXX \n > 9度,西北风1级,空气良89,相对温度73%\n > ![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png)\n > ###### 10点20分发布 [天气](https://www.dingtalk.com) \n"); +// request.setTitle("杭州天气"); +// alarm.sender(request, MessageType.MARKDOWN); + + } + + @Test + public void oaDingTalkByYamlTest() { + String configId = "oaDingTalkByYaml"; + OaSender alarm = OaFactory.getSmsOaBlend(configId); + Request request = new Request(); + ArrayList phones = new ArrayList<>(); + phones.add(PHONE); + request.setPhoneList(phones); + request.setIsNoticeAll(false); + request.setContent("HertzBeat"); + request.setTitle("HertzBeat"); + alarm.sender(request, MessageType.TEXT); + + } + + @Test + public void oaByteTalkTest() { + String configId = "oaByteTalk"; + ByteTalkConfig dingTalkConfig = new ByteTalkConfig(); + dingTalkConfig.setConfigId(configId); + dingTalkConfig.setSign(SIGN); + dingTalkConfig.setTokenId(TOKENID); + OaSender alarm = OaFactory.createAndGetOa(dingTalkConfig); + Request request = new Request(); + ArrayList userNameList = new ArrayList<>(); + userNameList.add("user1"); + userNameList.add("user2"); + request.setUserNamesList(userNameList); + request.setContent("测试消息"); + request.setIsNoticeAll(true); +// request.setTitle("测试消息标题"); + alarm.sender(request, MessageType.TEXT); + } + + + @Test + public void oaByteTalkByYamlTest() { + String configId = "oaByteTalkByYaml"; + OaSender alarm = OaFactory.getSmsOaBlend(configId); + Request request = new Request(); + request.setOaType(OaType.BYTETALK.getType()); + ArrayList userNameList = new ArrayList<>(); + userNameList.add("user1"); + userNameList.add("user2"); + request.setUserNamesList(userNameList); + request.setContent("测试消息"); + request.setIsNoticeAll(true); +// request.setTitle("测试消息标题"); + alarm.sender(request, MessageType.TEXT); + } + + @Test + public void oaWeTalkTest() { + String configId = "oaWeTalk"; + WeTalkConfig weTalkConfig = new WeTalkConfig(); + weTalkConfig.setConfigId(configId); + weTalkConfig.setTokenId(TOKENID); + OaSender alarm = OaFactory.createAndGetOa(weTalkConfig); + Request request = new Request(); + ArrayList phones = new ArrayList<>(); + phones.add(PHONE); + phones.add("131"); + request.setPhoneList(phones); + ArrayList userIds = new ArrayList<>(); + userIds.add("123"); + request.setUserIdList(userIds); +// request.setIsNoticeAll(true); + request.setContent("测试消息"); + request.setTitle("测试消息标题"); + alarm.sender(request, MessageType.TEXT); + + // 测试markdown,无法@ + // 企业微信的markdown直接是content,没有title +// request.setContent("#### 杭州天气 @150XXXXXXXX \n > 9度,西北风1级,空气良89,相对温度73%\n > ![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png)\n > ###### 10点20分发布 [天气](https://www.dingtalk.com) \n"); +// request.setTitle("杭州天气"); +// alarm.sender(request, MessageType.MARKDOWN); + } + + + @Test + public void oaWeTalkByYamlTest() { + String configId = "oaWeTalkByYaml"; + OaSender alarm = OaFactory.getSmsOaBlend(configId); + Request request = new Request(); + request.setOaType(OaType.WETALK.getType()); + ArrayList phones = new ArrayList<>(); + phones.add(PHONE); + phones.add("131"); + request.setPhoneList(phones); + ArrayList userIds = new ArrayList<>(); + userIds.add("123"); + request.setUserIdList(userIds); +// request.setIsNoticeAll(true); + request.setContent("测试消息"); + request.setTitle("测试消息标题"); + alarm.sender(request, MessageType.TEXT); + + // 测试markdown,无法@ + // 企业微信的markdown直接是content,没有title +// request.setContent("#### 杭州天气 @150XXXXXXXX \n > 9度,西北风1级,空气良89,相对温度73%\n > ![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png)\n > ###### 10点20分发布 [天气](https://www.dingtalk.com) \n"); +// request.setTitle("杭州天气"); +// alarm.sender(request, MessageType.MARKDOWN); + } +} + + +