diff --git a/README.md b/README.md index 811c407..57aac23 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,106 @@ # Dinger(叮鸽) ![GitHub license](https://img.shields.io/github/license/AnswerAIL/dingtalk-spring-boot-starter) +[![Dinger Logo](https://gitee.com/jaemon/docs/raw/master/dinger.png)](https://github.com/AnswerAIL/dingtalk-spring-boot-starter) + + [![Maven Central](https://img.shields.io/maven-central/v/com.github.answerail/dingtalk-spring-boot-starter)](https://mvnrepository.com/artifact/com.github.answerail/dingtalk-spring-boot-starter) [![GitHub stars](https://img.shields.io/github/stars/AnswerAIL/dingtalk-spring-boot-starter.svg?style=social)](https://github.com/AnswerAIL/dingtalk-spring-boot-starter) [![Gitee stars](https://gitee.com/jaemon/dingtalk-spring-boot-starter/badge/star.svg?theme=dark)](https://gitee.com/jaemon/dingtalk-spring-boot-starter) -[![GitHub issues](https://img.shields.io/github/issues/AnswerAIL/dingtalk-spring-boot-starter)](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/issues?q=is%3Aopen+is%3Aissue) -[![GitHub closed issues](https://img.shields.io/github/issues-closed/AnswerAIL/dingtalk-spring-boot-starter)](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/issues?q=is%3Aissue+is%3Aclosed) ![JDK](https://img.shields.io/badge/JDK-%3E=1.8-green?logo=appveyor) +![SpringBoot](https://img.shields.io/badge/springboot-1.x%20&%202.x-green?logo=appveyor) +   -## What -springboot集成钉钉机器人实现消息通知中间件。项目基于[钉钉开放平台-群机器人](https://ding-doc.dingtalk.com/doc#/serverapi3/iydd5) API的基础上做了一层封装,让使用更简单便捷。 +## What(Dinger是什么) +Dinger一个是以SpringBoot框架为基础开发的消息发送中间件, 对现有两大移动办公系统[钉钉](https://ding-doc.dingtalk.com/doc#/serverapi3/iydd5)和[企业微信](https://work.weixin.qq.com/api/doc/90000/90136/91770)的群机器人API做了一层封装,让使用更简单便捷。 -只需要简单的配置(最简单的发送功能只需要一行代码),即可快速的在springboot项目中将消息发送到指定的钉钉群聊中。 +只需要简单的配置(最简单的发送功能只需要一行代码),即可快速的在springboot项目中将消息发送到指定的钉钉或企业微信群聊中。   -## Why - - **`上手简单`**: 配置简单,无需花费太多精力在群机器人的使用上; - - **`代码解耦`**: 插拔式功能组件,和业务代码解耦; - - **`扩展性强`**: 核心功能面向接口编程, 可以据具体业务对功能进行定制化; - - **`用法多样`**: 消息体支持[DingTalk V1.x](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/wiki/Docs-for-DingTalk-1.x)的完全自定义和[DingTalk V2.x](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/wiki/Docs-for-DingTalk-2.x)的XML方式配置及注解方式定义; +## Why(为什么用Dinger) + - 配置简单,上手容易,无需花费太多精力在群机器人API的使用上; + - 插拔式功能组件,和业务代码解耦; + - 核心功能面向接口编程, 可以据具体业务对功能进行定制化来满足不同的业务需求; + - 支持集中式管理消息,提供xml标签,支持编写动态消息体; + - 基于具体消息编程,消息体可支持XML标签方式配置和注解方式定义; + - 支持钉钉和企业微信群机器人一键切换使用和混合使用;   -## How -- [V1.X快速入门](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/wiki/Getting-Started-V1.x) - -- [V2.X快速入门](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/wiki/Getting-Started-V2.x) +## How(如何使用Dinger-快速使用) +### 引入依赖 +```xml + + com.github.answerail + dinger-spring-boot-starter + 1.0.0 + +``` + +### 配置文件配置 +**使用钉钉群机器人配置** +```yaml +spring: + dinger: + project-id: ${spring.application.name} + dingers: + # 使用钉钉机器人, 请根据自己机器人配置信息进行修改 + dingtalk: + tokenId: 87dbeb7bc28894c3ycyl3d12457228ad309966275b5f427cd85f9025ebb520cf + secret: AEQ74a9039ai01f2ljm017b90ycye9asg6335f97c658ff37ff371ec8120581c7f09 +``` + +**使用企业群机器人配置** +```yaml +spring: + dinger: + project-id: ${spring.application.name} + dingers: + # 使用企业微信机器人, 请根据自己机器人配置信息进行修改 + wetalk: + token-id: 32865206-7082-46l5-8j39-2m7ycy6d868 +``` + +### 代码中使用 +```java +@Component +public class AppInit implements InitializingBean { + @Autowired + private DingerSender dingerSender; + @Override + public void afterPropertiesSet() throws Exception { + // 发送text类型消息 + dingerSender.send( + MessageSubType.TEXT, + DingerRequest.request("Hello World, Hello Dinger") + ); + + // 发送markdown类型消息 + dingerSender.send( + MessageSubType.MARKDOWN, + DingerRequest.request("Hello World, Hello Dinger", "启动通知") + ); + } +} +```   ## Documentation, Getting Started and Developer Guides -- [Dingtalk Wiki](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/wiki) +- [Dinger Wiki](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/wiki)   ## Upgrade Log -- [版本变更日志](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/wiki/Dingtalk-Upgrade-Log) - +- [版本变更日志](https://github.com/AnswerAIL/dingtalk-spring-boot-starter/wiki/Dinger-Upgrade-Log)   diff --git a/src/main/java/com/github/jaemon/dinger/DingerSender.java b/src/main/java/com/github/jaemon/dinger/DingerSender.java index eced17e..f0d883d 100644 --- a/src/main/java/com/github/jaemon/dinger/DingerSender.java +++ b/src/main/java/com/github/jaemon/dinger/DingerSender.java @@ -15,6 +15,7 @@ */ package com.github.jaemon.dinger; +import com.github.jaemon.dinger.core.entity.DingerProperties; import com.github.jaemon.dinger.core.entity.DingerRequest; import com.github.jaemon.dinger.core.entity.enums.DingerType; import com.github.jaemon.dinger.core.entity.enums.MessageSubType; @@ -32,6 +33,10 @@ public interface DingerSender { /** * 发送预警消息到钉钉 * + *
+     *     使用配置的默认钉钉机器人, {@link DingerProperties#getDefaultDinger()}
+     * 
+ * * @param messageSubType * 消息类型{@link MessageSubType} * @param request diff --git a/src/main/java/com/github/jaemon/dinger/config/BeanConfiguration.java b/src/main/java/com/github/jaemon/dinger/config/BeanConfiguration.java index 24504bc..14d3c64 100644 --- a/src/main/java/com/github/jaemon/dinger/config/BeanConfiguration.java +++ b/src/main/java/com/github/jaemon/dinger/config/BeanConfiguration.java @@ -96,7 +96,7 @@ public DingerIdGenerator dingerIdGenerator() { @Bean @ConditionalOnMissingBean(DingerAsyncCallback.class) public DingerAsyncCallback dingerAsyncCallback() { - return new DefaultDkCallable(); + return new DefaultDingerAsyncCallable(); } @Bean diff --git a/src/main/java/com/github/jaemon/dinger/config/DingerThreadPoolProperties.java b/src/main/java/com/github/jaemon/dinger/config/DingerThreadPoolProperties.java index 591aa35..390fa7b 100644 --- a/src/main/java/com/github/jaemon/dinger/config/DingerThreadPoolProperties.java +++ b/src/main/java/com/github/jaemon/dinger/config/DingerThreadPoolProperties.java @@ -28,23 +28,23 @@ public class DingerThreadPoolProperties { private static final int DEFAULT_CORE_SIZE = Runtime.getRuntime().availableProcessors() + 1; /** - * 线程池维护线程的最小数量 + * 线程池维护线程的最小数量, 选填 */ private int coreSize = DEFAULT_CORE_SIZE; /** - * 线程池维护线程的最大数量 + * 线程池维护线程的最大数量, 选填 */ private int maxSize = DEFAULT_CORE_SIZE * 2; /** - * 空闲线程的存活时间 + * 空闲线程的存活时间, 选填 */ private int keepAliveSeconds = 60; /** - * 持有等待执行的任务队列 + * 持有等待执行的任务队列, 选填 */ private int queueCapacity = 10; /** - * 线程名称前缀 + * 线程名称前缀, 选填 */ private String threadNamePrefix = DingerConstant.DEFAULT_THREAD_NAME_PREFIX; diff --git a/src/main/java/com/github/jaemon/dinger/core/AbstractDingerDefinitionResolver.java b/src/main/java/com/github/jaemon/dinger/core/AbstractDingerDefinitionResolver.java index f1e4869..a0a728c 100644 --- a/src/main/java/com/github/jaemon/dinger/core/AbstractDingerDefinitionResolver.java +++ b/src/main/java/com/github/jaemon/dinger/core/AbstractDingerDefinitionResolver.java @@ -153,7 +153,7 @@ protected List> dingerAnnotationResolver() throws Exception { PackageUtils.classNames(basePackage, dingerClasses, true); } } else { - log.warn("annotation dingerScan is not configured."); + log.warn("annotation dingerScan is not configured and will execute Dinger scanner registrar."); } if (dingerClasses.isEmpty()) { diff --git a/src/main/java/com/github/jaemon/dinger/core/AbstractDingerSender.java b/src/main/java/com/github/jaemon/dinger/core/AbstractDingerSender.java index 53d1377..7320792 100644 --- a/src/main/java/com/github/jaemon/dinger/core/AbstractDingerSender.java +++ b/src/main/java/com/github/jaemon/dinger/core/AbstractDingerSender.java @@ -21,6 +21,8 @@ import com.github.jaemon.dinger.exception.DingerException; import com.github.jaemon.dinger.core.entity.DingerCallback; import com.github.jaemon.dinger.support.CustomMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * AbstractDingTalkSender @@ -31,6 +33,7 @@ public abstract class AbstractDingerSender extends DingerHelper implements DingerSender { + protected static final Logger log = LoggerFactory.getLogger(AbstractDingerSender.class); protected DingerProperties dingerProperties; protected DingerManagerBuilder dingTalkManagerBuilder; diff --git a/src/main/java/com/github/jaemon/dinger/core/ClassPathScanForResources.java b/src/main/java/com/github/jaemon/dinger/core/ClassPathScanForResources.java new file mode 100644 index 0000000..e278aaa --- /dev/null +++ b/src/main/java/com/github/jaemon/dinger/core/ClassPathScanForResources.java @@ -0,0 +1,137 @@ +/* + * Copyright ©2015-2020 Jaemon. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.jaemon.dinger.core; + +import com.github.jaemon.dinger.exception.DingerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.util.ClassUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static com.github.jaemon.dinger.core.entity.enums.ExceptionEnum.RESOURCE_CONFIG_EXCEPTION; + +/** + * ClassPathScanForResources + * + * @author Jaemon + * @since 1.0 + */ +public final class ClassPathScanForResources { + private static final Logger log = LoggerFactory.getLogger(ClassPathScanForResources.class); + private static final String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; + private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; + private static final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + + /** + * 扫描包 + * + * @param packageSearchPath + * 扫描的包路径, classpath*:com.jaemon.dinger/**\/*.class + * @return + * 包下的所有资源文件集 + */ + public static Resource[] doScanPackage(String packageSearchPath) { + try { + return resolver.getResources(packageSearchPath); + } catch (IOException ex) { + log.error(packageSearchPath, ex); + throw new DingerException(RESOURCE_CONFIG_EXCEPTION, packageSearchPath); + } + } + + /** + * @param basePackage + * 包名, eg: com.jaemon.dinger + * @return + * 包下的所有接口集合 + */ + public static List> scanInterfaces(String basePackage) { + return scanClasses(basePackage, true); + } + + + /** + * @param basePackage + * 包名, eg: com.jaemon.dinger + * @return + * 包下的所有类集合 + */ + public static List> scanClasses(String basePackage) { + return scanClasses(basePackage, false); + } + + + /** + * @param basePackage + * 包名, eg: com.jaemon.dinger + * @param filterInterface + * 是否过滤接口 + * @return + * 包下的所有类集合 + */ + private static List> scanClasses(String basePackage, boolean filterInterface) { + boolean debugEnabled = log.isDebugEnabled(); + String packageSearchPath = CLASSPATH_ALL_URL_PREFIX + + resolveBasePackage(basePackage) + "/" + DEFAULT_RESOURCE_PATTERN; + Resource[] resources = doScanPackage(packageSearchPath); + + List> classes = new ArrayList<>(); + + if (resources.length == 0) { + return classes; + } + + SimpleMetadataReaderFactory factory = new SimpleMetadataReaderFactory(); + for (Resource resource : resources) { + String resourceFilename = resource.getFilename(); + if (!resource.isReadable()) { + if (debugEnabled) { + log.debug("Ignored because not readable: {} ", resourceFilename); + } + continue; + } + try { + MetadataReader metadataReader = factory.getMetadataReader(resource); + ClassMetadata classMetadata = metadataReader.getClassMetadata(); + Class clazz = Class.forName(classMetadata.getClassName()); + if (filterInterface && !clazz.isInterface()) { + if (debugEnabled) { + log.debug("source class={} is interface and skip.", resourceFilename); + } + continue; + } + classes.add(clazz); + } catch (IOException | ClassNotFoundException e) { + log.warn("resource={} read exception and message={}.", resourceFilename, e.getMessage()); + continue; + } + } + return classes; + } + + private static String resolveBasePackage(String basePackage) { + return ClassUtils.convertClassNameToResourcePath(basePackage); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionGeneratorFactory.java b/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionGeneratorFactory.java index 407ee00..cf0fc1f 100644 --- a/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionGeneratorFactory.java +++ b/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionGeneratorFactory.java @@ -16,6 +16,8 @@ package com.github.jaemon.dinger.core; import com.github.jaemon.dinger.exception.DingerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; @@ -29,6 +31,7 @@ * @since 1.0 */ public class DingerDefinitionGeneratorFactory { + private static final Logger log = LoggerFactory.getLogger(DingerDefinitionGeneratorFactory.class); /** dingerDefinition生成器 */ static final Map dingTalkDefinitionGeneratorMap = new HashMap<>(); @@ -43,13 +46,13 @@ public class DingerDefinitionGeneratorFactory { public static DingerDefinitionGenerator get(String key) { DingerDefinitionGenerator dingTalkDefinitionGenerator = dingTalkDefinitionGeneratorMap.get(key); if (dingTalkDefinitionGenerator == null) { - throw new DingerException(key + "无对应的Dinger定义生成器", DINGERDEFINITION_ERROR); + if (log.isDebugEnabled()) { + log.debug("key={}, dingTalkDefinitionGeneratorMap={}.", + key, dingTalkDefinitionGeneratorMap.keySet()); + } + throw new DingerException(DINGERDEFINITION_ERROR, key); } return dingTalkDefinitionGenerator; } - static void clear() { - dingTalkDefinitionGeneratorMap.clear(); - } - } \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionHandler.java b/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionHandler.java index f40a1fc..a9591b1 100644 --- a/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionHandler.java +++ b/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionHandler.java @@ -116,7 +116,7 @@ protected static DingerDefinition xmlHandler( MessageMainType messageMainType = dingerDefinitionType.messageMainType(); if (messageMainType != MessageMainType.XML) { throw new DingerException( - dingerDefinitionType + "中消息体定义主类型应该为" + MessageMainType.XML, DINGERDEFINITIONTYPE_ERROR + DINGERDEFINITIONTYPE_ERROR, dingerDefinitionType, MessageMainType.XML, messageMainType ); } diff --git a/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionResolver.java b/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionResolver.java index e5afa59..c824ea3 100644 --- a/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionResolver.java +++ b/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionResolver.java @@ -34,8 +34,6 @@ import org.springframework.core.io.Resource; import org.springframework.util.FileCopyUtils; -import java.io.File; -import java.io.FileReader; import java.lang.reflect.Method; import java.util.*; @@ -86,20 +84,25 @@ protected List> doAnalysis(ApplicationEnvironmentPreparedEvent event) t void analysisDingerXml(Resource[] resources) throws Exception { boolean debugEnabled = log.isDebugEnabled(); for (Resource resource : resources) { - File file = resource.getFile(); - String xml = FileCopyUtils.copyToString(new FileReader(file)); + if (!resource.isReadable()) { + if (debugEnabled) { + log.debug("Ignored because not readable: {} ", resource.getFilename()); + } + continue; + } + String xml = new String(FileCopyUtils.copyToByteArray(resource.getInputStream())); xml = transferXml(xml); BeanTag dingerBean = XmlUtils.xmlToJavaBean(xml, BeanTag.class); if (dingerBean == null) { if (debugEnabled) { - log.debug("dinger xml file: {} content is empty.", file.getName()); + log.debug("dinger xml file: {} content is empty.", resource.getFilename()); } continue; } String namespace = dingerBean.getNamespace(); Class dingerClass = Class.forName(namespace); if (dingerClass == null) { - throw new DingerException(namespace, DINER_XML_NAMESPACE_INVALID); + throw new DingerException(DINER_XML_NAMESPACE_INVALID, namespace); } DingerConfig dingerConfiguration = dingerConfiguration(dingerClass); @@ -109,7 +112,7 @@ void analysisDingerXml(Resource[] resources) throws Exception { String dingerName = namespace + SPOT_SEPERATOR + message.getIdentityId(); String messageSubType = message.getDingerType(); if (!MessageSubType.contains(messageSubType)) { - throw new DingerException(dingerName + "-" + messageSubType, DINER_XML_MSGTYPE_INVALID); + throw new DingerException(DINER_XML_MSGTYPE_INVALID, dingerName, messageSubType); } String dingerDefinitionKey = MessageMainType.XML + SPOT_SEPERATOR + message.getDingerType(); @@ -149,7 +152,9 @@ void analysisDingerAnnotation(List> dingerClasses) throws Exception { dingerConfiguration ); } else { - log.info("register dingerDefinition and skip method={}.", dingerName); + if (log.isDebugEnabled()) { + log.debug("register annotation dingerDefinition and skip method={}(possible use xml definition).", dingerName); + } } } diff --git a/src/main/java/com/github/jaemon/dinger/core/DingerMessageHandler.java b/src/main/java/com/github/jaemon/dinger/core/DingerMessageHandler.java index fb10d37..200b9d2 100644 --- a/src/main/java/com/github/jaemon/dinger/core/DingerMessageHandler.java +++ b/src/main/java/com/github/jaemon/dinger/core/DingerMessageHandler.java @@ -131,10 +131,6 @@ private T copyProperties(MsgType src) { * 返回Dinger */ DingerType dingerType(Method method) { - if (method.isAnnotationPresent(Dinger.class)) { - return method.getAnnotation(Dinger.class).value(); - } - Class dingerClass = method.getDeclaringClass(); if (dingerClass.isAnnotationPresent(Dinger.class)) { return dingerClass.getAnnotation(Dinger.class).value(); @@ -147,7 +143,7 @@ DingerType dingerType(Method method) { * 获取Dinger定义 * *
-     *     优先级: local(dinger为空使用默认 {@link DingerMessageHandler#dingerType}) > multi > default
+     *     优先级: local(dinger为空使用默认 {@link DingerMessageHandler#dingerType}) > multi > default({@link DingerMessageHandler#dingerType})
      * 
* * @param useDinger @@ -163,38 +159,39 @@ DingerDefinition dingerDefinition(DingerType useDinger, String keyName) { // 优先使用用户设定 dingerConfig if (localDinger == null) { - keyName = useDinger + SPOT_SEPERATOR + keyName; + String dingerName = useDinger + SPOT_SEPERATOR + keyName; dingerDefinition = DingerXmlPreparedEvent - .Container.INSTANCE.get(keyName); + .Container.INSTANCE.get(dingerName); if (dingerDefinition == null) { - log.warn("{} there is no corresponding dinger message config", keyName); + log.warn("{} there is no corresponding dinger message config", dingerName); return null; } + DingerConfig dingerMethodDefaultDingerConfig = dingerDefinition.dingerConfig(); // 判断是否是multiDinger if (multiDinger()) { MultiDingerConfig multiDingerConfig = MultiDingerConfigContainer - .INSTANCE.get(keyName); + .INSTANCE.get(useDinger, keyName); DingerConfig dingerConfig = null; if (multiDingerConfig != null) { // 拿到MultiDingerConfig中当前应该使用的DingerConfig dingerConfig = multiDingerConfig.getAlgorithmHandler() .dingerConfig( multiDingerConfig.getDingerConfigs(), - dingerDefinition.dingerConfig() + dingerMethodDefaultDingerConfig ); } // use default dingerConfig if (dingerConfig == null) { - dingerConfig = dingerDefinition.dingerConfig(); + dingerConfig = dingerMethodDefaultDingerConfig; } DingerHelper.assignDinger(dingerConfig); } else { - DingerHelper.assignDinger(dingerDefinition.dingerConfig()); + DingerHelper.assignDinger(dingerMethodDefaultDingerConfig); } } else { diff --git a/src/main/java/com/github/jaemon/dinger/core/DingerRefresh.java b/src/main/java/com/github/jaemon/dinger/core/DingerRefresh.java index 9e1a756..578a982 100644 --- a/src/main/java/com/github/jaemon/dinger/core/DingerRefresh.java +++ b/src/main/java/com/github/jaemon/dinger/core/DingerRefresh.java @@ -25,7 +25,6 @@ public class DingerRefresh { protected static void dingerFresh() { AbstractDingerDefinitionResolver.clear(); - DingerDefinitionGeneratorFactory.clear(); } } \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/core/DingerRobot.java b/src/main/java/com/github/jaemon/dinger/core/DingerRobot.java index 6e5cbed..c335da6 100644 --- a/src/main/java/com/github/jaemon/dinger/core/DingerRobot.java +++ b/src/main/java/com/github/jaemon/dinger/core/DingerRobot.java @@ -129,6 +129,10 @@ protected DingerResponse send(T message) { StringBuilder webhook = new StringBuilder(); webhook.append(dinger.getRobotUrl()).append("=").append(dinger.getTokenId()); + if (log.isDebugEnabled()) { + log.debug("dingerId={} send message and use dinger={}, tokenId={}.", dkid, dingerType, dinger.getTokenId()); + } + // 处理签名问题(只支持DingTalk) if (dingerType == DingerType.DINGTALK && DingerUtils.isNotEmpty((dinger.getSecret()))) { @@ -137,14 +141,14 @@ protected DingerResponse send(T message) { } Map headers = new HashMap<>(); - headers.put("Content-Type", "application/json; charset=utf-8"); + headers.put("Content-Type", MediaTypeEnum.JSON.type()); // 异步处理, 直接返回标识id if (dinger.isAsync()) { dingTalkManagerBuilder.dingTalkExecutor.execute(() -> { try { String result = dingTalkManagerBuilder.dingerHttpClient.post( - webhook.toString(), headers, message, MediaTypeEnum.JSON + webhook.toString(), headers, message ); dingTalkManagerBuilder.dingerAsyncCallback.execute(dkid, result); } catch (Exception e) { @@ -155,7 +159,7 @@ protected DingerResponse send(T message) { } String response = dingTalkManagerBuilder.dingerHttpClient.post( - webhook.toString(), headers, message, MediaTypeEnum.JSON + webhook.toString(), headers, message ); return DingerResponse.success(dkid, response); } catch (Exception e) { diff --git a/src/main/java/com/github/jaemon/dinger/core/ParamHandler.java b/src/main/java/com/github/jaemon/dinger/core/ParamHandler.java index 373b129..2858534 100644 --- a/src/main/java/com/github/jaemon/dinger/core/ParamHandler.java +++ b/src/main/java/com/github/jaemon/dinger/core/ParamHandler.java @@ -27,11 +27,14 @@ public interface ParamHandler { /** - * paramsHandler + * Dinger方法参数处理 * - * @param parameters parameters - * @param values values - * @return params map + * @param parameters + * Dinger方法形参集 + * @param values + * Dinger方法实参 + * @return + * 形参和实参的映射关系 */ Map paramsHandler(Parameter[] parameters, Object[] values); diff --git a/src/main/java/com/github/jaemon/dinger/core/ResultHandler.java b/src/main/java/com/github/jaemon/dinger/core/ResultHandler.java index 24fa109..c7b8e46 100644 --- a/src/main/java/com/github/jaemon/dinger/core/ResultHandler.java +++ b/src/main/java/com/github/jaemon/dinger/core/ResultHandler.java @@ -23,11 +23,14 @@ */ public interface ResultHandler { /** - * resultHandler + * Dinger方法返回结果处理 * - * @param resultType resultType + * @param resultType + * 返回结果类型 * @param t T - * @return object + * 实际返回信息 + * @return + * 最终返回信息 */ Object resultHandler(Class resultType, T t); } \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/DingerProperties.java b/src/main/java/com/github/jaemon/dinger/core/entity/DingerProperties.java index 5e9e177..09e7b06 100644 --- a/src/main/java/com/github/jaemon/dinger/core/entity/DingerProperties.java +++ b/src/main/java/com/github/jaemon/dinger/core/entity/DingerProperties.java @@ -41,22 +41,22 @@ public class DingerProperties implements InitializingBean { private static final Logger log = LoggerFactory.getLogger(DingerProperties.class); /** - * 是否启用DingTalk, 默认true + * 是否启用DingTalk, 默认true, 选填 */ private boolean enabled = true; /** - * dinger类型-必填 + * dinger类型 key={@link DingerType}, value={@link Dinger}, 必填 */ private Map dingers = new HashMap<>(); /** - * 必填, 项目名称 + * 项目名称, 必填 eg: ${spring.application.name} * */ private String projectId; /** - * 使用dinger时, 对应的 xml配置路径. + * dinger xml配置路径(需要配置xml方式Dinger时必填), 选填 * *
* spring.dinger.dinger-locations: classpath*:dinger/*.xml @@ -65,8 +65,8 @@ public class DingerProperties implements InitializingBean { * */ private String dingerLocations; - /** 默认的Dinger, default {@link DingerType#DINGTALK} */ - private DingerType defaultDinger = DingerType.DINGTALK; + /** 默认的Dinger, 不指定则使用{@link DingerProperties#dingers}中的第一个, 选填 */ + private DingerType defaultDinger; public boolean isEnabled() { return enabled; @@ -114,7 +114,7 @@ public static class Dinger { * */ private String robotUrl; /** - * 获取 access_token + * 获取 access_token, 必填 * *
* 填写Dinger机器人设置中 webhook access_token | key后面的值 @@ -130,17 +130,17 @@ public static class Dinger { * */ private String tokenId; /** - * 可选, 签名秘钥。 需要验签时必填(钉钉机器人提供) + * 选填, 签名秘钥。 需要验签时必填(钉钉机器人提供) */ private String secret; /** - * 可选, 是否需要对tokenId进行解密, 默认false + * 选填, 是否需要对tokenId进行解密, 默认false */ private boolean decrypt = false; /** - * 可选(当decrypt=true时, 必填), 解密密钥 + * 选填(当decrypt=true时, 必填), 解密密钥 * *

* @@ -153,7 +153,7 @@ public static class Dinger { private String decryptKey; /** - * 可选, 是否开启异步处理, 默认: false + * 选填, 是否开启异步处理, 默认: false */ private boolean async = false; @@ -247,6 +247,11 @@ public void afterPropertiesSet() throws Exception { } else { dinger.decryptKey = null; } + + if (defaultDinger == null) { + defaultDinger = dingerType; + log.warn("defaultDinger undeclared and use fisrt dingers dingerType, defaultDinger={}", defaultDinger); + } } if (dingers.isEmpty()) { diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/DingerRequest.java b/src/main/java/com/github/jaemon/dinger/core/entity/DingerRequest.java index ab946eb..6f7a80e 100644 --- a/src/main/java/com/github/jaemon/dinger/core/entity/DingerRequest.java +++ b/src/main/java/com/github/jaemon/dinger/core/entity/DingerRequest.java @@ -15,6 +15,7 @@ */ package com.github.jaemon.dinger.core.entity; +import java.util.ArrayList; import java.util.List; /** @@ -29,7 +30,7 @@ public class DingerRequest { /** 标题(dingtalk-markdown) */ private String title; /** 艾特成员信息 */ - private List phones; + private List phones = new ArrayList<>(); /** 艾特成员 */ private boolean atAll = false; @@ -63,26 +64,88 @@ private DingerRequest(String content, String title, boolean atAll) { } + /** + * 构建Dinger请求体 + * + * @param content + * 具体消息内容 + * @return + * Dinger请求体实例 + */ public static DingerRequest request(String content) { return new DingerRequest(content); } + /** + * 构建Dinger请求体 + * + * @param content + * 具体消息内容 + * @param title + * 标题, 仅限钉钉markdown消息使用 + * @return + * Dinger请求体实例 + */ public static DingerRequest request(String content, String title) { return new DingerRequest(content, title); } + /** + * 构建Dinger请求体 + * + * @param content + * 具体消息内容 + * @param phones + * 需要@的成员列表 + * @return + * Dinger请求体实例 + */ public static DingerRequest request(String content, List phones) { return new DingerRequest(content, phones); } + /** + * 构建Dinger请求体 + * + * @param content + * 具体消息内容 + * @param atAll + * 是否需要@全部成员 + * @return + * Dinger请求体实例 + */ public static DingerRequest request(String content, boolean atAll) { return new DingerRequest(content, atAll); } + /** + * 构建Dinger请求体 + * + * @param content + * 具体消息内容 + * @param title + * 标题, 仅限钉钉markdown消息使用 + * @param phones + * 需要@的成员列表 + * @return + * Dinger请求体实例 + */ public static DingerRequest request(String content, String title, List phones) { return new DingerRequest(content, title, phones); } + /** + * 构建Dinger请求体 + * + * @param content + * 具体消息内容 + * @param title + * 标题, 仅限钉钉markdown消息使用 + * @param atAll + * 是否需要@全部成员 + * @return + * Dinger请求体实例 + */ public static DingerRequest request(String content, String title, boolean atAll) { return new DingerRequest(content, title, atAll); } diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/ExceptionPairs.java b/src/main/java/com/github/jaemon/dinger/core/entity/ExceptionPairs.java new file mode 100644 index 0000000..cdef110 --- /dev/null +++ b/src/main/java/com/github/jaemon/dinger/core/entity/ExceptionPairs.java @@ -0,0 +1,32 @@ +/* + * Copyright ©2015-2020 Jaemon. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.jaemon.dinger.core.entity; + +/** + * 异常对 + * + * @author Jaemon + * @since 1.0 + */ +public interface ExceptionPairs extends Pairs { + + @Override + default String message(Object... args) { + String message = String.format(this.desc(), args); + return String.format("{code=%d, message=%s}", code(), message); + } + +} \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/Pairs.java b/src/main/java/com/github/jaemon/dinger/core/entity/Pairs.java index 92b377e..1ce7da1 100644 --- a/src/main/java/com/github/jaemon/dinger/core/entity/Pairs.java +++ b/src/main/java/com/github/jaemon/dinger/core/entity/Pairs.java @@ -37,4 +37,14 @@ public interface Pairs { */ V desc(); + /** + * message + * + * @param args + * args + * @return + * message + */ + V message(Object... args); + } \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/enums/ExceptionEnum.java b/src/main/java/com/github/jaemon/dinger/core/entity/enums/ExceptionEnum.java index e9d69f5..14825b6 100644 --- a/src/main/java/com/github/jaemon/dinger/core/entity/enums/ExceptionEnum.java +++ b/src/main/java/com/github/jaemon/dinger/core/entity/enums/ExceptionEnum.java @@ -15,7 +15,7 @@ */ package com.github.jaemon.dinger.core.entity.enums; -import com.github.jaemon.dinger.core.entity.Pairs; +import com.github.jaemon.dinger.core.entity.ExceptionPairs; /** * 异常枚举 @@ -23,7 +23,7 @@ * @author Jaemon * @since 1.0 */ -public enum ExceptionEnum implements Pairs { +public enum ExceptionEnum implements ExceptionPairs { /** 发送异常, 1XXX, {@link com.github.jaemon.dinger.exception.SendMsgException} */ SEND_MSG(1000, "发送消息异常"), @@ -51,6 +51,7 @@ public enum ExceptionEnum implements Pairs { MULTI_DINGER_SCAN_ERROR(4000, "配置了多个DingerScan注解"), /** {@link com.github.jaemon.dinger.exception.ConfigurationException} */ CONFIG_ERROR(4001, "配置异常"), + RESOURCE_CONFIG_EXCEPTION(4002, "读取资源[%s]信息异常"), @@ -64,12 +65,11 @@ public enum ExceptionEnum implements Pairs { /** Dinger解析XML相关异常, 60XX */ - DINER_XML_NAMESPACE_INVALID(6000, "xml文件namespace=%s无效"), - DINER_XML_MSGTYPE_INVALID(6001, "xml文件message type=%s无效"), + DINER_XML_NAMESPACE_INVALID(6000, "xml文件namespace=%s对应的类不存在"), + DINER_XML_MSGTYPE_INVALID(6001, "xml id=%s文件message type=%s无效"), - // TODO - DINGERDEFINITION_ERROR(6004, "dingerDefinition异常"), - DINGERDEFINITIONTYPE_ERROR(6005, "DingerDefinitionType异常"), + DINGERDEFINITION_ERROR(6004, "key=%s无对应的DingerDefinitionGenerator"), + DINGERDEFINITIONTYPE_ERROR(6005, "%s中消息体定义主类型期望=%s, 实际=%s"), /** Dinger解析注解相关异常, 63XX */ @@ -85,8 +85,9 @@ public enum ExceptionEnum implements Pairs { /** Multi Dinger解析相关异常, 70XX */ - DINGER_CONFIG_HANDLER_EXCEPTION(7000, "DingerConfigHandler=%s中指定的dingerconfigs[%d]数据异常"), - MULTIDINGER_ALGORITHM_EXCEPTION(7001, "DingerConfigHandler=%s中算法为空"), + DINGER_CONFIG_HANDLER_EXCEPTION(7000, "%s中指定的dingerconfigs[%d]数据异常"), + MULTIDINGER_ALGORITHM_EXCEPTION(7001, "%s中算法为空"), + MULTIDINGER_ANNOTATTION_EXCEPTION(7002, "%s中的MultiDinger.dinger=%s已经被警用"), /** Multi Dinger属性注入相关异常, 75XX */ ALGORITHM_FIELD_INSTANCE_NOT_EXISTS(7500, "算法[%s]中属性字段[%s]实例不存在"), diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/enums/MessageSubType.java b/src/main/java/com/github/jaemon/dinger/core/entity/enums/MessageSubType.java index dcb72e0..0acddeb 100644 --- a/src/main/java/com/github/jaemon/dinger/core/entity/enums/MessageSubType.java +++ b/src/main/java/com/github/jaemon/dinger/core/entity/enums/MessageSubType.java @@ -43,7 +43,7 @@ public MsgType msgType(DingerType dingerType, String content, String title, List if (atAll) { message.setAt(new Message.At(true)); - } else if (!phones.isEmpty()) { + } else if (phones != null && !phones.isEmpty()) { message.setAt(new Message.At(phones)); } @@ -53,7 +53,7 @@ public MsgType msgType(DingerType dingerType, String content, String title, List WeText weText = new WeText(text); if (atAll) { text.setMentioned_mobile_list(Arrays.asList(WETALK_AT_ALL)); - } else if (!phones.isEmpty()) { + } else if (phones != null && !phones.isEmpty()) { text.setMentioned_mobile_list(phones); } return weText; diff --git a/src/main/java/com/github/jaemon/dinger/core/spring/ApplicationHome.java b/src/main/java/com/github/jaemon/dinger/core/spring/ApplicationHome.java new file mode 100644 index 0000000..e9656fd --- /dev/null +++ b/src/main/java/com/github/jaemon/dinger/core/spring/ApplicationHome.java @@ -0,0 +1,170 @@ +/* + * Copyright ©2015-2020 Jaemon. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.jaemon.dinger.core.spring; + +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import java.util.Enumeration; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +/** + * ApplicationHome + * + * @author Jaemon + * @since 1.0 + */ +public class ApplicationHome { + private final File source; + + private final File dir; + + /** + * Create a new {@link org.springframework.boot.system.ApplicationHome} instance. + */ + public ApplicationHome() { + this(null); + } + + /** + * Create a new {@link org.springframework.boot.system.ApplicationHome} instance for the specified source class. + * @param sourceClass the source class or {@code null} + */ + public ApplicationHome(Class sourceClass) { + this.source = findSource((sourceClass != null) ? sourceClass : getStartClass()); + this.dir = findHomeDir(this.source); + } + + private Class getStartClass() { + try { + ClassLoader classLoader = getClass().getClassLoader(); + return getStartClass(classLoader.getResources("META-INF/MANIFEST.MF")); + } + catch (Exception ex) { + return null; + } + } + + private Class getStartClass(Enumeration manifestResources) { + while (manifestResources.hasMoreElements()) { + try (InputStream inputStream = manifestResources.nextElement().openStream()) { + Manifest manifest = new Manifest(inputStream); + String startClass = manifest.getMainAttributes().getValue("Start-Class"); + if (startClass != null) { + return ClassUtils.forName(startClass, getClass().getClassLoader()); + } + } + catch (Exception ex) { + } + } + return null; + } + + private File findSource(Class sourceClass) { + try { + ProtectionDomain domain = (sourceClass != null) + ? sourceClass.getProtectionDomain() : null; + CodeSource codeSource = (domain != null) ? domain.getCodeSource() : null; + URL location = (codeSource != null) ? codeSource.getLocation() : null; + File source = (location != null) ? findSource(location) : null; + if (source != null && source.exists() && !isUnitTest()) { + return source.getAbsoluteFile(); + } + return null; + } + catch (Exception ex) { + return null; + } + } + + private boolean isUnitTest() { + try { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + for (int i = stackTrace.length - 1; i >= 0; i--) { + if (stackTrace[i].getClassName().startsWith("org.junit.")) { + return true; + } + } + } + catch (Exception ex) { + } + return false; + } + + private File findSource(URL location) throws IOException { + URLConnection connection = location.openConnection(); + if (connection instanceof JarURLConnection) { + return getRootJarFile(((JarURLConnection) connection).getJarFile()); + } + return new File(location.getPath()); + } + + private File getRootJarFile(JarFile jarFile) { + String name = jarFile.getName(); + int separator = name.indexOf("!/"); + if (separator > 0) { + name = name.substring(0, separator); + } + return new File(name); + } + + private File findHomeDir(File source) { + File homeDir = source; + homeDir = (homeDir != null) ? homeDir : findDefaultHomeDir(); + if (homeDir.isFile()) { + homeDir = homeDir.getParentFile(); + } + homeDir = homeDir.exists() ? homeDir : new File("."); + return homeDir.getAbsoluteFile(); + } + + private File findDefaultHomeDir() { + String userDir = System.getProperty("user.dir"); + return new File(StringUtils.hasLength(userDir) ? userDir : "."); + } + + /** + * Returns the underlying source used to find the home directory. This is usually the + * jar file or a directory. Can return {@code null} if the source cannot be + * determined. + * @return the underlying source or {@code null} + */ + public File getSource() { + return this.source; + } + + /** + * Returns the application home directory. + * @return the home directory (never {@code null}) + */ + public File getDir() { + return this.dir; + } + + @Override + public String toString() { + return getDir().toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/core/spring/DingerScannerRegistrar.java b/src/main/java/com/github/jaemon/dinger/core/spring/DingerScannerRegistrar.java index 864dee7..c220d96 100644 --- a/src/main/java/com/github/jaemon/dinger/core/spring/DingerScannerRegistrar.java +++ b/src/main/java/com/github/jaemon/dinger/core/spring/DingerScannerRegistrar.java @@ -48,7 +48,6 @@ public class DingerScannerRegistrar @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - boolean isTraceEnabled = log.isTraceEnabled(); boolean isDebugEnabled = log.isDebugEnabled(); log.info("ready to execute dingerScanner..."); try { diff --git a/src/main/java/com/github/jaemon/dinger/dingtalk/entity/Message.java b/src/main/java/com/github/jaemon/dinger/dingtalk/entity/Message.java index 6c72b8d..f458bff 100644 --- a/src/main/java/com/github/jaemon/dinger/dingtalk/entity/Message.java +++ b/src/main/java/com/github/jaemon/dinger/dingtalk/entity/Message.java @@ -76,11 +76,11 @@ public void setAtMobiles(List atMobiles) { this.atMobiles = atMobiles; } - public Boolean getAtAll() { + public Boolean getIsAtAll() { return isAtAll; } - public void setAtAll(Boolean atAll) { + public void setIsAtAll(Boolean atAll) { isAtAll = atAll; } } diff --git a/src/main/java/com/github/jaemon/dinger/exception/DingerAnalysisException.java b/src/main/java/com/github/jaemon/dinger/exception/DingerAnalysisException.java index 67188fc..7c829b3 100644 --- a/src/main/java/com/github/jaemon/dinger/exception/DingerAnalysisException.java +++ b/src/main/java/com/github/jaemon/dinger/exception/DingerAnalysisException.java @@ -15,7 +15,7 @@ */ package com.github.jaemon.dinger.exception; -import com.github.jaemon.dinger.core.entity.Pairs; +import com.github.jaemon.dinger.core.entity.ExceptionPairs; /** * Dinger解析异常 @@ -24,11 +24,11 @@ * @since 1.0 */ public class DingerAnalysisException extends DingerException { - public DingerAnalysisException(Pairs pairs) { + public DingerAnalysisException(ExceptionPairs pairs) { super(pairs); } - public DingerAnalysisException(Pairs pairs, String message) { + public DingerAnalysisException(ExceptionPairs pairs, String message) { super(message, pairs); } } \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/exception/DingerException.java b/src/main/java/com/github/jaemon/dinger/exception/DingerException.java index d65d11e..c218979 100644 --- a/src/main/java/com/github/jaemon/dinger/exception/DingerException.java +++ b/src/main/java/com/github/jaemon/dinger/exception/DingerException.java @@ -15,7 +15,7 @@ */ package com.github.jaemon.dinger.exception; -import com.github.jaemon.dinger.core.entity.Pairs; +import com.github.jaemon.dinger.core.entity.ExceptionPairs; /** * 异常类 @@ -24,29 +24,29 @@ * @since 1.0 */ public class DingerException extends RuntimeException { - private Pairs pairs; + private ExceptionPairs pairs; - public DingerException(Pairs pairs) { + public DingerException(ExceptionPairs pairs) { super(pairs.desc()); this.pairs = pairs; } - public DingerException(String msg, Pairs pairs) { + public DingerException(String msg, ExceptionPairs pairs) { super(msg); this.pairs = pairs; } - public DingerException(Pairs pairs, Object... msgArgs) { - super(String.format(pairs.desc(), msgArgs)); + public DingerException(ExceptionPairs pairs, Object... msgArgs) { + super(pairs.message(msgArgs)); this.pairs = pairs; } - public DingerException(Throwable cause, Pairs pairs) { + public DingerException(Throwable cause, ExceptionPairs pairs) { super(cause); this.pairs = pairs; } - public Pairs getPairs() { + public ExceptionPairs getPairs() { return pairs; } } diff --git a/src/main/java/com/github/jaemon/dinger/exception/MultiDingerRegisterException.java b/src/main/java/com/github/jaemon/dinger/exception/MultiDingerRegisterException.java index aeeb5bb..3a5c56d 100644 --- a/src/main/java/com/github/jaemon/dinger/exception/MultiDingerRegisterException.java +++ b/src/main/java/com/github/jaemon/dinger/exception/MultiDingerRegisterException.java @@ -15,7 +15,7 @@ */ package com.github.jaemon.dinger.exception; -import com.github.jaemon.dinger.core.entity.Pairs; +import com.github.jaemon.dinger.core.entity.ExceptionPairs; /** * 多Dinger配置注册异常 @@ -24,11 +24,11 @@ * @since 1.0 */ public class MultiDingerRegisterException extends DingerException { - public MultiDingerRegisterException(Pairs pairs) { + public MultiDingerRegisterException(ExceptionPairs pairs) { super(pairs); } - public MultiDingerRegisterException(Pairs pairs, String message) { + public MultiDingerRegisterException(ExceptionPairs pairs, String message) { super(message, pairs); } diff --git a/src/main/java/com/github/jaemon/dinger/listeners/DingerXmlPreparedEvent.java b/src/main/java/com/github/jaemon/dinger/listeners/DingerXmlPreparedEvent.java index e54602e..73f7a01 100644 --- a/src/main/java/com/github/jaemon/dinger/listeners/DingerXmlPreparedEvent.java +++ b/src/main/java/com/github/jaemon/dinger/listeners/DingerXmlPreparedEvent.java @@ -16,6 +16,7 @@ package com.github.jaemon.dinger.listeners; import com.github.jaemon.dinger.core.DingerDefinitionResolver; +import com.github.jaemon.dinger.core.annatations.DingerScan; import com.github.jaemon.dinger.core.entity.enums.DingerType; import com.github.jaemon.dinger.core.entity.enums.ExceptionEnum; import com.github.jaemon.dinger.exception.DingerAnalysisException; @@ -24,10 +25,14 @@ import com.github.jaemon.dinger.core.DingerConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringBootVersion; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.context.ApplicationListener; import org.springframework.core.env.Environment; +import java.util.HashSet; +import java.util.Set; + import static com.github.jaemon.dinger.constant.DingerConstant.SPOT_SEPERATOR; /** @@ -44,7 +49,7 @@ public class DingerXmlPreparedEvent @Override public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { log.info("ready to execute dinger analysis."); - + loadPrimarySources(event); registerDefaultDingerConfig(event.getEnvironment()); try { @@ -56,6 +61,31 @@ public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { } } + /** + * loadPrimarySources + * + * @param event + * event {@link ApplicationEnvironmentPreparedEvent} + */ + private void loadPrimarySources(ApplicationEnvironmentPreparedEvent event) { + Set allSources; + if (SpringBootVersion.getVersion().startsWith("1.")) { + allSources = event.getSpringApplication().getSources(); + } else { + allSources = event.getSpringApplication().getAllSources(); + } + Set> primarySources = new HashSet<>(); + for (Object source : allSources) { + if (Class.class.isInstance(source)) { + Class clazz = (Class) source; + if (clazz.isAnnotationPresent(DingerScan.class)) { + primarySources.add(clazz); + } + } + } + DingerListenersProperty.primarySources = primarySources; + } + /** * 注册默认的Dinger机器人信息, 即配置文件内容 * diff --git a/src/main/java/com/github/jaemon/dinger/listeners/StartEventListener.java b/src/main/java/com/github/jaemon/dinger/listeners/StartEventListener.java deleted file mode 100644 index 926fc74..0000000 --- a/src/main/java/com/github/jaemon/dinger/listeners/StartEventListener.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright ©2015-2020 Jaemon. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.github.jaemon.dinger.listeners; - -import com.github.jaemon.dinger.core.annatations.DingerScan; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.context.event.ApplicationStartingEvent; -import org.springframework.context.ApplicationListener; - -import java.util.HashSet; -import java.util.Set; - -/** - * Start Listener - * - * @author Jaemon - * @since 1.0 - */ -public class StartEventListener implements ApplicationListener { - private static final Logger log = LoggerFactory.getLogger(StartEventListener.class); - - @Override - public void onApplicationEvent(ApplicationStartingEvent event) { - Set allSources = event.getSpringApplication().getAllSources(); - Set> primarySources = new HashSet<>(); - for (Object source : allSources) { - if (Class.class.isInstance(source)) { - Class clazz = (Class) source; - if (clazz.isAnnotationPresent(DingerScan.class)) { - primarySources.add(clazz); - } - } - } - DingerListenersProperty.primarySources = primarySources; - } -} \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/multi/DingerConfigHandler.java b/src/main/java/com/github/jaemon/dinger/multi/DingerConfigHandler.java index d750532..a9b0165 100644 --- a/src/main/java/com/github/jaemon/dinger/multi/DingerConfigHandler.java +++ b/src/main/java/com/github/jaemon/dinger/multi/DingerConfigHandler.java @@ -19,6 +19,7 @@ import com.github.jaemon.dinger.multi.algorithm.AlgorithmHandler; import com.github.jaemon.dinger.multi.algorithm.DefaultHandler; import com.github.jaemon.dinger.multi.algorithm.DingerHandler; +import com.github.jaemon.dinger.multi.annotations.MultiDinger; import java.util.List; @@ -31,7 +32,12 @@ public interface DingerConfigHandler { /** - * 多钉钉机器人配置 + * 多Dinger机器人配置 + * + *
+     *     1. DingerConfig中的DingerType统一使用 {@link MultiDinger#dinger()} 中指定的
+     *     2. dingerConfigs的配置信息必须是 {@link MultiDinger#dinger()} 指定的机器人配置信息
+     * 
* * @return dingerConfigs * */ diff --git a/src/main/java/com/github/jaemon/dinger/multi/MultiDingerConfigContainer.java b/src/main/java/com/github/jaemon/dinger/multi/MultiDingerConfigContainer.java index 24661a3..ff0ea10 100644 --- a/src/main/java/com/github/jaemon/dinger/multi/MultiDingerConfigContainer.java +++ b/src/main/java/com/github/jaemon/dinger/multi/MultiDingerConfigContainer.java @@ -15,6 +15,8 @@ */ package com.github.jaemon.dinger.multi; +import com.github.jaemon.dinger.constant.DingerConstant; +import com.github.jaemon.dinger.core.entity.enums.DingerType; import com.github.jaemon.dinger.multi.entity.MultiDingerConfig; import java.util.HashMap; @@ -64,11 +66,12 @@ public boolean isEmpty() { return this.container.isEmpty(); } - public MultiDingerConfig get(String key) { + public MultiDingerConfig get(DingerType dingerType, String key) { + key = dingerType + DingerConstant.SPOT_SEPERATOR + key; if (this.container.containsKey(key)) { return this.container.get(key); } - return this.container.get(GLOABL_KEY); + return this.container.get(dingerType + DingerConstant.SPOT_SEPERATOR + GLOABL_KEY); } protected static void clear() { diff --git a/src/main/java/com/github/jaemon/dinger/multi/MultiDingerScannerRegistrar.java b/src/main/java/com/github/jaemon/dinger/multi/MultiDingerScannerRegistrar.java index 7dd42fd..d8ae20d 100644 --- a/src/main/java/com/github/jaemon/dinger/multi/MultiDingerScannerRegistrar.java +++ b/src/main/java/com/github/jaemon/dinger/multi/MultiDingerScannerRegistrar.java @@ -50,6 +50,7 @@ import static com.github.jaemon.dinger.constant.DingerConstant.SPOT_SEPERATOR; import static com.github.jaemon.dinger.core.entity.enums.ExceptionEnum.MULTIDINGER_ALGORITHM_EXCEPTION; +import static com.github.jaemon.dinger.core.entity.enums.ExceptionEnum.MULTIDINGER_ANNOTATTION_EXCEPTION; import static com.github.jaemon.dinger.multi.MultiDingerConfigContainer.GLOABL_KEY; /** @@ -186,10 +187,15 @@ private void multiDingerHandler(BeanDefinitionRegistry registry, List> * @param key * 当前dingerClass类名 * @param dingerConfigHandler - * dingerClass指定的multiHandler处理器 + * dingerClass指定的multiHandler处理器实例 */ private void registerHandler(BeanDefinitionRegistry registry, DingerType dinger, String key, DingerConfigHandler dingerConfigHandler) { String dingerConfigHandlerClassName = dingerConfigHandler.getClass().getSimpleName(); + + if (!dinger.isEnabled()) { + throw new DingerException(MULTIDINGER_ANNOTATTION_EXCEPTION, key, dinger); + } + // 获取当前指定算法类名, 默认四种,或使用自定义 Class algorithm = dingerConfigHandler.algorithmHandler(); // if empty? use default dinger config @@ -199,14 +205,10 @@ private void registerHandler(BeanDefinitionRegistry registry, DingerType dinger, throw new DingerException(MULTIDINGER_ALGORITHM_EXCEPTION, dingerConfigHandlerClassName); } - dingerConfigs.stream().forEach(e -> { - - }); for (int i = 0; i < dingerConfigs.size(); i++) { DingerConfig dingerConfig = dingerConfigs.get(i); - if (DingerUtils.isEmpty(dingerConfig.getTokenId()) || ( - dingerConfig.getDingerType() != null && dinger != dingerConfig.getDingerType()) - ) { + dingerConfig.setDingerType(dinger); + if (DingerUtils.isEmpty(dingerConfig.getTokenId())) { throw new DingerException(ExceptionEnum.DINGER_CONFIG_HANDLER_EXCEPTION, dingerConfigHandlerClassName, i); } } diff --git a/src/main/java/com/github/jaemon/dinger/support/DefaultDkCallable.java b/src/main/java/com/github/jaemon/dinger/support/DefaultDingerAsyncCallable.java similarity index 91% rename from src/main/java/com/github/jaemon/dinger/support/DefaultDkCallable.java rename to src/main/java/com/github/jaemon/dinger/support/DefaultDingerAsyncCallable.java index 12eb8a2..7cd67f9 100644 --- a/src/main/java/com/github/jaemon/dinger/support/DefaultDkCallable.java +++ b/src/main/java/com/github/jaemon/dinger/support/DefaultDingerAsyncCallable.java @@ -25,8 +25,8 @@ * @author Jaemon * @since 1.0 */ -public class DefaultDkCallable implements DingerAsyncCallback { - private static final Logger log = LoggerFactory.getLogger(DefaultDkCallable.class); +public class DefaultDingerAsyncCallable implements DingerAsyncCallback { + private static final Logger log = LoggerFactory.getLogger(DefaultDingerAsyncCallable.class); @Override public void execute(String dingerId, String result) { diff --git a/src/main/java/com/github/jaemon/dinger/support/TextMessage.java b/src/main/java/com/github/jaemon/dinger/support/TextMessage.java index 3236002..644a257 100644 --- a/src/main/java/com/github/jaemon/dinger/support/TextMessage.java +++ b/src/main/java/com/github/jaemon/dinger/support/TextMessage.java @@ -29,7 +29,7 @@ public class TextMessage implements CustomMessage { @Override public String message(String projectId, String title, String content, List phones) { return MessageFormat.format( - "【Dinger通知】 {0}\n- 项目名称: {1}\n- 内容: {2}.", - title, projectId, content); + "【Dinger通知】 {0}\n- 内容: {1}.", + projectId, content); } } \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/support/client/AbstractDingerHttpClient.java b/src/main/java/com/github/jaemon/dinger/support/client/AbstractDingerHttpClient.java index 51404f8..bb40bc7 100644 --- a/src/main/java/com/github/jaemon/dinger/support/client/AbstractDingerHttpClient.java +++ b/src/main/java/com/github/jaemon/dinger/support/client/AbstractDingerHttpClient.java @@ -42,11 +42,6 @@ public String get(String url, Map headers, Map params return null; } - @Override - public String get(String url, Map headers, Map params, MediaTypeEnum mediaType) throws SendMsgException { - return null; - } - @Override public String post(String url, String message) throws SendMsgException { return null; @@ -61,11 +56,4 @@ public String post(String url, Map headers, String message) thro public String post(String url, Map headers, Map params) throws SendMsgException { return null; } - - - @Override - public String post(String url, Map headers, Map params, MediaTypeEnum mediaType) { - return null; - } - } \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/support/client/DingerHttpClient.java b/src/main/java/com/github/jaemon/dinger/support/client/DingerHttpClient.java index 50a0f34..08fdbfa 100644 --- a/src/main/java/com/github/jaemon/dinger/support/client/DingerHttpClient.java +++ b/src/main/java/com/github/jaemon/dinger/support/client/DingerHttpClient.java @@ -69,24 +69,6 @@ public interface DingerHttpClient { */ String get(String url, Map headers, Map params) throws SendMsgException; - /** - * get request - * - * @param url - * 请求URL地址 - * @param headers - * 请求头 - * @param params - * 请求参数 - * @param mediaType - * 内容类型 - * @return - * 响应内容 - * @throws SendMsgException - * ex {@link SendMsgException} - */ - String get(String url, Map headers, Map params, MediaTypeEnum mediaType) throws SendMsgException; - /** * post request * @@ -117,22 +99,6 @@ public interface DingerHttpClient { */ String post(String url, Map headers, String message) throws SendMsgException; - /** - * post request - * - * @param url - * 请求URL地址 - * @param headers - * 请求头 - * @param params - * 请求参数 - * @return - * 响应内容 - * @throws SendMsgException - * ex {@link SendMsgException} - */ - String post(String url, Map headers, Map params) throws SendMsgException; - /** * post request @@ -145,14 +111,12 @@ public interface DingerHttpClient { * 请求体信息 * @param * 请求内容类型 - * @param mediaType - * 内容类型 * @return * 响应内容 * @throws SendMsgException * ex {@link SendMsgException} */ - String post(String url, Map headers, T message, MediaTypeEnum mediaType) throws SendMsgException; + String post(String url, Map headers, T message) throws SendMsgException; /** * post request @@ -163,12 +127,10 @@ public interface DingerHttpClient { * 请求头 * @param params * 请求参数 - * @param mediaType - * 内容类型 * @return * 响应内容 * @throws SendMsgException * ex {@link SendMsgException} */ - String post(String url, Map headers, Map params, MediaTypeEnum mediaType) throws SendMsgException; + String post(String url, Map headers, Map params) throws SendMsgException; } \ No newline at end of file diff --git a/src/main/java/com/github/jaemon/dinger/support/client/DingerHttpTemplate.java b/src/main/java/com/github/jaemon/dinger/support/client/DingerHttpTemplate.java index 9c3415a..8892dba 100644 --- a/src/main/java/com/github/jaemon/dinger/support/client/DingerHttpTemplate.java +++ b/src/main/java/com/github/jaemon/dinger/support/client/DingerHttpTemplate.java @@ -21,7 +21,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.web.client.RestTemplate; import java.util.Map; @@ -38,9 +37,12 @@ public class DingerHttpTemplate extends AbstractDingerHttpClient { private RestTemplate restTemplate; @Override - public String post(String url, Map headers, T message, MediaTypeEnum mediaType) throws SendMsgException { + public String post(String url, Map headers, T message) throws SendMsgException { HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.setContentType(MediaType.parseMediaType(mediaType.type())); + headers.forEach((headerName, headerValue) -> { + httpHeaders.set(headerName, headerValue); + }); + HttpEntity request = new HttpEntity<>(message, httpHeaders); return restTemplate.postForObject(url, request, String.class); } diff --git a/src/main/java/com/github/jaemon/dinger/utils/PackageUtils.java b/src/main/java/com/github/jaemon/dinger/utils/PackageUtils.java index a719fbb..cac21d1 100644 --- a/src/main/java/com/github/jaemon/dinger/utils/PackageUtils.java +++ b/src/main/java/com/github/jaemon/dinger/utils/PackageUtils.java @@ -15,9 +15,9 @@ */ package com.github.jaemon.dinger.utils; +import com.github.jaemon.dinger.core.spring.ApplicationHome; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.boot.system.ApplicationHome; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index 30d5c78..0d21228 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -7,6 +7,5 @@ com.github.jaemon.dinger.config.DingerThreadPoolConfig # Application Listeners org.springframework.context.ApplicationListener=\ -com.github.jaemon.dinger.listeners.StartEventListener,\ -com.github.jaemon.dinger.listeners.ExitEventListener,\ -com.github.jaemon.dinger.listeners.DingerXmlPreparedEvent \ No newline at end of file +com.github.jaemon.dinger.listeners.DingerXmlPreparedEvent,\ +com.github.jaemon.dinger.listeners.ExitEventListener diff --git a/src/test/java/com/github/jaemon/dinger/core/OrderDinger.java b/src/test/java/com/github/jaemon/dinger/core/OrderDinger.java index 9f789f3..177856a 100644 --- a/src/test/java/com/github/jaemon/dinger/core/OrderDinger.java +++ b/src/test/java/com/github/jaemon/dinger/core/OrderDinger.java @@ -15,7 +15,6 @@ */ package com.github.jaemon.dinger.core; -import com.dingerframework.core.annatations.*; import com.github.jaemon.dinger.core.annatations.*; import com.github.jaemon.dinger.core.entity.DingerResponse; diff --git a/src/test/java/com/github/jaemon/dinger/core/UserDinger.java b/src/test/java/com/github/jaemon/dinger/core/UserDinger.java index 6fa4008..77edddf 100644 --- a/src/test/java/com/github/jaemon/dinger/core/UserDinger.java +++ b/src/test/java/com/github/jaemon/dinger/core/UserDinger.java @@ -16,6 +16,8 @@ package com.github.jaemon.dinger.core; import com.github.jaemon.dinger.core.annatations.Parameter; +import com.github.jaemon.dinger.core.entity.enums.DingerType; +import com.github.jaemon.dinger.multi.annotations.MultiDinger; import com.github.jaemon.dinger.multi.annotations.MultiHandler; import com.github.jaemon.dinger.core.annatations.DingerMarkdown; import com.github.jaemon.dinger.core.annatations.DingerText; @@ -29,7 +31,9 @@ * @since 1.0 */ // 标识对应的处理器 -@MultiHandler(UserDingerConfigHandler.class) +@MultiHandler( + @MultiDinger(dinger = DingerType.DINGTALK, handler = UserDingerConfigHandler.class) +) public interface UserDinger { /** * 用户注册通知 diff --git a/src/test/java/com/github/jaemon/dinger/httpclient/HttpClientDingTalkTemplate.java b/src/test/java/com/github/jaemon/dinger/httpclient/HttpClientDingTalkTemplate.java new file mode 100644 index 0000000..cff16e5 --- /dev/null +++ b/src/test/java/com/github/jaemon/dinger/httpclient/HttpClientDingTalkTemplate.java @@ -0,0 +1,82 @@ +/* + * Copyright ©2015-2020 Jaemon. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.jaemon.dinger.httpclient; + +import com.github.jaemon.dinger.dingtalk.entity.DingText; +import com.github.jaemon.dinger.dingtalk.entity.Message; +import com.github.jaemon.dinger.support.sign.SignResult; +import com.github.jaemon.dinger.wetalk.entity.WeText; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.client.RestTemplate; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +/** + * HttpClientDingTalkTemplate + * + * @author Jaemon + * @since 1.0 + */ +public class HttpClientDingTalkTemplate { + + public static void main(String[] args) throws Exception { + String tokenId="5ba9b9232rede0e13b87dd6ef90f1fbcfd5e42a81966d1ds441dcec85ddsds10"; + StringBuilder url = new StringBuilder("https://oapi.dingtalk.com/robot/send?access_token="); + String secret = "AEQ520acbce5db4af557323db5af55d41ee780412efg370b1c1a2f66535f6313255"; + Long timestamp = System.currentTimeMillis(); + String sign = algorithm(timestamp, secret); + url.append(tokenId).append("&").append("sign=").append(sign) + .append("&") + .append("timestamp=").append(timestamp); + + DingText dingText = new DingText(new DingText.Text("Hello Dinger")); + dingText.setAt(new Message.At(true)); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity request = new HttpEntity<>(dingText, headers); + + RestTemplate restTemplate = new RestTemplate(); + String response = restTemplate.postForObject(url.toString(), request, String.class); + System.out.println(response); + + } + + private static String algorithm(Long timestamp, String secret) throws Exception { + String stringToSign = timestamp + "\n" + secret; + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init( + new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256") + ); + byte[] signData = mac.doFinal( + stringToSign.getBytes(StandardCharsets.UTF_8) + ); + String sign = URLEncoder.encode( + Base64.getEncoder().encodeToString(signData), + StandardCharsets.UTF_8.name() + ); + return sign; + } +} \ No newline at end of file