diff --git a/README.md b/README.md index 4000f9e..8243078 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Maven Central](https://img.shields.io/maven-central/v/com.github.answerail/dinger-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) -![JDK](https://img.shields.io/badge/JDK-%3E=1.8-green?logo=appveyor) +![JDK](https://img.shields.io/badge/JDK-1.8+-green?logo=appveyor) ![SpringBoot](https://img.shields.io/badge/springboot-1.x%20&%202.x-green?logo=appveyor) diff --git a/pom.xml b/pom.xml index 6ade2cf..e4aff5c 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.github.answerail dinger-spring-boot-starter jar - 1.0.1 + 1.1.0 dinger-spring-boot-starter Dinger-SpringBoot集成钉钉/企业微信群机器人实现消息通知中间件 diff --git a/src/main/java/com/github/jaemon/dinger/DingerSender.java b/src/main/java/com/github/jaemon/dinger/DingerSender.java index f8509c2..24530df 100644 --- a/src/main/java/com/github/jaemon/dinger/DingerSender.java +++ b/src/main/java/com/github/jaemon/dinger/DingerSender.java @@ -31,7 +31,7 @@ public interface DingerSender { /** - * 发送预警消息到钉钉 + * 发送消息到指定群 * *
      *     使用配置的默认钉钉机器人, {@link DingerProperties#getDefaultDinger()}
@@ -47,7 +47,7 @@ public interface DingerSender {
     DingerResponse send(MessageSubType messageSubType, DingerRequest request);
 
     /**
-     * 发送预警消息到钉钉
+     * 发送消息到指定群
      *
      * @param dingerType
      *              Dinger类型 {@link DingerType}
@@ -59,5 +59,4 @@ public interface DingerSender {
      *              响应报文
      * */
     DingerResponse send(DingerType dingerType, MessageSubType messageSubType, DingerRequest request);
-
 }
\ No newline at end of file
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 3863cf7..a9aeb4e 100644
--- a/src/main/java/com/github/jaemon/dinger/core/AbstractDingerDefinitionResolver.java
+++ b/src/main/java/com/github/jaemon/dinger/core/AbstractDingerDefinitionResolver.java
@@ -16,6 +16,8 @@
 package com.github.jaemon.dinger.core;
 
 import com.github.jaemon.dinger.constant.DingerConstant;
+import com.github.jaemon.dinger.core.annatations.DingerImageText;
+import com.github.jaemon.dinger.core.annatations.DingerLink;
 import com.github.jaemon.dinger.core.annatations.DingerScan;
 import com.github.jaemon.dinger.core.annatations.Parameter;
 import com.github.jaemon.dinger.core.entity.enums.DingerDefinitionType;
@@ -36,8 +38,9 @@
 import java.util.List;
 
 import static com.github.jaemon.dinger.core.AbstractDingerDefinitionResolver.Container.INSTANCE;
-import static com.github.jaemon.dinger.core.entity.enums.ExceptionEnum.DINGER_REPEATED_EXCEPTION;
-import static com.github.jaemon.dinger.core.entity.enums.ExceptionEnum.MULTI_DINGER_SCAN_ERROR;
+import static com.github.jaemon.dinger.core.entity.enums.ExceptionEnum.*;
+import static com.github.jaemon.dinger.utils.DingerUtils.methodParamsGenericType;
+import static com.github.jaemon.dinger.utils.DingerUtils.methodParamsType;
 
 /**
  * AbstractDingerDefinitionResolver
@@ -183,21 +186,22 @@ protected List> dingerAnnotationResolver() throws Exception {
      *          dingerDefinitionKey
      * @param dingerConfiguration
      *          Dinger层配置DingerConfig
-     * @param methodParams
-     *          方法参数信息
+     * @param dingerMethod
+     *          方法参数信息和方法中的泛型信息
+     *
      */
     void registerDingerDefinition(
             String dingerName, Object source,
             String dingerDefinitionKey,
             DingerConfig dingerConfiguration,
-            String[] methodParams
+            DingerMethod dingerMethod
     ) {
         boolean debugEnabled = log.isDebugEnabled();
         for (DingerType dingerType : enabledDingerTypes) {
             DingerConfig defaultDingerConfig = defaultDingerConfigs.get(dingerType);
             if (dingerConfiguration == null) {
                 if (debugEnabled) {
-                    log.info("dinger={} not open and skip the corresponding dinger registration.", dingerType);
+                    log.debug("dinger={} not open and skip the corresponding dinger registration.", dingerType);
                 }
                 continue;
             }
@@ -206,7 +210,11 @@ void registerDingerDefinition(
             Class dingerDefinitionGeneratorClass =
                     dingerDefinitionGeneratorMap.get(key);
             if (dingerDefinitionGeneratorClass == null) {
-                throw new DingerException(ExceptionEnum.DINGERDEFINITIONTYPE_UNDEFINED_KEY, key);
+//                throw new DingerException(ExceptionEnum.DINGERDEFINITIONTYPE_UNDEFINED_KEY, key);
+                if (debugEnabled) {
+                    log.debug("当前key=%s在DingerDefinitionType中没定义", key);
+                }
+                continue;
             }
 
             DingerDefinitionGenerator dingerDefinitionGenerator = DingerDefinitionGeneratorFactory.get(
@@ -225,7 +233,12 @@ void registerDingerDefinition(
             if (INSTANCE.contains(keyName)) {
                 throw new DingerException(DINGER_REPEATED_EXCEPTION, keyName);
             }
-            dingerDefinition.setMethodParams(methodParams);
+
+            if (dingerMethod.check()) {
+                throw new DingerException(METHOD_DEFINITION_EXCEPTION, dingerMethod.methodName);
+            }
+            dingerDefinition.setMethodParams(dingerMethod.methodParams);
+            dingerDefinition.setGenericIndex(dingerMethod.paramTypes);
 
             // DingerConfig Priority: `@DingerText | @DingerMarkdown | XML` > `@DingerConfiguration` > `***.yml | ***.properties`
             dingerDefinition.dingerConfig()
@@ -245,15 +258,28 @@ void registerDingerDefinition(
      * @param dingerClass
      *          Dinger接口层类
      * @return
-     *          当前Dinger接口定义的方法的参数信息
+     *          当前Dinger接口定义的方法的参数信息和泛型信息
      */
-    protected Map dingerClassMethods(Class dingerClass) {
-        Method[] declaredMethods = dingerClass.getDeclaredMethods();
-        Map dingerMethodParams = new HashMap<>();
-        for (Method declaredMethod : declaredMethods) {
-            String methodName = declaredMethod.getName();
-            String[] methodParams = methodParams(declaredMethod);
-            dingerMethodParams.put(methodName, methodParams);
+    protected Map dingerClassMethods(Class dingerClass) {
+        Method[] methods = dingerClass.getMethods();
+        Map dingerMethodParams = new HashMap<>();
+        for (Method method : methods) {
+            String methodName = method.getName();
+            String methodAllName = dingerClass.getSimpleName() + DingerConstant.SPOT_SEPERATOR + methodName;
+            int[] paramTypes = null;
+            if (method.isAnnotationPresent(DingerImageText.class)) {
+                paramTypes = methodParamsGenericType(method, DingerImageText.clazz);
+                if (paramTypes.length != 1) {
+                    throw new DingerException(IMAGETEXT_METHOD_PARAM_EXCEPTION, methodAllName);
+                }
+            } else if (method.isAnnotationPresent(DingerLink.class)) {
+                paramTypes = methodParamsType(method, DingerLink.clazz);
+                if (paramTypes.length != 1) {
+                    throw new DingerException(LINK_METHOD_PARAM_EXCEPTION, methodAllName);
+                }
+            }
+            String[] methodParams = methodParams(method);
+            dingerMethodParams.put(methodName, new DingerMethod(methodAllName, methodParams, paramTypes));
         }
         return dingerMethodParams;
     }
@@ -285,6 +311,33 @@ protected String[] methodParams(Method method) {
         return params;
     }
 
+    static class DingerMethod {
+        String methodName;
+        String[] methodParams;
+        int[] paramTypes;
+
+        public DingerMethod(String methodName, String[] methodParams, int[] paramTypes) {
+            this.methodName = methodName;
+            this.methodParams = methodParams;
+            this.paramTypes = paramTypes;
+        }
+
+        boolean check() {
+            if (paramTypes == null) {
+                return false;
+            }
+
+            int length = this.methodParams.length;
+            for (int index : paramTypes) {
+                if (index >= length) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+    }
+
     /**
      * Container for DingerDefinition
      */
@@ -293,7 +346,7 @@ protected enum Container {
         private Map container;
 
         Container() {
-            this.container = new HashMap<>(256);
+            this.container = new HashMap<>(128);
         }
 
         /**
diff --git a/src/main/java/com/github/jaemon/dinger/core/DefaultDingerDefinition.java b/src/main/java/com/github/jaemon/dinger/core/DefaultDingerDefinition.java
index ac06cff..3dc4bb3 100644
--- a/src/main/java/com/github/jaemon/dinger/core/DefaultDingerDefinition.java
+++ b/src/main/java/com/github/jaemon/dinger/core/DefaultDingerDefinition.java
@@ -35,7 +35,10 @@ public class DefaultDingerDefinition implements DingerDefinition {
     private DingerType dingerType;
     private MessageMainType messageMainType;
     private MessageSubType messageSubType;
+    /** dinger方法的参数信息 */
     private String[] methodParams;
+    /** dinger方法的泛型信息 */
+    private int[] genericIndex;
 
     @Override
     public String dingerName() {
@@ -110,11 +113,29 @@ public void setMessageSubType(MessageSubType messageSubType) {
 
     @Override
     public String[] methodParams() {
-        return methodParams == null ? new String[0] : methodParams;
+        return methodParams;
     }
 
     @Override
     public void setMethodParams(String[] methodParams) {
+        if (methodParams == null) {
+            this.methodParams = new String[0];
+            return;
+        }
         this.methodParams = methodParams;
     }
+
+    @Override
+    public int[] genericIndex() {
+        return genericIndex;
+    }
+
+    @Override
+    public void setGenericIndex(int[] genericIndex) {
+        if (genericIndex == null) {
+            this.genericIndex = new int[0];
+            return;
+        }
+        this.genericIndex = genericIndex;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/core/DingerDefinition.java b/src/main/java/com/github/jaemon/dinger/core/DingerDefinition.java
index 7a209ff..892cc9f 100644
--- a/src/main/java/com/github/jaemon/dinger/core/DingerDefinition.java
+++ b/src/main/java/com/github/jaemon/dinger/core/DingerDefinition.java
@@ -146,4 +146,20 @@ public interface DingerDefinition {
      */
     void setMethodParams(String[] methodParams);
 
+    /**
+     * genericIndex
+     *
+     * @return
+     *      genericIndex
+     */
+    int[] genericIndex();
+
+    /**
+     * setGenericIndex
+     *
+     * @param genericIndex
+     *          genericIndex
+     */
+    void setGenericIndex(int[] genericIndex);
+
 }
\ 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 70f1eb0..42f1a43 100644
--- a/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionHandler.java
+++ b/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionHandler.java
@@ -15,9 +15,7 @@
  */
 package com.github.jaemon.dinger.core;
 
-import com.github.jaemon.dinger.core.annatations.DingerTokenId;
-import com.github.jaemon.dinger.core.annatations.DingerMarkdown;
-import com.github.jaemon.dinger.core.annatations.DingerText;
+import com.github.jaemon.dinger.core.annatations.*;
 import com.github.jaemon.dinger.core.entity.DingerRequest;
 import com.github.jaemon.dinger.core.entity.MsgType;
 import com.github.jaemon.dinger.core.entity.enums.*;
@@ -105,6 +103,52 @@ protected static DingerDefinition dingerMarkdownHandler(DingerType dingerType, D
         return dingerDefinition;
     }
 
+    /**
+     * 处理注解-ImageText定义的Dinger消息
+     *
+     * @param dingerType
+     *          Dinger类型 {@link DingerType}
+     * @param context
+     *          Dinger定义源
+     * @return
+     *          dingerDefinition {@link DingerDefinition}
+     */
+    protected static DingerDefinition dingerImageTextHandler(DingerType dingerType, DingerDefinitionGeneratorContext context) {
+        String keyName = context.getKeyName();
+        DingerImageText dinger = context.getSource();
+        DingerDefinition dingerDefinition = annotationDingerDefition(keyName, dinger.tokenId(), dinger.asyncExecute());
+        dingerDefinition.setDingerType(dingerType);
+        dingerDefinition.setMessageSubType(MessageSubType.IMAGETEXT);
+
+        MsgType msgType = dingerDefinition.messageSubType().msgType(dingerType, null);
+        dingerDefinition.setMessage(msgType);
+
+        return dingerDefinition;
+    }
+
+    /**
+     * 处理注解-Link定义的Dinger消息
+     *
+     * @param dingerType
+     *          Dinger类型 {@link DingerType}
+     * @param context
+     *          Dinger定义源
+     * @return
+     *          dingerDefinition {@link DingerDefinition}
+     */
+    protected static DingerDefinition dingerLinkHandler(DingerType dingerType, DingerDefinitionGeneratorContext context) {
+        String keyName = context.getKeyName();
+        DingerLink dinger = context.getSource();
+        DingerDefinition dingerDefinition = annotationDingerDefition(keyName, dinger.tokenId(), dinger.asyncExecute());
+        dingerDefinition.setDingerType(dingerType);
+        dingerDefinition.setMessageSubType(MessageSubType.LINK);
+
+        MsgType msgType = dingerDefinition.messageSubType().msgType(dingerType, null);
+        dingerDefinition.setMessage(msgType);
+
+        return dingerDefinition;
+    }
+
 
     /**
      * 处理Xml定义的Dinger消息
@@ -141,30 +185,32 @@ protected static DingerDefinition xmlHandler(
         Optional configuration = Optional.ofNullable(messageTag.getConfiguration());
         dingerConfig(dingerConfig, configuration);
 
-        Optional body = Optional.ofNullable(messageTag.getBody());
+        DingerRequest request = null;
+        if (dingerDefinitionType.messageSubType().isSupport()) {
+            Optional body = Optional.ofNullable(messageTag.getBody());
 
-        // 处理@成员逻辑
-        Optional phonesTag = body.map(e -> e.getPhones());
-        Boolean atAll = phonesTag.map(e -> e.getAtAll()).orElse(false);
+            // 处理@成员逻辑
+            Optional phonesTag = body.map(e -> e.getPhones());
+            Boolean atAll = phonesTag.map(e -> e.getAtAll()).orElse(false);
 
-        List phoneTags = phonesTag.map(e -> e.getPhones()).orElse(null);
-        List phones;
-        if (phoneTags != null) {
-            phones = phoneTags.stream().map(PhoneTag::getValue).collect(Collectors.toList());
-        } else {
-            phones = new ArrayList<>();
-        }
+            List phoneTags = phonesTag.map(e -> e.getPhones()).orElse(null);
+            List phones;
+            if (phoneTags != null) {
+                phones = phoneTags.stream().map(PhoneTag::getValue).collect(Collectors.toList());
+            } else {
+                phones = new ArrayList<>();
+            }
 
-        // 处理消息体逻辑
-        Optional contentTag = body.map(e -> e.getContent());
-        String content = contentTag.map(e -> e.getContent()).orElse("");
-        String title = contentTag.map(e -> e.getTitle()).orElse("Dinger Title");
+            // 处理消息体逻辑
+            Optional contentTag = body.map(e -> e.getContent());
+            String content = contentTag.map(e -> e.getContent()).orElse("");
+            String title = contentTag.map(e -> e.getTitle()).orElse("Dinger Title");
 
-        DingerRequest request;
-        if (atAll) {
-            request = DingerRequest.request(content, title, true);
-        } else {
-            request = DingerRequest.request(content, title, phones);
+            if (atAll) {
+                request = DingerRequest.request(content, title, true);
+            } else {
+                request = DingerRequest.request(content, title, phones);
+            }
         }
 
         MsgType message = dingerDefinitionType.messageSubType().msgType(dingerDefinitionType.dingerType(), request);
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 54cc284..2046aeb 100644
--- a/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionResolver.java
+++ b/src/main/java/com/github/jaemon/dinger/core/DingerDefinitionResolver.java
@@ -16,10 +16,7 @@
 package com.github.jaemon.dinger.core;
 
 import com.github.jaemon.dinger.constant.DingerConstant;
-import com.github.jaemon.dinger.core.annatations.AsyncExecute;
-import com.github.jaemon.dinger.core.annatations.DingerConfiguration;
-import com.github.jaemon.dinger.core.annatations.DingerMarkdown;
-import com.github.jaemon.dinger.core.annatations.DingerText;
+import com.github.jaemon.dinger.core.annatations.*;
 import com.github.jaemon.dinger.core.entity.enums.MessageMainType;
 import com.github.jaemon.dinger.core.entity.enums.MessageSubType;
 import com.github.jaemon.dinger.core.entity.xml.BeanTag;
@@ -39,6 +36,8 @@
 
 import static com.github.jaemon.dinger.constant.DingerConstant.SPOT_SEPERATOR;
 import static com.github.jaemon.dinger.core.entity.enums.ExceptionEnum.*;
+import static com.github.jaemon.dinger.utils.DingerUtils.methodParamsGenericType;
+import static com.github.jaemon.dinger.utils.DingerUtils.methodParamsType;
 
 /**
  * DingerDefinitionResolver
@@ -104,7 +103,7 @@ void analysisDingerXml(Resource[] resources) throws Exception {
             if (dingerClass == null) {
                 throw new DingerException(DINER_XML_NAMESPACE_INVALID, namespace);
             }
-            Map dingerClassMethods = dingerClassMethods(dingerClass);
+            Map dingerClassMethods = dingerClassMethods(dingerClass);
 
             DingerConfig dingerConfiguration = dingerConfiguration(dingerClass);
 
@@ -147,25 +146,42 @@ void analysisDingerAnnotation(List> dingerClasses) throws Exception {
                 String dingerName = namespace + SPOT_SEPERATOR + method.getName();
                 String dingerDefinitionKey = MessageMainType.ANNOTATION + SPOT_SEPERATOR;
 
+                Object source;
+                MessageSubType messageSubType;
+                int[] paramTypes = null;
                 if (method.isAnnotationPresent(DingerText.class)) {
-                    registerDingerDefinition(
-                            dingerName, method.getAnnotation(DingerText.class),
-                            dingerDefinitionKey + MessageSubType.TEXT,
-                            dingerConfiguration,
-                            methodParams(method)
-                    );
+                    source = method.getAnnotation(DingerText.class);
+                    messageSubType = MessageSubType.TEXT;
                 } else if (method.isAnnotationPresent(DingerMarkdown.class)) {
-                    registerDingerDefinition(
-                            dingerName, method.getAnnotation(DingerMarkdown.class),
-                            dingerDefinitionKey + MessageSubType.MARKDOWN,
-                            dingerConfiguration,
-                            methodParams(method)
-                    );
+                    source = method.getAnnotation(DingerMarkdown.class);
+                    messageSubType = MessageSubType.MARKDOWN;
+                } else if (method.isAnnotationPresent(DingerImageText.class)) {
+                    paramTypes = methodParamsGenericType(method, DingerImageText.clazz);
+                    if (paramTypes.length != 1) {
+                        throw new DingerException(IMAGETEXT_METHOD_PARAM_EXCEPTION, dingerName);
+                    }
+                    source = method.getAnnotation(DingerImageText.class);
+                    messageSubType = MessageSubType.IMAGETEXT;
+                } else if (method.isAnnotationPresent(DingerLink.class)) {
+                    paramTypes = methodParamsType(method, DingerLink.clazz);
+                    if (paramTypes.length != 1) {
+                        throw new DingerException(LINK_METHOD_PARAM_EXCEPTION, dingerName);
+                    }
+                    source = method.getAnnotation(DingerLink.class);
+                    messageSubType = MessageSubType.LINK;
                 } else {
                     if (log.isDebugEnabled()) {
                         log.debug("register annotation dingerDefinition and skip method={}(possible use xml definition).", dingerName);
                     }
+                    continue;
                 }
+
+                registerDingerDefinition(
+                        dingerName, source,
+                        dingerDefinitionKey + messageSubType,
+                        dingerConfiguration,
+                        new DingerMethod(dingerName, methodParams(method), paramTypes)
+                );
             }
 
         }
diff --git a/src/main/java/com/github/jaemon/dinger/core/DingerHandleProxy.java b/src/main/java/com/github/jaemon/dinger/core/DingerHandleProxy.java
index edb2e5a..376cae3 100644
--- a/src/main/java/com/github/jaemon/dinger/core/DingerHandleProxy.java
+++ b/src/main/java/com/github/jaemon/dinger/core/DingerHandleProxy.java
@@ -18,6 +18,7 @@
 import com.github.jaemon.dinger.core.annatations.DingerClose;
 import com.github.jaemon.dinger.core.entity.DingerProperties;
 import com.github.jaemon.dinger.core.entity.MsgType;
+import com.github.jaemon.dinger.core.entity.enums.DingerResponseCodeEnum;
 import com.github.jaemon.dinger.core.entity.enums.DingerType;
 import com.github.jaemon.dinger.core.entity.DingerResponse;
 import org.slf4j.Logger;
@@ -70,16 +71,21 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
             DingerDefinition dingerDefinition = dingerDefinition(
                     useDinger, dingerClassName, keyName
             );
-            if (dingerDefinition == null) {
-                return null;
-            }
 
-            // method params map
-            Map params = paramsHandler(method, dingerDefinition.methodParams(), args);
+            DingerResponse dingerResponse;
+            if (dingerDefinition == null) {
+//                log.warn("method {} does not support dinger {}。", keyName, useDinger);
+                dingerResponse = DingerResponse.failed(
+                        DingerResponseCodeEnum.MESSAGE_TYPE_UNSUPPORTED,
+                        String.format("method %s does not support dinger %s.", keyName, useDinger));
+            } else {
+                // method params map
+                Map params = paramsHandler(method, dingerDefinition, args);
 
-            MsgType message = transfer(dingerDefinition, params);
+                MsgType message = transfer(dingerDefinition, params);
 
-            DingerResponse dingerResponse = dingerRobot.send(message);
+                dingerResponse = dingerRobot.send(message);
+            }
 
             // return...
             return resultHandler(method.getReturnType(), dingerResponse);
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 49dd16c..8974069 100644
--- a/src/main/java/com/github/jaemon/dinger/core/DingerMessageHandler.java
+++ b/src/main/java/com/github/jaemon/dinger/core/DingerMessageHandler.java
@@ -54,12 +54,23 @@ public class DingerMessageHandler
     protected DingerProperties dingerProperties;
 
     @Override
-    public Map paramsHandler(Method method, String[] keys, Object[] values) {
+    public Map paramsHandler(Method method, DingerDefinition dingerDefinition, Object[] values) {
         Map params = new HashMap<>();
         int valueLength = values.length;
         if (valueLength == 0) {
             return params;
         }
+
+        String[] keys = dingerDefinition.methodParams();
+        int[] genericIndex = dingerDefinition.genericIndex();
+        if (genericIndex.length > 0) {
+            for (int i : genericIndex) {
+                params.put(keys[i], values[i]);
+            }
+
+            return params;
+        }
+
         int keyLength = keys.length;
         if (keyLength == valueLength) {
             for (int i = 0; i < valueLength; i++) {
@@ -175,7 +186,6 @@ DingerDefinition dingerDefinition(DingerType useDinger, String dingerClassName,
                     .Container.INSTANCE.get(dingerName);
 
             if (dingerDefinition == null) {
-                log.warn("{} there is no corresponding dinger message config", dingerName);
                 return null;
             }
             DingerConfig dingerMethodDefaultDingerConfig = dingerDefinition.dingerConfig();
@@ -215,7 +225,6 @@ DingerDefinition dingerDefinition(DingerType useDinger, String dingerClassName,
                     .Container.INSTANCE.get(keyName);
 
             if (dingerDefinition == null) {
-                log.warn("{} there is no corresponding dinger message config", keyName);
                 return null;
             }
         }
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 69ff7dc..4d7853f 100644
--- a/src/main/java/com/github/jaemon/dinger/core/DingerRobot.java
+++ b/src/main/java/com/github/jaemon/dinger/core/DingerRobot.java
@@ -31,7 +31,6 @@
 import org.springframework.beans.BeanUtils;
 
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 
@@ -54,6 +53,9 @@ public DingerResponse send(MessageSubType messageSubType, DingerRequest request)
 
     @Override
     public DingerResponse send(DingerType dingerType, MessageSubType messageSubType, DingerRequest request) {
+        if (!messageSubType.isSupport()) {
+            return DingerResponse.failed(DingerResponseCodeEnum.MESSAGE_TYPE_UNSUPPORTED);
+        }
         CustomMessage customMessage = customMessage(messageSubType);
         String msgContent = customMessage.message(
                 dingerProperties.getProjectId(), request
@@ -86,7 +88,7 @@ protected  DingerResponse send(T message) {
                                 dingers.containsKey(dingerType)
                 )
         ) {
-            return DingerResponse.failed(DingerResponseCodeEnum.DINGER_DISABLED, dkid);
+            return DingerResponse.failed(dkid, DingerResponseCodeEnum.DINGER_DISABLED);
         }
 
         DingerConfig localDinger = getLocalDinger();
@@ -141,7 +143,7 @@ protected  DingerResponse send(T message) {
             return DingerResponse.success(dkid, response);
         } catch (Exception e) {
             exceptionCallback(dkid, message, new SendMsgException(e));
-            return DingerResponse.failed(DingerResponseCodeEnum.SEND_MESSAGE_FAILED, dkid);
+            return DingerResponse.failed(dkid, DingerResponseCodeEnum.SEND_MESSAGE_FAILED);
         }
     }
 
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 ddd89fe..e44a72a 100644
--- a/src/main/java/com/github/jaemon/dinger/core/ParamHandler.java
+++ b/src/main/java/com/github/jaemon/dinger/core/ParamHandler.java
@@ -31,13 +31,13 @@ public interface ParamHandler {
      *
      * @param method
      *          执行方法
-     * @param parameters
-     *          Dinger方法形参集
+     * @param dingerDefinition
+     *          Dinger定义
      * @param values
      *          Dinger方法实参
      * @return
      *          形参和实参的映射关系
      */
-    Map paramsHandler(Method method, String[] parameters, Object[] values);
+    Map paramsHandler(Method method, DingerDefinition dingerDefinition, Object[] values);
 
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/core/annatations/DingerImageText.java b/src/main/java/com/github/jaemon/dinger/core/annatations/DingerImageText.java
new file mode 100644
index 0000000..251939a
--- /dev/null
+++ b/src/main/java/com/github/jaemon/dinger/core/annatations/DingerImageText.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright ©2015-2021 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.annatations;
+
+import com.github.jaemon.dinger.core.entity.ImageTextDeo;
+import com.github.jaemon.dinger.core.entity.enums.AsyncExecuteType;
+
+import java.lang.annotation.*;
+
+/**
+ * DingerImageText
+ *
+ *  @author Jaemon
+ * @since 1.0
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Documented
+public @interface DingerImageText {
+    /**
+     * tokenId
+     *
+     * @return token info
+     */
+    DingerTokenId tokenId() default @DingerTokenId("");
+
+    /**
+     * asyncExecute
+     *
+     * @return async execute send
+     */
+    AsyncExecuteType asyncExecute() default AsyncExecuteType.NONE;
+
+    Class clazz = ImageTextDeo.class;
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/core/annatations/DingerLink.java b/src/main/java/com/github/jaemon/dinger/core/annatations/DingerLink.java
new file mode 100644
index 0000000..c0dc5ad
--- /dev/null
+++ b/src/main/java/com/github/jaemon/dinger/core/annatations/DingerLink.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright ©2015-2021 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.annatations;
+
+import com.github.jaemon.dinger.core.entity.LinkDeo;
+import com.github.jaemon.dinger.core.entity.enums.AsyncExecuteType;
+
+import java.lang.annotation.*;
+
+/**
+ * DingerLink(仅限DingTalk {@link com.github.jaemon.dinger.core.entity.enums.DingerType#DINGTALK})
+ *
+ *  @author Jaemon
+ * @since 1.0
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Documented
+public @interface DingerLink {
+    /**
+     * tokenId
+     *
+     * @return token info
+     */
+    DingerTokenId tokenId() default @DingerTokenId("");
+
+    /**
+     * asyncExecute
+     *
+     * @return async execute send
+     */
+    AsyncExecuteType asyncExecute() default AsyncExecuteType.NONE;
+
+    Class clazz = LinkDeo.class;
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/DingerResponse.java b/src/main/java/com/github/jaemon/dinger/core/entity/DingerResponse.java
index 523524a..6f54ba8 100644
--- a/src/main/java/com/github/jaemon/dinger/core/entity/DingerResponse.java
+++ b/src/main/java/com/github/jaemon/dinger/core/entity/DingerResponse.java
@@ -41,16 +41,24 @@ public class DingerResponse {
      */
     private String data;
 
-    private DingerResponse(DingerResponseCodeEnum resultCode, String logid) {
+
+    private DingerResponse(DingerResponseCodeEnum resultCode) {
         this.code = resultCode.code();
         this.message = resultCode.message();
+    }
+
+    private DingerResponse(String logid, DingerResponseCodeEnum resultCode) {
+        this(resultCode);
         this.logid = logid;
     }
 
+    private DingerResponse(DingerResponseCodeEnum resultCode, String data) {
+        this(resultCode);
+        this.data = data;
+    }
+
     private DingerResponse(DingerResponseCodeEnum resultCode, String logid, String data) {
-        this.code = resultCode.code();
-        this.message = resultCode.message();
-        this.logid = logid;
+        this(logid, resultCode);
         this.data = data;
     }
 
@@ -63,11 +71,19 @@ public static  DingerResponse success(DingerResponseCodeEnum resultCode, Stri
     }
 
     public static DingerResponse failed(String logid) {
-        return new DingerResponse(DingerResponseCodeEnum.FAILED, logid);
+        return new DingerResponse(logid, DingerResponseCodeEnum.FAILED);
+    }
+
+    public static DingerResponse failed(String logid, DingerResponseCodeEnum resultCode) {
+        return new DingerResponse(logid, resultCode);
+    }
+
+    public static DingerResponse failed(DingerResponseCodeEnum resultCode, String data) {
+        return new DingerResponse(resultCode, data);
     }
 
-    public static DingerResponse failed(DingerResponseCodeEnum resultCode, String logid) {
-        return new DingerResponse(resultCode, logid);
+    public static DingerResponse failed(DingerResponseCodeEnum resultCode) {
+        return new DingerResponse(resultCode);
     }
 
     public String getCode() {
diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/ImageTextDeo.java b/src/main/java/com/github/jaemon/dinger/core/entity/ImageTextDeo.java
new file mode 100644
index 0000000..c0c0cf6
--- /dev/null
+++ b/src/main/java/com/github/jaemon/dinger/core/entity/ImageTextDeo.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright ©2015-2021 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;
+
+/**
+ * Dinger图文类型实体
+ *
+ * @author Jaemon
+ * @since 1.0
+ */
+public class ImageTextDeo {
+    /** 标题 */
+    private String title;
+    /** 描述-仅限Wetalk */
+    private String description;
+    /** title点击链接地址 */
+    private String url;
+    /** 图片地址 */
+    private String picUrl;
+
+    private ImageTextDeo(String title, String url, String picUrl) {
+        this.title = title;
+        this.url = url;
+        this.picUrl = picUrl;
+    }
+
+    private ImageTextDeo(String title, String description, String url, String picUrl) {
+        this(title, url, picUrl);
+        this.description = description;
+    }
+
+    public static ImageTextDeo instance(String title, String url, String picUrl) {
+        return new ImageTextDeo(title, url, picUrl);
+    }
+
+    public static ImageTextDeo instance(String title, String description, String url, String picUrl) {
+        return new ImageTextDeo(title, description, url, picUrl);
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getPicUrl() {
+        return picUrl;
+    }
+
+    public void setPicUrl(String picUrl) {
+        this.picUrl = picUrl;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/LinkDeo.java b/src/main/java/com/github/jaemon/dinger/core/entity/LinkDeo.java
new file mode 100644
index 0000000..5419d1f
--- /dev/null
+++ b/src/main/java/com/github/jaemon/dinger/core/entity/LinkDeo.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright ©2015-2021 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;
+
+/**
+ * Dinger图文类型实体对象
+ *
+ * @author Jaemon
+ * @since 1.0
+ */
+public class LinkDeo {
+    /** 消息标题 */
+    private String title;
+    /** 消息内容。如果太长只会部分展示 */
+    private String text;
+    /** 点击消息跳转的URL */
+    private String messageUrl;
+    /** 图片URL */
+    private String picUrl;
+
+    private LinkDeo(String title, String text, String messageUrl, String picUrl) {
+        this.title = title;
+        this.text = text;
+        this.messageUrl = messageUrl;
+        this.picUrl = picUrl;
+    }
+
+    public static LinkDeo instance(String title, String text, String messageUrl, String picUrl) {
+        return new LinkDeo(title, text, messageUrl, picUrl);
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public String getMessageUrl() {
+        return messageUrl;
+    }
+
+    public void setMessageUrl(String messageUrl) {
+        this.messageUrl = messageUrl;
+    }
+
+    public String getPicUrl() {
+        return picUrl;
+    }
+
+    public void setPicUrl(String picUrl) {
+        this.picUrl = picUrl;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/core/entity/enums/DingerDefinitionType.java b/src/main/java/com/github/jaemon/dinger/core/entity/enums/DingerDefinitionType.java
index 987d243..cc6c732 100644
--- a/src/main/java/com/github/jaemon/dinger/core/entity/enums/DingerDefinitionType.java
+++ b/src/main/java/com/github/jaemon/dinger/core/entity/enums/DingerDefinitionType.java
@@ -43,6 +43,24 @@ public enum DingerDefinitionType {
             DingerType.DINGTALK, MessageMainType.ANNOTATION, MessageSubType.MARKDOWN, DingTalkDefinitionGenerator.AnnotationMarkdown.class
     ),
 
+    DINGTALK_XML_IMAGETEXT(
+            DingerType.DINGTALK, MessageMainType.XML, MessageSubType.IMAGETEXT, DingTalkDefinitionGenerator.XmlImageText.class
+    ),
+
+    DINGTALK_ANNOTATION_IMAGETEXT(
+            DingerType.DINGTALK, MessageMainType.ANNOTATION, MessageSubType.IMAGETEXT, DingTalkDefinitionGenerator.AnnotationImageText.class
+    ),
+
+    DINGTALK_XML_LINK(
+            DingerType.DINGTALK, MessageMainType.XML, MessageSubType.LINK, DingTalkDefinitionGenerator.XmlLink.class
+    ),
+
+    DINGTALK_ANNOTATION_LINK(
+            DingerType.DINGTALK, MessageMainType.ANNOTATION, MessageSubType.LINK, DingTalkDefinitionGenerator.AnnotationLink.class
+    ),
+
+
+
     /** 企业微信机器人消息类型 */
     WETALK_XML_TEXT(
             DingerType.WETALK, MessageMainType.XML, MessageSubType.TEXT, WeTalkDefinitionGenerator.XmlText.class
@@ -55,7 +73,15 @@ public enum DingerDefinitionType {
     ),
     WETALK_ANNOTATION_MARKDOWN(
             DingerType.WETALK, MessageMainType.ANNOTATION, MessageSubType.MARKDOWN, WeTalkDefinitionGenerator.AnnotationMarkDown.class
-    )
+    ),
+
+    WETALK_XML_IMAGETEXT(
+            DingerType.WETALK, MessageMainType.XML, MessageSubType.IMAGETEXT, WeTalkDefinitionGenerator.XmlImageText.class
+    ),
+
+    WETALK_ANNOTATION_IMAGETEXT(
+            DingerType.WETALK, MessageMainType.ANNOTATION, MessageSubType.IMAGETEXT, WeTalkDefinitionGenerator.AnnotationImageText.class
+    ),
 
     ;
     public static final DingerDefinitionType[] dingerDefinitionTypes = values();
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 22044b5..ecb6a84 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
@@ -76,9 +76,13 @@ public enum ExceptionEnum implements ExceptionPairs {
 
 
     /** Dinger解析公共相关异常, 65XX */
-    /** 注定DingerText和Dinger xml重复配置也会抛出该异常 */
+    /** 注解DingerText和Dinger xml重复配置也会抛出该异常 */
     DINGER_REPEATED_EXCEPTION(6500, "重复的DingerId=%s对象"),
     DINGERDEFINITIONTYPE_UNDEFINED_KEY(6501, "当前key=%s在DingerDefinitionType中没定义"),
+    IMAGETEXT_METHOD_PARAM_EXCEPTION(6502, "方法%s的参数不符合图文消息定义规范"),
+    METHOD_DEFINITION_EXCEPTION(6503, "方法%s定义不符合规范"),
+    LINK_METHOD_PARAM_EXCEPTION(6504, "方法%s的参数不符合Link消息定义规范"),
+    DINGER_UNSUPPORT_MESSAGE_TYPE_EXCEPTION(6505, "Dinger[%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 f1789e2..79dd9a2 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
@@ -16,18 +16,20 @@
 package com.github.jaemon.dinger.core.entity.enums;
 
 import com.github.jaemon.dinger.core.entity.DingerRequest;
-import com.github.jaemon.dinger.dingtalk.entity.DingMarkDown;
-import com.github.jaemon.dinger.dingtalk.entity.DingText;
+import com.github.jaemon.dinger.dingtalk.entity.*;
 import com.github.jaemon.dinger.core.entity.MsgType;
-import com.github.jaemon.dinger.dingtalk.entity.Message;
+import com.github.jaemon.dinger.exception.DingerException;
 import com.github.jaemon.dinger.wetalk.entity.WeMarkdown;
+import com.github.jaemon.dinger.wetalk.entity.WeNews;
 import com.github.jaemon.dinger.wetalk.entity.WeText;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
 import static com.github.jaemon.dinger.core.DingerDefinitionHandler.WETALK_AT_ALL;
+import static com.github.jaemon.dinger.core.entity.enums.ExceptionEnum.DINGER_UNSUPPORT_MESSAGE_TYPE_EXCEPTION;
 
 /**
  * 消息体定义子类型
@@ -36,7 +38,8 @@
  * @since 1.0
  */
 public enum MessageSubType {
-    TEXT {
+    /** Text类型 */
+    TEXT(true) {
         @Override
         public MsgType msgType(DingerType dingerType, DingerRequest request) {
             String content = request.getContent();
@@ -65,7 +68,8 @@ public MsgType msgType(DingerType dingerType, DingerRequest request) {
         }
     },
 
-    MARKDOWN {
+    /** Markdown类型 */
+    MARKDOWN(true) {
         @Override
         public MsgType msgType(DingerType dingerType, DingerRequest request) {
             String content = request.getContent();
@@ -85,11 +89,43 @@ public MsgType msgType(DingerType dingerType, DingerRequest request) {
                 return weMarkdown;
             }
         }
+    },
+
+    /** 图文类型 */
+    IMAGETEXT(false) {
+        @Override
+        public MsgType msgType(DingerType dingerType, DingerRequest request) {
+            if (dingerType == DingerType.DINGTALK) {
+                return new DingFeedCard(new ArrayList<>());
+            } else {
+                return new WeNews(new ArrayList<>());
+            }
+        }
+    },
+
+    /** link类型, 只支持 {@link DingerType#DINGTALK} */
+    LINK(false) {
+        @Override
+        public MsgType msgType(DingerType dingerType, DingerRequest request) {
+            if (dingerType == DingerType.DINGTALK) {
+                return new DingLink();
+            } else {
+                throw new DingerException(DINGER_UNSUPPORT_MESSAGE_TYPE_EXCEPTION, dingerType, this.name());
+            }
+        }
     }
 
     ;
 
-    MessageSubType() {
+    /** 是否支持显示设置消息子类型调用 */
+    private boolean support;
+
+    MessageSubType(boolean support) {
+        this.support = support;
+    }
+
+    public boolean isSupport() {
+        return support;
     }
 
     /**
diff --git a/src/main/java/com/github/jaemon/dinger/dingtalk/DingTalkDefinitionGenerator.java b/src/main/java/com/github/jaemon/dinger/dingtalk/DingTalkDefinitionGenerator.java
index 74b7423..71ed7d6 100644
--- a/src/main/java/com/github/jaemon/dinger/dingtalk/DingTalkDefinitionGenerator.java
+++ b/src/main/java/com/github/jaemon/dinger/dingtalk/DingTalkDefinitionGenerator.java
@@ -19,6 +19,8 @@
 import com.github.jaemon.dinger.core.DingerDefinitionGenerator;
 import com.github.jaemon.dinger.core.DingerDefinitionGeneratorContext;
 import com.github.jaemon.dinger.core.DingerDefinitionHandler;
+import com.github.jaemon.dinger.core.annatations.DingerImageText;
+import com.github.jaemon.dinger.core.annatations.DingerLink;
 import com.github.jaemon.dinger.core.entity.enums.DingerType;
 import com.github.jaemon.dinger.core.entity.xml.MessageTag;
 import com.github.jaemon.dinger.core.annatations.DingerMarkdown;
@@ -43,9 +45,7 @@ public static class AnotationText extends DingerDefinitionGenerator
 
         @Override
         public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
-            DingerDefinition dingerDefinition = dingerTextHandler(DingerType.DINGTALK, context);
-
-            return dingerDefinition;
+            return dingerTextHandler(DingerType.DINGTALK, context);
         }
     }
 
@@ -56,9 +56,7 @@ public DingerDefinition generator(DingerDefinitionGeneratorContext c
     public static class AnnotationMarkdown extends DingerDefinitionGenerator {
         @Override
         public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
-            DingerDefinition dingerDefinition = dingerMarkdownHandler(DingerType.DINGTALK, context);
-
-            return dingerDefinition;
+            return dingerMarkdownHandler(DingerType.DINGTALK, context);
         }
     }
 
@@ -70,9 +68,7 @@ public static class XmlText extends DingerDefinitionGenerator {
 
         @Override
         public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
-            DingerDefinition dingerDefinition = xmlHandler(DingerDefinitionType.DINGTALK_XML_TEXT, context);
-
-            return dingerDefinition;
+            return xmlHandler(DingerDefinitionType.DINGTALK_XML_TEXT, context);
         }
     }
 
@@ -83,11 +79,51 @@ public DingerDefinition generator(DingerDefinitionGeneratorContext c
     public static class XmlMarkdown extends DingerDefinitionGenerator {
         @Override
         public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
-            DingerDefinition dingerDefinition = xmlHandler(DingerDefinitionType.DINGTALK_XML_MARKDOWN, context);
+            return xmlHandler(DingerDefinitionType.DINGTALK_XML_MARKDOWN, context);
+        }
+    }
+
+
+    /**
+     * 生成注解 ImageText消息体定义
+     */
+    public static class AnnotationImageText extends DingerDefinitionGenerator {
+        @Override
+        public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
+            return dingerImageTextHandler(DingerType.DINGTALK, context);
+        }
+    }
+
+
+    /**
+     * 生成XML ImageText消息体定义
+     */
+    public static class XmlImageText extends DingerDefinitionGenerator {
+        @Override
+        public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
+            return xmlHandler(DingerDefinitionType.DINGTALK_XML_IMAGETEXT, context);
+        }
+    }
+
 
-            return dingerDefinition;
+    /**
+     * 生成注解 Link消息体定义
+     */
+    public static class AnnotationLink extends DingerDefinitionGenerator {
+        @Override
+        public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
+            return dingerLinkHandler(DingerType.DINGTALK, context);
         }
     }
 
 
+    /**
+     * 生成XML Link消息体定义
+     */
+    public static class XmlLink extends DingerDefinitionGenerator {
+        @Override
+        public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
+            return xmlHandler(DingerDefinitionType.DINGTALK_XML_LINK, context);
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/dingtalk/entity/DingFeedCard.java b/src/main/java/com/github/jaemon/dinger/dingtalk/entity/DingFeedCard.java
index dd8d102..9a9d032 100644
--- a/src/main/java/com/github/jaemon/dinger/dingtalk/entity/DingFeedCard.java
+++ b/src/main/java/com/github/jaemon/dinger/dingtalk/entity/DingFeedCard.java
@@ -15,10 +15,12 @@
  */
 package com.github.jaemon.dinger.dingtalk.entity;
 
+import com.github.jaemon.dinger.core.entity.ImageTextDeo;
 import com.github.jaemon.dinger.dingtalk.entity.enums.DingTalkMsgType;
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.Map;
 
 /**
  * FeedCard类型
@@ -37,6 +39,11 @@ public DingFeedCard() {
         setMsgtype(DingTalkMsgType.FEED_CARD.type());
     }
 
+    public DingFeedCard(List links) {
+        this();
+        this.feedCard = new FeedCard(links);
+    }
+
     public FeedCard getFeedCard() {
         return feedCard;
     }
@@ -51,6 +58,13 @@ public static class FeedCard implements Serializable {
          */
         private List links;
 
+        public FeedCard() {
+        }
+
+        public FeedCard(List links) {
+            this.links = links;
+        }
+
         public List getLinks() {
             return links;
         }
@@ -73,6 +87,15 @@ public static class Link implements Serializable {
              */
             private String picURL;
 
+            public Link() {
+            }
+
+            public Link(String title, String messageURL, String picURL) {
+                this.title = title;
+                this.messageURL = messageURL;
+                this.picURL = picURL;
+            }
+
             public String getTitle() {
                 return title;
             }
@@ -98,4 +121,18 @@ public void setPicURL(String picURL) {
             }
         }
     }
+
+    @Override
+    public void transfer(Map params) {
+        for (Map.Entry entry : params.entrySet()) {
+            Object value = entry.getValue();
+            if (List.class.isInstance(value)) {
+                List imageTexts = (List) value;
+                for (ImageTextDeo imageText : imageTexts) {
+                    this.feedCard.links.add(new FeedCard.Link(imageText.getTitle(), imageText.getUrl(), imageText.getPicUrl()));
+                }
+                break;
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/dingtalk/entity/DingLink.java b/src/main/java/com/github/jaemon/dinger/dingtalk/entity/DingLink.java
new file mode 100644
index 0000000..7e323d8
--- /dev/null
+++ b/src/main/java/com/github/jaemon/dinger/dingtalk/entity/DingLink.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright ©2015-2021 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.dingtalk.entity;
+
+import com.github.jaemon.dinger.core.annatations.DingerLink;
+import com.github.jaemon.dinger.core.entity.LinkDeo;
+import com.github.jaemon.dinger.dingtalk.entity.enums.DingTalkMsgType;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Link类型
+ *
+ * @author Jaemon
+ * @since 1.0
+ */
+public class DingLink extends DingTalkMessage {
+    /** {@link Link} */
+    private Link link;
+
+    public DingLink() {
+        setMsgtype(DingTalkMsgType.LINK.type());
+    }
+
+    public DingLink(Link link) {
+        this();
+        this.link = link;
+    }
+
+    public Link getLink() {
+        return link;
+    }
+
+    public void setLink(Link link) {
+        this.link = link;
+    }
+
+    public static class Link implements Serializable {
+        /** 消息标题 */
+        private String title;
+        /** 消息内容。如果太长只会部分展示 */
+        private String text;
+        /** 点击消息跳转的URL */
+        private String messageUrl;
+        /** 图片URL */
+        private String picUrl;
+
+        public Link() {
+        }
+
+        public Link(String title, String text, String messageUrl, String picUrl) {
+            this.title = title;
+            this.text = text;
+            this.messageUrl = messageUrl;
+            this.picUrl = picUrl;
+        }
+
+        public String getTitle() {
+            return title;
+        }
+
+        public void setTitle(String title) {
+            this.title = title;
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public void setText(String text) {
+            this.text = text;
+        }
+
+        public String getMessageUrl() {
+            return messageUrl;
+        }
+
+        public void setMessageUrl(String messageUrl) {
+            this.messageUrl = messageUrl;
+        }
+
+        public String getPicUrl() {
+            return picUrl;
+        }
+
+        public void setPicUrl(String picUrl) {
+            this.picUrl = picUrl;
+        }
+    }
+
+    @Override
+    public void transfer(Map params) {
+        for (Map.Entry entry : params.entrySet()) {
+            Object value = entry.getValue();
+            if (DingerLink.clazz.isInstance(value)) {
+                LinkDeo link = (LinkDeo) value;
+                this.link = new Link(link.getTitle(), link.getText(), link.getMessageUrl(), link.getPicUrl());
+                break;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/utils/DingerUtils.java b/src/main/java/com/github/jaemon/dinger/utils/DingerUtils.java
index 6318c2d..c08727b 100644
--- a/src/main/java/com/github/jaemon/dinger/utils/DingerUtils.java
+++ b/src/main/java/com/github/jaemon/dinger/utils/DingerUtils.java
@@ -16,8 +16,10 @@
 package com.github.jaemon.dinger.utils;
 
 import java.io.Closeable;
-import java.util.Base64;
-import java.util.UUID;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.*;
 
 /**
  * DingTalk Utils
@@ -124,4 +126,60 @@ public static String uuid() {
         return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
     }
 
+
+    /**
+     * 获取方法中参数的泛型的参数信息
+     *
+     * @param method
+     *          method
+     * @param clazz
+     *          clazz
+     * @return
+     *          arr
+     */
+    public static int[] methodParamsGenericType(Method method, Class clazz) {
+        Type[] genericParameterTypes = method.getGenericParameterTypes();
+        int length = genericParameterTypes.length;
+        int[] arr = new int[length];
+        for (int i = 0; i < length; i++) {
+            Type type = genericParameterTypes[i];
+            arr[i] = -1;
+            if (ParameterizedType.class.isInstance(type)) {
+                ParameterizedType parameterizedType = (ParameterizedType) type;
+                if (parameterizedType.getRawType() == List.class) {
+                    Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0];
+                    if (actualTypeArgument == clazz) {
+                        arr[i] = i;
+                    }
+                }
+            }
+        }
+        return Arrays.stream(arr).filter(e -> e > -1).toArray();
+    }
+
+    /**
+     * 获取方法中参数的指定类型信息
+     *
+     * @param method
+     *          method
+     * @param clazz
+     *          clazz
+     * @return
+     *          arr
+     */
+    public static int[] methodParamsType(Method method, Class clazz) {
+        Class[] parameterTypes = method.getParameterTypes();
+        int length = parameterTypes.length;
+        int[] arr = new int[length];
+        for (int i = 0; i < length; i++) {
+            Class parameterType = parameterTypes[i];
+            if (parameterType.getName().equals(clazz.getName())) {
+                arr[i] = i;
+            } else {
+                arr[i] = -1;
+            }
+        }
+        return Arrays.stream(arr).filter(e -> e > -1).toArray();
+    }
+
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/wetalk/WeTalkDefinitionGenerator.java b/src/main/java/com/github/jaemon/dinger/wetalk/WeTalkDefinitionGenerator.java
index dead6ed..faeb707 100644
--- a/src/main/java/com/github/jaemon/dinger/wetalk/WeTalkDefinitionGenerator.java
+++ b/src/main/java/com/github/jaemon/dinger/wetalk/WeTalkDefinitionGenerator.java
@@ -19,6 +19,7 @@
 import com.github.jaemon.dinger.core.DingerDefinitionGenerator;
 import com.github.jaemon.dinger.core.DingerDefinitionGeneratorContext;
 import com.github.jaemon.dinger.core.DingerDefinitionHandler;
+import com.github.jaemon.dinger.core.annatations.DingerImageText;
 import com.github.jaemon.dinger.core.entity.enums.DingerType;
 import com.github.jaemon.dinger.core.annatations.DingerMarkdown;
 import com.github.jaemon.dinger.core.annatations.DingerText;
@@ -39,9 +40,7 @@ public static class AnnotationText extends DingerDefinitionGenerator
 
         @Override
         public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
-            DingerDefinition dingerDefinition = dingerTextHandler(DingerType.WETALK, context);
-
-            return dingerDefinition;
+            return dingerTextHandler(DingerType.WETALK, context);
         }
     }
 
@@ -52,9 +51,7 @@ public DingerDefinition generator(DingerDefinitionGeneratorContext c
     public static class AnnotationMarkDown extends DingerDefinitionGenerator {
         @Override
         public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
-            DingerDefinition dingerDefinition = dingerMarkdownHandler(DingerType.WETALK, context);
-
-            return dingerDefinition;
+            return dingerMarkdownHandler(DingerType.WETALK, context);
         }
     }
 
@@ -66,8 +63,7 @@ public static class XmlText extends DingerDefinitionGenerator {
 
         @Override
         public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
-            DingerDefinition dingerDefinition = xmlHandler(DingerDefinitionType.WETALK_XML_TEXT, context);
-            return dingerDefinition;
+            return xmlHandler(DingerDefinitionType.WETALK_XML_TEXT, context);
         }
     }
 
@@ -78,8 +74,29 @@ public DingerDefinition generator(DingerDefinitionGeneratorContext c
     public static class XmlMarkdown extends DingerDefinitionGenerator {
         @Override
         public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
-            DingerDefinition dingerDefinition = xmlHandler(DingerDefinitionType.WETALK_XML_MARKDOWN, context);
-            return dingerDefinition;
+            return xmlHandler(DingerDefinitionType.WETALK_XML_MARKDOWN, context);
+        }
+    }
+
+
+    /**
+     * 生成XML ImageText消息体定义
+     */
+    public static class AnnotationImageText extends DingerDefinitionGenerator {
+        @Override
+        public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
+            return dingerImageTextHandler(DingerType.WETALK, context);
+        }
+    }
+
+
+    /**
+     * 生成XML ImageText消息体定义
+     */
+    public static class XmlImageText extends DingerDefinitionGenerator {
+        @Override
+        public DingerDefinition generator(DingerDefinitionGeneratorContext context) {
+            return xmlHandler(DingerDefinitionType.WETALK_XML_IMAGETEXT, context);
         }
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/jaemon/dinger/wetalk/entity/WeNews.java b/src/main/java/com/github/jaemon/dinger/wetalk/entity/WeNews.java
index 94b4f77..c51296b 100644
--- a/src/main/java/com/github/jaemon/dinger/wetalk/entity/WeNews.java
+++ b/src/main/java/com/github/jaemon/dinger/wetalk/entity/WeNews.java
@@ -15,10 +15,12 @@
  */
 package com.github.jaemon.dinger.wetalk.entity;
 
+import com.github.jaemon.dinger.core.entity.ImageTextDeo;
 import com.github.jaemon.dinger.wetalk.entity.enums.WeTalkMsgType;
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 企业微信-消息类型-图文类型
@@ -27,6 +29,7 @@
  * @since 1.0
  */
 public class WeNews extends WeTalkMessage {
+    private static final int ARTICLE_LIMIT = 8;
     /** 图文类型 */
     private News news;
 
@@ -34,6 +37,11 @@ public WeNews() {
         setMsgtype(WeTalkMsgType.NEWS.type());
     }
 
+    public WeNews(List articles) {
+        this();
+        this.news = new News(articles);
+    }
+
     public News getNews() {
         return news;
     }
@@ -47,6 +55,13 @@ public static class News implements Serializable {
         /** 图文消息,一个图文消息支持1到8条图文 */
         private List
articles; + public News() { + } + + public News(List
articles) { + this.articles = articles; + } + public List
getArticles() { return articles; } @@ -65,6 +80,16 @@ public static class Article implements Serializable { /** 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图 1068*455,小图150*150。 */ private String picurl; + public Article() { + } + + public Article(String title, String description, String url, String picurl) { + this.title = title; + this.description = description; + this.url = url; + this.picurl = picurl; + } + public String getTitle() { return title; } @@ -98,4 +123,23 @@ public void setPicurl(String picurl) { } } } + + @Override + public void transfer(Map params) { + for (Map.Entry entry : params.entrySet()) { + Object value = entry.getValue(); + if (List.class.isInstance(value)) { + List imageTexts = (List) value; + int size = imageTexts.size(); + size = size > ARTICLE_LIMIT ? ARTICLE_LIMIT : size; + for (int i = 0; i < size; i++) { + + } + for (ImageTextDeo imageText : imageTexts) { + this.news.articles.add(new News.Article(imageText.getTitle(), imageText.getDescription(), imageText.getUrl(), imageText.getPicUrl())); + } + } + break; + } + } } \ No newline at end of file diff --git a/src/main/resources/META-INF/schema/dinger.dtd b/src/main/resources/META-INF/schema/dinger.dtd index a6bdfea..546da41 100644 --- a/src/main/resources/META-INF/schema/dinger.dtd +++ b/src/main/resources/META-INF/schema/dinger.dtd @@ -23,9 +23,10 @@ namespace CDATA #REQUIRED +