微信公众号开发二

标签: 微信 分类: Javascript 创建时间:2019-12-19 08:19:03 更新时间:2025-01-17 10:39:23

1.接入客服功能

微信公众号提供了客服功能,开发者可以通过添加微信客服插件来添加客服服务功能。
(1) 添加客服插件

(2) 绑定客服微信号

(3) 打开网页聊天,用客服的微信扫一扫二维码,就可以实现和微信公众号用户进行一对一的会话了。用户在微信公众号输入任何文字和语音,图片等,网页上都可以显示出来。

(4) 用户在微信公众号上输入文字图片等消息发送给微信公众号后台。

注意
如果公众号处于开发者模式,可能上面的操作就不管用了。

如果公众号处于开发模式,普通微信用户向公众号发消息时,微信服务器会先将消息POST到开发者填写的url上,如果希望将消息转发到客服系统,则需要开发者在响应包中返回MsgType为transfer_customer_service的消息,微信服务器收到响应后会把当次发送的消息转发至客服系统。

2.获取用户发送给后台的消息

(1) 明文的方式比较简单,公众号服务器会将用户发送的消息,按如下格式:

1
2
3
4
5
6
7
8
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
</xml>

转发到开发者填写的url上。只需要解析这个xml,提取有用信息即可。如果需要转发到客服,只需要返回:

1
2
3
4
5
6
 <xml> 
<ToUserName><![CDATA[touser]]></ToUserName>
<FromUserName><![CDATA[fromuser]]></FromUserName>
<CreateTime>1399197672</CreateTime>
<MsgType><![CDATA[transfer_customer_service]]></MsgType>
</xml>

(2) 密文的时候,就比较麻烦
使用安全模式的时候,微信公众号通过post将数据发送到开发者配置的服务器url上:

1
2
3
4
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<Encrypt><![CDATA[msg_encrypt]]></Encrypt>
</xml>

其中msg_encrypt即为用户名为发送的消息内容(见第一条),另外在url中还附带了signature签名参数,java可以使用:request.getParameter("signature") 方法获取到其中的内容,以便验证签名是否正确。msg_encrypt解密,可以使用官方提供的java代码中的WXBizMsgCrypt.decrypt函数进行解密,解密后,获取其中的内容,修改MsgType类型为transfer_customer_service,就可以使用WXBizMsgCrypt.encryptMsg方法进行加密,然后返回给微信服务器,消息就被正常的转发到客服页面了,打开微信客服页面,就可以进行实时对话了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@RequestMapping(value = "/",method = RequestMethod.POST)
public void loginPOST(){
try{
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");

// 随机字符串
String noncestr= RandomStringUtils.randomAlphanumeric(16);
// 时间戳获取到秒数
String timestamp=String.valueOf(System.currentTimeMillis()/1000);

PrintWriter out = response.getWriter();
// parseXml使用了dom4j解析xml数据
Map<String, String> parseXml = WeiXinUtil.parseXml(request);
String tousername = parseXml.get("ToUserName");

// 解密
String encryptString=parseXml.get("Encrypt");
String s=WeiXinUtil.decryptMsg(encryptString);

// 将xml解析位map
parseXml = WeiXinUtil.parseXmlString(s);

String msgType = parseXml.get("MsgType");
String content = parseXml.get("Content");
String CreateTime = parseXml.get("CreateTime");
String fromusername = parseXml.get("FromUserName");

// 将消息转发给客服
/*
* <xml>
* <ToUserName><![CDATA[touser]]></ToUserName>
* <FromUserName><![CDATA[fromuser]]></FromUserName>
* <CreateTime>1399197672</CreateTime>
* <Content><![CDATA[this is a test]]></Content>
* <MsgType><![CDATA[transfer_customer_service]]></MsgType>
* </xml>
*
* */

// 判断消息类型MsgType
/*
* 链接:link
* 地理位置:location
* 小视频:shortvideo
* 视频:video
* 语音:voice
* 图片:image
* 文本:text
* */

StringBuilder stringBuilder=new StringBuilder("<xml>");
stringBuilder.append("<ToUserName><![CDATA["+fromusername+"]]></ToUserName>");
stringBuilder.append("<Content><![CDATA["+content+"]]></Content>");
stringBuilder.append("<CreateTime>"+CreateTime+"</CreateTime>");
stringBuilder.append("<FromUserName><![CDATA["+tousername+"]]></FromUserName>");
stringBuilder.append("<MsgType><![CDATA[transfer_customer_service]]></MsgType>");
stringBuilder.append("</xml>");

// 加密字符串
String result=WeiXinUtil.encryptMsg(stringBuilder.toString(),timestamp,noncestr);

// 转发到客服
out.write(result);
}catch (Exception e){
System.out.println(e);
logger.error("loginPOST",e);
}

}

注意
其中需要注意的点。
(1) 消息体的xml一定要正确。
(2) 再转发时ToUserName是用户的OpenID,FromUserName是微信公众号,和接收到的消息解析后的ToUserName、FromUserName正好相反。

3.事件推送

除了用户的消息会被微信服务器使用POST推送到用户填写的服务器地址之外,用户点击公众号底部的菜单,微信服务器也会把相应的点击事件POST到用户填写的服务器地址上。信息如下:

1
2
3
4
5
6
7
8
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[CLICK]]></Event>
<EventKey><![CDATA[EVENTKEY]]></EventKey>
</xml>

还有其他类型的事件推送:点击菜单跳转链接时的事件推送、scancode_push:扫码推事件的事件推送、scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框的事件推送、pic_sysphoto:弹出系统拍照发图的事件推送、pic_photo_or_album:弹出拍照或者相册发图的事件推送、pic_weixin:弹出微信相册发图器的事件推送、location_select:弹出地理位置选择器的事件推送、点击菜单跳转小程序的事件推送,后台的POST接口,可以分别根据相应的内容,进行回复。

服务器地址的配置,可以在公众号后台->基本配置->服务器配置中找到。

参考文章:
1.微信公众平台开发(58)自定义菜单
2.微信会把点击事件推送给开发者
3.微信公众号开发之自定义菜单
4.接入概述 登录微信公众平台官网后,在公众平台官网的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。也就是说,这个服务器地址,要既能支持get请求,又能支持post请求

4.模板消息通知

公众号内,存在几类不同的消息:群发消息、被动回复消息、客服消息、模板消息。消息通知,即向用户推送消息。微信公众号分为服务号和订阅号,服务号支持模板消息,订阅号不支持模板消息。

(1) 登录微信公众号,选择添加功能插件->选择模板消息

(2) 点击申请,填写相关信息,主营行业、副营行业,申请理由等,进行模板消息的申请

(3) 发送模板消息,这个工作其实挺简单的,就是构造一个post请求,将相关的参数作为body发送到微信指定的地址上即可。下面是一个示例,其中的TemplateData就像参考文章3中编写的差不多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public CommonResult wxmsg(){
try{
// 构建地址
String access=wxUtils.getCredentialsToken();
String url="https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+access;
// 将数据封装到模板中
String postData=TemplateData.New()
.setTouser("oJ293jrt5b")
.setTemplate_id("9x_4")
.setUrl("")
.add("productType","恭喜啊","#173177")
.add("name","恭喜啊","#173177")
.add("number","恭喜啊","#173177")
.add("remark","恭喜啊","#173177")
.build();

// 发送请求
String result = HttpRequest.post(url)
.header("Content-Type", "application/json")
.body(postData)
.execute().body();
// 获取返回值
if(result!=null&&!result.isEmpty()){
JSONObject resultObj=JSONObject.parseObject(result);
if(resultObj.getInteger("errcode")==0&&resultObj.getString("errmsg").equals("ok")){
return CommonResult.success("通知发送成功");
}
}
return CommonResult.failed("通知发送失败");
}catch (Exception e){
return CommonResult.failed("通知发送失败");
}
}

(4) 获取全部模版消息
构造 get 请求,连接如下,可以获取全部模版消息,但是不包括 类目模版消息

1
https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=
参考文章:
1.公众号、小程序发送消息能力 (这篇文章对公众号内各种不同的消息及其应用场景和限制进行了一个概述)
2.模板消息 (微信官方关于模板消息的说明)
3.微信公众号开发之模板消息 (对于接口的封装也有些讲解,就是把发送通知的组成json数据的方法进行了封装)
4.公众号模版消息介绍 (公众号模板消息,向认证后的服务号开放。所有服务号都可以在功能->添加功能插件处看到申请模板消息功能的入口,但只有认证后的服务号才可以申请模板消息的使用权限并获得该权限。)
5.Hutool工具类之HttpUtil使用Https
6.微信模版消息 touser 能否多个 群发 (微信官方是不提供群发功能的,如果非要发送给多个人,只能多次调用,一天最多推送10000条)

5.订阅消息通知

上面的模板消息,是说再2021年4月30号之前还能使用的,等过了这个时间之后,就不能继续使用了,无奈我是刚开始接触这个发送消息的功能的,等我开发完这个模板消息的功能之后,刚好过期了,不能用了,也是罪了。我使用模板消息的时候,赶紧挺好用的啊,不知道脑残的微信团队为什么还要多此一举。老板的要求是实现给用户发送消息,可以任意发送,这可难到我了,微信模板消息都不能实现发送任意推送的消息,只能发送特定的模板类消息,更别提什么订阅消息了,订阅消息有两种,一种一次性订阅,一种是长期订阅。一次性订阅,就是用户订阅一次,平台就只能发送一条消息;长期订阅就是和模板消息类似了,但是现在只对政府和医疗类订阅开放,对于我们这种电力设备仪器仪表行业,更不可能有这个长期订阅功能了。

参考文章:
1.微信服务号模板消息即将下线,一箭射中教育企业的膝盖 (写了对各行各业的影响)
2.微信下线模板消息,订阅通知如何使用? (微信于今日宣布 《服务号模板消息能力调整》,原先的模板消息能力将于 2021 年 4 月 30 日 24:00 下线,届时将无法使用此接口发送模板消息。微信开发社区是一片狼藉啊,是一边倒的说法,去掉模板消息功能,就是一个烂的不能再烂的决定了。)
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。