xxl-job企业微信告警实现

前言

xxl-job默认提供了邮箱告警,添加企微告警要折腾一番,并不是像营销文说的那么简单加个实现类就行,本文提供xxl-job企微告警实现。

效果展现

■ 编辑UI展示

在这里插入图片描述

■ 告警推送展示

在这里插入图片描述

列出改动清单

在这里插入图片描述

开始敲代码。。。

■ 获取corpid和corpsecret

企业ID和应用的凭证密钥,按官方文档获取。上传个图片创建应用就行了,我当时是登错了地方,进了企业微信服务商的管理后台一直找不到入口,坑了不少时间。

■ Properties

corpid=XXXXXXXXXXXXXXXXX
corpsecret=XXXXXX_XXXXXXXXXXXXXXXXXXXXX-XXXXXXXXXXXXXX

■ POM

<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpcore</artifactId>
	<version>4.4.6</version>
</dependency>
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.5.5</version>
</dependency>

■ 工具类准备

为了节省开发时间,几个企微工具类我也是从网上搜索过来改造,并不是我喜欢的方式。
① IacsUrlDataVo

package com.xxl.job.admin.core.alarm.WeiUtils;

public class IacsUrlDataVo {
    
    
    String corpid;
    String corpsecret;
    String Get_Token_Url;
    String SendMessage_Url;

    public String getCorpid() {
    
    
        return corpid;
    }
    public void setCorpid(String corpid) {
    
    
        this.corpid = corpid;
    }
    public String getCorpsecret() {
    
    
        return corpsecret;
    }
    public void setCorpsecret(String corpsecret) {
    
    
        this.corpsecret = corpsecret;
    }
    public void setGet_Token_Url(String corpid,String corpsecret) {
    
    
        this.Get_Token_Url ="https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid="+corpid+"&corpsecret="+corpsecret;
    }
    public String getGet_Token_Url() {
    
    
        return Get_Token_Url;
    }
    public String getSendMessage_Url(){
    
    
        SendMessage_Url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";
        return SendMessage_Url;
    }
}

② IacsWeChatDataVo

package com.xxl.job.admin.core.alarm.WeiUtils;

public class IacsWeChatDataVo {
    
    
    String touser;
    String toparty;
    String msgtype;
    int agentid;
    Object text;//实际接收Map类型数据
    Object markdown;//实际接收Map类型数据

    public Object getText() {
    
    
        return text;
    }
    public void setText(Object text) {
    
    
        this.text = text;
    }

    public Object getMarkdown() {
    
    
        return markdown;
    }

    public void setMarkdown(Object markdown) {
    
    
        this.markdown = markdown;
    }

    public String getMsgtype() {
    
    
        return msgtype;
    }
    public void setMsgtype(String msgtype) {
    
    
        this.msgtype = msgtype;
    }
    public int getAgentid() {
    
    
        return agentid;
    }
    public void setAgentid(int agentid) {
    
    
        this.agentid = agentid;
    }
    public String getTouser() {
    
    
        return touser;
    }
    public void setTouser(String touser) {
    
    
        this.touser = touser;
    }

    public String getToparty() {
    
    
        return toparty;
    }

    public void setToparty(String toparty) {
    
    
        this.toparty = toparty;
    }
}

③ SendWeChatUtils

package com.xxl.job.admin.core.alarm.WeiUtils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class SendWeChatUtils {
    
    

    private CloseableHttpClient httpClient;
    private HttpPost httpPost;//用于提交登陆数据
    private HttpGet httpGet;//用于获得登录后的页面
    public static final String CONTENT_TYPE = "Content-Type";
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static String token = "";
    private static Gson gson = new Gson();


//    /**
//     * 微信授权请求,GET类型,获取授权响应,用于其他方法截取token
//     *
//     * @param Get_Token_Url
//     * @return String 授权响应内容
//     * @throws IOException
//     */
    public String toAuth(String Get_Token_Url) throws IOException {
    
    

        httpClient = HttpClients.createDefault();
        httpGet = new HttpGet(Get_Token_Url);
        CloseableHttpResponse response = httpClient.execute(httpGet);
        String resp;
        try {
    
    
            HttpEntity entity = response.getEntity();
            resp = EntityUtils.toString(entity, "utf-8");
            EntityUtils.consume(entity);
        } finally {
    
    
            response.close();
        }
        LoggerFactory.getLogger(getClass()).info(" resp:{}", resp);
        return resp;
    }

    /**
     * 获取toAuth(String Get_Token_Url)返回结果中键值对中access_token键的值
     *
     * @param corpid 应用组织编号   corpsecret 应用秘钥
     */
    public void refreshToken() throws IOException {
    
    
        String corpid = Global.getConfig("corpid");
        String corpsecret = Global.getConfig("corpsecret");
        IacsUrlDataVo uData = new IacsUrlDataVo();
        uData.setGet_Token_Url(corpid, corpsecret);
        String resp = toAuth(uData.getGet_Token_Url());

        Map<String, Object> map = gson.fromJson(resp,
                new TypeToken<Map<String, Object>>() {
    
    
                }.getType());
        SendWeChatUtils.token = map.get("access_token").toString();
    }


    /**
     * @param touser         发送消息接收者    ,msgtype消息类型(文本/图片等),
     * @param application_id 应用编号。
     * @return String
     * @Title:创建微信发送请求post数据
     */
    public String createpostdata(String touser, String toparty, String msgtype,
                                 int application_id, String contentKey, String contentValue) {
    
    
        IacsWeChatDataVo wcd = new IacsWeChatDataVo();
        wcd.setTouser(touser);
        wcd.setToparty(toparty);
        wcd.setAgentid(application_id);
        wcd.setMsgtype(msgtype);
        Map<Object, Object> content = new HashMap<Object, Object>();
        content.put(contentKey, contentValue + "\n--------\n" + df.format(new Date()));
        if("markdown".equals(msgtype)) {
    
    
            wcd.setMarkdown(content);
        } else {
    
    
            wcd.setText(content);
        }
        return gson.toJson(wcd);
    }

    /**
     * @param charset 消息编码    ,contentType 消息体内容类型,
     * @param url     微信消息发送请求地址,data为post数据,token鉴权token
     * @return String
     * @Title 创建微信发送请求post实体
     */
    public String post(String charset, String contentType, String url,
                       String data, String token) throws IOException {
    
    
       return post(charset, contentType, url, data, token, 3);
    }

    public String post(String charset, String contentType, String url,
                       String data, String token, int count) throws IOException {
    
    
        CloseableHttpClient httpclient = HttpClients.createDefault();
        httpPost = new HttpPost(url + token);
        httpPost.setHeader(CONTENT_TYPE, contentType);
        httpPost.setEntity(new StringEntity(data, charset));
        CloseableHttpResponse response = httpclient.execute(httpPost);
        String resp;
        try {
    
    
            HttpEntity entity = response.getEntity();
            resp = EntityUtils.toString(entity, charset);
            EntityUtils.consume(entity);
        } finally {
    
    
            response.close();
        }

        Map<String, Object> map = gson.fromJson(resp,
                new TypeToken<Map<String, Object>>() {
    
    
                }.getType());
        String errcode = map.get("errcode").toString();
        if (!"0.0".equals(errcode) && !"0".equals(errcode) && count > 0) {
    
    
            refreshToken();
            LoggerFactory.getLogger(getClass()).info("token失效");
            return post(charset, contentType, url, data, SendWeChatUtils.token, --count);
        }

        LoggerFactory.getLogger(getClass()).info(
                "call [{}], param:{}, resp:{}", url, data, resp);
        return resp;
    }
}

④ Global
获取配置工具类

/**
 * Copyright &copy; 2012-2014 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 */
package com.xxl.job.admin.core.alarm.WeiUtils;

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;

/**
 * 全局配置类
 *
 * @author bbq
 * @version 2021-05-13
 */
@Component
public class Global implements EnvironmentAware {
    
    

    private static Environment environment;

    public static String getConfig(String key) {
    
    
        return environment.getProperty(key);
    }

    public static String getConfig(String key, String defaultValue) {
    
    
        String value = getConfig(key);
        return value != null ? value : defaultValue;
    }

    public static Integer getConfigInteger(String key) {
    
    
        return environment.getProperty(key, Integer.class);
    }

    public static Integer getConfigInteger(String key, Integer defaultValue) {
    
    
        Integer value = getConfigInteger(key);
        return value != null ? value : defaultValue;
    }

    @Override
    public void setEnvironment(Environment environment) {
    
    
        Global.environment = environment;
    }

    /**
     * 当前对象实例
     */
    private static Global global = new Global();

    /**
     * 获取当前对象实例
     */
    public static Global getInstance() {
    
    
        return global;
    }

}

■ UI修改

① message_zh_CN.properties
在这里插入图片描述

jobinfo_field_weimail=企业微信告警
jobinfo_field_weimail_placeholder=例:user1|user2&&party1|party2,不发给部门省略&&以及后面,多个对象|分隔

② jobinfo.index.1.js
在这里插入图片描述

$("#updateModal .form input[name='alarmWei']").val( row.alarmWei );

③ jobinfo.index.ftl
在这里插入图片描述

<div class="form-group">
	<label for="lastname" class="col-sm-2 control-label">${
    
    I18n.jobinfo_field_weimail}<font color="black">*</font></label>
	<div class="col-sm-8"><input type="text" class="form-control" name="alarmWei" placeholder="${I18n.jobinfo_field_weimail_placeholder}" maxlength="100" ></div>
</div>

■ curd代码

① xml
XxlJobInfoMapper.xml
在这里插入图片描述

<result column="alarm_wei" property="alarmWei" />
t.alarm_wei,
alarm_wei,
#{alarmWei},
alarm_wei = #{alarmWei},

② bean
com.xxl.job.admin.core.model.XxlJobInfo
在这里插入图片描述

private String alarmWei;	// 企业微信告警

③ servicempl
com.xxl.job.admin.service.impl.XxlJobServiceImpl
在这里插入图片描述

exists_jobInfo.setAlarmWei(jobInfo.getAlarmWei());

④ 告警thread
com.xxl.job.admin.core.thread.JobFailMonitorHelper
在这里插入图片描述

if (info != null && ((info.getAlarmEmail() != null && info.getAlarmEmail().trim().length() > 0)
										|| (info.getAlarmWei() != null && info.getAlarmWei().trim().length() > 0))) {
    
    

⑤ WeiJobAlarm
com.xxl.job.admin.core.alarm.impl.WeiJobAlarm
终于来到了具体的告警实现,也就是网上所谓的复制粘贴改改就好了。。。

package com.xxl.job.admin.core.alarm.impl;

import com.xxl.job.admin.core.alarm.JobAlarm;
import com.xxl.job.admin.core.alarm.WeiUtils.IacsUrlDataVo;
import com.xxl.job.admin.core.alarm.WeiUtils.SendWeChatUtils;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.MessageFormat;

/**
 * job alarm by wei
 *
 * @author bbq 2021-05-12
 */
@Component
public class WeiJobAlarm implements JobAlarm {
    
    
    private static Logger logger = LoggerFactory.getLogger(WeiJobAlarm.class);
    private static String token = "";

    /**
     * fail alarm
     *
     * @param jobLog
     */
    @Override
    public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog){
    
    
        boolean alarmResult = true;

        // send monitor email
        if (info!=null && info.getAlarmWei()!=null && info.getAlarmWei().trim().length()>0) {
    
    

            // alarmContent
            String alarmContent = "Alarm Job LogId=" + jobLog.getId();
            if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) {
    
    
                alarmContent += "\nTriggerMsg=\n" + jobLog.getTriggerMsg().replaceAll("<br>","|| ");
            }
            if (jobLog.getHandleCode()>0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) {
    
    
                alarmContent += "\nHandleCode=" + jobLog.getHandleMsg();
            }

            // email info
            XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup()));
            String content = MessageFormat.format(loadEmailJobAlarmTemplate(),
                    group!=null?group.getTitle():"null",
                    info.getId(),
                    info.getJobDesc(),
                    alarmContent);

            SendWeChatUtils msgUtils = new SendWeChatUtils();
            try {
    
    
                String touser = info.getAlarmWei().trim();
                String toparty = "";
                if(touser.contains("&&")) {
    
    
                    String str[] = touser.split("&&");
                    touser = str[0];
                    if(str.length > 1) {
    
    
                        toparty = str[1];
                    }
                }
                String postdata = msgUtils.createpostdata(touser, toparty,"markdown", 应用id, "content", content);
                String resp = msgUtils.post("utf-8", SendWeChatUtils.CONTENT_TYPE, (new IacsUrlDataVo()).getSendMessage_Url(), postdata, SendWeChatUtils.token);
//                System.out.println("请求数据======>" + postdata);
//                System.out.println("发送微信的响应数据======>" + resp);
            } catch (IOException e) {
    
    
                e.printStackTrace();
                alarmResult = false;
            }
        }

        return alarmResult;
    }

    /**
     * load email job alarm template
     *
     * @return
     */
    private static final String loadEmailJobAlarmTemplate(){
    
    
        String mailBodyTemplate = "# {2}\n"
                + "> `**事项详情**` \n"
                + "> " + I18nUtil.getString("jobinfo_field_jobgroup") + ":<font color=\"comment\">{0}</font> \n"
                + "> " + I18nUtil.getString("jobinfo_field_id")+":<font color=\"warning\">{1}</font>\n"
                + "> " + I18nUtil.getString("jobconf_monitor_alarm_title") + ":<font color=\"comment\">"
                + I18nUtil.getString("jobconf_monitor_alarm_type") + "</font>\n"
                + "> "+ I18nUtil.getString("jobconf_monitor_alarm_content") + ":\n<font color=\"info\">{3}</font> \n";

        return mailBodyTemplate;
    }

}

⑥ 数据库
最后别忘了往你的数据库添加字段即完成。

最后

然后就可以类似配置邮箱一样配置企微了,可配置部门和用户。

猜你喜欢

转载自blog.csdn.net/qq_24054301/article/details/118116323