您的位置:首页 > 编程语言 > Java开发

使用springboot开发微信智能聊天小机器人(基于图灵问答api接口)

2018-01-05 15:56 1091 查看
废话不多说,也不介绍一下什么背景之类的。。。直接开始。。。。。

首先,我们需要注册一个微信公众号。。类型的话无所谓,订阅号就可以了。(个人只能注册订阅号)

然后进入公众号后台,启用服务器配置。。



启用服务器配置时,微信会向你填写的服务器地址去发送一天get请求进行验证。。验证规则见下:



代码见下:

/**
* 确认请求来自微信服务器
* @param signature 微信加密签名
* @param timestamp 时间戳
* @param nonce 随机数
* @param echostr 随机字符串
*/
@ResponseBody
@GetMapping("/")
public String doGet(String signature,String timestamp,String nonce,String echostr){
if(SignUtil.checkSignature(signature,timestamp,nonce)){
return echostr;
}
return null;
}
   校验代码:

 

package com.yunhui.wx.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
* @Author: Yun
* @Description: 检验signature工具类
* @Date: Crea
4000
ted in 2017-11-29 9:49
*/
public class SignUtil {
/**
* 与微信后台配置的Token要一致
*/
private static String token = "souvcweixin";

/**
* 方法名:checkSignature</br>
* 详述:验证签名</br>
* @param signature
* @param timestamp
* @param nonce
* @return
* @throws
*/
public static boolean checkSignature(String signature, String timestamp,String nonce) {
// 1.将token、timestamp、nonce三个参数进行字典序排序
String[] arr = new String[] { token, timestamp, nonce };
Arrays.sort(arr);

// 2. 将三个参数字符串拼接成一个字符串进行sha1加密
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md;
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();
}
// 3.将sha1加密后的字符串可与signature对比,标识该请求来源于微信
return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
}

/**
* 方法名:byteToStr</br>
* 详述:将字节数组转换为十六进制字符串</br>
* 开发人员:souvc </br>
* 创建时间:2015-9-29  </br>
* @param byteArray
* @return
* @throws
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}

/**
* 方法名:byteToHexStr</br>
* 详述:将字节转换为十六进制字符串</br>
* @param mByte
* @return
* @throws
*/
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;
}
}
如果你微信公众号后台配置无误,而且你的服务器后台也没有啥问题的。。到此,微信与你的服务器已经对接上了。。在这里,顺便讲一下公众号(微信后台)、用户、我们的服务器这三者之间是如何传递消息的。



上面是微信官方的说法。我们理解一下,简单来说,就是用户发送消息给我们公众号,公众号也就是微信后台,在接收到这个消息时,会将这条消息的内容、发送人、时间等一些参数封装成xml格式,然后再转发给我们的服务器。我们的服务器接收到这个请求时,需要作出对应的回复,再讲回复封装成xml转发给微信后台。。。微信后台收到我们服务器发送的xml之后,然后再将数据发送给用户。。这就是用户与公众号之间的一次消息传递过程。。。

消息传递的过程很简单,,,,,我们唯一要关心的点就是,对于用户的输入,我们该反馈什么样的结果给与用户。。。。。这也是我们服务器主要做的事情。。。。

微信支持的消息有六种,,这里我们只做回复文本消息。。。



回复文本消息,我们的核心就是调用图灵的问答api接口。。将用户发送的消息作为请求参数,我们去请求图灵机器人的问答系统开放接口,获取回复后,我们将回复的内容再经过转换发送给用户,这就实现了机器人聊天的功能了。。。。

代码见下:

  用户发送消息之后,微信服务器会将此消息以post的请求方式、xml的数据格式转发给我们服务器。服务器收到此消息,也要返回一条对应的xml格式数据回复给微信服务器

@ResponseBody
@PostMapping("/")
public String doPost(HttpServletRequest request){
/*
在收到微信服务器的请求之后,我们需要做如下几件事!
1、解析微信发送的请求数据(将xml转换成map,获取消息发送人、消息接收人、时间、内容)
2、发送请求给图灵的接口,获取返回值,并解析提取回复内容
3、将回复内容和第一步解析到的消息发送人封装成xml格式,再返回给微信服务器
*/
return coreService.process(request);
}  
package com.yunhui.wx.service;

import com.yunhui.wx.bean.response.TextRespMessage;
import com.yunhui.wx.robot.service.*;
import com.yunhui.wx.util.MessageUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;

/**
* @Author: Yun
* @Description:
* @Date: Created in 2017-11-29 14:24
*/
@Service
public class CoreService {

public String process(HttpServletRequest request){
// xml格式的消息数据
String respXml = null;
// 默认返回的文本消息内容
String respContent = "未知的消息类型!";
try {
// 调用parseXml方法解析请求消息
Map<String, String> requestMap = MessageUtils.parseXml(request);
// 发送方帐号
String fromUserName = requestMap.get("FromUserName");
// 开发者微信号
String toUserName = requestMap.get("ToUserName");
// 消息类型
String msgType = requestMap.get("MsgType");
// 消息内容
String info=requestMap.get("Content");

// 回复文本消息
TextRespMessage textMessage = new TextRespMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(System.currentTimeMillis());
textMessage.setMsgType(MessageUtils.RESP_MESSAGE_TYPE_TEXT);

// 文本消息
if (msgType.equals(MessageUtils.REQ_MESSAGE_TYPE_TEXT)) {
//如果用户发送的是文本消息,则调用图灵机器人的接口,获取回复内容并返回给微信服务器
respContent=TlRobotService.getTextResponse(fromUserName,info);
}
// 图片消息
else if (msgType.equals(MessageUtils.REQ_MESSAGE_TYPE_IMAGE)) {
respContent = "您发送的是图片消息,小云还不知道怎么回答嘛。。。";
}
// 语音消息
else if (msgType.equals(MessageUtils.REQ_MESSAGE_TYPE_VOICE)) {
respContent = "您发送的是语音消息,小云还不知道怎么回答嘛。。。";
}
// 视频消息
else if (msgType.equals(MessageUtils.REQ_MESSAGE_TYPE_VIDEO)) {
respContent = "您发送的是视频消息,小云还不知道怎么回答嘛。。。";
}
// 视频消息
else if (msgType.equals(MessageUtils.REQ_MESSAGE_TYPE_SHORTVIDEO)) {
respContent = "您发送的是小视频消息,小云还不知道怎么回答嘛。。。";
}
// 地理位置消息
else if (msgType.equals(MessageUtils.REQ_MESSAGE_TYPE_LOCATION)) {
respContent = "您发送的是地理位置消息,小云还不知道怎么回答嘛。。。";
}
// 链接消息
else if (msgType.equals(MessageUtils.REQ_MESSAGE_TYPE_LINK)) {
respContent = "您发送的是链接消息,小云还不知道怎么回答嘛。。。";
}
// 事件推送
else if (msgType.equals(MessageUtils.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType = requestMap.get("Event");
// 关注
if (eventType.equals(MessageUtils.EVENT_TYPE_SUBSCRIBE)) {
respContent = "欢迎关注机器人小云。。。。";
}
// 取消关注
else if (eventType.equals(MessageUtils.EVENT_TYPE_UNSUBSCRIBE)) {
// TODO 取消订阅后用户不会再收到公众账号发送的消息,因此不需要回复
}
// 扫描带参数二维码
else if (eventType.equals(MessageUtils.EVENT_TYPE_SCAN)) {
// TODO 处理扫描带参数二维码事件
}
// 上报地理位置
else if (eventType.equals(MessageUtils.EVENT_TYPE_LOCATION)) {
// TODO 处理上报地理位置事件
}
// 自定义菜单
else if (eventType.equals(MessageUtils.EVENT_TYPE_CLICK)) {
// TODO 处理菜单点击事件
}
}
// 设置文本消息的内容
textMessage.setContent(respContent);
// 将文本消息对象转换成xml
respXml = MessageUtils.messageToXml(textMessage);
} catch (Exception e) {
e.printStackTrace();
}
return respXml;
}

}

   调用图灵api接口时,我们先需要注册一个图灵的账号。。然后添加一个机器人(小云机器人是我已经添加好的)



   然后点击设置,进入机器人管理页面。。。里面有api接入的说明,我们需要下面的两个参数



即下面:

public class BaseCommon {
/**
* 图灵机器人的配置参数
*/
public static final String TL_ROBOT_API_URL="http://www.tuling123.com/openapi/api";
public static final String TL_ROBOT_API_KEY="xxxxxxxxxxxx";//这里填写你自己的
}


  调用图灵机器人的代码见下:
  有一点需要说明一下。。由于人的问答具有连贯性,,所以我们在调用图灵的问答接口时,需要设置userid这个参数。。

  在我的代码里,userid使用的是用户的openid。。。

package com.yunhui.wx.robot.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yunhui.wx.robot.bean.request.BaseReqMessage;
import com.yunhui.wx.robot.bean.response.BaseRespMessage;
import com.yunhui.wx.robot.bean.response.RobotResponTypeEnum;
import com.yunhui.wx.robot.common.BaseCommon;
import com.yunhui.wx.robot.util.HttpRequestUtil;

/**
* @Author: Yun
* @Description: 图灵机器人的服务类
* @Date: Created in 2017-11-30 10:51
*/
public class TlRobotService {

/**
* 调用图灵的问答API,并返回文本响应值
* @param userid
* @param info
* @return
*/
public static String getTextResponse(String userid,String info){
//封装请求参数对象
BaseReqMessage reqMessage=new BaseReqMessage();
reqMessage.setKey(BaseCommon.TL_ROBOT_API_KEY);
reqMessage.setInfo(info);
reqMessage.setUserid(userid);
//转换为json
ObjectMapper mapper=new ObjectMapper();
try {
String json=mapper.writeValueAsString(reqMessage);
String result=HttpRequestUtil.doPost(BaseCommon.TL_ROBOT_API_URL,json,"UTF-8");
BaseRespMessage respMessage=mapper.readValue(result,BaseRespMessage.class);
RobotResponTypeEnum robotResponTypeEnum=RobotResponTypeEnum.getRobotResponseType(respMessage.getCode(),respMessage.getText());
return robotResponTypeEnum.getText();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
  由于篇幅限制,这里是不可能将所有的代码都展示出来了。。完整的项目源码在这。。。
  Springboot开发微信公众号智能机器人(基于图灵api)

  上面讲述的不够细。。比如微信发送的xml数据格式,,有哪些属性。。我们返回的xml要包含哪些属性。。。请求图灵机器人的格式要求、图灵机器人回复的json格式。。。。这个项目里面有大量的数据格式转换。。。建议下载我的代码,然后对照微信的公众号开发文档和图灵的api接入文档对比着看。。这样比较好。。。。。。

附一张我项目的结构图(这个项目作为一个springboot的项目,还是比较简单的。。。新手可以拿来熟悉springboot):



最后,,附一下我开发的微信公众号智能问答小机器人的微信号,欢迎大家前去骚扰。。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐