最近用java做了一个实现在微信小程序内根据用户发送的消息内容回复用不通的消息功能,相当于一个自动回复的客服消息,效果图如下:
当用户在小程序输入框中输入内容或其他操作时,后台根据用户输入的内容动态给用户回复,微信的参考文档为:
微信小程序客服消息回复开发
customerServiceMessage.send 档
微信的垃圾文档我就懒得喷了啊,按它这个文档做简直是一团乱麻
整个流程是这样的我们可以在微信小程序的开发者后台设置消息的回调地址,当用户进入小程序的客服页面,或在客服页面的输入框中输入内容时,微信小程序就会根据我们配置的消息回调地址把这条消息或这个事件回调给我们的服务器,我们可以进行相关处理,并给用户回复消息如上图显示的那些我输入 22 ,给我回复一个链接地址或其他东西,可以在回调中配置;
然后遇到的几个问题说一下:
1、回调地址解析:在微信后台配置回调地址时它会先发一个get请求测试地址是否可用,然后用户在发消息的时候会发post请求把用户消息发过来:如下
@Override
public void autoResponse(HttpServletRequest req, HttpServletResponse resp) throws Exception {
switch (req.getMethod().toUpperCase()){
case GET:
doGet(req, resp);
break;
case POST:
doPost(req, resp);
break;
default:
throw new IllegalStateException("Unexpected value: " + req.getMethod());
}
}
//回复get请求,说明地址可用
private void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception {
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
String signature = req.getParameter("signature");
String timestamp = req.getParameter("timestamp");
String nonce = req.getParameter("nonce");
String echostr = req.getParameter("echostr");
String sortString = SignUtil.sort(config.getRespToken(), timestamp, nonce);
String mySignature = SignUtil.sha1(sortString);
if (mySignature != null && mySignature != "" && mySignature.equals(signature)) {
resp.getWriter().write(echostr);
} else {
log.error("签名校验失败.");
}
}
//回复post请求
private void doPost(HttpServletRequest req, HttpServletResponse resp)throws Exception {
try{
resp.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
String line = null;
StringBuffer xmlStr = new StringBuffer();
BufferedReader reader = req.getReader();
while ((line = reader.readLine()) != null) {
log.info(line);
xmlStr.append(line);
}
Map<String,String> map = XmlUtil.xmlToMap(xmlStr.toString());
CustomerMsgReq customerMsgReq = WXAutoRespReqUtil.buildResponseMessage(map, config.getAppletsAppId(), config.getRespHref(), config.getRespText());
log.info("send custom message param :{}", customerMsgReq);
if(customerMsgReq == null){
return;
}
String accessToken = getCacheAccessToken();
JSONObject sendResult = wxAppletsRemoting.messageCustomSend(accessToken, customerMsgReq);
log.info("send custom message result :{}", sendResult);
if(sendResult.containsKey(("errcode")) && sendResult.getString("errcode").equals("0.0")){
return;
}
log.error("access token may expire", sendResult);
accessToken = getRealAccessToken();
sendResult = wxAppletsRemoting.messageCustomSend(accessToken, customerMsgReq);
log.info("resend custom message result :{}", sendResult);
}finally {
resp.getWriter().println("success");
}
这里有一个问题,根据文档描述应该可以直接在回调接口中回复用户消息,如下这样操作,但是实际开发中,我测试这样回复用户没有收到消息,也不报错,不知道是我理解有问题还是哪里配置有问题,欢迎各位小伙伴指正
private void doPost(HttpServletRequest req, HttpServletResponse resp)throws Exception {
try{
resp.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
String line = null;
StringBuffer xmlStr = new StringBuffer();
BufferedReader reader = req.getReader();
while ((line = reader.readLine()) != null) {
log.info(line);
xmlStr.append(line);
}
Map<String,String> map = XmlUtil.xmlToMap(xmlStr.toString());
//链接内容
String msgText ="<a href=\""+href+"\">"+text+"</a>";ZZ
//发送方帐号
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
String respXml = String.format( "<xml>" +
"<ToUserName><![CDATA[%s]]></ToUserName>" +
"<FromUserName><![CDATA[%s]]></FromUserName>" +
"<CreateTime>%s</CreateTime>" +
"<MsgType><![CDATA[text]]></MsgType>" +
"<Content><![CDATA[%s]]></Content>" +
"</xml>", fromUserName, toUserName, getMessageCreateTime(), msgText);
resp.setContentType("application/xml; charset=utf-8");
resp.getWriter().println(respXml);
}finally {
}
因为不能直接回复,需要调微信
POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
这个接口给用户回复,参考微信文档
因此又牵扯到获取微信小程序appid,secret 然后根据appid,secret获取access_token 还有access_token的缓存等一大堆问题,我就不细说了,涉及到的代码已提交到码云
最近又有小伙伴请教微信小程序自动回复的问题,在交流的时候,发现了一个新的东西,微信云回复,逻辑就是在微信小程序的后台上传一个云服务的回复接口js,后面要自动回复用户消息的时候就直接调 云服务的回复接口,这样可以省去提供自动回复服务端的实现,可以不用自己再维护后台服务了