java实现微信小程序客服功能开发

第一步:先在后台接入配置URL

  官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/customer-message/customer-message.html

  如图:

  

 

第二步:在后台服务器配置接入接口   接入URL配置是  后台使用Get接收。注意 后台Token需要与微信小程序端配置的Token一致。

接入URL代码如下:

  

@ApiOperation("小程序消息推送接口")
    @RequestMapping(value = "/sendTempMess", method = {RequestMethod.GET, RequestMethod.POST})
    public void sendTempMess(HttpServletRequest request, HttpServletResponse response) {
        boolean isGet = request.getMethod().toLowerCase().equals("get");
        if (isGet) {//首次验证token
            // 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
            String signature = request.getParameter("signature");
            // 时间戳
            String timestamp = request.getParameter("timestamp");
            // 随机数
            String nonce = request.getParameter("nonce");
            // 随机字符串
            String echostr = request.getParameter("echostr");
            PrintWriter out = null;
            try {
                out = response.getWriter();
                // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败  
                if (WechatUtil.checkSignature(signature, timestamp, nonce)) {
                    System.out.println("成功");
                    out.print(echostr);
                    out.flush(); //必须刷新
                }
                System.out.println("失败");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                out.close();
            }
        } else {//进行客服操作
            try {
//            JSON.toJSONString(Tools.resolveParam(request));
                //log.info("小程序返回消息:{}" , JSON.toJSONString(Tools.resolveParam(request)));
                // 进入POST聊天处理
                // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
                request.setCharacterEncoding("UTF-8");
                response.setCharacterEncoding("UTF-8");
                // 接收消息并返回消息
                String result = wxService.acceptMessage(request, response);
                // 响应消息
                PrintWriter out = response.getWriter();
                out.print(result);
                out.close();
            } catch (Exception ex) {
                log.error("微信帐号接口配置失败!", ex);
                 ex.printStackTrace();
        }

        }
    }
WechatUtil:
此处token,需要与微信小程序后端配置的token一致
public static boolean checkSignature(String signature, String timestamp, String nonce) {
    String[] arr = new String[]{token, timestamp, nonce};
    // 将token、timestamp、nonce三个参数进行字典序排序
    // Arrays.sort(arr);
    sort(arr);
    StringBuilder content = new StringBuilder();
    for (int i = 0; i < arr.length; i++) {
        content.append(arr[i]);
    }
    MessageDigest md = null;
    String tmpStr = null;

    try {
        md = MessageDigest.getInstance("SHA-1");
        // 将三个参数字符串拼接成一个字符串进行sha1加密
        byte[] digest = md.digest(content.toString().getBytes());
        tmpStr = byteToStr(digest);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    content = null;
    // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
    return tmpStr != null && tmpStr.equals(signature.toUpperCase());
}

接入成功之后,进行客服对话。文本。会话,卡片,图片等。

  客服对话代码:入口参考上面接入的接口,同一个。

   

WxService:
private Logger logger = LoggerFactory.getLogger(WxService.class);

    private static String SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send";

    @Autowired
    private WxXCXTempSend wxXCXTempSend;


    @Autowired
    public WxService(UserDao userDao) {
        super(userDao);
    }


    public String acceptMessage(HttpServletRequest request, HttpServletResponse response) {
//        {CreateTime=1548042266, Event=user_enter_tempsession, ToUserName=gh_e6198220cbff,
//                FromUserName=oZvme4q2Oi7Dz3FChXc43kqw28, MsgType=event, SessionFrom=wxapp}
        String respMessage = "";
        try {
            // xml请求解析
            Map<String, String> requestMap = MessageUtil.parseApplet(request);
            logger.info(">>>>>>>>>>>>>"+requestMap);
            // 发送方帐号(open_id)
            String fromUserName = requestMap.get("FromUserName");
            // 公众帐号
            String toUserName = requestMap.get("ToUserName");
            // 消息类型
            String msgType = requestMap.get("MsgType");
            //人工服务
            String content = requestMap.get("Content");
            String accessToken=getAccessToken();
            //此处我默认为直接人工服务  可根据实际业务调整
            return switchCustomerService(fromUserName,toUserName,requestMap);
            //小程序客服 文本信息
           /* if(msgType.equals("text")){
                if("人工服务".equals(content)){
                    HashMap<String, Object> resultMap = new HashMap<>();
                     resultMap.put("ToUserName",fromUserName);
                     resultMap.put("FromUserName",toUserName);
                     resultMap.put("CreateTime", requestMap.get("CreateTime"));
                     resultMap.put("MsgType","transfer_customer_service");
                     String json = JSON.toJSONString(resultMap);
                     JSONObject result = JSONObject.parseObject(json);
                     logger.info("POST   result"  +  result);
                     return result;
                }
                sendCustomerTextMessage(fromUserName,"你好,欢迎使用人工服务",accessToken);
            }else if(msgType.equals("event")){//会话功能
                String sessionFrom = (String) requestMap.get("SessionFrom");
                logger.info("SessionFrom   SessionFrom"  +  sessionFrom);
                int i = sessionFrom.indexOf("+");
                String sessionFromFirst = "1";
                String appId = wxXCXTempSend.APP_ID;
                if( i > 0){
                    sessionFromFirst = sessionFrom.substring(0, i); //标志位 1 2 3 4 5 6
                    logger.info("SessionFrom   sessionFromFirst    "  +  sessionFromFirst);
                    String sessionFromLast = sessionFrom.substring(i+1);  //{"appId":"","data":"test"}
                    logger.info("SessionFrom   sessionFromLast     "  +  sessionFromLast);
                    if(JSONObject.parseObject(sessionFromLast).get("appId") != null){
                        appId = (String) JSONObject.parseObject(sessionFromLast).get("appId");
                    }
                    sendCustomerTextMessage(fromUserName,"你好,欢迎使用会话服务",accessToken);
                }

            }else if(msgType.equals("image")){
                logger.info("公众号接受图片..........");
                sendCustomerImageMessage(fromUserName,requestMap.get("MediaId"),accessToken);
            }else{

            }*/

        } catch (Exception e) {
            e.printStackTrace();
        }
        return respMessage;
    }

    private String getAccessToken() {
        String accessToken = null;
        try {
            accessToken = wxXCXTempSend.getAccessToken();
            if ("0".equals(accessToken)) {
                logger.error("微信小程序获取token调用失败");
                accessToken = "0";
            } else if ("1".equals(accessToken)) {
                logger.error("微信小程序获取token系统繁忙");
                accessToken = "0";
            } else if ("2".equals(accessToken)) {
                logger.error("微信小程序获取token,AppSecret错误或者AppID不合法");
                accessToken = "0";
            } else {
                logger.error("微信小程序获取token失败。");
            }
        } catch (Exception e) {
            logger.error("微信小程序获取token异常");
            e.printStackTrace();
            accessToken = "0";
        }
        return accessToken;
    }

    /**
     * 文本事件
     * */
    public  String sendCustomerTextMessage(String openid,String text,String accessToken)throws Exception{
        Map<String,Object> map_content = new HashMap<>();
        map_content.put("content",text);
        Map<String,Object> map = new HashMap<>();
        map.put("touser",openid);
        map.put("msgtype","text");
        map.put("text",map_content);
        String content =  JSON.toJSONString(map);
        return HttpClientUtils.httpPost(SEND_URL+"?access_token="+accessToken,content);

    }

    /**
     * 会话事件
     * */
    public  String sendFirstMessage(String openid, String text,String accessToken) throws Exception {

        Map<String, Object> map_content = new HashMap<>();
        map_content.put("content", text);

        Map<String, Object> map = new HashMap<>();
        map.put("touser", openid);
        map.put("msgtype", "text");
        map.put("text", map_content);

        String content = JSON.toJSONString(map);
        return HttpClientUtils.httpPost(SEND_URL + "?access_token=" + accessToken, content);
    }

    /***
     * 文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/custommsg/conversation.html
     * 发送的图片消息
     */
    public  String sendCustomerImageMessage (String openid, String mediaId,String accessToken)throws Exception{
        Map<String, Object> map_content = new HashMap<>();
        map_content.put("media_id", mediaId);
        Map<String, Object> map = new HashMap<>();

        map.put("touser", openid);
        map.put("msgtype", "image");

        map.put("image", map_content);
        String content = JSON.toJSONString(map);
        return HttpClientUtils.httpPost(SEND_URL + "?access_token=" + accessToken, content);
    }


    /***
     * 文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/custommsg/conversation.html
     * 转发至人工客服 现在默认都为人工客服
     */
    public  String switchCustomerService  (String fromUserName, String toUserName,Map requestMap)throws Exception{
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("ToUserName",fromUserName);
        resultMap.put("FromUserName",toUserName);
        resultMap.put("CreateTime", requestMap.get("CreateTime"));
        resultMap.put("MsgType","transfer_customer_service");
        String json = JSON.toJSONString(resultMap);
        JSONObject result = JSONObject.parseObject(json);
        logger.info("POST   result"  +  result);
        return result.toString();
    }

 

 

获取AccessToken的工具类如下

WxXCXTempSend:
@Slf4j
@Component
public class WxXCXTempSend {

    @Autowired
    private RedisLite redisLite;

    private static String TEMP_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send";

    public static final String APP_ID = "wx97bad4e6906f882e";
    private static final String APP_SECRET = "f4c25b849e24f0b02826a540edbe95f7";
   
    /**
     * 获取小程序token,(ps:0=token获取失败)
     *
     * @return
     */
    public String getAccessToken() {

        return SimpleCache.get(RedisCacheKeys.WxXCX.wxAccessToken, String.class, redisLite, 60*105, () -> {
            String accessToken = "0";
            try {
                 //此处APP_ID APP_SECRET  在微信小程序后端可见
                String accessTokenUrl = String.format(WechatConfig.XCX_ACCESS_TOKEN_URL, APP_ID, APP_SECRET);
                String result = HttpClientUtils.httpGet(accessTokenUrl, null, null);
                Map<String, Object> resultMap = JSON.parseObject(result, Map.class);
                if(resultMap.containsKey("access_token")) {
                    accessToken = resultMap.get("access_token").toString();
                }
            } catch (IOException ioe) {
                log.error("小程序http请求异常");
                ioe.printStackTrace();
            }
            return accessToken;
        });
    }
}

 

RedisCacheKeys:
/**
 * 微信小程序有关缓存key
 *
 */
public class WxXCX {
    public static final String wxAccessToken = BasePrefix + "wx:xcx:accessToken";
}

 

HttpClientUtils:
/**
 * http请求工具类,get请求
 *
 * @param url
 * @param params
 * @param resonseCharSet
 * @return
 * @throws Exception
 */
public static String httpGet(String url, Map<String, Object> params, String... resonseCharSet) throws IOException {
    DefaultHttpClient defaultHttpClient = null;
    BufferedReader bufferedReader = null;
    try {
        defaultHttpClient = new DefaultHttpClient();
        if (params != null) {
            StringBuilder stringBuilder = new StringBuilder();
            Iterator<String> iterator = params.keySet().iterator();
            String key;
            while (iterator.hasNext()) {
                key = iterator.next();
                Object val = params.get(key);
                if (val instanceof List) {
                    List v = (List) val;
                    for (Object o : v) {
                        stringBuilder.append(key).append("=").append(o.toString()).append("&");
                    }
                } else {
                    stringBuilder.append(key).append("=").append(val.toString()).append("&");
                }
            }
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            url = url + "?" + stringBuilder.toString();
            log.info("url:{}", url);
        }
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Content-Type", "application/json;charset=ut-8");
        HttpResponse httpResponse = defaultHttpClient.execute(httpGet);
        if (httpResponse.getStatusLine().getStatusCode() != 200) {
            String errorLog = "请求失败,errorCode:" + httpResponse.getStatusLine().getStatusCode();
            log.info(errorLog);
            throw new HttpRequestException(url + errorLog);
        }
        //读取返回信息
        String charSet = "utf-8";
        if (resonseCharSet != null && resonseCharSet.length > 0)
            charSet = resonseCharSet[0];
        String output;
        bufferedReader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), charSet));

        StringBuilder dataBuilder = new StringBuilder();
        while ((output = bufferedReader.readLine()) != null) {
            dataBuilder.append(output);
        }
        return dataBuilder.toString();
    } catch (IOException e) {
        e.printStackTrace();
        throw e;
    } finally {
        if (defaultHttpClient != null)
            defaultHttpClient.getConnectionManager().shutdown();
        if (bufferedReader != null)
            bufferedReader.close();
    }
}

 

/**
 * http请求工具类,post请求
 *
 * @param url    url
 * @param param 参数值 仅支持String
 * @return
 * @throws Exception
 */
public static String httpPost(String url, String param) throws IOException {
    DefaultHttpClient defaultHttpClient = null;
    BufferedReader bufferedReader = null;
    try {
        defaultHttpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-Type", "application/json;charset=ut-8");
        if (StringUtils.isNotBlank(param)) {
            log.info("参数值:{}", param);
            HttpEntity httpEntity = new StringEntity(param, "utf-8");
            httpPost.setEntity(httpEntity);
        }
        HttpResponse httpResponse = defaultHttpClient.execute(httpPost);
        if (httpResponse.getStatusLine().getStatusCode() != 200) {
            String errorLog = "请求失败,errorCode:" + httpResponse.getStatusLine().getStatusCode();
            log.info(errorLog);
            throw new HttpRequestException(url + errorLog);
        }
        //读取返回信息
        String output;
        bufferedReader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "utf-8"));
        StringBuilder stringBuilder = new StringBuilder();
        while ((output = bufferedReader.readLine()) != null) {
            stringBuilder.append(output);
        }
        return stringBuilder.toString();
    } catch (IOException e) {
        e.printStackTrace();
        throw e;
    } finally {
        if (defaultHttpClient != null)
            defaultHttpClient.getConnectionManager().shutdown();
        if (bufferedReader != null)
            bufferedReader.close();
    }
}

 

 

如果有什么疑问,可以联系我QQ  976452322  有时间 一起讨论  此部分代码,暂时无Git 

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值