实现语言  java

实现的前提:已经实现了公众号的其他一些基本功能,比如访问菜单。

1、微信公众号中添加客服功能 

2、添加客服

 3、接口编写。

3-1、 我找了好久才找到。微信公众号接口文档中--自定义菜单中,创建一个类型为click的菜单(如下图1,2)

图1

这里会去访问 创建客服会话的- 新版客服功能 - 创建会话接口,微信文档中都有(https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN)

然后点击立即咨询 客服连接成功 回复消息。

图2

{    "type":"click","name":"立即咨询","key":"kf"},

kf是自定义的。

*  1、click:点击推事件用户点击click类型按钮后,微信会会向你的接口工程发送消息(你自己接口工程的地址是公众号配置中的验证地址 如图3)消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;

这个button 会跟关注和取消关注一样去发送给后端服务器请求,就是配置的地址。 (公众号中配置的地址位置如下)

图3

3-2 、java代码  ,

controller

/*** 处理消息请求(包括关注和取消关注) 包好所有微信发给服务器的通知** @param msg* @return*/
@RequestMapping(value = "validate", method = RequestMethod.POST, produces = {MediaType.TEXT_XML_VALUE})
@ResponseBody
public Object handleMesg(@RequestBody RecieveMsg msg) throws Exception {Object out = weiXinService.handleMessage(msg);System.out.println(String.valueOf(msg));return out;
}

service

/*** 取消和关注操作 推送  也有客服按钮请求的操作(kf为自定义)*  * @param msg* @return*/
public Object handleMessage(RecieveMsg msg) {if(Objects.equals(msg.getEvent(),"CLICK") &&Objects.equals(msg.getEventKey(),"kf")){String kf = kfseesion(msg.getFromUserName());PushMsg out = new PushMsg();out.setFromUserName(msg.getToUserName());out.setToUserName(msg.getFromUserName());out.setMsgType("text");out.setCreateTime(System.currentTimeMillis());out.setContent(kf);return out;}String url = "/handleValidate";JSONObject obj = HttpClientUtils.httpRequest(weiXinBean.getHttpUrl() + url, "POST", JSONUtils.beanToJson(msg));PushMsg out = new PushMsg();out.setContent(String.valueOf(obj.get("content")).replace("APPID",weiXinBean.getAppId()).replace("REDIRECT_URL",weiXinBean.getYuMing()));out.setFromUserName(String.valueOf(obj.get("fromUserName")));out.setMsgType(String.valueOf(obj.get("msgType")));out.setToUserName(String.valueOf(obj.get("toUserName")));out.setCreateTime(obj.getLong("createTime"));return out;
}

/**
 * 功能描述:创建会话
 * @param:
 * @return:
 * @author: syl
 * @date: 2019/2/23 0023 下午 4:02
 */
public String kfseesion(String openId) {
    String accessToken = Tools.getAccessToken(getAccessTokenUrl());
    String urlToken = WxContstants.kfSessionUrl.replace("ACCESS_TOKEN",accessToken);

JSONObject kfInfo = getonlinekflist();
    if(!StringUtils.isEmpty(kfInfo.get("kf_online_list"))){
        JSONArray kfOnlineList = kfInfo.getJSONArray("kf_online_list");
        if(kfOnlineList.size()==0){
            return "服务人员未在线";
        }
        Random random = new Random();
        int i = random.nextInt(kfOnlineList.size());
        JSONObject pj = new JSONObject();
        JSONObject item = (JSONObject) kfOnlineList.get(i);
        pj.put("kf_account",String.valueOf(item.get("kf_account")));
        //pj.put("kf_account","kf2002@gh_02e32b1d4ea2");
        pj.put("openid",openId);
        JSONObject jsonObject = HttpClientUtils.httpRequest(urlToken,"POST", String.valueOf(pj));
        Integer errcode =  jsonObject.getInteger("errcode");
        String errmsg =  jsonObject.getString("errmsg");
        if (Objects.equals(0, errcode)) {
            return "客服连接成功,请问有什么可以帮助您";
        } else if(Objects.equals(65415, errcode)) {
            return "服务人员未在线";
        }else{
            return errmsg;
        }
    }else{
        return "服务人员未在线";
    }

}

/*** 功能描述:获取在线客服列表 * @param: * @return: * @author: syl* @date: 2019/8/13 0013 上午 10:31*/
public JSONObject getonlinekflist() {String accessToken = Tools.getAccessToken(getAccessTokenUrl());String urlToken = WxContstants.getonlinekflist.replace("ACCESS_TOKEN",accessToken);JSONObject jsonObject = HttpClientUtils.httpRequest(urlToken, "GET", "");return jsonObject;
}

工具类

RecieveMsg.java

package com.navitek.maternal.apiweb.bean;import lombok.Getter;
import lombok.Setter;import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;/*** @author 26968*/
@Setter
@Getter
@XmlRootElement(name="xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class RecieveMsg {/*** 开发者微信号*/protected String FromUserName;/*** 发送方帐号(一个OpenID)*/protected String ToUserName;/***  消息创建时间*/protected Long CreateTime;/*** 消息类型* text 文本消息* image 图片消息* voice 语音消息* video 视频消息* music 音乐消息*/protected String MsgType;/*** 消息id*/protected Long MsgId;/*** 文本内容*/private String Content;/*** 图片链接地址 有系统生成*/private String PicUrl;/*** 多媒体*/private String MediaId;/*** 事件*/private  String Event;/*** 菜单的KEY值*/private String EventKey;/****/private String Ticket;}

WxContstants.java

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;/*** @author 26968*/
public class WxContstants {//保存用户验证码public static ConcurrentMap<String, Map<String, Object>> VERIFY_CODE = new ConcurrentHashMap<String, Map<String, Object>>();//验证码超时时间public static long maxTime = 300;/*** 菜单类型*/public static String VIEW = "view";/*** 网页授权后根据code 获取用access_token*/public static final String WEB_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";/*** 获取用户基本信息接口*/public static final String GET_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";/*** 暂时存储accesstoken*/public static final Map<String, Long> currentHashMap = new HashMap<>();/*** 放token值*/public static final Map<String, Object> TOKEN_MAP = new HashMap<>();public static final String ACCESS_TOKEN = "access_token";/*** 消息类型 (文本类型)*/public static final String TEXT = "text";/*** image类型*/public static final String IMAGE = "image";/*** event 事件类型*/public static final String Event = "event";/*** subscribe 关注事件*/public static final String SUBSCRIBE = "subscribe";/*** unsubscribe 取消关注事件*/public static final String UNSUBSCRIBE = "unsubscribe";/*** 菜单点击事件*/public static final String CLICK = "CLICK";/*** news 图文消息*/public static final String NEWS = "news";/*** 获取access_token的Url*/public static final String ACCESSTOKENURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET";/*** 创建自定义菜单接口*/public static final String ButtonUrl = " https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";/*** 删除菜单*/public static final String DELETEBUTTON = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=";/*** 网页授权url*/public static final String AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT&response_type=code&scope=snsapi_userinfo&state=22#wechat_redirect";/*** 客服相关 新增  获取 删除 绑定*/public static final String addKfUrl = " https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN";public static final String getKfListUrl = " https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN";public static final String getonlinekflist = " https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist?access_token=ACCESS_TOKEN";public static final String delKfUrl = "https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT";public static final String bbKfUrl = " https://api.weixin.qq.com/customservice/kfaccount/inviteworker?access_token=ACCESS_TOKEN";public static final String kfSessionUrl = " https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN";public static final String actSessionUrl = " https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";public static final String templateSend = " https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";}

tools.java

import com.alibaba.fastjson.JSONObject;
import com.navitek.maternalweb.common.WxContstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.UUID;/*** @author 26968*/
@Slf4j
public class Tools {/*** 将 map转化为xml格式** @param params* @return*/public static String toXml(Map<String, String> params) {StringBuilder xml = new StringBuilder();xml.append("<xml>");Iterator iterator = params.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, String> entry = (Map.Entry) iterator.next();String key = (String) entry.getKey();String value = (String) entry.getValue();if (!StringUtils.isEmpty(value)) {xml.append("<").append(key).append(">");xml.append((String) entry.getValue());xml.append("</").append(key).append(">");}}xml.append("</xml>");return xml.toString();}/*** 将xml格式的字符串转化为 map** @param xmlStr* @return*/public static Map<String, String> xmlToMap(String xmlStr) {XmlHelper xmlHelper = XmlHelper.of(xmlStr);return xmlHelper.toMap();}public static String getRealIp(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;}public static String getRealIpV2(HttpServletRequest request) {String accessIP = request.getHeader("x-forwarded-for");return null == accessIP ? request.getRemoteAddr() : accessIP;}/*** 获取access_Token** @return*/public static String getAccessToken(String ACCESSTOKENURL) {/*** @Todo 暂时存在静态 map中*/String accessToken = null;//先判断时间Long tokenTime = StringUtils.isEmpty((Long) WxContstants.currentHashMap.get(WxContstants.ACCESS_TOKEN)) ? 0:(Long) WxContstants.currentHashMap.get(WxContstants.ACCESS_TOKEN);//如果当前时间大于设置的时间则进行重新获取accessTokenif (Instant.now().getEpochSecond() > tokenTime) {JSONObject result = HttpClientUtils.httpRequest(ACCESSTOKENURL, "GET", "");if (StringUtils.isEmpty(result.get(WxContstants.ACCESS_TOKEN))){log.info("调取微信接口获取access_token失败=="+result);}accessToken = String.valueOf(result.get(WxContstants.ACCESS_TOKEN));WxContstants.TOKEN_MAP.put(WxContstants.ACCESS_TOKEN,accessToken);WxContstants.currentHashMap.put(WxContstants.ACCESS_TOKEN,Instant.now().getEpochSecond()+6000);}accessToken = String.valueOf(WxContstants.TOKEN_MAP.get(WxContstants.ACCESS_TOKEN));return accessToken;}public static String getRandCode(){Random ne=new Random();return String.valueOf(ne.nextInt(9999-1000+1)+1000);}public static String getUUID(){UUID uuid=UUID.randomUUID();String str = uuid.toString();String uuidStr=str.replace("-", "");return uuidStr;}}

4、效果。这样就可以实现简单的客服功能了,客服必须在线。 不在线就回复代码中写的反馈信息。

(如图4 ,5)

图4

图5

微信公众号客服 简单实现相关推荐

  1. 微信公众号客服功能如何开通?

    微信公众号客服功能如何使用,很多人想要通过公众号推广自己的产品,但是不知道该如何使用客服功能,其实很简单,在公众号后台就可以设置 首先登陆微信公众号进入公众号后台 然后点击"添加功能插件&q ...

  2. 微信公众号客服系统怎么实现消息提醒,快速回复粉丝留言?

    很多做微信公众号运营的小编,都会有这样的工作经验吧,一上班就开始刷新微信公众号后台,看看有没有粉丝留言,然后这一天就开始了时不时打开后台页面看一下,即使这样还是免不了粉丝留言晚回或者漏回的情况发生,追 ...

  3. h5 修改title 微信_微信公众号客服消息不限次数推送如何设置?

    在公众平台发送客服消息,只能通过消息管理功能实现,仅支持一个个粉丝单独发送文本信息,如果想要实现更多功能效果,可以使用微号帮平台的48小时信息推送功能实现,或者通过公众号平台的接口编程开发实现功能,都 ...

  4. Java实现微信公众号客服功能和本地联调

    Java实现微信公众号客服功能 微信公众平台设置 生产环境 公众号 设置 [开发]–> [基本配置]–> [服务器配置] 注: a.服务器地址(URL) 是开发者用来接收微信消息和事件的接 ...

  5. 怎么在一台电脑登录多个微信公众号客服-微信公众号使用教程25

    微信公众号可以设置100个微信客服人员, 如果每台电脑只登录一个客服人员, 就需要100台电脑, 无疑这样极大的提高了公司的人力成本和物资成本! 那么有没有什么方法, 可以在一台电脑上登录多个微信客服 ...

  6. 微信公众号客服系统怎么生成能追踪效果的二维码?

    想要做好微信公众号的运营,专业的技能少不了,但是也要具有善于使用工具的能力,正所谓"工欲善其事必先利其器",一款好的客服系统,不但可以方便我们进行客户接待,还能帮助我们生分析公众号 ...

  7. 自助微信公众号客服提醒功能开发的实现

    本周我公司的技术人员做了一个有技术含量的一个新功能:客服功能.此功能主要用于微信公众号客服提醒,比如客户的商家认证审核通过,用户购买商品成功等功能提醒,可以有效减少网站项目开发所必要的资金节约. 1. ...

  8. php 公众号指定人发消息,微信公众号客服接口给指定用户openid发送消息

    微信公众号客服接口给指定用户openid发送消息 2018-09-23 微信开发文档: 客服接口-发消息 接口调用请求说明 http请求方式: POSThttps://api.weixin.qq.co ...

  9. 微信公众号客服系统消息能即时提醒吗?

    微信公众号的客服系统,当有用户在后台留言的时候,网页版客服系统只能通过提示声音来判断,不会弹出消息提醒.所以只能采用戴耳机安音响这种方式了嘛?当然不是,你需要的是一款可以消息即时提醒的微信公众号客服系 ...

最新文章

  1. Apache commons-io
  2. 命名实参和可选实参(C#)
  3. jQuery中实现全选功能时使用attr( )改变checked值只能生效一次的问题
  4. 趣谈设计模式 | 单例模式(Singleton) :独一无二的对象
  5. java 方法 示例_Java语言环境getVariant()方法与示例
  6. android EditText使用详解,29.Android EditText使用详解
  7. 吴恩达机器学习 10.支持向量机
  8. sigar 网络 java_java-Sigar网络速度
  9. 经验分享:我是如何在网店无货源情况下快速出单?
  10. AD库文件(元件库+封装库+3D模型)
  11. 我的世界服务器雪球菜单无限雪球,我的世界:雪球玩法?关于指令的高端玩法,操作简单老玩家都在用...
  12. English学习经典视频
  13. 西安电子科技大学计算机网络技术,计算机网络技术与应用课后题答案(西安电子科技大学).doc...
  14. 杂项-DB:DW/DWH(数据仓库)
  15. Python缓存cacheout的使用
  16. 谈谈我对华为HarmonyOS 2.0的看法
  17. Python的学习(十八)---- 单元测试工具nose
  18. Android简易计分器
  19. 《人月神话》(The Mythical Man-Month)3 外科手术队伍(The Surgical Team)
  20. 数组是“二等公民”的话题

热门文章

  1. 618活动九宫格抽奖
  2. 《建设工程消防物联网通用技术规程》成功过审!上海铭控参编
  3. 监控录像机数据删除后重录如何恢复
  4. 毕业2年想跳槽人工智能,不知道AI是干什么的,现在学习人工智能还有希望吗?
  5. java arraylist去重_java ArrayList去重
  6. C. Serval and Toxel‘s Arrays codeforces1789C
  7. 码云如何下载历史版本代码_git和码云的使用
  8. 我的写作进度之三-初稿完成
  9. 扩展城市信道etu模型matlab仿真,关于无线通信系统的仿真、分析和测试的结果分享...
  10. 获取传感器温度-cpu 温度篇