最近一个微信的项目里需要发送微信模板消息给卖家或者供应商等,微信开发其实也就按照微信的官方接口要求组装起来即可,下面简单介绍一下我的微信模板发送代码。
1.获取access token,至于access token是什么,大家可以自行微信接口文档看一下,这边不多说
获取access token我这边主要是用定时器没大概2分钟获取一次,每天获取的次数是100000次,用法如下:
1 #region 2 3 using System; 4 using System.Timers; 5 6 #endregion 7 8 namespace OAO2O.BusinessService.BLL 9 { 10 public class WeChatTokenKeepBLL 11 { 12 /// <summary> 13 /// 用于存放获取的token 14 /// </summary> 15 private Timer _keepTokenTimer; 16 17 #region access_token对象保持在线 18 19 public void Initial() 20 { 21 // 初始化应用程序池时候,初始化token(第一次请求) 22 _KeepAccessToken(); 23 24 //初始化计时器 25 _keepTokenTimer = new Timer(TimeSpan.FromHours(1.55).TotalMilliseconds); 26 //1.55 TimeSpan.FromHours(1.55).TotalMilliseconds 27 _keepTokenTimer.Elapsed += _keepTokenTimer_Elapsed; 28 _keepTokenTimer.Enabled = true; 29 _keepTokenTimer.Start(); 30 } 31 32 private void _keepTokenTimer_Elapsed(object sender, ElapsedEventArgs e) 33 { 34 _KeepAccessToken(); 35 } 36 37 /// <summary> 38 /// 获取token 39 /// </summary> 40 private void _KeepAccessToken() 41 { 42 string appid = ConfigBLL.APPID; 43 string appSecret = ConfigBLL.APPSECRET; 44 string token = WeChatBLL.GetAccessToken(appid, appSecret); 45 46 ACCESS_TOKEN = token; 47 //Application[Consts.ACCESS_TOKEN] = token; 48 } 49 /// <summary> 50 /// ACCESS_TOKEN 51 /// </summary> 52 public static string ACCESS_TOKEN { private set; get; } 53 54 #endregion 55 } 56 }
2.定义消息主体内容,区分大小写(经过测试必须小写,java的风格)
实体如下:
1 #region 2 3 using System; 4 using System.Collections.Generic; 5 6 #endregion 7 8 namespace OAO2O.BusinessService.Entity 9 { 10 [Serializable] 11 public sealed class WeChatTemplatecsMsg 12 { 13 public string touser { get; set; } 14 public string template_id { get; set; } 15 public string topcolor { get; set; } 16 public string url { get; set; } 17 public Dictionary<string, MessageData> data { get; set; } 18 } 19 20 [Serializable] 21 public sealed class MessageData 22 { 23 public string value { get; set; } 24 public string color { get; set; } = "#1C86EE"; 25 } 26 }
需要注意的是因为我们这边是内部调用不走soap协议,如果走soap协议, Dictionary<string, MessageData>是不能被二进制序列化的
3.编写发送微信消息方法
代码如下:
1 public static string SendTempleteMessage(WeChatTemplatecsMsg messageInfo, string access_token) 2 { 3 try 4 { 5 //临时测试脚本,正式使用将换成模板配置文件(等需求组确定模板之后) 6 string jsonDataParams = messageInfo == null 7 ? "" : SerializationEx.ToJson(messageInfo); 8 string requestUrl = string.Format(ConfigBLL.URL_POSTTEMELETETEXTMESSAGE, access_token); 9 return WebAPITransfer.Request(requestUrl,"POST", jsonDataParams); 10 } 11 catch (Exception ex) 12 { 13 return ex.Message; 14 } 15 }
主要就是将实体转为json,没什么难度
4.定义xml配置文件
因为刚刚上面那个实体中,除了data和touser需要后期代码取值,三个是可以配置的,故写在配置文件中
1 <Configs> 2 <WeChatNodes> 3 <!--(上级)新客户加入通知--> 4 <WeChatNode name="AutoRegisterSuccess"> 5 <template_id>消息模板id</template_id> 6 <topcolor>这个现在貌似没用了,但是还是要保留</topcolor> 7 <url>收到消息下面有个详情,就是这边配置的地址</url> 8 </WeChatNode> 9 <!--(上级)订单支付完成--> 10 <WeChatNode name="PaySuccess"> 11 <template_id>消息模板id</template_id> 12 <topcolor>这个现在貌似没用了,但是还是要保留</topcolor> 13 <url>收到消息下面有个详情,就是这边配置的地址</url> 14 </WeChatNode> 15 <!--(上级)订单取消通知--> 16 <WeChatNode name="OrderCancleSuccess"> 17 <template_id>消息模板id</template_id> 18 <topcolor>这个现在貌似没用了,但是还是要保留</topcolor> 19 <url>收到消息下面有个详情,就是这边配置的地址</url> 20 </WeChatNode> 21 <!--(上级)订单退货通知--> 22 <WeChatNode name="OrderReturnSuccess"> 23 <template_id>消息模板id</template_id> 24 <topcolor>这个现在貌似没用了,但是还是要保留</topcolor> 25 <url>收到消息下面有个详情,就是这边配置的地址</url> 26 </WeChatNode> 27 <!--(上级)营业额达标通知--> 28 <WeChatNode name="MonthSalesSuccess"> 29 <template_id>消息模板id</template_id> 30 <topcolor>这个现在貌似没用了,但是还是要保留</topcolor> 31 <url>收到消息下面有个详情,就是这边配置的地址</url> 32 </WeChatNode> 33 </WeChatNodes> 34 </Configs>
5.编写反序列化xml文件到对象的类
首先需要编写一个与xml关联的类,代码如下:
1 #region 2 3 using System; 4 using System.Collections.Generic; 5 using System.Xml.Serialization; 6 7 #endregion 8 9 namespace OAO2O.BusinessService.Entity 10 { 11 [XmlRoot("WeChatNode")] 12 public class WeChatNode 13 { 14 //定义NodeName属性的序列化为name节点的属性 15 [XmlAttribute("name")] 16 public string NodeName { get; set; } 17 18 //设置TemplateId属性序列化为Xml子元素template_id 19 [XmlElement("template_id")] 20 public string TemplateId { get; set; } 21 22 //设置Topcolor属性序列化为Xml子元素topcolor 23 [XmlElement("topcolor")] 24 public string Topcolor { get; set; } 25 26 //设置Url属性序列化为Xml子元素url 27 [XmlElement("url")] 28 public string Url { get; set; } 29 } 30 31 [XmlRoot("Configs")] 32 public class WeChatNodes 33 { 34 [XmlArray("WeChatNodes"), XmlArrayItem("WeChatNode")] 35 public WeChatNode[] WeChatNodeList { get; set; } 36 } 37 38 /// <summary> 39 /// 节点名称枚举 40 /// </summary> 41 public enum EnumNodeName 42 { 43 /// <summary> 44 /// 自动注册成功 45 /// </summary> 46 AutoRegisterSuccess, 47 /// <summary> 48 /// 支付成功 49 /// </summary> 50 PaySuccess, 51 /// <summary> 52 /// 订单取消成功 53 /// </summary> 54 OrderCancleSuccess, 55 /// <summary> 56 /// 订单退货成功 57 /// </summary> 58 OrderReturnSuccess, 59 /// <summary> 60 /// 营业额达标成功 61 /// </summary> 62 MonthSalesSuccess 63 } 64 }
然后编写反序列化xml的公共类,放到公共类库中,代码如下:
1 public static T FromXmlFile<T>(string xmlFile) 2 { 3 if ( !File.Exists(xmlFile)) throw new ArgumentNullException(xmlFile, "文件不存在!"); 4 using (FileStream fs = new FileStream(xmlFile, FileMode.Open, FileAccess.Read)) 5 { 6 XmlSerializer ser = new XmlSerializer(typeof(T)); 7 return (T)ser.Deserialize(fs); 8 } 9 }
6.因为微信模板消息体都是固定的五个参数,故把获取微信模板实体的方法放到一个公共的类中
代码如下:
1 /// <summary> 2 /// 构造微信模板消息体 3 /// </summary> 4 public class TemplateMsgConstructor 5 { 6 /// <summary> 7 /// 从xml中获取所有的发送微信的节点集合 8 /// </summary> 9 public static WeChatNodes WeChatNodes = SerializationEx.FromXmlFile<WeChatNodes>(AppDomain.CurrentDomain.BaseDirectory + "\\config\\WechatMsgTemplate.xml"); 10 11 /// <summary> 12 /// (上级)新客户加入通知 13 /// </summary> 14 /// <param name="memberId"></param> 15 /// <param name="memberName"></param> 16 /// <returns></returns> 17 public static WeChatTemplatecsMsg GetMemberRegistMsg(string memberId, string memberName) 18 { 19 #region 模板 20 21 // { { first.DATA} } 22 // 会员编号:{ { keyword1.DATA} } 23 // 加入时间:{ { keyword2.DATA} } 24 // { { remark.DATA} } 25 26 #endregion 27 28 //微信发送节点 29 WeChatNode weChatNode = WeChatNodes.WeChatNodeList.FirstOrDefault(item => item.NodeName == EnumNodeName.AutoRegisterSuccess.ToString()); 30 var msg = new WeChatTemplatecsMsg 31 { 32 template_id = weChatNode?.TemplateId, 33 touser = string.Empty, 34 topcolor = weChatNode?.Topcolor, 35 url = weChatNode?.Url, 36 data = new Dictionary<string, MessageData> 37 { 38 {"first", new MessageData {value = $"您推荐的客户【{memberName}】已经加入了南京宁商汇"}}, 39 {"keyword1", new MessageData {value = memberId}}, 40 {"keyword2", new MessageData {value = DateTime.Now.ToString("yyyy-MM-dd HH:mm")}}, 41 {"remark", new MessageData {value = "感谢您的努力!"}} 42 } 43 }; 44 return msg; 45 } 46 47 /// <summary> 48 /// (上级)订单支付完成 49 /// </summary> 50 /// <param name="orderId"></param> 51 /// <param name="orderTotalMoney"></param> 52 /// <param name="orderName"></param> 53 /// <returns></returns> 54 public static WeChatTemplatecsMsg GetOrderPayMsg(string orderId, string orderTotalMoney) 55 { 56 #region 模板 57 58 // { { first.DATA} } 59 // 60 // 支付金额:{ { orderMoneySum.DATA} } 61 // 商品信息:{ { orderProductName.DATA} } 62 // { { Remark.DATA} } 63 64 #endregion 65 66 //微信发送节点 67 WeChatNode weChatNode = WeChatNodes.WeChatNodeList.FirstOrDefault(item => item.NodeName == EnumNodeName.PaySuccess.ToString()); 68 var msg = new WeChatTemplatecsMsg 69 { 70 template_id = weChatNode?.TemplateId, 71 touser = string.Empty, 72 topcolor = weChatNode?.Topcolor, 73 url = weChatNode?.Url, 74 data = new Dictionary<string, MessageData> 75 { 76 {"first", new MessageData {value = $"图牛有订单,请关注!(订单号:{orderId})"}}, 77 {"orderMoneySum", new MessageData {value = orderTotalMoney + "元"}}, 78 {"orderProductName", new MessageData {value = orderId}}, 79 {"Remark", new MessageData {value = " 如有问题请致电400 666 2060!"}} 80 } 81 }; 82 return msg; 83 } 84 85 /// <summary> 86 /// (上级)订单取消通知 87 /// </summary> 88 /// <param name="orderId"></param> 89 /// <returns></returns> 90 public static WeChatTemplatecsMsg GetCancleOrderMsg(string orderId) 91 { 92 #region 模板 93 94 // { { first.DATA} } 95 // 订单编号:{ { keyword1.DATA} } 96 // 时间:{ { keyword2.DATA} } 97 // { { remark.DATA} } 98 99 #endregion 100 101 //微信发送节点 102 WeChatNode weChatNode = WeChatNodes.WeChatNodeList.FirstOrDefault(item => item.NodeName == EnumNodeName.OrderCancleSuccess.ToString()); 103 var msg = new WeChatTemplatecsMsg 104 { 105 template_id = weChatNode?.TemplateId, 106 touser = string.Empty, 107 topcolor = weChatNode?.Topcolor, 108 url = weChatNode?.Url, 109 data = new Dictionary<string, MessageData> 110 { 111 {"first", new MessageData {value = "订单被取消,请关注!"}}, 112 {"keyword1", new MessageData {value = orderId}}, 113 {"keyword2", new MessageData {value = DateTime.Now.ToString("yyyy-MM-dd HH:mm")}}, 114 {"remark", new MessageData {value = "如有问题请致电400 666 2060!"}} 115 } 116 }; 117 return msg; 118 } 119 120 /// <summary> 121 /// (上级)订单退货通知 122 /// </summary> 123 /// <param name="orderId"></param> 124 /// <param name="orderName"></param> 125 /// <param name="orderTotalMoney"></param> 126 /// <returns></returns> 127 public static WeChatTemplatecsMsg GetSalesReturnMsg(string orderId, string orderTotalMoney) 128 { 129 #region 模板 130 131 // { { first.DATA} } 132 // 订单编号:{ { keyword1.DATA} } 133 // 商品名称:{ { keyword2.DATA} } 134 // 订单金额:{ { keyword3.DATA} } 135 // { { remark.DATA} } 136 137 #endregion 138 139 //微信发送节点 140 WeChatNode weChatNode = WeChatNodes.WeChatNodeList.FirstOrDefault(item => item.NodeName == EnumNodeName.OrderReturnSuccess.ToString()); 141 var msg = new WeChatTemplatecsMsg 142 { 143 template_id = weChatNode?.TemplateId, 144 touser = string.Empty, 145 topcolor = weChatNode?.Topcolor, 146 url = weChatNode?.Url, 147 data = new Dictionary<string, MessageData> 148 { 149 {"first", new MessageData {value = "订单被退货,请关注!"}}, 150 {"keyword1", new MessageData {value = orderId}}, 151 {"keyword2", new MessageData {value = orderId}}, 152 {"keyword3", new MessageData {value = orderTotalMoney + "元"}}, 153 {"remark", new MessageData {value = DateTime.Now.ToString("yyyy-MM-dd HH:mm")}} 154 } 155 }; 156 return msg; 157 } 158 159 /// <summary> 160 /// (上级)营业额达标通知 161 /// </summary> 162 /// <param name="orderSumMoney"></param> 163 /// <param name="first"></param> 164 /// <returns></returns> 165 public static WeChatTemplatecsMsg GetOrderAmountUpToStandard(string orderSumMoney, 166 string first = "完善企业资质后,") 167 { 168 #region 模板 169 170 // { { first.DATA} } 171 // 汇总周期:{ { keyword1.DATA} } 172 // 营业额:{ { keyword2.DATA} } 173 // { { remark.DATA} } 174 175 #endregion 176 177 //微信发送节点 178 WeChatNode weChatNode = WeChatNodes.WeChatNodeList.FirstOrDefault(item => item.NodeName == EnumNodeName.MonthSalesSuccess.ToString()); 179 var msg = new WeChatTemplatecsMsg 180 { 181 template_id = weChatNode?.TemplateId, 182 touser = string.Empty, 183 topcolor = weChatNode?.Topcolor, 184 url = weChatNode?.Url, 185 data = new Dictionary<string, MessageData> 186 { 187 {"first", new MessageData {value = $"您当月累计营业额已达标。{first}将于当月最后一日激活解冻资金。"}}, 188 { 189 "keyword1", 190 new MessageData 191 { 192 value = 193 new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).ToString("yyyy-MM-dd") + "-" + 194 DateTime.Now.ToString("yyyy-MM-dd") 195 } 196 }, 197 {"keyword2", new MessageData {value = orderSumMoney + "元"}}, 198 {"remark", new MessageData {value = "感谢您的关注!"}} 199 } 200 }; 201 return msg; 202 } 203 }
7.找到需要发送微信的环节,添加发送微信消息的代码
代码如下:
1 /// <summary> 2 /// 新客户加入发送微信通知 3 /// </summary> 4 /// <param name="reg"></param> 5 private static void SendRegistMsg(RegisterEntity reg) 6 { 7 try 8 { 9 //获取WeChatTemplatecsMsg实体 10 WeChatTemplatecsMsg entity = TemplateMsgConstructor.GetMemberRegistMsg(reg.MemberId, reg.MemberName); 11 //设置被发送者openid 12 entity.touser = GetMemberMasterOpenId(reg.MemberId); 13 14 CommonBLL.DebugLog(entity, "SendRegistMsg-Param"); 15 16 if (!entity.touser.IsEmptyString()) 17 { 18 //发送微信消息 19 var result = WeChatBLL.SendTempleteMessage(entity, WeChatTokenKeepBLL.ACCESS_TOKEN); 20 CommonBLL.DebugLog(result, "SendRegistMsg-Result"); 21 } 22 } 23 catch(Exception ex) 24 { 25 CommonBLL.DebugLog(ex, "SendRegistMsg-Exception"); 26 } 27 }
总结:
整个流程按步骤下来大家发现其实也没啥难度,第三方接口开发只要对方接口描述比较准确,各种规定比较明确,基本就是封装成接口需要的东西就完事了