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

废话不多说,也不介绍一下什么背景之类的。。。直接开始。。。。。

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

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


启用服务器配置时,微信会向你填写的服务器地址去发送一天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: Created 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):


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







猜你喜欢

转载自blog.csdn.net/qq_29992111/article/details/78982289