精华内容
下载资源
问答
  • Jenkins企业微信通知开发

    千次阅读 2018-12-21 16:28:59
    Jenkins企业微信通知开发 整个的开发过程我自己分为了两步 1:调用微信接口,可以进行自定义的消息推送. 2:获取到jenkins构建完成之后的构建结果. 首先贴上pom文件 <?xml version=&...

    Jenkins企业微信通知开发

    整个的开发过程我自己分为了两步

    	1:调用微信接口,可以进行自定义的消息推送.
    	2:获取到jenkins构建完成之后的构建结果.
    	3:代码方面有做一些调整,没有贴出最后的代码,整理之后的代码会简单很多,几乎不用自己进行手写代码,在文章后面会提到有哪些方面进行了改动
    

    首先贴上pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <parent>
        <groupId>org.jenkins-ci.plugins</groupId>
        <artifactId>plugin</artifactId>
        <version>1.580.1</version>
        <relativePath/>
      </parent>
      
      
      <groupId>com.jysong.jenkins</groupId>
      <artifactId>newplugon</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>hpi</packaging>
      <name>TODO Plugin</name>
      <description>TODO</description>
      <url>https://wiki.jenkins-ci.org/display/JENKINS/TODO+Plugin</url>
      <licenses>
        <license>
          <name>MIT License</name>
          <url>http://opensource.org/licenses/MIT</url>
        </license>
      </licenses>
      
      <repositories>
        <repository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </repository>
      </repositories>
      
       <dependencies>
    	<dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.2</version>
    	</dependency>
    	<dependency>
    	    <groupId>org.apache.httpcomponents</groupId>
    	    <artifactId>httpclient</artifactId>
    	    <version>4.5.2</version>
    	</dependency>
     
    	<dependency>
    	    <groupId>org.apache.httpcomponents</groupId>
    	    <artifactId>httpcore</artifactId>
    	    <version>4.4.5</version>
    	</dependency>
    	
    	<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    	<dependency>
    	    <groupId>org.slf4j</groupId>
    	    <artifactId>slf4j-api</artifactId>
    	    <version>1.8.0-beta2</version>
    	</dependency>
    	
    </dependencies>
      
      <pluginRepositories>
        <pluginRepository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </pluginRepository>
      </pluginRepositories>
    
    </project>
    
    

    其中调用微信接口进行消息通知,比较简单,直接贴上代码

    public class urlData {
    	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;
    	}
    
    }
    
    
    public class weChatData {
    		 String touser;
    	     String msgtype;
    	     int agentid;
    	     Object text;//实际接收Map类型数据
    	
    	     public Object getText() {
    	         return text;
    	     }
    	     public void setText(Object text) {
    	         this.text = text;
    	     }
    	     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;
    	     }     
    }
    

    这为两个实体类,对一些简单的信息进行了封装

    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    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 com.google.gson.Gson;
    import com.google.gson.reflect.TypeToken;
    
    import net.sf.json.JSONArray;
    import net.sf.json.JSONObject;
    
    public class send_weChatMsg {
    	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");//
    
    	private static Gson gson = new Gson();
    
    	/**
    	 * 微信授权请求,GET类型,获取授权响应,用于其他方法截取token
    	 * 
    	 * @param Get_Token_Url
    	 * @return String 授权响应内容
    	 * @throws IOException
    	 */
    	protected 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应用秘钥
    	 */
    	protected String getToken(String corpid, String corpsecret) throws IOException {
    		send_weChatMsg sw = new send_weChatMsg();
    		urlData uData = new urlData();
    		uData.setGet_Token_Url(corpid, corpsecret);
    		String resp = sw.toAuth(uData.getGet_Token_Url());
    
    		Map<String, Object> map = gson.fromJson(resp, new TypeToken<Map<String, Object>>() {
    		}.getType());
    		return map.get("access_token").toString();
    	}
    
    	/**
    	 * @Title:创建微信发送请求post数据
    	 * @param touser发送消息接收者
    	 *            ,msgtype消息类型(文本/图片等),
    	 * @param application_id应用编号。
    	 * @param 本方法适用于text型微信消息,contentKey和contentValue只能组一对
    	 * @return String
    	 */
    	protected String createpostdata(String touser, String msgtype, int application_id, String contentKey,
    			String contentValue) {
    		weChatData wcd = new weChatData();
    		wcd.setTouser(touser);
    		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()));
    		wcd.setText(content);
    		return gson.toJson(wcd);
    	}
    
    	/**
    	 * @Title 创建微信发送请求post实体
    	 * @param charset消息编码
    	 *            ,contentType消息体内容类型,
    	 * @param url微信消息发送请求地址,data为post数据,token鉴权token
    	 * @return String
    	 */
    	public String post(String charset, String contentType, String url, String data, String token) 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();
    		}
    		LoggerFactory.getLogger(getClass()).info("call [{}], param:{}, resp:{}", url, data, resp);
    		return resp;
    	}
    
    }
    
    

    上面的createpostdata方法中的touser为向谁进行消息的推送,需要填写的为企业用户id.

    1:如果有多个用户需要进行推送,用|分开  如:zhangsan|lisi 即可向两人分别进行推送
      
    2:或者这个值为 @all  即为向所有成员进行推送
    

    这样微信的消息推送即完成了,但是这里面也有考虑到一点就是当我们获取token时有一个需要注意的事情就是,我们需要对token进行缓存起来,防止频繁的调用接口而出现一些问题
    在这里插入图片描述
    我自己用的是单例模式全局缓存token,这里直接贴上代码

    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Singleton {
    	  //缓存accessToken 的Map,map中包含 一个accessToken 和 缓存的时间戳
        private Map<String, String> map = new HashMap<String,String>();
    
        private Singleton() {
            
        }
    
        private static Singleton single = null;
    
        // 静态工厂方法
        public static Singleton getInstance() {
            if (single == null) {
                single = new Singleton();
            }
            return single;
        }
    
        public Map<String, String> getMap() {
            return map;
        }
    
        public void setMap(Map<String, String> map) {
            this.map = map;
        }
    
        public static Singleton getSingle() {
            return single;
        }
    
        public static void setSingle(Singleton single) {
            Singleton.single = single;
        }
        
        /**
         * 获取 accessToken Jsapi_ticket 已加入缓存机制
         * @param appid
         * @param appsecret
         * @return
         */
        public  Map<String,Object> getAccessTokenAndJsapiTicket(String appid, String appsecret) {
        		Map<String,Object> result = new HashMap<String,Object>();
            try {
    			Singleton singleton = Singleton.getInstance();
    			Map<String, String> map = singleton.getMap();
    			String time = map.get("time");//从缓存中拿数据
    			String accessToken = map.get("access_token");//从缓存中拿数据
    			Long nowDate = new Date().getTime();
    			//这里设置过期时间 5400 * 1000就好了 一个半小时
    			if (accessToken != null && time != null && nowDate - Long.parseLong(time) < 5400 * 1000) {
    			    System.out.println("-----从缓存读取access_token:"+accessToken);
    			    //从缓存中拿数据为返回结果赋值
    			    result.put("access_token", accessToken);
    			} else {
    			    send_weChatMsg sw = new send_weChatMsg();
    			    String token = sw.getToken(appid, appsecret);
    			    //将信息放置缓存中
    			    map.remove("time");//将key删掉
    			    map.put("time", nowDate + "");//重新添加time
    			    map.put("access_token", token);
    			    //为返回结果赋值
    			    result.put("access_token", token);
    			    }
    			return result;
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
            return result;
        }
    
    }
    

    这里就基本上完成了微信的推送,是否正确的完成,就需要写一个test测试类进行测试了

    import java.util.Map;
    
    public class Test {
    	 public static void main(String[] args) {
             send_weChatMsg sw = new send_weChatMsg();
             try {
            	 Singleton singleton = Singleton.getInstance();
            	 Map<String, Object> map = singleton.getAccessTokenAndJsapiTicket(你的企业微信id,
            			 应用私钥);
            	 String token = (String) map.get("access_token");
                 String postdata = sw.createpostdata(推送人员id, "text", 应用id, "content","消息提醒");
                 String resp = sw.post("utf-8", send_weChatMsg.CONTENT_TYPE,(new urlData()).getSendMessage_Url(), postdata, token);
                 System.out.println(token);
                 String a = sw.getDep(token);
                 System.out.println(a);
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
    }
    

    将上面需要修改的进行相对应的修改,我相信不会出现什么问题

    那么现在我们已经完成了第一步,向企业微信中的某一个部门进行消息推送,接下来需要做的是 获取jenkins构建之后的构建结果,然后通过微信的接口向相关的人员进行通知

    接下来我们就来完成jenkins的插件开发
    需要的环境为

    1:maven 版本3以上, 开始我的maven版本低了所以会出现一些莫名其妙的错误,
      后来换成了3.6,一切问题就都没了.所以maven的版本需要进行注意一下.
    2:Jdk 需要在1.6以上,我自己用的为1.8,没有出现问题
    

    在cmd输入命令 最好是选择一个空的文件夹进行执行

    mvn -Uorg.jenkins-ci.tools:maven-hpi-plugin:create
    运行中间需要输入你的groupId和artifactId,前面的为包名,后面的插件的名称
    然后在文件夹下面就会出现一个maven工程,然后将工程导入自己的开发工具,我用的是eclipse.

    会有一个类为HelloWorldBuilder 这里我就不进行一个介绍了,因为我自己也不特别的懂,以免误导到大家了
    先贴上自己代码

    package com.jysong.jenkins.newplugon;
    
    import java.io.IOException;
    import java.util.Map;
    
    import javax.servlet.ServletException;
    
    import org.kohsuke.stapler.DataBoundConstructor;
    import org.kohsuke.stapler.QueryParameter;
    import org.kohsuke.stapler.StaplerRequest;
    
    import hudson.Extension;
    import hudson.FilePath;
    import hudson.Launcher;
    import hudson.model.AbstractProject;
    import hudson.model.Run;
    import hudson.model.TaskListener;
    import hudson.tasks.BuildStepDescriptor;
    import hudson.tasks.BuildStepMonitor;
    import hudson.tasks.Builder;
    import hudson.tasks.Notifier;
    import hudson.tasks.Publisher;
    import hudson.util.FormValidation;
    import jenkins.model.Jenkins;
    import jenkins.tasks.SimpleBuildStep;
    import net.sf.json.JSONObject;
    
    /**
     * Sample {@link Builder}.
     *
     * <p>
     * When the user configures the project and enables this builder,
     * {@link DescriptorImpl#newInstance(StaplerRequest)} is invoked and a new
     * {@link HelloWorldBuilder} is created. The created instance is persisted to
     * the project configuration XML by using XStream, so this allows you to use
     * instance fields (like {@link #name}) to remember the configuration.
     *
     * <p>
     * When a build is performed, the {@link #perform} method will be invoked.
     *
     * @author Kohsuke Kawaguchi
     */
    public class HelloWorldBuilder extends Notifier implements SimpleBuildStep {
    	
    	private final String name;
    	public String getName() {
    		return name;
    	}
    
    	private final String corpid;
    	private final String secret;
    	private final int pushdepid;
    	private final int agentid;
    	private final String push;
    	
    	public String getCorpid() {
    		return corpid;
    	}
    
    	public String getSecret() {
    		return secret;
    	}
    
    	public int getPushdepid() {
    		return pushdepid;
    	}
    
    	public int getAgentid() {
    		return agentid;
    	}
    
    	public String getPush() {
    		return push;
    	}
    
    	@DataBoundConstructor
    	public HelloWorldBuilder(String name, String corpid, String secret, int pushdepid, int agentid, String push) {
    		super();
    		this.name = name;
    		this.corpid = corpid;
    		this.secret = secret;
    		this.pushdepid = pushdepid;
    		this.agentid = agentid;
    		this.push = push;
    	}
    
    	@SuppressWarnings("deprecation")
    	@Override
    	public void perform(Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener) {
    			send_weChatMsg sw = new send_weChatMsg();
    //			String fullDisplayName = build.getFullDisplayName();
    //			String[] split = fullDisplayName.split("#");
    //			String name1 = split[1].trim();
    		try {
    			//获取构建结果
    			String string = build.getResult().toString();
    			int number = build.getNumber();
    			String resuit = null;
    			if(string.equals("SUCCESS")){
    				resuit="构建结果:成功";
    			}else if(string.equals("FAILURE")){
    				resuit="构建结果:失败";
    			}else if(string.equals("UNSTABLE")){
    				resuit="构建结果:不稳定";
    			}else if(string.equals("ABORTED")){
    				resuit="构建结果:中断构建";
    			}
    			String url = build.getAbsoluteUrl();
    			Singleton singleton = Singleton.getInstance();
           	    Map<String, Object> map = singleton.getAccessTokenAndJsapiTicket(corpid,secret);
           	    String token = (String) map.get("access_token");
    			String postdata = sw.createpostdata(push, "text", agentid, 
    					"content", name+"任务"+resuit+"\n--------\n"+"构建结果信息:"+url,pushdepid);
    			
    			String resp = sw.post("utf-8", send_weChatMsg.CONTENT_TYPE, (new urlData()).getSendMessage_Url(), postdata,
    					token);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    	}
    
    	
    
    	@Override
    	public BuildStepMonitor getRequiredMonitorService() {
    		return BuildStepMonitor.NONE;
    	}
    
    	@Extension
    	public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {
    		private boolean useFrench;
    
    		public DescriptorImpl() {
    			load();
    		}
    
    		public FormValidation doCheckName(@QueryParameter String value) throws IOException, ServletException {
    			if (value.length() == 0)
    				return FormValidation.error("Please set a name");
    			if (value.length() < 4)
    				return FormValidation.warning("Isn't the name too short?");
    			return FormValidation.ok();
    		}
    
    		public boolean isApplicable(Class<? extends AbstractProject> aClass) {
    			return true;
    		}
    
    		public String getDisplayName() {
    			return "微信配置通知";
    		}
    		
    		public String getDefaultURL() {
                Jenkins instance = Jenkins.getInstance();
                assert instance != null;
                if(instance.getRootUrl() != null){
                    return instance.getRootUrl();
                }else{
                    return "";
                }
            }
    		
    		@Override
    		public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
    			useFrench = formData.getBoolean("useFrench");
    			save();
    			return super.configure(req, formData);
    		}
    
    		public boolean getUseFrench() {
    			return useFrench;
    		}
    	}
    
    	
    }
    
    
    

    会有一个类为HelloWorldBuilder 这里我就不进行一个介绍了,因为我自己也不特别的懂,以免误导到你了,其实自己写的代码也没有几行
    我觉得只需要了解到几个点就行

    1:在jenkins每次构建时都会调用上面perform这个方法,所以我们的逻辑只需要在这里面进行完成.
         里面的参数我在参考别的帖子时,感觉上去是很厉害的.可能自己的方式不对,基本上没用到那几个参数
    2:我们需要让HelloWorldBuilder 这个类继承Notifier这个类 , 
         Notifier这个类就为通知类,简单直观的区别在于如果不是继承这个我们的插件在使用时只能在构建中那个环节使用,
         如果继承了这个类就可以在构建后这个环节进行使用
    3:就是当我们需要什么参数时,我们都可以进行自定义,参数是非常的灵活
    

    在这里插入图片描述
    在这里填写我们需要的参数,jenkins可以在构建时获取到这些参数,当然也是要进行相对应的配置
    在我们导入的工程的配置文件里有一个文件为config.jelly,在这里就可以自定义参数

    在这里插入图片描述
    在这里插入图片描述
    需要注意的是类里面的参数名与配置文件里面的参数名需要一样
    然后在类里面重新生成有参构造,不能把构建函数上面的注解弄没了

    既然已经可以获取到jenkins的构建结果,在这里我们的整个微信插件的编写基本上是已经完成了.我们就需要进到工程目录进行对项目的打包 mvn clean package,会生成一个target文件夹,里面就会有一个hpi的文件我们要的就是这个

    后面进行了一些代码的整改

    1:向部门推送消息,在接口里面有参数,可以直接填入部门id就行
    
    2:添加了一个插件参数,用于除了部门以外的人员进行消息的推送
    
    展开全文
  • 一、需求描述 最近公司将RTX更新为了企业微信,并且准备将之前的OA邮箱之类的都废弃掉了。...和公司负责企业微信推广的同事聊了聊之后,发现可以通过企业微信提供的api来进行开发,然后实现将Je...

    一、需求描述

    最近公司将RTX更新为了企业微信,并且准备将之前的OA邮箱之类的都废弃掉了。而之前我们的Jenkins编译结果都是通过发送到OA邮箱来进行通知的,因此后面OA邮箱被废弃掉的话,那么我们就无法收到Jenkins的编译结果了。

    因此我们得想其他办法来通知相关人员关于Jenkins的编译结果。和公司负责企业微信推广的同事聊了聊之后,发现可以通过企业微信提供的api来进行开发,然后实现将Jenkins的编译结果通过企业微信来发送消息。

    二、了解企业微信的api

    2.1 api相关参考资料

    在腾讯,能够看到的信息如下

    没有更多的消息,企业微信发消息的api和微信企业号发送的有点类似,大致看下即可。

    2.2 公司封装的企业微信发消息的api文档

    公司负责企业微信推广的同事对企业微信发送消息的api进行了再次封装,然后发送了一篇api文档给我,大致如下:

    2.2.1 请求接口步骤

    • 1 获取apid与Secret
      请联系公司内部推广企业微信的同事,可得到调用所需的ClientId与Secret

    • 2 获取token的api
      请求api

    	POST: http://ip地址:8000/connect/token
    	{
    		client_id:步骤1中获得,
    		client_secret:步骤1中获得,
    		grant_type:"client_credentials",
    		scope:"ApiGateway"
    	}
    

    注:body使用x-www-form-urlencoded

    返回的内容

    	返回内容:
    	{
    		"access_token":"",
    		"expires_in": 3600,
    		"token_type":"Bearer"
    	}
    
    • 3 使用步骤2中得到的Bearer Token请求资源.

    2.2.2 请求接口步骤发送微信消息接口说明

      1. 发送图文信息
    POST: http://ip地址:8000/api/wechat/news
    {
       "toUser" : "工号1|工号2....",
       "agentId" : 0,
       "news" : {
           "articles" : [
               {
                   "title" : "中秋节礼品领取",
                   "description" : "今年中秋节公司有豪礼相送",
                   "url" : "URL",
                   "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png",
                   "btntxt":"更多"
               }
            ]
       }
    }
    
      1. 发送文本消息
    POST: http://ip地址:8000/api/wechat/text
    {
       "toUser" : "工号1|工号2....",
       "agentId" : 0,
       "content":"xxxxxx"
    }
    
      1. 文本卡片消息
    POST: http://ip地址:8000/api/wechat/textcard
    
    {
       "toUser" : "工号1|工号2....",
       "agentId" : 0,
       "title" : "领奖通知",
       "description" : "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>",
       "url":"http://www.baidu.com",
       "btntxt":"更多"
       
    }
    

    三、编写python脚本来调用企业微信api

    在你的项目中,加入一个python脚本和一个jenkins账号和企业微信工号的配置文件,如下所示

    在这里插入图片描述

    3.1 编写Jenkins账户对应的企业微信的工号映射表

    上面的python脚本在执行的时候,会将Jenkins账户转换为企业微信的工号,这个转换过程是通过读取Jenkins账户对应的企业微信的工号映射表jenkins_users.xml来进行的。

    jenkins_users.xml的格式如下:

    <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
    <users>
        <user>
            <name>欧阳鹏</name>
            <wechat>000001</wechat>
        </user>
        <user>
            <name>员工2</name>
            <wechat>000002</wechat>
        </user>
        <user>
            <name>员工3</name>
            <wechat>000003</wechat>
        </user>
        <user>
            <name>员工4</name>
            <wechat>000004</wechat>
        </user>
        <user>
            <name>员工4</name>
            <wechat>000005</wechat>
        </user>
    </users>
    

    3.2 python脚本 xutils.py 内容如下

    #!/usr/bin/python2.7  
    # -*- coding: utf-8 -*-
    
    import json
    import os
    import sys
    import time
    import urllib
    import urllib2
    import xml.dom.minidom
    
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    ISOTIMEFORMAT = "%Y-%m%d-%H%M"
    
    TIMEFORMAT = "%Y-%m-%d %H:%M:%S"
    
    # %Y 四位数的年份表示(000-9999)
    # %m 月份(01-12)
    # %d 月内中的一天(0-31)
    FTP_TIMEFORMAT = "%Y-%m-%d"
    
    def getNowTimeForFTP():
        nowtime = time.strftime(FTP_TIMEFORMAT, time.localtime(time.time()))
        return nowtime
    
    def getNowTimeFormat():
        nowtime = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
        return nowtime
    
    
    def getNowTime():
        nowtime = time.strftime(TIMEFORMAT, time.localtime(time.time()))
        return nowtime
    
    class XTCMessage:
        """ ESB接入说明  企业微信接口对接
        1.获取apid与Secret,请联系系统管理部架构及IT可得到调用所需的ClientId与Secret
        2.获取token
            POST: http://ip地址/connect/token
            {
                client_id:步骤1中获得,
                client_secret:步骤1中获得,
                grant_type:"client_credentials",
                scope:"ApiGateway"
            }
            注:body使用x-www-form-urlencoded
    
            返回内容:
            {
                "access_token":"",
                "expires_in": 3600,
                "token_type":"Bearer"
            }
        3.使用步骤2中得到的Bearer Token请求资源.
        """
    
        def __init__(self):
            self.access_token = ''
    
        auth_data = {"client_id": "xxxxxxxxx", "client_secret": "xxxxxxxxx",
                     "grant_type": "client_credentials", "scope": "ApiGateway"}
        auth_url = 'http://ip地址:8000/connect/token'
    
        # x-www-form-urlencoded
        def __post_xwwwformurlencoded(self, url, body_value):
            body_value = urllib.urlencode(body_value)
            request = urllib2.Request(url, body_value)
            response = urllib2.urlopen(request)
            print response.getcode()
            print response.geturl()
            ret = response.read()
            return ret
    
        def login(self):
            data = self.__post_xwwwformurlencoded(self.auth_url, self.auth_data)
            json_data = json.loads(data)
            self.access_token = 'Bearer ' + json_data['access_token']
            return
    
        # x-www-form-urlencoded
        def __post(self, url, body, token):
            request = urllib2.Request(url)
            request.add_header('Content-TYPE', 'application/json')
            request.add_header('Authorization', self.access_token)
            response = urllib2.urlopen(request, json.dumps(body))
            print response.getcode()
            print response.geturl()
            ret = response.read()
            return ret
    
        def send_text(self, users, message):
            msg_text_url = 'http://ip地址:8000/api/wechat/text'
            """  发送文本消息
            POST: http://ip地址/api/wechat/text
            {
               "toUser" : "工号1|工号2",
               "agentId" : 0,
               "content":"xxxxxx"
            }
            """
            data = {"toUser": users, "agentId": 0, "content": message}
            print('send_text():url = %s  ,data = %s' % (msg_text_url, data))
            self.__post(msg_text_url, data, self.access_token)
    
        def send_card(self, users, title, detail, link='http://www.baidu.com'):
            """  发送图文信息
            POST: http://ip地址/api/wechat/textcard
            {
               "toUser" : "工号1|工号2....",
               "agentId" : 0,
               "title" : "领奖通知",
               "description" : "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>",
               "url":"http://www.baidu.com",
               "btntxt":"更多"
            }
            """
            msg_card_url = 'http://ip地址:8000/api/wechat/textcard'
            data = {"toUser": users, "agentId": 0, "title": title, "description": detail, "url": link}
            print('send_card():url = %s  ,data = %s' % (msg_card_url, data))
            self.__post(msg_card_url, data, self.access_token)
    
        def send_news(self, users, title, detail, url, picurl):
            """  发送图文信息
            POST: http://ip地址/api/wechat/news
            {
               "toUser" : "工号1|工号2....",
               "agentId" : 0,
               "news" : {
                   "articles" : [
                       {
                           "title" : "中秋节礼品领取",
                           "description" : "今年中秋节公司有豪礼相送",
                           "url" : "URL",
                           "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png",
                           "btntxt":"更多"
                       }
                    ]
               }
            }
            """
            msg_news_url = 'http://ip地址:8000/api/wechat/news'
            data = {"toUser": users, "agentId": 0, "news": {
                "articles": [{"title": title, "description": detail, "url": url, "picUrl": picurl}]}}
            print('send_news():url = %s  ,data = %s' % (msg_news_url, data))
            self.__post(msg_news_url, data, self.access_token)
    
    
    def call_xtcmessager(argv):
        xtcmsger = XTCMessage()
        xtcmsger.login()
        if len(argv) == 3:
            xtcmsger.send_text(argv[1], argv[2])
        elif len(argv) == 5:
            xtcmsger.send_card(argv[1], argv[2], argv[3], argv[4])
        elif len(argv) == 6:
            xtcmsger.send_news(argv[1], argv[2], argv[3], argv[4], argv[5])
        else:
            print('error: parameter wrong!')
            print(argv)
    
    class Jenkins():
        def __init__(self):
            self.argv = []
    
        def get_wechat(self, fname, username):
            """
                获取jenkins用户名对应的企业微信的工号 ,比如:jenkins用户名   【欧阳鹏】对应的工号是【0000001】
                参数:
                       fname 配置文件名
                       username:Jenins用户名
           """
            if os.path.exists(fname):
                # filecontent = XmlReader.read_content(self,fname)
                # if None != filecontent:
                # dom = xml.dom.minidom.parseString(filecontent)
                dom = xml.dom.minidom.parse(fname)
                collection = dom.documentElement
                users = collection.getElementsByTagName("user")
    
                for idx in range(0, len(users)):
                    user = users[idx]
    
                    name = user.getElementsByTagName('name')[0].childNodes[0].data
                    wechat = user.getElementsByTagName('wechat')[0].childNodes[0].data
    
                    if username == name:
                        return wechat
    
            print('wechat of user ' + username + ' can not be found!')
            return ''
    
        def sendmessage(self, title, job_name, build_number, branch, user, git_commit, build_url,
                        weichat_receivers):
            """
                 发送jenkins编译消息给企业微信
                  参数:
                        title 提醒标题
                        job_name:Jenins任务名
                        build_number: Jenins编译次数
                        branch: git分支
                        user: Jenins编译触发者
                        git_commit: git commit sha1码
                        build_url: Jenins编译的url地址
                        weichat_receivers:企业微信接收者 , 比如:"欧阳鹏|员工2"  用 | 分隔
            """
            self.argv.append('vrix')
    
            message = """		
    				  <li><font color="#0B610B">%(TITLE)s</font><li>
    				  <li><font color="#0B610B">构建信息</font><li>
    				  <li>------------------------<li>
    				  <li>%(TIME)s<li>
    				  <li>------------------------<li>
    				  <li>用户名&nbsp;:%(USER)s</li>
    				  <li>任务名&nbsp;:%(PROJECT_NAME)s</li>
    				  <li>分支名&nbsp;:%(GIT_BRANCH)s</li>
    				  <li>构建编号&nbsp;:第%(BUILD_NUMBER)s次构建</li>
    				  <li>GIT&nbsp;SHA1&nbsp;:%(GIT_COMMIT)s</li>
    				  <li>构建日志&nbsp;:<a href="%(BUILD_URL)sconsole">%(BUILD_URL)sconsole</a></li>
    				  <li>FTP归档地址如下所示:(用户名:xxxx 密码:xxxx)</li>
    				  <li>ftp://ftp的ip地址/project/AndroidPhone/%(PROJECT_NAME)s/%(FTP_TIME)s-git-%(GIT_COMMIT)s-build-%(BUILD_NUMBER)s<li>
    				  <li>静态代码分析报告</li>
    				  <li>Android Lint 报告&nbsp;: <a href="%(BUILD_URL)sandroidLintResult">%(BUILD_URL)sandroidLintResult </a></li>
    			      <li>FindBugs 报告&nbsp;:<a href="%(BUILD_URL)sfindbugsResult">%(BUILD_URL)sfindbugsResult </a></li>
    			      <li>发送企业微信信息给&nbsp;:%(WEICHAT_RECEIVERS)s</li>
    			""" % dict(
                TITLE=title,
                TIME=getNowTime(),
                USER=user,
                GIT_BRANCH=branch,
                PROJECT_NAME=job_name,
                BUILD_NUMBER=build_number,
                GIT_COMMIT=git_commit,
                BUILD_URL=build_url,
                WEICHAT_RECEIVERS=weichat_receivers,
                FTP_TIME = getNowTimeForFTP()
            )
            # 最终要发送的企业微信user拼接列表
            wechat_receiver_users_string = ''
            # 分隔外面传进来的  企业微信接收者
            weichat_receivers_list = weichat_receivers.split('|')
            for weichat_receiver_user in weichat_receivers_list:
                wechat_user = self.get_wechat('jenkins_users.xml', weichat_receiver_user)
                print('Jenkins user:' + weichat_receiver_user + " weichat user_number:" + wechat_user)
                if wechat_user == '':
                    print('Jenkins user:' + weichat_receiver_user + " weichat user_number is null")
                else:
                    #  拼接成格式:   "工号1|工号2"
                    wechat_receiver_users_string = wechat_receiver_users_string + wechat_user + "|"
    
    
            if wechat_receiver_users_string != '':
                print('-----------send msg to user ' + wechat_receiver_users_string)
                self.argv.append(wechat_receiver_users_string)
                self.argv.append(message)
            else:
                print('-----------send to vrix')
                # 默认发送给 00001  如果要加人的话  用 | 分开
                # self.argv.append('工号1|工号1')
                self.argv.append('00001')
                self.argv.append(message)
            call_xtcmessager(self.argv)
    
    
    def call_jenkins(argv):
        """
             发送jenkins编译消息给企业微信
             参数:
                        title 提醒标题
                        jobname:Jenins任务名
                        build_number: Jenins编译次数
                        branch: git分支
                        user: Jenins编译触发者
                        git_commit: git commit sha1码
                        build_url: Jenins编译的url地址
        """
        job_name = argv[2]
        build_number = argv[3]
        branch = argv[4]
        user = argv[5]
        git_commit = argv[6]
        build_url = argv[7]
        weichat_receivers = argv[8]
    
        jenkins = Jenkins()
        jenkins.sendmessage('---Jenkins 构建提醒----', job_name, build_number, branch, user, git_commit,
                            build_url, weichat_receivers)
    
    
    if __name__ == "__main__":
        if len(sys.argv) > 1:
            print(sys.argv)
            if sys.argv[1] == 'jenkins':
                print('--- jenkins')
                call_jenkins(sys.argv)
            else:
                call_xtcmessager(sys.argv)
        else:
            print('usage:')
            print('测试  python xutils.py "00001|00002" \"hello world!\" ')
            print('测试  Jenkins的话   python xutils.py jenkins ${JOB_NAME} ${BUILD_NUMBER} ${GIT_BRANCH} ${BUILD_USER} ${JOB_DESCRIPTION} ${GIT_COMMIT} ${CAUSE} ${BUILD_URL} ${PROJECT_URL} ${WEICHAT_RECEIVERS} ')
    
    

    该脚本在jenkins的任务中,通过shell脚本进行调用,具体怎么调用,继续看下面的内容。

    四 、配置jenkins的任务

    4.1 勾选【Set jenkins user build variables】

    【构建环境】中 勾选【Set jenkins user build variables】,不然jenkins的环境变量无法读取

    在这里插入图片描述

    4.2 添加一个【参数构建化过程】

    在【General】中,添加一个【参数构建化过程】,增加一个参数,如下所示:

    在这里插入图片描述

    • 参数名
      参数名为 WEICHAT_RECEIVERS,

    • 默认值
      默认值为要发送给企业微信的人员列表,

    可以是一个列表,用 | 分隔符分开即可,比如 员工1|员工2|员工3|员工4|欧阳鹏|员工5|员工6|员工7
    也可以只写一个人,比如欧阳鹏

    • 描述

    要发送给企业微信的人员列表

    4.3 增加一个构建过程 【Execute Shell】

    如下图所示,在 jenkins的具体任务中,【构建】最后加入一个【Execute shell】,然后复制脚本进入即可

    在这里插入图片描述

    # 进入workspace
    cd ${WORKSPACE}
    # 执行python脚本,发送编译结果给企业微信
    python xutils.py jenkins ${JOB_NAME} ${BUILD_NUMBER} ${GIT_BRANCH} ${BUILD_USER} ${JOB_DESCRIPTION} ${GIT_COMMIT} ${CAUSE} ${BUILD_URL} ${PROJECT_URL} ${WEICHAT_RECEIVERS}
    
    

    4.4 删除原来的发送邮件到OA的模块,因为已经没意义了。

    【构建后操作】–>【Editable Email Notification】 然后点击右上角的 红色叉号,直接删除邮件发送模块
    在这里插入图片描述

    4.5 配置FTP地址

    【构建后操作】–>【Send build artifacts over FTP 】

    配置地址为 下面的内容,因为脚本中是读取这个地址的

    AndroidPhone/${JOB_NAME}/'yyyy-MM-dd-HH-mm-ss-'git-${GIT_COMMIT}-build-${BUILD_NUMBER}
    

    在这里插入图片描述

    五、执行Jenkins任务

    5.1 执行jenkins

    1、因为添加了 动态参数化构建,所以点击这个 【Build with Parameters】进行构建

    在这里插入图片描述

    2、点击之后,会让你修改 要通知的企业微信的人员列表,如果不修改的话,直接点击【开始构建】,如果要修改的话,请按提示的格式来即可。

    在这里插入图片描述

    5.2 执行完毕

    发送给单个用户

    在这里插入图片描述
    1、当jenkins项目执行完毕之后,就会自动发送消息给企业微信
    在这里插入图片描述

    2、在你的企业微信中,会收到 【门户君】发送给你的消息,如下所示。
    在这里插入图片描述

    如上所示,ftp的地址直接打印出来了,这样就可以直接方便提测,直接复制地址即可。

    发送给多个用户

    配置发送给多个用户

    在这里插入图片描述

    编译过程中
    在这里插入图片描述

    多人接收到该消息

    在这里插入图片描述

    六、总结

    使用到的技术有:Python、Shell、XML、Jenkins,大家可以了解了解!

    关于使用shell脚本实现该功能的,可以参考下面的链接:


    作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
    转载请保留原文地址:https://blog.csdn.net/qq446282412/article/details/86361318
    ☞ 本人QQ: 3024665621
    ☞ QQ交流群: 123133153
    github.com/ouyangpeng
    oypcz@foxmail.com
    如果本文对您有所帮助,欢迎您扫码下图所示的支付宝和微信支付二维码对本文进行打赏。


    展开全文
  • 例如我的网站小蝴蝶内网穿透当有用户下单的时候,或者付款的时候我希望能接到实时的通知…… 接入过程 step1 创建我们自己的应用 记录如下两个地方的信息 step2 WeChatData import lombok....

            做开发的小伙伴应该都知道部分场景下我们需要针对业务的部分异常或者操作埋点;例如我的网站小蝴蝶内网穿透 当有用户下单的时候,或者付款的时候我希望能接到实时的通知……

     

    接入过程

    step1

    创建我们自己的应用

     

    记录如下两个地方的信息

     

    step2

    WeChatData

    import lombok.Data;
    import lombok.experimental.Accessors;
    
    /**
     * @Author l'amour solitaire
     * @Description 微信消息发送实体类
     * @Date 2021/1/8 下午5:02
     **/
    @Data
    @Accessors(chain = true)
    public class WeChatData {
        /**
         * 成员账号
         */
        private String touser;
    
        /**
         * 消息类型
         */
        private String msgtype;
    
        /**
         * 企业用用的agentid
         */
        private String agentid;
    
        /**
         * 实际接收map类型数据
         */
        private Object text;
    
    }

     

    WeChatUrlData

    import lombok.Data;
    import lombok.experimental.Accessors;
    
    /**
     * @Author l'amour solitaire
     * @Description 微信授权请求
     * @Date 2021/1/8 下午5:01
     **/
    @Data
    @Accessors(chain = true)
    public class WeChatUrlData {
    
        /**
         * 企业Id
         */
        private String corpid;
    
        /**
         * secret管理组的凭证密钥
         */
        private String corpsecret;
    
    }

     

    WeChatMsgSend

    import com.google.gson.Gson;
    import com.google.gson.reflect.TypeToken;
    import lombok.extern.slf4j.Slf4j;
    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 java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Author l'amour solitaire
     * @Description 微信发送消息
     * @Date 2021/1/8 下午5:07
     **/
    @Slf4j
    public class WeChatMsgSend {
    
        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");
    
        private static Gson gson = new Gson();
    
        private static final String GET_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s";
        private static final String SEND_MESSAGE_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";
    
        /**
         * @Author l'amour solitaire
         * @Description 微信授权请求,GET类型,获取授权响应,用于其他方法截取token
         * @Date 2021/1/8 下午5:07
         **/
        protected 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);
            } catch (Exception e) {
                e.getStackTrace();
            } finally {
                response.close();
            }
            log.info("resp:{}", resp);
            return resp;
        }
    
        /**
         * @Author l'amour solitaire
         * @Description corpid应用组织编号 corpsecret应用秘钥 获取toAuth(String Get_Token_Url)返回结果中键值对中access_token键的值
         * @Date 2021/1/8 下午5:08
         **/
        public String getToken(String corpid, String corpsecret) throws IOException {
            WeChatMsgSend sw = new WeChatMsgSend();
            String resp = sw.toAuth(String.format(GET_TOKEN_URL, corpid, corpsecret));
            log.info("resp=====:" + resp);
            try {
                Map<String, Object> map = gson.fromJson(resp, new TypeToken<Map<String, Object>>() {
                }.getType());
                return map.get("access_token").toString();
            } catch (Exception e) {
                e.getStackTrace();
                return resp;
            }
        }
    
        /**
         * @Author l'amour solitaire
         * @Description 创建微信发送请求post数据 touser发送消息接收者 ,msgtype消息类型(文本/图片等), application_id应用编号。
         * 本方法适用于text型微信消息,contentKey和contentValue只能组一对
         * @Date 2021/1/8 下午5:09
         **/
        public String createpostdata(String touser, String msgtype, int application_id, String contentKey,
                                     String contentValue) {
            WeChatData wcd = new WeChatData();
            wcd.setTouser(touser);
            wcd.setAgentid(String.valueOf(application_id));
            wcd.setMsgtype(msgtype);
            Map<Object, Object> content = new HashMap<Object, Object>();
            content.put(contentKey, contentValue);
            wcd.setText(content);
            return gson.toJson(wcd);
        }
    
        /**
         * @Author l'amour solitaire
         * @Description @Title 创建微信发送请求post实体,charset消息编码,contentType消息体内容类型,
         * url微信消息发送请求地址,data为post数据,token鉴权token
         * @Date 2021/1/8 下午5:09
         **/
        public String post(String charset, String contentType, String url, String data, String token) 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();
            }
            log.info("call [{}], param:{}, resp:{}", url, data, resp);
            return resp;
        }
    
        /**
         * @Author l'amour solitaire
         * @Description 这里的相关信息可以走配置
         * @Date 2021/1/8 下午5:10
         **/
        public static void send(String massege) {
            WeChatMsgSend swx = new WeChatMsgSend();
            try {
                String token = swx.getToken("corpid", "corpsecret");
                String postdata = swx.createpostdata("企业用户", "text", 123, "content", massege);
                String resp = swx.post("utf-8", WeChatMsgSend.CONTENT_TYPE, SEND_MESSAGE_URL, postdata, token);
                log.info("获取到的token======>" + token);
                log.info("请求数据======>" + postdata);
                log.info("发送微信的响应数据======>" + resp);
            } catch (Exception e) {
                e.getStackTrace();
            }
        }
    
    }

    上面的代码大家可以根据自己的项目调整,相关的信息可以放配置里面去,这里为了简单演示,代码就没有太工整了……

    欢迎关注公众号《JAVA拾贝》

    展开全文
  • /// 企业通知消息接口发送消息 https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.dWrFg3&treeId=172&articleId=104973&docType=1 可用此方法 /// </summary> /// 目标用户</param> /// ...

    前期资料如怎么配置,怎么创建应用 参考:http://blog.csdn.net/xxdddail/article/category/6776456 感谢原作者

    Oa效果图如下:


    引用:

    TopSDK.dll 下载网址https://open-doc.dingtalk.com/doc/sdk.htm?spm=a219a.7629140.0.0.mItbfA&treeId=177&articleId=104963&docType=1 选择 .Net版本TOP接入SDK  下载后改扩展名为zip  rar然后解压然后得到dll 在项目中引用

    using DingTalk.Api;
    using DingTalk.Api.Request;
    using DingTalk.Api.Response;

    主要调用 CorpMessageCorpconversationAsyncsendResponse 企业会话消息异步发送

    参考文章:https://open-doc.dingtalk.com/docs/doc.htm?treeId=172&articleId=28915&docType=2

     #region 钉钉发送消息通知
            /// <summary>  
            /// 企业通知消息接口发送消息  https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.dWrFg3&treeId=172&articleId=104973&docType=1  可用此方法
            /// </summary>  
            /// <param name="toUser">目标用户</param>  
            /// <param name="toParty">目标部门.当toParty和toUser同时指定时,以toParty来发送。</param>  
            /// <param name="content">消息文本</param>  
            /// <returns></returns>  
            //public static SendMessageResult GroupSendTextMsg(string toUser, string toParty, string content)
            //{
            //    var txtmsg = new
            //    {
            //        touser = toUser,//员工id列表(消息接收者,多个接收者用|分隔)
            //        toparty = toParty,//部门id列表
            //        msgtype = MsgType.text.ToString(),
            //        agentid = ConfigHelper.FetchAgentID(),//应用的标识
            //        text = new
            //        {
            //            content = content
            //        }
            //    };
            //    string apiurl = ApiTool.FormatApiUrlWithToken(Urls.group_message_send);
            //    string json = JsonConvert.SerializeObject(txtmsg);
            //    var result = Analyze.Post<SendMessageResult>(apiurl, json);
            //    return result;
            //}
    
            /// <summary>
            /// 发送到部门群组\单个人
            /// </summary>
            /// <param name="toUser"></param>
            /// <param name="content"></param>
            /// <param name="forceUpdate"></param>
            /// <returns></returns>
            public static void AsyncSendDingTalkTextMessage(string toUser, string msgContent,string trueName, bool forceUpdate = false)
            {
                log4net.ILog log = log4net.LogManager.GetLogger("发送钉钉text消息格式");
                ApiTool.EndUpdateAccessToken(forceUpdate);
                IDingTalkClient client = new DefaultDingTalkClient(Urls.corpconversation_asyncsend);
                var txtmsg = new CorpMessageCorpconversationAsyncsendRequest()
                {
                    Msgtype = MsgType.text.ToString(),//消息类型
                    AgentId = Convert.ToInt64(ConfigHelper.FetchAgentID()),// 	微应用的id
                    UseridList = toUser,//接收者的用户userid列表 
                    Msgcontent = "{ \"content\": \""+msgContent+"\" } "
                };
    
                 CorpMessageCorpconversationAsyncsendResponse rsp = client.Execute(txtmsg, AccessToken.Value);
                var result = rsp.Body;
                log.Info(new LogContent(ShareApplyClass.GetIPAddress(),HttpContext.Current.Server.UrlDecode(trueName) , "发送钉钉text消息格式", msgContent + "信息如下。" + result));
            }
    
            /// <summary>
            ///  通过判断个人是否有钉钉审批进行发送钉钉消息
            /// </summary>
            /// <param name="insertType"></param>
            /// <param name="approveID"></param>
            /// <param name="dingTalkID">下一步审批人的钉钉ID</param>
            /// <param name="trueName">下一步审批人的真实姓名</param>
            /// authorName 提交人
            public static void AsyncSendDingTalkOAMessage(string insertType, string approveID, string dingTalkID, string trueName, string authorName, bool forceUpdate = false)
            {
                log4net.ILog log;
                ApiTool.EndUpdateAccessToken(forceUpdate);
                IDingTalkClient client = new DefaultDingTalkClient(Urls.corpconversation_asyncsend);
                using (WHSMDataContext db = new WHSMDataContext())
                {
                    var getApproveInfo = db.ApprovePlanOrder_Header.SingleOrDefault(x => x.approveID.Equals(approveID));
                    if (getApproveInfo != null)
                    {
                        var approveTitle = getApproveInfo.approveTitle;
                        log = log4net.LogManager.GetLogger(approveTitle);
                        //
                        var workName = WorkFlowModule.ReturnTypeName(insertType);
                        //存放是采购、领用等
                        var typeName = string.Empty;
                        var form = new List<OaBodyFormJsonList>() { };     
       form = new List<OaBodyFormJsonList>()
                                {
                                    new OaBodyFormJsonList() {key="流水号:",value=getApproveInfo.approveNo },
                                    new OaBodyFormJsonList() {key="申请人:",value=getApproveInfo.approvePlanPeople },
                                    new OaBodyFormJsonList() {key = "申请部门:", value = db.Base_Department.SingleOrDefault(x=>x.sortId==getApproveInfo.approveDept).sortName},
                                    new OaBodyFormJsonList() {key="申请时间:",value=getApproveInfo.approveDate.ToString() },
                                    new OaBodyFormJsonList() {key="入库仓库:",value=db.Base_WareHouse.SingleOrDefault(x=>x.whcode==getApproveInfo.approveWh).whname },
                                    new OaBodyFormJsonList() {key="备注说明:",value=getApproveInfo.approveNote }
                                };
                                typeName = "采购";
        List<ApprovePlanOrder_Details> lstApproveDetails = new List<ApprovePlanOrder_Details>();
                      var getApproveDetails = db.ApprovePlanOrder_Details.Where(x => x.approveID.Equals(approveID)).ToList();
                        if (getApproveDetails.Count > 0)
                        {
                            lstApproveDetails = getApproveDetails;
                        }
                        else
                        {
    //                        SELECT a.*from ApprovePlanOrder_Details a INNER JOIN(
    //SELECT b.approveID from ApprovePlanOrder_Header a INNER JOIN(SELECT approveID, CgCostsID from ApprovePlanOrder_Header)
    //b on a.approveID = b.CgCostsID where a.approveID = '77634e39-25aa-4cec-8688-5f17c41fb56d')b on a.approveID = b.approveID
                            lstApproveDetails  = (from a in db.ApprovePlanOrder_Details
                                                  join b in (
                                                      (from a0 in db.ApprovePlanOrder_Header
                                                       join b in (
                                                         (from approveplanorder_header in db.ApprovePlanOrder_Header
                                                           select new
                                                           {
                                                               approveplanorder_header.approveID,
                                                               approveplanorder_header.CgCostsID
                                                           })) on new { approveID = a0.approveID } equals new { approveID = b.CgCostsID }
                                                       where  a0.approveID.Equals(approveID)
                                                       select new  { b.approveID  })) on a.approveID equals b.approveID
                                                  select a
                                                   ).ToList();
                        }
                        if (lstApproveDetails.Count > 0)
                        {
                            System.Text.StringBuilder sb = new System.Text.StringBuilder();
                            sb.Append("所属流程:" + workName + "\n");
                            sb.Append(typeName + "商品总数:" + lstApproveDetails.Sum(x => x.goodsBuyNo) + " 件(个)\n");
                            sb.Append("上一步办理人给您的提示:" + db.Approve_NextStepInfo.Single(x =>
                            x.Instance_ID.Equals(approveID) && x.Reg_Code == getApproveInfo.approvePeople).App_InnerIdea);
                            var url = System.Configuration.ConfigurationManager.AppSettings["HttpUrl"]+"DingTalkApproval.aspx?insertType=" + insertType + "&approveID=" + approveID + "&DingTalkID=" + dingTalkID + "&TrueName=" + trueName + "";
                            oa newOA = new oa()
                            {
                                message_url = url,
                                pc_message_url = "dingtalk:dingtalkclient/page/link?url=" + HttpContext.Current.Server.UrlEncode(url) + "&pc_slide=true",
                                head = new OaHeadJsonList() { bgcolor = "FFBBBBBB", text = approveTitle },
                                body = new OaBodyJsonList()
                                {
                                    title = "流程标题:[" + approveTitle + "]正等待您的审批",
                                    form = form,
                                    rich = new OaRichJsonList() { num = lstApproveDetails.Sum(x => x.goodsBuyNo * x.goodsPrice).ToString(), unit = "元" },
                                    file_count = string.IsNullOrWhiteSpace(getApproveInfo.approveFilePath) == true ? "" : "1",
                                    content = sb.ToString(),
                                    author = string.IsNullOrWhiteSpace(authorName) == true ?trueName : authorName,
                                    //db.Base_SuperAdmin.SingleOrDefault(x => x.dingtalkid == getApproveInfo.approvePeople).truename
                                },
                            };
                            var jsonContent = JsonConvert.SerializeObject(newOA);
                            var txtmsg = new CorpMessageCorpconversationAsyncsendRequest()
                            {
                                Msgtype = MsgType.OA.ToString(),//消息类型
                                AgentId = Convert.ToInt64(ConfigHelper.FetchAgentID()),//     微应用的id
                                UseridList = dingTalkID,//接收者的用户userid列表 
                                Msgcontent = jsonContent
                            };
                            CorpMessageCorpconversationAsyncsendResponse rsp = client.Execute(txtmsg, AccessToken.Value);
                            var result = rsp.Body;
    
                            log.Info(new LogContent(ShareApplyClass.GetIPAddress(), trueName,
          "发送钉钉信息", "发送流程编号为:" + approveID + "的标题[" + approveTitle + "]信息如下。" + result));
                        }
                        else
                        {
                            log.Fatal(new LogContent(ShareApplyClass.GetIPAddress(), trueName,
          "发送钉钉信息", "发送流程编号为:" + approveID + "的标题[" + approveTitle + "]没有明细信息"));
                        }
    }
    }
    

    调用方法参考:

     AsyncSendDingTalkTextMessage 方法参考:

     var sendMessageAlert = "您的" + typeName + ":【" + approveTitle + "】已被【" + trueName + "】审批通过。";
     ShareApplyClass.AsyncSendDingTalkTextMessage(regDingTalkID,  sendMessageAlert,trueName);
    
    AsyncSendDingTalkOAMessage 方法参考: 
    var handlerType = ((Button)sender).CommandArgument == "5" ? "已成功退回给【" + drpBackApprovePeople.SelectedItem.Text + "】,等待重新处理后再次审批。" : "正在等待【" + drpApprovePeople.SelectedItem.Text + "】审批,如紧急或等待时间过长,您可点击催办进行催促当前办理人进行审批。";
                            var sendMessageAlert = "【" + txtApproveTtile.Value + "】" + handlerType;
                            var agreeCode = ((Button)sender).CommandArgument == "5" ? drpBackApprovePeople.SelectedValue : drpApprovePeople.SelectedValue;
                            if (ShareApplyClass.GetIfDingtalkAgreeStatus(agreeCode) == 'Y')
                            {
                                ShareApplyClass.AsyncSendDingTalkOAMessage(Request["insertType"], Request["ApproveID"], agreeCode, ShareApplyClass.GetBackNextApproveTureName(agreeCode), Request["TrueName"]);
                            }
                            else
                            {
                                ShareApplyClass.AsyncSendDingTalkTextMessage(agreeCode, sendMessageAlert, Request["TrueName"]);
                            }
    
    



    展开全文
  • 企业微信是腾讯微信团队打造的企业通讯与办公工具,具有与微信一致的沟通体验,丰富的OA应用,和连接微信生态的能力,可帮助企业连接内部、连接生态伙伴、连接消费者。专业协作、安全管理、人即服务。成为了大部分...
  • 说起快递通知提醒大家都不陌生,经常购物的小伙伴基本天天都有各家快递给发送的取货通知短信。丰巢及各家快递柜的迅速普及极大的减轻了送货员的时间和精力,取件通知短信的更多使用也带来了各种问题。比如短信被手机...
  • 9 decodeRefundNotifyInfo 解析微信通知的加密内容,返回数组(解密AES的应该用openssl方法) 仅供参考,请勿用于业务开发,出了问题我不负责的昂== class WeChatPayService { private static $instance ; ...
  • 支付结果通知

    千次阅读 2018-06-07 22:51:41
    对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15/15/30/180/1800/1800...
  • Web网站通知系统设计

    千次阅读 2014-07-25 09:40:45
    写在前面: 通知系统是网站信息传播机制的重要的一部分,足够写一大章来说明。本文只梳理设计原则,后续相关内容会持续更新。 这里的通知包括但不限于公告、提醒或消息(不同使用场景下的功能定义不同)。 关于各...
  • 微信企业号开发 - 企业号配置

    千次阅读 2015-07-21 14:18:14
    微信企业号是微信为企业客户提供的移动服务,旨在提供企业移动应用入口。它可以帮助企业建立员工、上下游供应链与企业IT 系统间的连接。利用企业号,企业或第三方服务商可以快速、低成本的实现高质量的企业移动轻...
  • 知识库 编号:002

    万次阅读 2012-08-30 10:27:09
    : 位于杭州西边 合伙企业新入伙必须经过: : 全部同意 和五四前后的许多前驱者不同,鲁迅对现实对未来并不乐观,甚至有些消沉,他躲在S会馆里抄古碑,也以写小说来排遣苦的寂寞。这些小说后结集为: : 《呐喊》 ...
  • 某Java大佬在地表最强Java企业(阿里)面试总结

    万次阅读 多人点赞 2020-08-23 19:48:06
    而产品经理则是互联网企业的核心岗位之一,产品经理负责用户需求分析、竞品分析、产品设计和上下层需求的沟通,需要超强的逻辑思考和分析能力、用户洞察能力和沟通协作能力。(阐述自己对岗位的理解)。 而我毕业于...
  • MT 210 Notice to Receive通知接收

    千次阅读 2017-11-05 19:30:31
    MT 210 Notice to Receive通知接收 MT 210 电文范围 此电文类型: ... ...这是一个提前通知给账户服务机构,告知他将收到贷记到收报行账户的...在企业-银行环境使用电文,参考www.swift.com.中的企业客户MT电文使用指南
  • 关于公布部分非法刊物的通知各系(部)处室: 现将冀职改办字(2006)48号《关于公布部分非法刊物的通知》转发给你们,请务必及时传达给每一位专业技术人员。根据冀职改办规定,今年职称评审对公布取缔的非法刊物上...
  • Atitit 微信支付 支付结果通用通知

    千次阅读 2016-10-18 23:43:44
    微信支付 支付结果通用通知   Wechat hto sh ma 返回页面return_url - 熊佳佳的博客 d ,only notyfi url-...       接口链接 该链接是通过【统一下单API】中提交的参数notify_url设置,如果链接无法...
  • 日常生活中的企业监控

    千次阅读 2020-02-25 19:19:00
    10年后,数据公司如雨后春笋般涌现,它们不仅包括像 Facebook 和谷歌这样的大公司,还包括来自不同行业数以千计的其他企业,它们不断地相互分享和交易数据。公司已经开始整合来自网络和智能手机的数据,链接他们已经...
  • 第三类医疗器械经营企业注册条件 相关法规: ...(四)国家食品药品监督管理总局《关于印发体外诊断试剂(医疗器械)经营企业验收标准的通知》。 办理程序: 申请人提交申请材料——→(材料...
  • 分布式事务10_最大努力通知

    千次阅读 2018-02-16 21:35:05
    分布式事务10_最大努力通知形势更多干货分布式事务处理一分布式事务二分布式事务处理三分布式事务四_基于可靠消息的最终一致性分布式事务五_基于可靠消息的最终一致性_异常流程分布式事务六_常规MQ队列分布式事务七_...
  • 当存在用户发起提现无需审核时 ,当用户作为服务提供者向企业提供服务时,等等场景。 企业需要向用户付款,缺又不想走繁琐的审核程序,通过第三方支付平台转账接口向用户直接转账,即时到账。 2.微信【企业付款】-...
  • asp.net mvc推送微信消息通知

    千次阅读 2019-01-16 16:40:54
    asp.net mvc推送微信消息通知1.将CacheHelper类添加进项目2调用接口类3调用微信接口 1.将CacheHelper类添加进项目 源码如下(亦可以百度): public class CacheHelper { /// /// 获取数据缓存 /// /// 键 public ...
  • (事件编号与描述) 672 身份验证服务(AS)票证得到成功发行与验证。 673 票证授权服务(TGS)票证得到授权。TGS是一份由Kerberos 5.0版票证授权服务(TGS)发行、且允许用户针对域中特定服务进行身份验证的...
  • 实战:基于ESB的企业系统集成

    千次阅读 2016-03-18 13:36:25
    随着企业信息化程度的不断提高,越来越多的信息系统逐渐上线,这些系统在为企业带来效益的同时,也带来了一些让开发及维护人员头痛不已的问题,主要表现在系统分散,信息孤岛,交互复杂,维护成本太高。 多说无益,...
  • 基于SOA的OA与ERP的整合应用10 引言办公自动化(Office automation,OA)系统是实现办公自动化的信息系统。企业资源计划系统( Enterp rise ResourcePlanning, ERP)是对企业中的
  • iOS企业开发者计划介绍及使用方法

    万次阅读 2012-05-23 17:56:45
    现在苹果公司有三种计划可以注册:个人计划、企业个人计划、企业开发者计划。   * 个人计划:以个人身份注册、发布程序至Apple Store、作者的名字是个人的。 * 企业个人计划:以企业身份注册、发布程序至Apple ...
  • 前言:今天逛了一逛Zac的博客,看了一篇文章,我认为可以给许多seo小白或者说老手都很有帮助,所以今天把这篇文章发出来给大家看一看,一个企业或者说公司,里面的SEO部门应该做些什么,SEO初期应该做些什么,企业...
  • 企业微信流程审批开发

    千次阅读 热门讨论 2020-10-15 13:40:04
    企业ID(我的企业企业信息》企业ID) 审批应用ID,审批应用Secret,审批流模版ID 模版ID位置比较变态点开审批流在url里 创建流程所需的参数还差三个 1.获取token /** * 获取access_token * * @...
  • 插件比较-社区版和企业版 NO. 插件类型 社区版 企业版 1 审计跟踪 提供额外的流程监控功能。如,获取报表或用户通知 流程数据控制 将流程数据存入数据表“app_report_*”...
  • 关于公布部分非法刊物的通知及冀职改办字 2006 48号
  • 青岛大学2006年硕士研究生复试通知

    千次阅读 2006-04-13 10:52:00
    青岛大学2006年硕士研究生复试通知注意:今年我校不再寄发书面复试通知书,在复试资格查询系统中具有复试资格的考生,请按照此通知的要求进行复试。根据国家教育部“关于做好2006年全国研究生录取工作的通知(征求...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,848
精华内容 5,139
关键字:

企业通知编号