java对接钉钉和企业微信

需要用到的枚举类


import enums.ICommonEnum;
import external.robot.common.enums.TransformEnum;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumAnnotation {

    /**
     * <p>枚举类</p>
     * */
    Class< ? extends ICommonEnum> clz();
    /**
     * <p>转换方式(code转换value或者type转value)</p>
     * <p>默认code到value的转换</p>
     * */
    TransformEnum transform() default TransformEnum.CODE_TO_VALUE;
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <p>自定义注解,用于参数校验</p>
 * @author
 * 李萌*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Required {

    /**
     * <p>消息</p>
     * */
    String errorMsg() default "不能为空";
    /**
     * <p>备注</p>
     * */
    String remark() default "";
    /**
     * <p>是否需要对这个类进行解释</p>
     * */
    boolean classParse() default false;

}

异常类

package external.robot.common.dto;

import external.robot.common.enums.ExceptionCode;
import lombok.Getter;

/**
 * 基类异常
 */
@Getter
public class BaseException extends RuntimeException{

    private int code= ExceptionCode.FAIL.getKey();
    private ExceptionCode errorCode;
    private String message;
    private  Object entity;
    public BaseException() {
        errorCode = ExceptionCode.SYSTEM_ERROR;
    }
    public BaseException(String message) { this.message = message; }
    public BaseException(String message, Throwable e) { super(message, e); }
    public BaseException(Throwable e) { super(e); }
    public BaseException(ExceptionCode exceptionCode){
        this.errorCode=exceptionCode;
    }
    public BaseException(ExceptionCode exceptionCode, Object entity) {
        super();
        errorCode = exceptionCode;
        this.entity=entity;
    }
    public BaseException(ExceptionCode exceptionCode, Throwable e) {
        super(e);
        errorCode = exceptionCode;
    }
    public BaseException(String message, ExceptionCode exceptionCode) {
        super(message);
        errorCode = exceptionCode;
        this.message = message;
    }
    public BaseException(String message, ExceptionCode exceptionCode, Throwable e) {
        super(message, e);
        errorCode = exceptionCode;
    }
    public ExceptionCode getErrorCode() {
        return errorCode;
    }
    public BaseException(int code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }
}

机器人的响应以及请求体

package external.robot.common.dto;

import cn.hutool.core.net.URLEncodeUtil;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@NoArgsConstructor
public class RobotRequest{
    private String requestInterface;
    private String requestParams;
    private String requestBody;
    private String responseResult;
    private String responseDate;
    private String requestIp;
    private String requestUserId;
    private String userAgent;
    private String stackInfo;
    public RobotRequest(String requestInterface, String requestParams, String requestBody, String responseResult, String responseDate,String requestIp,String requestUserId,String userAgent,String stackInfo) {
        this.requestInterface = requestInterface;
        this.requestParams = requestParams;
        this.requestBody = requestBody;
        this.responseResult = responseResult;
        this.responseDate = responseDate;
        this.requestIp=requestIp;
        this.requestUserId=requestUserId;
        this.userAgent=userAgent;
        this.stackInfo=stackInfo;
    }
    public String toJson(){
        return JSONObject.toJSONString(this);
    }

    public String encode(){
        return URLEncodeUtil.encode(toJson());
    }
}
package external.robot.common.dto;

import external.robot.common.enums.ExceptionCode;
import lombok.Data;

/**
 * 机器人的响应体
 */
@Data
public class RobotResponse {

    /**
     * <p>成功标识</p>
     * */
    private static final String SUCCESS_CODE = "0";
    /**
     * <p>响应码</p>
     * */
    private String errcode= ExceptionCode.FAIL.getCode();
    /**
     * <p>响应消息</p>
     * */
    private String errmsg= ExceptionCode.FAIL.getValue();
    /**
     * <p>消息发送是否成功</p>
     * */
    private boolean isSuccess(){ return SUCCESS_CODE.equals(errcode); }
    public RobotResponse(){super();}
    public RobotResponse(String errcode, String errmsg) {
        this.errcode = errcode;
        this.errmsg = errmsg;
    }
    public RobotResponse(ExceptionCode exceptionCode){
        this(exceptionCode.getCode(),exceptionCode.getValue());
    }
}

转换枚举类和异常枚举类

package external.robot.common.enums;


import enums.ICommonEnum;
import lombok.Getter;

@Getter
public enum  AlgorithmEnum implements ICommonEnum {
    HmacSHA256("HmacSHA256","HmacSHA256"),
    MD5("MD5","MD5");
    private final String code;
    private final String value;
    AlgorithmEnum(String code, String value) {
        this.code = code;
        this.value = value;
    }
    @Override
    public Integer getKey() { return null; }

}
package external.robot.common.enums;

import enums.ICommonEnum;
import lombok.Getter;

/**
 * 类型转换
 */
@Getter
public enum TransformEnum implements ICommonEnum {
    CODE_TO_VALUE("getValueByCode", "code到value的转换"),
    TYPE_TO_VALUE("getValueByType","type到value的转换");
    private final String code;
    private final String value;
    TransformEnum(String code, String value) {
        this.code = code;
        this.value = value;
    }
    @Override
    public Integer getKey() { return Integer.parseInt(code); }
}
package external.robot.common.enums;

import enums.ICommonEnum;
import lombok.Getter;

/**
 * @description: 异常编码枚举
 */
public enum ExceptionCode implements ICommonEnum {
    SUCCESS(0,"成功"),
    FAIL(201,"操作失败"),
    NO_AUTHORIZATION(204,"无权访问"),
    ERROR(400,"错误请求"),
    MISSING_PARAMETERS(401,"参数缺失"),
    MISSING_REQUIRED_PARAMETERS(402,"缺少必要参数"),
    VERIFICATION_FAILED(404,"验证不通过"),
    SYSTEM_ERROR(500,"服务器繁忙...");
    @Getter
    private String value;
    @Getter
    private Integer key;
    ExceptionCode(Integer key, String value) {
        this.key=key;
        this.value = value;
    }
    @Override
    public String getCode() { return key.toString(); }
}

验证工具类

package external.robot.common.util;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import external.robot.common.annotations.Required;
import external.robot.common.dto.BaseException;
import utils.ReflectUtil;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;


public class CheckUtil {

    public static ExecutorService robotExecutor = ThreadUtil.newExecutor(4);

    /**
     * <p>验证对象是否通过验证</p>
     * @param object 待验证的对象
     * @return
     * */
    public static boolean isRequiredPass(Object object) throws Exception {
        Class<?> clz = object.getClass();
        Map<String, Field> fieldMap = ReflectUtil.getClassField(clz);
        Iterator<Field> iterator = fieldMap.values().iterator();
        while(iterator.hasNext()){
            Field field =  iterator.next();
            Required required = field.getAnnotation(Required.class);
            if(null==required){ continue; }
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), clz);
            Method method = propertyDescriptor.getReadMethod();
            Object value = method.invoke(object);
            if(null==value){
                String errorMessage = required.errorMsg();
                errorMessage = StrUtil.isBlank(errorMessage)?String.format("%s为必填参数!",field.getName()):errorMessage;
                throw new BaseException(errorMessage);
            }
            boolean parse = required.classParse();
            // 如果注解中的 classParse 不为 true,则不进行解释
            if(!parse){ continue; }
            boolean _primitive = ReflectUtil.isPrimitive(field.getDeclaringClass());
            // 如果是基本类型或包装类型则不进行解释
            if(_primitive){continue;}

            Map<String, Field> _map = ReflectUtil.getClassField(value.getClass());

            boolean pass = isRequiredPass(value);   // TODO 这里递归有bug ....
            if(!pass){ return Boolean.FALSE; }
        }
        return true;
    }

}

钉钉发送消息(文本,图片,链接,是否@所有人)对应的实体

package external.robot.dingding.entity;

import external.robot.common.annotations.Required;
import lombok.Getter;
import lombok.Setter;


@Getter
@Setter
public class BaseRequest<T> {
    /**
     * <p>时间戳</p>
     * */
    @Required(errorMsg = "时间戳不能为空或null",remark="时间戳",classParse = false)
    private long timestamp;
    /**
     * <p>密钥</p>
     */
    @Required(errorMsg = "密钥不能为空",remark="加签的密钥",classParse = false)
    private String secret;
    @Required(errorMsg = "消息类型不能为空",remark="消息类型",classParse = false)
    private String msgtype;
    @Required(errorMsg = "访问令牌不能为空",remark="访问令牌",classParse = false)
    private String accessToken;
}
package external.robot.dingding.entity;


import external.robot.common.annotations.Required;
import external.robot.dingding.enums.DingTalkEnum;
import lombok.Data;


@Data
public class DingActionCardRequest extends BaseRequest {

    @Required(errorMsg = "actionCard不能为空",remark="actionCard",classParse = true)
    private ActionCard actionCard;

    public DingActionCardRequest(ActionCard actionCard) {
        super.setMsgtype(DingTalkEnum.MSG_TYPE.ACTION_CARD.getCode());
        this.actionCard = actionCard;
        super.setTimestamp(System.currentTimeMillis());
    }

    public DingActionCardRequest(String title, String text, String singleTitle, String singleURL, DingTalkEnum.BTN_ORIENTATION btnOrientation) {
        super.setMsgtype(DingTalkEnum.MSG_TYPE.ACTION_CARD.getCode());
        this.actionCard = new ActionCard(title,text,singleTitle,singleURL,btnOrientation);
        super.setTimestamp(System.currentTimeMillis());
    }

    public DingActionCardRequest(String title, String text, String singleTitle, String singleURL) {
        this(title,text,singleTitle,singleURL, DingTalkEnum.BTN_ORIENTATION.STANDARD);
    }

    @Data
    public static class ActionCard{
        @Required(errorMsg = "首屏会话透出的展示内容不能为空",remark="首屏会话透出的展示内容",classParse = false)
        private String title;
        @Required(errorMsg = "消息内容不能为空",remark="markdown格式的消息",classParse = false)
        private String text;
        @Required(errorMsg = "按钮的标题不能为空",remark="单个按钮的标题,注意:(设置此项和singleURL后,btns无效)。",classParse = false)
        private String singleTitle;
        @Required(errorMsg = "跳转的URL不能为空",remark="点击消息跳转的URL,打开方式如下:移动端(在钉钉客户端内打开),PC端(默认侧边栏打开)",classParse = false)
        private String singleURL;
        // --------------- 非必填 ---------------
        /**
         * <p>按钮排列方向(0:按钮竖直排列、1:按钮横向排列)</p>
         * */
        private int btnOrientation;
        // --------------- 构建函数 ---------------
        public ActionCard(String title, String text, String singleTitle, String singleURL){
            this(title,text,singleTitle,singleURL, DingTalkEnum.BTN_ORIENTATION.STANDARD);
        }
        public ActionCard(String title, String text, String singleTitle, String singleURL, DingTalkEnum.BTN_ORIENTATION btnOrientation) {
            this.title = title;
            this.text = text;
            this.singleTitle = singleTitle;
            this.singleURL = singleURL;
            this.btnOrientation = btnOrientation.getKey();
        }
    }
}
package external.robot.dingding.entity;


import external.robot.common.annotations.Required;
import external.robot.dingding.enums.DingTalkEnum;
import lombok.Data;

/**
 * @category 带链接的消息
 */
@Data
public class DingLinkRequest extends BaseRequest<DingLinkRequest> {

    @Required(errorMsg = "link不能为空",remark="link",classParse = true)
    private Link link;

    public DingLinkRequest(String title, String text, String messageUrl){
        this(new Link(title,text,messageUrl,null));
    }
    public DingLinkRequest(String title, String text, String messageUrl, String picUrl){
        this(new Link(title,text,messageUrl,picUrl));
    }

    public DingLinkRequest(Link link) {
        super.setMsgtype(DingTalkEnum.MSG_TYPE.LINK.getCode());
        this.link = link;
        super.setTimestamp(System.currentTimeMillis());
    }
    public DingLinkRequest(){super();}

    @Data
    public static class Link {
        @Required(errorMsg = "消息标题不能为空",remark="消息标题",classParse = false)
        private String title;
        @Required(errorMsg = "消息内容不能为空",remark="消息内容",classParse = false)
        private String text;
        @Required(errorMsg = "跳转的URL不能为空",remark="跳转的URL",classParse = false)
        private String messageUrl;
        // --------------- 非必填 ---------------
        private String picUrl;
        // --------------- 构建函数 ---------------
        public Link(String title, String text, String messageUrl, String picUrl) {
            this.title = title;
            this.text = text;
            this.messageUrl = messageUrl;
            this.picUrl = picUrl;
        }
        public Link(String title, String text, String messageUrl){
            this(title,text,messageUrl,null);
        }
    }

}
package external.robot.dingding.entity;


import external.robot.common.annotations.Required;
import external.robot.dingding.enums.DingTalkEnum;
import lombok.Data;


@Data
public class DingMarkDownRequest extends BaseRequest {

    @Required(errorMsg = "markdown不能为空",remark="markdown",classParse = true)
    private Markdown markdown;
    // --------------- 非必填 ---------------
    private At at;
    // --------------- 构建函数 ---------------
    public DingMarkDownRequest(Markdown markdown, At at) {
        super.setMsgtype(DingTalkEnum.MSG_TYPE.MARKDOWN.getCode());
        this.markdown = markdown;
        this.at = at;
        super.setTimestamp(System.currentTimeMillis());
    }
    public DingMarkDownRequest(Markdown markdown){
        this(markdown,null);
    }
    public DingMarkDownRequest(String title, String text){
        this(new Markdown(title,text),null);
    }
    // -------------------------->> 内部类 <<--------------------------
    @Data
    public static class Markdown{
        @Required(errorMsg = "首屏会话透出的展示内容不能为空!",remark = "首屏会话透出的展示内容",classParse = false)
        private String title;
        @Required(errorMsg = "消息不能为空!",remark = "markdown格式的消息",classParse = false)
        private String text;
        public Markdown(String title, String text) {
            this.title = title;
            this.text = text;
        }
    }
    @Data
    public static class At{
        /**
         * <p>被@人的手机号(注意:在text内容里要有@人的手机号,只有在群内的成员才可被@,非群内成员手机号会被脱敏)</p>
         * */
       private String[] atMobiles;
       /**
        * <p>被@人的用户userid(注意 在content里添加@人的userid)</p>
        * */
       private String[] atUserIds;
       /**
        * <p>是否@所有人</p>
        * */
       private boolean isAtAll;
       public At(String[] atMobiles, String[] atUserIds, boolean isAtAll) {
            this.atMobiles = atMobiles;
            this.atUserIds = atUserIds;
            this.isAtAll = isAtAll;
       }
    }
}
package external.robot.dingding.entity;


import external.robot.common.annotations.Required;
import external.robot.dingding.enums.DingTalkEnum;
import lombok.Data;

import java.util.List;


@Data
public class DingTextRequest extends BaseRequest {

    @Required(errorMsg = "text不能为空",remark="text",classParse = true)
    private Text text;
    private At at;
    @Data
    public static class At{
        /**
         * <p>是否@所有人</p>
         * */
        private boolean isAtAll;
        /**
         * <p>注意:在content里添加@人的手机号,且只有在群内的成员才可被@,非群内成员手机号会被脱敏。</p>
         * */
        private List<String> atMobiles;
        /**
         * <p>被@人的用户userid。注意:在content里添加@人的userid。</p>
         * */
        private List<String> atUserIds;
    }
    @Data
    public static class Text {
        @Required(errorMsg = "消息内容不能为空",remark="消息内容",classParse = false)
        private String content;
        public Text(String content) { this.content = content; }
    }
    public DingTextRequest(){super();}
    public DingTextRequest(String message, At at) {
        super.setMsgtype(DingTalkEnum.MSG_TYPE.TEXT.getCode());
        this.text = new Text(message);
        this.at = at;
        super.setTimestamp(System.currentTimeMillis());
    }
    public DingTextRequest(String message){ this(message,null); }

}

钉钉需要的枚举类

package external.robot.dingding.enums;


import enums.ICommonEnum;
import external.robot.dingding.entity.*;
import external.robot.dingding.service.*;
import lombok.Getter;

/***
 ** @category 钉钉Talk枚举
 **/
public class DingTalkEnum {

    @Getter
    /**
     * <p>消息类型</p>
     * */
    public enum MSG_TYPE implements ICommonEnum {
        TEXT( "text","文本消息", TextMsgService.class, DingTextRequest.class),
        LINK("link","带URL链接的消息", LinkMsgService.class, DingLinkRequest.class),
        MARKDOWN("markdown","markdown消息", MarkDownMsgService.class, DingMarkDownRequest.class),
        ACTION_CARD("actionCard","ActionCard消息", ActionCardMsgService.class, DingActionCardRequest.class),
        FEED_CARD("feedCard","feedCard消息");
        private final String code;
        private final String value;
        private final Class<?extends AbsDingTalkMessage> service;
        private final Class<?extends BaseRequest> request;
        MSG_TYPE(String code, String value){ this(code,value,null,null); }
        MSG_TYPE(String code, String value, Class<?extends AbsDingTalkMessage> service, Class<?extends BaseRequest> request) {
            this.code = code;
            this.value = value;
            this.service=service;
            this.request=request;
        }
        @Override
        public Integer getKey() { return null; }
    }
    /**
     * <p>按钮排列方向</p>
     * */
    @Getter
    public enum BTN_ORIENTATION implements ICommonEnum{
        VERTICAL("0","按钮竖直排列"),
        STANDARD("1","按钮横向排列");
        private final String code;
        private final String value;
        BTN_ORIENTATION(String code, String value) {
            this.code = code;
            this.value = value;
        }
        @Override
        public Integer getKey() { return Integer.parseInt(code); }
    }

}

机器人扩展接口

package external.robot.dingding.service.interfaces;

import enums.ICommonEnum;

/**
 * @category 机器人扩展接口
 */
public interface IRobot<T extends Enum> extends ICommonEnum {

    /**
     * <p>群编码</p>
     * */
    String getGroupCode();
    /**
     * <p>群名称</p>
     * */
    String getGroupName();
    /**
     * <p>访问令牌</p>
     * */
    String getAccessToken();

}
package external.robot.dingding.service;

import cn.hutool.core.codec.Base64;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import enums.EncodingEnum;
import external.robot.common.dto.RobotResponse;
import external.robot.common.enums.AlgorithmEnum;
import external.robot.common.enums.ExceptionCode;
import external.robot.common.util.CheckUtil;
import external.robot.dingding.entity.BaseRequest;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;


public abstract class AbsDingTalkMessage {

    /**
     * <p>处理请求(子类需要根据不同场景实现)</p>
     * @param request
     * @return
     * */
    public abstract <T> String handle(BaseRequest<T> request);

    /**
     * <p>处理请求</p>
     * @param request
     * @return
     * */
    public <T> RobotResponse doHandle(BaseRequest<T> request) throws Exception {
        boolean pass = CheckUtil.isRequiredPass(request);
        if(!pass){return new RobotResponse(ExceptionCode.VERIFICATION_FAILED);}
        String result = handle(request);
        return JSONUtil.toBean(new JSONObject(result), RobotResponse.class);
    }
    /**
     * <p>加签(把timestamp+"\n"+secret当做签名字符串,使用HmacSHA256算法计算签名,然后进行Base64 encode,最后再把签名参数再进行urlEncode,得到最终的签名(需要使用UTF-8字符集))</p>
     * @param timestamp
     * @param secret
     * @return
     * */
    protected static String getSign(long timestamp,String secret) throws Exception {
        String stringToSign = String.format("%s\n%s",timestamp,secret);
        Mac mac = Mac.getInstance(AlgorithmEnum.HmacSHA256.getCode());
        mac.init(new SecretKeySpec(secret.getBytes(EncodingEnum.UTF_8.getCode()), AlgorithmEnum.HmacSHA256.getCode()));
        byte[] signData = mac.doFinal(stringToSign.getBytes(EncodingEnum.UTF_8.getCode()));
        return URLEncoder.encode(Base64.encode(signData),EncodingEnum.UTF_8.getCode());
    }

    /**
     * <p>发送消息</p>
     * @param request 待发送的消息
     * @return
     * */
    protected static <T> String send(BaseRequest<T> request){
        try {
            long timestamp = System.currentTimeMillis();
            String sign = getSign(timestamp,request.getSecret());
            //钉钉机器人地址(配置机器人的webhook)
            String params = String.format("?access_token=%s&timestamp=%s&sign=%s",new Object[]{request.getAccessToken(),timestamp,sign});
            String dingUrl = String.format("https://oapi.dingtalk.com/robot/send%s",params);
            //推送消息(http请求)
            return HttpUtil.post(dingUrl, JSONUtil.toJsonStr(request));
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
package external.robot.dingding.service;


import external.robot.dingding.entity.BaseRequest;

public class ActionCardMsgService extends AbsDingTalkMessage {

    @Override
    public String handle(BaseRequest request) {
       return send(request);
    }
}
package external.robot.dingding.service;

import external.robot.dingding.entity.BaseRequest;


public class LinkMsgService extends AbsDingTalkMessage {
    @Override
    public String handle(BaseRequest request) {
        return send(request);
    }
}
package external.robot.dingding.service;

import external.robot.dingding.entity.BaseRequest;


public class MarkDownMsgService extends AbsDingTalkMessage {
    @Override
    public String handle(BaseRequest request) {
        return send(request);
    }
}
package external.robot.dingding.service;

import external.robot.dingding.entity.BaseRequest;


public class TextMsgService extends AbsDingTalkMessage {

    @Override
    public String handle(BaseRequest request) {
        return send(request);
    }

}

钉钉发送消息工具类

package external.robot.dingding.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import external.config.RobotDingConf;
import external.robot.common.util.CheckUtil;
import external.robot.dingding.entity.*;
import external.robot.dingding.enums.DingTalkEnum;
import utils.EnumUtil;

import java.util.List;
import java.util.Map;
import java.util.Random;


public class DingTalkUtil {

    /**
     * <p>发送钉钉消息</p>
     *
     * @param jsonParams 待发送的消息
     * @return
     */
    public static void sendMessage(String jsonParams) {
        BaseRequest request = JSONUtil.toBean(jsonParams, BaseRequest.class);
        if (null == request) {
            return;
        }
        DingTalkEnum.MSG_TYPE msgTypeEnum = EnumUtil.getEnumByCode(DingTalkEnum.MSG_TYPE.class, request.getMsgtype());
        if (null == msgTypeEnum) {
            return;
        }
        sendMessage(JSONUtil.toBean(jsonParams, msgTypeEnum.getRequest()));
    }

    /**
     * <p>发送钉钉消息</p>
     *
     * @param paramsMap 待发送的消息
     * @return
     */
    public static void sendMessage(Map<String, Object> paramsMap) {
        sendMessage(JSONUtil.toJsonStr(paramsMap));
    }


    public static void sendMessage(String title, String text, String url) {
        BaseRequest request = new DingTextRequest(text);
        if (StrUtil.isNotBlank(url)) {
            int result = new Random().nextInt(3);
            request = result == 0 ? new DingMarkDownRequest(title, String.format("> %s &#x000A; %s", title, text)) : result == 1 ? new DingLinkRequest(title, text, url) : new DingActionCardRequest(title, text, title, url);
        }
        sendMessage(request);
    }

    /**
     * <p>发送钉钉消息</p>
     *
     * @param request 待发送的请求消息
     * @return
     */
    public static <T extends BaseRequest> void sendMessage(T request) {
        if (null == request) {
            return;
        }
        DingTalkEnum.MSG_TYPE MSG_TYPE_ENUM = EnumUtil.getEnumByCode(DingTalkEnum.MSG_TYPE.class, request.getMsgtype());
        RobotDingConf.DingDto robot = selectRobot();
        if (null == MSG_TYPE_ENUM || null == robot) {
            return;
        }
        CheckUtil.robotExecutor.execute(() -> {
            request.setSecret(robot.getSecretKey());
            request.setAccessToken(robot.getAccessToken());
            try {
                MSG_TYPE_ENUM.getService().newInstance().doHandle(request);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * <p>采用轮询算法,获取某一个机器人</p>
     * <p>因为钉钉每个机器人每分钟发送的消息频率为30条,超过则会屏蔽掉</p>
     */
    private static Integer index = 0;

    private static RobotDingConf.DingDto selectRobot() {
        RobotDingConf.DingDto robot = null;
        List<RobotDingConf.DingDto> robotList = RobotDingConf.getInstance().getList();
        if (CollUtil.isEmpty(robotList)) {
            return null;
        }
        synchronized (index) {
            // 下标复位
            if (index >= robotList.size()) {
                index = 0;
            }
                robot = robotList.get(index);
                index++;

        }
        return robot;
    }
}

UTF-8枚举类和通用枚举类接口

package enums;

import lombok.Getter;


@Getter
public enum EncodingEnum implements ICommonEnum {
    UTF_8("UTF-8","utf-8编码"),
    GBK("GBK","GBK编码");
    private final String code;
    private final String value;
    EncodingEnum(String code, String value) {
        this.code = code;
        this.value = value;
    }
    @Override
    public Integer getKey() { return null; }
}
package enums;

/**
 * <p>通用枚举接口</p>
 */
public interface ICommonEnum {
    /**code(key) */
    default String getCode() {return null;}

    /**value */
    String getValue();

    /**当code值为数字类型时,在调用getKey时会将字符类型转换成Integer类型方便调用*/
    Integer getKey();
}

钉钉机器人配置

package external.config;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * <p>钉钉机器人配置</p>
 */
@Data
@Component
@ConfigurationProperties(prefix = "robot.ding")
public class RobotDingConf {

    private List<DingDto> list;

    private static volatile RobotDingConf instance;
    private RobotDingConf(){}
    public static synchronized RobotDingConf getInstance(){
        if(null==instance){
            synchronized (RobotDingConf.class){
                if(null==instance){
                    instance = new RobotDingConf();
                }
            }
        }
        return instance;
    }

    @PostConstruct
    public void init (){
        RobotDingConf conf = RobotDingConf.getInstance();
        conf.setList(list);
    }

    @Data
    @NoArgsConstructor
    public static class DingDto{
        private String accessToken;
        private String secretKey;
        public DingDto(String accessToken, String secretKey) {
            this.accessToken = accessToken;
            this.secretKey = secretKey;
        }
    }
}

yml配置

spring:
  profiles:
    active: @profiles.active@

mybatis-plus:
  mapper-locations: classpath*:mybatis/**/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

robot:
  wechat:
    list:
      - ***************
      -
  ding:
    list:
      - accessToken: **********
        secretKey: *************

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值