最近公司在做小程序,涉及到客服及消息推送,简单的记录下开发过程及心得
小程序自带的有客服功能只需要开启就行了.
首先在开发 开发设置中配置消息推送
URL: 服务器 设置自己服务器的路径.
Token(令牌): 自己设置,后面再自己的URL需对应.
EncodingAESkey(消息加密秘钥):涉及到加密解密,自己设置,推荐使用随机生成.
消息加密方式: 我这里选择的是明文模式.
数据格式: XML 和 JSON 都行,我选择的是JSON(听说JSON有问题,不过目前没遇到).
配置完后点击保存配置,此时微信端会发送一个GET请求到之前配置的URL路径中进行校检.废话不说直接贴代码
// 与接口配置信息中的Token要一致
private static String WECHAT_TOKEN = "ZIJIESHANYAO";
@RequestMapping("/checkToken")
public void get(HttpServletRequest request, HttpServletResponse response) throws Exception {
boolean isGet = request.getMethod().toLowerCase().equals("get");
PrintWriter print;
if (isGet) {
// 微信加密签名
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
if (signature != null && checkSignature(signature, timestamp, nonce)) {
System.out.println("111111111");
System.out.println("jiaoyanchenggong");
try {
print = response.getWriter();
print.write(echostr);
print.flush();
} catch (IOException e) {
e.printStackTrace();
}
} else {
}
} else {
}
}
/**
* 验证签名
*
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public static boolean checkSignature(String signature, String timestamp, String nonce) {
String[] arr = new String[]{WECHAT_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()) : false;
}
/**
* 将字节数组转换为十六进制字符串
*
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 将字节转换为十六进制字符串
*
* @param mByte
* @return
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
public static void sort(String a[]) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = i + 1; j < a.length; j++) {
if (a[j].compareTo(a[i]) < 0) {
String temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
校检成功后就可以选择模板进行设置发送消息了,至于如何设置选择模板,这里不多说,直接看下就知道了,下面说下消息推送的具体实现.
第一步 : 获取模板 ID 自己去选择适合自己的模板 https://mp.weixin.qq.com
第二步 : 获取form_id ,前端设置按钮,点击按钮提交表单可以获取 formId(对于后台,直接去找前端要就行了).
第三步 : 调用接口具体的实现.
/*
* 微信小程序推送单个用户
* */
@RequestMapping(value = "/Phsu", method = RequestMethod.POST)
@ResponseBody
public String pushOneUser(String openid, String formid, Long orderId) {
//获取access_token
String access_token = getAccess_token(Global.appId, Global.secret);//这里是自己小程序的appId和secretKey
String url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send" +
"?access_token=" + access_token;
//拼接推送的模版
WxMssVo wxMssVo = new WxMssVo();
wxMssVo.setTouser(openid);//用户openid
wxMssVo.setTemplate_id("DkA9fB-xmODJLVf1JvRtWdxr5-iTGETOfV5_6Nuk8NU");//模版id
wxMssVo.setForm_id(formid);//formid
Map<String, TemplateDataVo> m = new HashMap<>();
if (order.getStatus().equals(20)) {
List<OrderProduct> orderProducts = order.getOrderProducts();
String ProductName = null;
for (OrderProduct orderProduct : orderProducts) {
ProductName = orderProduct.getName();
}
TemplateDataVo keyword1 = new TemplateDataVo();
keyword1.setValue(ProductName);//商品名称
m.put("keyword1", keyword1);
wxMssVo.setData(m);
System.out.println(keyword1.getValue() + ":name");
TemplateDataVo keyword2 = new TemplateDataVo();
keyword2.setValue(order.getOrderSn() + "");//订单编号
m.put("keyword2", keyword2);
wxMssVo.setData(m);
System.out.println(keyword2.getValue() + ":bianhao");
TemplateDataVo keyword3 = new TemplateDataVo();
keyword3.setValue(order.getTotalPrice() + "");//订单金额
m.put("keyword3", keyword3);
wxMssVo.setData(m);
System.out.println(keyword3.getValue() + ":jine");
TemplateDataVo keyword4 = new TemplateDataVo();
keyword4.setValue(order.getPoyTime() + "");//支付时间
m.put("keyword4", keyword4);
wxMssVo.setData(m);
System.out.println(keyword4.getValue() + ":time");
}
ResponseEntity<String> responseEntity =
restTemplate.postForEntity(url, wxMssVo, String.class);
System.out.println(responseEntity.getBody() + "wancheng");
//发送成功
return responseEntity.getBody()
}
/*
* 获取access_token
* appid和appsecret到小程序后台获取,当然也可以让小程序开发人员给你传过来
* */
public String getAccess_token(String appid, String appsecret) {
//获取access_token
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
"&appid=" + appid + "&secret=" + appsecret;
String json = restTemplate.getForObject(url, String.class);
AccessToken accessToken = new Gson().fromJson(json, AccessToken.class);
return accessToken.getAccess_token();
}
看下文档, https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/customer-message/trans.html 发现
如果配置了消息推送,所有用户发给小程序的消息都会被转发到已填写的服务器地址中,此时我们需要处理的是将微信转发到后台的消息取出返回给客服,并将客服消息返回给用户.
官网上有对各种消息的具体格式.https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/customer-message/receive.html
下面我只处理文本形式.
当微信将消息推送到后台,会推送到之前配置的URL 地址,以POST请求的方式.
/**
* 接收微信后台发来的用户消息
* @return
*/
@RequestMapping(value = "/checkToken", method = RequestMethod.POST)
@ResponseBody
public String receiveMessage(@RequestBody Map<String, Object> msg) {
//获取token
String access_token = getAccess_token(Global.appId, Global.secret);
System.out.println("access_token:--------" + access_token);
//用户openId
String fromUserName = msg.get("FromUserName").toString();
String createTime = msg.get("CreateTime").toString();
String toUserName = msg.get("ToUserName").toString();
String msgType = msg.get("MsgType").toString();
if (msgType.equals("text")) { //收到的是文本消息,并将消息返回给客服
HashMap<String, Object> resultMap = new HashMap<>();
resultMap.put("ToUserName", fromUserName);
resultMap.put("FromUserName", toUserName);
resultMap.put("CreateTime", Long.parseLong(createTime));
resultMap.put("MsgType", "transfer_customer_service");
String json = JSON.toJSONString(resultMap);
com.alibaba.fastjson.JSONObject result = com.alibaba.fastjson.JSONObject.parseObject(json);
return result.toString();
}
//客服方面,也回复一个文本消息
JSONObject text = new JSONObject();
text.element("content", msg.get("MsgType"));
JSONObject json = new JSONObject();
json.element("touser", toUserName);
json.element("text", text);
json.element("msgtype", "text");
//发送aip
sendMsToCustomer(access_token, json);
return "success";
}
/**
* 用户发送消息给客服
*
* @param json 消息的参数
*/
private void sendMsToCustomer(String access_token, JSONObject json) {
RestTemplate restTemplate = new RestTemplate();
//access_token
String result = restTemplate.postForEntity("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" +
access_token, json, String.class).getBody();
}
其实整体流程还是比较简单的,只是开启消息推送的有点坑之外其他的还好说,做之前多看几遍文档熟悉,新人第一次写博客如有错误请指正,共同学习.