您当前的位置: 首页 > 

lootaa

暂无认证

  • 0浏览

    0关注

    68博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

公众号消息转发到客服

lootaa 发布时间:2022-10-10 16:24:24 ,浏览量:0

洛塔服务号回复012获取代码。

功能说明

给公众号发送消息,实现将消息转发给客服(可指定客服)。

  1. 普通微信用户发送消息到公众号
  2. 公众号将消息post到开发者填写的url上(设置与开发–>基本配置,右侧服务器配置)
  3. 接入成功后,后续会直接发给客服,不会继续走开发者填写的url
准备工作
  • 启动服务器配置 位置:设置与开发–>基本配置,右侧服务器配置 开启服务器配置需要将对应的url代码部署上,Java可以使用
	/**
	 * 完整项目源码可关注公众号"lootaayun"(洛塔),回复012获取
	 */
	@GetMapping("wx12")
	public void wxGet(HttpServletRequest request, PrintWriter pw) {
		// 微信加密签名,需要使用本地计算出来的和这个对比,确认是微信发送的消息
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp"); // 时间戳
		String nonce = request.getParameter("nonce"); // 随机数
		String echostr = request.getParameter("echostr"); // 随机字符串
		// 将token、timestamp、nonce三个参数进行字典序排序
		List list = new ArrayList();
		list.add("lootaa"); // 公众号后台设置的token
		list.add(timestamp);
		list.add(nonce);
		Collections.sort(list);
		// 将三个参数字符串拼接成一个字符串进行sha1加密
		String tokenStr = "";
		for (int i = 0; i < list.size(); i++) {
			tokenStr += list.get(i);
		}
		String signatureStr = DigestUtils.sha1Hex(tokenStr);
		// 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
		if (signature.equals(signatureStr)) {
			pw.write(echostr); // 原样返回echostr参数内容
		} else {
			pw.write("");
		}
	}
转发到客服

并非所有消息都可以转发到客服,除了点击事件、地理位置外,微信用户自己的消息类型也有限制。

  • 文本:可以正常转发到客服
  • 图片:可以正常转发到客服
  • 语音:可以转发,但是客服只能看到消息,不能听语音
  • 视频:可以正常转发到客服
  • 地理位置:转发无效,客服收不到
  • 链接:转发无效,客服收不到

如果需要微信来分配客服,可以使用下面的参数返回(对调接收到的ToUserName和FromUserName,见代码)

  
    
    
  1399197672  
   

如果指定给某个客服,添加个TransInfo来指定客服账号即可。客服账号的格式必须是客服号码@公众号的微信号。比如客服账号是lootaa,公众号设置的微信号是lootaayun,那么参数就需要使用lootaa@lootaayun

  
    
    
  1399197672  
    
   
     
   

几个参数的小问题

  1. ToUserName:就是url收到的FromUserName
  2. FromUserName:就是url收到的ToUserName
  3. CreateTime:不要使用当前时间,而是直接使用url收到的CreateTime
  4. MsgType:固定值 transfer_customer_service
  5. KfAccount:格式必须是客服账号@公众号微信号

测试代码

	@PostMapping("wx12")
	public void wxPost(HttpServletRequest request, HttpServletResponse response, PrintWriter pw) throws Exception {
		String token = "lootaa";
		String encodingAesKey = "FpKEYJDuwK92k2juU2z0sUvTmc3hB4W5wGLJEKay8oK";
		String appid = "wx276049d6a7551dca";
    	WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appid);
        String timestamp = request.getParameter("timestamp");    
        String nonce = request.getParameter("nonce");  
        String msgSignature = request.getParameter("msg_signature");  
		Document doc = getDocument(request);
		String result2 = pc.decryptMsg(msgSignature, timestamp, nonce, doc.asXML());
		System.out.println("解密后明文: " + result2);
		JSONObject resultJson = documentToJSONObject(result2);
		String messageType = resultJson.getString("MsgType");
		// 完全支持的类型: text image video shortvideo
		// 支持一半的类型(能收到消息但是不能播放): voice
		// 不支持的类型:location link
		if("text;image;voice;video;shortvideo;location;link".indexOf(messageType) > -1) {
			String result = "" + ""
					+ "" + ""
					+ resultJson.getString("CreateTime") + "" + ""
					+ "" //如果转发到指定客服就添加TransInfo
					+ "";
			result = pc.encryptMsg(result, timestamp, nonce);
			pw.write(result);
		}

	}

用到的几个辅助类

	public static Document getDocument(HttpServletRequest request) {
		SAXReader reader = new SAXReader();
		try {
			InputStream ins = request.getInputStream();
			Document doc = reader.read(ins);
			return doc;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static JSONObject documentToJSONObject(String xml) {
        JSONObject jsonObject = null;
        try {
            jsonObject = elementToJSONObject(DocumentHelper.parseText(xml).getRootElement());
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }
	
	@SuppressWarnings("unchecked")
	public static JSONObject elementToJSONObject(Element node) {
        JSONObject result = new JSONObject();
        // 当前节点的名称、文本内容和属性
		List listAttr = node.attributes();// 当前节点的所有属性的list
        for (Attribute attr : listAttr) {// 遍历当前节点的所有属性
            result.put(attr.getName(), attr.getValue());
        }
        // 递归遍历当前节点所有的子节点
        List listElement = node.elements();// 所有一级子节点的list
        if (!listElement.isEmpty()) {
            for (Element e : listElement) {// 遍历所有一级子节点
                if (e.attributes().isEmpty() && e.elements().isEmpty()) // 判断一级节点是否有属性和子节点
                    result.put(e.getName(), e.getTextTrim());// 沒有则将当前节点作为上级节点的属性对待
                else {
                    if (!result.containsKey(e.getName())) // 判断父节点是否存在该一级节点名称的属性
                        result.put(e.getName(), new JSONArray());// 没有则创建
                    ((JSONArray) result.get(e.getName())).add(elementToJSONObject(e));// 将该一级节点放入该节点名称的属性对应的值中
                }
            }
        }
        return result;
    }
完整代码
package com.lootaa.wechat;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.digest.DigestUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lootaa.wechat.util.WXBizMsgCrypt;

/**
 * 订阅通知
 * 前置条件:启用了服务器配置
 */
@RestController
public class Test012 {

	public static final String APPID = "wx276049d6a7551dca";
	public static final String SECRET = "cbe109fdf6f399bd72ed3a4afafa21b1";
	
	/**
	 * 完整项目源码可关注公众号"lootaayun"(洛塔),回复012获取
	 */
	@GetMapping("wx12")
	public void wxGet(HttpServletRequest request, PrintWriter pw) {
		// 微信加密签名,需要使用本地计算出来的和这个对比,确认是微信发送的消息
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp"); // 时间戳
		String nonce = request.getParameter("nonce"); // 随机数
		String echostr = request.getParameter("echostr"); // 随机字符串
		// 将token、timestamp、nonce三个参数进行字典序排序
		List list = new ArrayList();
		list.add("lootaa"); // 公众号后台设置的token
		list.add(timestamp);
		list.add(nonce);
		Collections.sort(list);
		// 将三个参数字符串拼接成一个字符串进行sha1加密
		String tokenStr = "";
		for (int i = 0; i < list.size(); i++) {
			tokenStr += list.get(i);
		}
		String signatureStr = DigestUtils.sha1Hex(tokenStr);
		// 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
		if (signature.equals(signatureStr)) {
			pw.write(echostr); // 原样返回echostr参数内容
		} else {
			pw.write("");
		}
	}
	
	public static Document getDocument(HttpServletRequest request) {
		SAXReader reader = new SAXReader();
		try {
			InputStream ins = request.getInputStream();
			Document doc = reader.read(ins);
			return doc;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static JSONObject documentToJSONObject(String xml) {
        JSONObject jsonObject = null;
        try {
            jsonObject = elementToJSONObject(DocumentHelper.parseText(xml).getRootElement());
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }
	
	@SuppressWarnings("unchecked")
	public static JSONObject elementToJSONObject(Element node) {
        JSONObject result = new JSONObject();
        // 当前节点的名称、文本内容和属性
		List listAttr = node.attributes();// 当前节点的所有属性的list
        for (Attribute attr : listAttr) {// 遍历当前节点的所有属性
            result.put(attr.getName(), attr.getValue());
        }
        // 递归遍历当前节点所有的子节点
        List listElement = node.elements();// 所有一级子节点的list
        if (!listElement.isEmpty()) {
            for (Element e : listElement) {// 遍历所有一级子节点
                if (e.attributes().isEmpty() && e.elements().isEmpty()) // 判断一级节点是否有属性和子节点
                    result.put(e.getName(), e.getTextTrim());// 沒有则将当前节点作为上级节点的属性对待
                else {
                    if (!result.containsKey(e.getName())) // 判断父节点是否存在该一级节点名称的属性
                        result.put(e.getName(), new JSONArray());// 没有则创建
                    ((JSONArray) result.get(e.getName())).add(elementToJSONObject(e));// 将该一级节点放入该节点名称的属性对应的值中
                }
            }
        }
        return result;
    }
	
	@PostMapping("wx12")
	public void wxPost(HttpServletRequest request, HttpServletResponse response, PrintWriter pw) throws Exception {
		String token = "lootaa";
		String encodingAesKey = "FpKEYJDuwK92k2juU2z0sUvTmc3hB4W5wGLJEKay8oK";
		String appid = "wx276049d6a7551dca";
    	WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appid);
        String timestamp = request.getParameter("timestamp");    
        String nonce = request.getParameter("nonce");  
        String msgSignature = request.getParameter("msg_signature");  
		Document doc = getDocument(request);
		String result2 = pc.decryptMsg(msgSignature, timestamp, nonce, doc.asXML());
		System.out.println("解密后明文: " + result2);
		JSONObject resultJson = documentToJSONObject(result2);
		String messageType = resultJson.getString("MsgType");
		// 完全支持的类型: text image video shortvideo
		// 支持一半的类型(能收到消息但是不能播放): voice
		// 不支持的类型:location link
		if("text;image;voice;video;shortvideo;location;link".indexOf(messageType) > -1) {
			String result = "" + ""
					+ "" + ""
					+ resultJson.getString("CreateTime") + "" + ""
					+ "" //如果转发到指定客服就添加TransInfo
					+ "";
			result = pc.encryptMsg(result, timestamp, nonce);
			pw.write(result);
		}

	}
	
}

关注
打赏
1663829960
查看更多评论
立即登录/注册

微信扫码登录

0.0421s