AS+图灵机器人官网+HTTP POST(json)+JsonReader实现安卓课设《智能聊天机器人》填坑记录

目录

  • 一.准备工作
  • 二.开始填坑
    • 1.ChatMessageAdapter
    • 2.图灵机器人官方api接入
    • 3.网络安全设置
    • 4.超级天坑——从json中得到数据
  • 三.成果展示
  • 四.结语

一.准备工作

根据导师留下的一个参考网址:Android智能聊天机器人的实现.我们可以自己参照做出一个大致的框架。可以把xml文件里的组件背景图片,显示文字改成自己喜欢的样子,然后我们开始着手内核。

二.开始填坑

一些小坑就不说了,自己也能调试出来,这里说些有点难受的大坑。

1.ChatMessageAdapter

在此文件第62行
AS+图灵机器人官网+HTTP POST(json)+JsonReader实现安卓课设《智能聊天机器人》填坑记录_第1张图片
viewHolder.message = (TextView) convertView
.findViewById(R.id.message)应该为viewHolder.message = (TextView) convertView
.findViewById(R.id.left_message);

2.图灵机器人官方api接入

我们进入官网API V2.0接入文档,可以清楚的看到

接口地址
http://openapi.tuling123.com/openapi/api/v2
请求方式
HTTP POST
请求参数
请求参数格式为 json

相较于参考网址代码,推测应该是图灵机器人官网进行的某次重大更新,api连接有非常大的改变,参考网址的接口地址即MyRobot.URL_KEY要换成http://openapi.tuling123.com/openapi/api/v2,且其请求方式是http get,所以我们必须用全新的,http post请求方式的,参数是json的网络请求函数。一句话——HttpRequest.java文件要大改。在这里先稍微解释一下json,其实就是一个具有指定格式的字符串,只要你按照要求写对了,你发送到官网接口去,官网就会回你一个json,也是一个字符串,里面有我们需要的信息。更多内容可以参考官网API V2.0接入文档,里面有样例和参数说明,可供理解。
先上代码

private static String fromjson(String message) {
        String msg = "";
            msg = "{" +
                    "\"perception\":{" +
                    "\"inputText\": {" +
                    "\"text\": \"" +
                    message+
                    "\"}}," +
                    "\"userInfo\":{" +
                    "\"apiKey\":\"" + MyRobot.API_KEY + "\"," +
                    "\"userId\":\"" + MyRobot.ID + "\"}}";
        return msg;
    }

这样,聊天中你输入的信息作为函数参数,返回的是一个最简单的符合要求的json字符串。
聪明的同学已经发现了,我们需要在MyRobot类中新增一个静态字符串成员ID。这个id就是你在图灵官网注册的用户id。这只是得到json,怎么与官网建立连接呢?别慌,上代码

public static String sendJsonPost(String Json) {
        // HttpClient 6.0被抛弃了
        String result = "";
        BufferedReader reader = null;
        try {
            String urlPath = MyRobot.URL_KEY ;
            URL url = new URL(urlPath);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            // 设置接收类型否则返回415错误
            conn.setRequestProperty("accept", "application/json");
            // 往服务器里面发送数据
            if (Json != null && !TextUtils.isEmpty(Json)) {
                byte[] writebytes = Json.getBytes();
                // 设置文件长度
                conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
                OutputStream outwritestream = conn.getOutputStream();
                outwritestream.write(Json.getBytes());
                outwritestream.flush();
                outwritestream.close();
               Log.d("msg", "doJsonPost: " + conn.getResponseCode());
            }
            if (conn.getResponseCode() == 200) {//上传成功
                reader = new BufferedReader(
                        new InputStreamReader(conn.getInputStream()));
                result = reader.readLine();//得到返回的json字符串
           }

        } catch (Exception e) {
            Log.d("msg","没成功");//Log出现这个一般是fromjson函数没写好,格式不对
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

以传输json为参数,返回得到的json字符串
具体使用:

 public static ChatMessage sendMessage(String message) {
        ChatMessage chatMessage = new ChatMessage();
        Log.d("msg",fromjson(message));
        String gsonResult = sendJsonPost(fromjson(message));//连接请求的内容
        if (gsonResult != null) {
            try {
               chatMessage.setMessage(GetText(gsonResult));//http连接获取的内容解析之后的结果给聊天信息赋值
            } catch (Exception e) {
                chatMessage.setMessage("请求错误...");
                Log.d("msg",gsonResult);
                Log.e("msg",Log.getStackTraceString(e));
            }
        }
        chatMessage.setDate(new Date());
        chatMessage.setType(ChatMessage.Type.INCOUNT);
        return chatMessage;
    }

这个时候你先别管GetText函数,你可以先尝试去 Log.d(“msg”,gsonResult),即看看你到底有没有收到官网回复的json,如果你Log出来类似
{“emotion”:{“robotEmotion”:{“a”:0,“d”:0,“emotionId”:0,“p”:0},“userEmotion”:{“a”:0,“d”:0,“emotionId”:20300,“p”:0}},“intent”:{“actionName”:"",“code”:10004,“intentName”:""},“results”:[{“groupType”:1,“resultType”:“text”,“values”:{“text”:“一颗蛋,哇哈哈~~”}}]}
那么,恭喜你,你离成功已经不远了,最后的text的内容就是机器人的智能回复
如果不行,那么你可以看看下面这个坑。

3.网络安全设置

安卓版本变高,在系统安全方面挖了不少坑,我们这里到图灵机器人官网的网络连接,可能被系统视为不安全的,导致连接失败。我们可以这样操作:
在res文件夹中新建一个文件夹,放入network_security_config.xml
AS+图灵机器人官网+HTTP POST(json)+JsonReader实现安卓课设《智能聊天机器人》填坑记录_第2张图片

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
 <base-config cleartextTrafficPermitted="true" />
</network-security-config>

再在AndroidManifest文件中添加

android:networkSecurityConfig="@xml/network_security_config"

AS+图灵机器人官网+HTTP POST(json)+JsonReader实现安卓课设《智能聊天机器人》填坑记录_第3张图片
对了,别忘了添加网络权限

<uses-permission android:name="android.permission.INTERNET" />

4.超级天坑——从json中得到数据

【一般的方法】
自定义一个Result类,让这个类契合json文本(json中{表示类,[表示集合),再利用google的gson包的函数,将json数据转换成Result类对象,最后在对象中调用gettext函数得到数据。但由于这里的json是类中含有类,天知道我在这里查了多久资料,debug了多久代码,一直以为我是Result类没写对,一直在调试。直到最后,我得到了结论——此方法不可行。如果谁用这个方法成功了,务必联系我,类中类的result类来一个好吗?秋梨膏!
【可行的方法】
JsonReader
一个通过输入流来得到json数据的数据流读入类,先上代码

  private static String GetText(String json) throws IOException {
        JsonReader reader = new JsonReader(new StringReader(json));
        String ans="";
        reader.beginObject();
       try {
           while(reader.hasNext()){
               String name=reader.nextName();
               if(name.equals("emotion")){
                   reader.beginObject();
                   reader.nextName();
                   reader.beginObject();
                   for(int i=0;i<4;i++){
                       reader.nextName();
                       reader.nextString();
                   }
                   reader.endObject();
                   name=reader.nextName();
                   reader.beginObject();
                   for(int i=0;i<4;i++){
                       reader.nextName();
                       reader.nextString();
                   }
                   reader.endObject();
                   reader.endObject();
               }
               else if(name.equals("intent")){
                   reader.beginObject();
                   for(int i=0;i<3;i++){
                       reader.nextName();
                       reader.nextString();
                   }
                   reader.endObject();
               }
               else if(name.equals("results")){ reader.beginArray();
                       reader.beginObject();
                       for(int i=0;i<2;i++){
                           reader.nextName();
                           reader.nextString();
                       }
                       name=reader.nextName();
                       if(name.equals("values")){
                           reader.beginObject();
                           reader.nextName();
                           ans=reader.nextString();
                           reader.close();
                           return  ans;
                       }
                   }

               }
        } finally {
           return ans;
        }

    }

针对下面这个回复json来看

{"emotion":{"robotEmotion":{"a":0,"d":0,"emotionId":0,"p":0},"userEmotion":{"a":0,"d":0,"emotionId":20300,"p":0}},"intent":{"actionName":"","code":10004,"intentName":""},"results":[{"groupType":1,"resultType":"text","values":{"text":"一颗蛋,哇哈哈~~"}}]}

1.这个是当你发的信息可以判断情绪的时候就会有这样的回复json,如果你发的是形如“1234”,“nmsl”(浓墨山峦),等机器判断不出情绪的消息,回复json中可能就会没有emotion这个类(包含robotEmotion和userEmotion),只有intent类和result集合。我们的程序要做到两种情况都能得到有效数据才算成功,这里我用while循环+if…else来解决这个问题。
2.简单介绍下上面函数reader能点出来的几个函数的意义
beginobject(),在这里可以理解成读入”{“;
beginArray(),在这里可以理解成读入”[“;
nextname(),读入emotion,robotemotion等等字段
nextString(),读入0,20300,text,一颗蛋,哇哈哈~~等字段后的字符串内容
endArray(),在这里可以理解成读入”]“;
endObject(),在这里可以理解成读入”}“;
好,那么剩下的就不讲了,就是对应json字符串内容字段顺序,一个一个读入但不处理,直到"text":“一颗蛋,哇哈哈~~”,最后用ans=reader.nextString()来记录数据。
有一说一,这个方法虽然看上去很笨重,但其实一个很底层的方法,所以是一个很通用的方法。对于这种 类中有类的json数据,我发现是不是只有这种方法才能实现数据的获取?在这里先打一个问号吧,欢迎来评论区交流。

三.成果展示

AS+图灵机器人官网+HTTP POST(json)+JsonReader实现安卓课设《智能聊天机器人》填坑记录_第4张图片
AS+图灵机器人官网+HTTP POST(json)+JsonReader实现安卓课设《智能聊天机器人》填坑记录_第5张图片
AS+图灵机器人官网+HTTP POST(json)+JsonReader实现安卓课设《智能聊天机器人》填坑记录_第6张图片
AS+图灵机器人官网+HTTP POST(json)+JsonReader实现安卓课设《智能聊天机器人》填坑记录_第7张图片

四.结语

有一说一,这安卓课设确实有点坑,在下身先士卒,为大伙填坑,希望能对大伙有所帮助吧。
联系QQ:2541884980

你可能感兴趣的:(andriod,studio,json,http,android,studio)