准备一个可以接收的数据接口,用来实现对话。当然你有更好的欢迎下面留言~我用的是下面这个接口,附上传送门:
这个接口的调用url是:http://api.qingyunke.com/api.php?key=free&appid=0&msg=关键词
手写js了好多次ajax请求,皆因跨域失败告终。没办法,想到了springboot做一个中转请求处理吧,请求发送到私服上的springboot程序,springboot再请求这个接口,emmm虽然挺麻烦,但是这个思路可以实现,开始撸码!
不想手写前端,遂找了一些框架,最终选择framework7,一个和原生应用很像的HTML,js框架,里面有个massage的例子,刚好就是对话框的主题。看一下最终效果吧:
先理解一下原理:前端发起ajax请求到springboot程序,springboot再请求接口实现消息返回,最后显示在页面上。具体代码如下:从页面开始:
<!DOCTYPE html>
<html>
<head>
<!-- Required meta tags-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!-- Your app title -->
<title>My App</title>
<!-- 使用bootcdn进行在线加速 -->
<link href="https://cdn.bootcss.com/framework7/4.2.2/css/framework7.min.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/framework7/4.2.2/css/framework7.bundle.min.css" rel="stylesheet">
<!-- 本地示例运行请参考:https://blog.csdn.net/qq_38815953/article/details/81984863 -->
</head>
<body>
<div class="page">
<div class="navbar">
<div class="navbar-inner">
<div class="title">消息列表</div>
</div>
</div>
<div class="toolbar messagebar">
<div class="toolbar-inner">
<div class="messagebar-area">
<textarea class="resizable" placeholder="输入"></textarea>
</div><a class="link send-link" href="#">发送</a>
</div>
</div>
<div class="page-content messages-content">
<div class="messages">
<!-- 消息标题,初始化为时间 -->
<div class="messages-title" id="messages-title_top"></div>
<!-- 完整的发送消息布局 -->
<!-- <div class="message message-sent">
<div class="message-avatar" style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-7.jpg);"></div>
<div class="message-content">
<div class="message-name">约翰</div>
<div class="message-header">消息头</div>
<div class="message-bubble">
<div class="message-text-header">消息描述</div>
<div class="message-text">苍茫的天涯是我的爱.</div>
<div class="message-text-footer">注脚</div>
</div>
<div class="message-footer">消息脚</div>
</div>
</div> -->
<!-- 完整接收布局消息 -->
<div class="message message-received">
<div class="message-avatar" style="background-image:url(https://头像url.png);"></div>
<div class="message-content">
<div class="message-name">菲菲</div>
<div class="message-bubble">
<div class="message-text">Hello,我是潜伏在网页里的智能客服菲菲,今天咱们唠点啥尼?</div>
</div>
<div class="message-footer">自动回复</div>
</div>
</div>
</div>
</div>
</div>
<!-- 主js文件和web支持 -->
<script src="https://cdn.bootcss.com/framework7/4.2.2/js/framework7.min.js"></script>
<script src="https://cdn.bootcss.com/framework7/4.2.2/js/framework7.bundle.min.js"></script>
<!-- jq -->
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$(function(){
var date = new Date();
$('#messages-title_top').text(date.toLocaleString());
});
// app初始化
var app = new Framework7();
var $$ = Dom7; //为了防止与jq冲突,实际上,借助framework7的dom操作与jq一样
// 初始化消息对象
var messages = app.messages.create({
el: '.messages',
// 第一条消息规则
firstMessageRule: function(message, previousMessage, nextMessage) {
// 跳过标题
if (message.isTitle) return false;
/* if:
- 如果之前没有消息
- 或以前的消息类型(发送/接收)不同
- 或者以前的邮件发件人名称不同
*/
if (!previousMessage || previousMessage.type !== message.type || previousMessage.name !== message.name) return true;
return false;
},
// Last message rule
lastMessageRule: function(message, previousMessage, nextMessage) {
// Skip if title
if (message.isTitle) return false;
/* if:
- there is no next message
- or next message type (send/received) is different
- or next message sender name is different
*/
if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
return false;
},
// Last message rule
tailMessageRule: function(message, previousMessage, nextMessage) {
// Skip if title
if (message.isTitle) return false;
/* if (bascially same as lastMessageRule):
- there is no next message
- or next message type (send/received) is different
- or next message sender name is different
*/
if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
return false;
}
});
// 初始化消息栏
var messagebar = app.messagebar.create({
el: '.messagebar'
});
// 响应
var responseInProgress = false;
var msg_info = ""; // 全局保存发送消息
// 发送消息
$$('.send-link').on('click', function() {
var text = messagebar.getValue().replace(/\n/g, '<br>').trim();
// 空消息返回不做处理
if (!text.length) return;
msg_info = text;
// 发送成功则清除描述
messagebar.clear();
// 将焦点返回到区域
messagebar.focus();
// 向邮件添加邮件
messages.addMessage({
text: text,
});
if (responseInProgress) return;
// 接收虚拟消息
receiveMessage();
});
// 随机生成虚拟消息
function receiveMessage() {
responseInProgress = true;
setTimeout(function() {
// 得到随机答案和随机人
// 显示载入指示
messages.showTyping({
header: '菲菲 正在输入',
avatar: 'https://这里是头像的路径.png'
});
// 向我的服务器发起ajax请求
var url = "http://请求服务的路径/520" + "?msg=" + msg_info;
$.ajax({
type: 'get',
url: url,
success: function(data){
console.log(data);
messages.addMessage({
text: data.content,
type: 'received',
name: '菲菲',
avatar: 'https://这里是头像的url'
});
// 隐藏输入指示
messages.hideTyping();
responseInProgress = false;
},
error: function(data){
// console.log(data);
}
});
setTimeout(function() {
}, 4000);
}, 1000);
}
</script>
</body>
</html>
直接copy过来demo改的,js资源取自bootcdn的加速
然后是主角springboot了,使用的是在线初始化的一个boot程序,pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lvfeng</groupId>
<artifactId>lvfeng</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>lvfeng</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>org.mybatis.spring.boot</groupId>-->
<!--<artifactId>mybatis-spring-boot-starter</artifactId>-->
<!--<version>2.0.0</version>-->
<!--</dependency>-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!--<scope>runtime</scope>-->
</dependency>
<!-- json处理 -->
<!-- <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.4</version>
</dependency> -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--maven打包时跳过单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
接下来是控制器
/**
* 跨域对话机器人请求
* 青云客:http://api.qingyunke.com/
* 接口:http://api.qingyunke.com/api.php?key=free&appid=0&msg=关键词
*/
@ResponseBody
@CrossOrigin
@GetMapping("/talk/{id}")
public Map getTalk(@PathVariable(name = "id") Long id, @RequestParam(name = "msg") String msg) throws Exception{
System.out.println("请求内容:" + msg);
String url = "http://api.qingyunke.com/api.php";
Map param = new HashMap(); // 配置
param.put("key","free");
param.put("appid","0");
param.put("msg",msg);
String res = NetTool.getNetData(url, param, "GET"); // 执行请求
JSONObject object = JSONObject.parseObject(res);
Map map = object.getInnerMap(); // 结果集转map
return map;
}
为了用着方便,参考了nowAPI的一些写法,封装了一下静态方法,以便之后更多接口的方便使用:
public static final String userAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";
public static final int DEF_CONN_TIMEOUT = 30000;
public static final int DEF_READ_TIMEOUT = 30000;
public static final String DEF_CHATSET = "UTF-8";
/**
* 创建Http连接并调用接口数据
*/
public static String getNetData(String strUrl, Map param, String method) throws Exception{
HttpURLConnection conn = null;
BufferedReader reader = null;
String res = null;
try {
StringBuffer sb = new StringBuffer();
if(null == method || "GET".equals(method)){
strUrl = strUrl + "?" + urlEncode(param);
}
URL url = new URL(strUrl);
conn = (HttpURLConnection) url.openConnection();
if(null == method || "GET".equals(method)){
conn.setRequestMethod("GET");
}else{
conn.setRequestMethod("POST");
conn.setDoOutput(true);
}
conn.setRequestProperty("User-agent",userAgent);
conn.setUseCaches(false);
conn.setConnectTimeout(DEF_CONN_TIMEOUT);
conn.setReadTimeout(DEF_READ_TIMEOUT);
conn.setInstanceFollowRedirects(false);
conn.connect();
if (null != param && "POST".equals(method)){
try {
DataOutputStream dos =new DataOutputStream(conn.getOutputStream());
dos.writeBytes(urlEncode(param));
} catch (Exception e){
e.printStackTrace();
}
}
InputStream is = conn.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET));
String strRead = null;
while (null != (strRead = reader.readLine())){
sb.append(strRead);
}
res = sb.toString();
}catch (IOException e){
e.printStackTrace();
}finally {
if (null != reader){
reader.close();
}
if (null != conn){
conn.disconnect();
}
}
return res;
}
/**
* 转码
*/
public static String urlEncode(Map<String,Object>data){
StringBuilder sb = new StringBuilder();
for (Map.Entry i : data.entrySet()) {
try {
sb.append(i.getKey()).append("=").append(URLEncoder.encode(i.getValue()+"","UTF-8")).append("&");
} catch (UnsupportedEncodingException e){
e.printStackTrace();
}
}
return sb.toString();
}
然后springboot打个jar包并上传在Linux上运行起来就欧克啦!
当然其中会遇到打包不顺利的情况,可以参考咱之前文章或者百度一下。