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

    技术2025-08-26  12

    目录

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

    一.准备工作

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

    二.开始填坑

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

    1.ChatMessageAdapter

    在此文件第62行 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

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

    再在AndroidManifest文件中添加

    android:networkSecurityConfig="@xml/network_security_config"

    对了,别忘了添加网络权限

    <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数据,我发现是不是只有这种方法才能实现数据的获取?在这里先打一个问号吧,欢迎来评论区交流。

    三.成果展示

    四.结语

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

    Processed: 0.014, SQL: 9