先看看简陋的聊天室
实现此功能需要使用到技术有:SpringBoot、RabbitMQ、WebSocker、stopm、sockjs、docker、bootstrap、ajax。
首先在Docker中拉取RabbitMQ镜像,先运行RabbitMQ镜像,进入RabbitMQ容器中,开启RabbitMQ插件,让其支持stopm协议。
rabbitmq-plugins enable rabbitmq_web_stomp rabbitmq_stomp rabbitmq_web_stomp_examples
这里有个跨域问题,如果不设置的话,消息无法跨域,就无法在不同域名下进行消息传送,自己玩的时候建议全部允许跨域,在项目中可以指定域名允许跨域消息。
在rabbitmq.conf中加上management.cors.allow_origins.1 = * 。星表示全部允许跨域,该配置文件在容器/etc/rabbitmq/目录下,在容器中不允许修改文件内容,这里还需要进行配置挂载,在宿主机目录下创建/usr/rabbitmq/conf目录,将容器中的配置文件和插件配置都拷贝到此目录下:
插件配置名:enabled_plugins
插件内容:
[rabbitmq_management,rabbitmq_stomp,rabbitmq_web_stomp,rabbitmq_web_stomp_examples].
配置文件名:rabbitmq.conf
配置内容:
loopback_users.guest = false
listeners.tcp.default = 5672
management.tcp.port = 15672
management.cors.allow_origins.1 = *
删除之前运行的容器,再次启动镜像,需要在启动时挂载一些参数
docker run -d -p 15672:15672 5672:5672 15674:15674 15670:15670 -v /usr/rabbitmq/conf:/etc/rabbitmq --name myrabbitmq rabbitmq:3.7.26
访问15670端口,看到以下内容表示你设置并启动成功了!
创建一个SpringBoot项目(发送方),依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<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>
配置信息:
# 应用服务 WEB 访问端口
server.port=8081
server.servlet.context-path=/
# 连接RabbitMQ配置
spring.rabbitmq.host=192.168.2.113
spring.rabbitmq.port=5672
spring.rabbitmq.username=root
spring.rabbitmq.password=123456
前端页面:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>带码人聊天室1</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.css}"/>
<script language="javascript" type="text/javascript" th:src="@{/js/jquery-3.5.0.js}"></script>
<script th:src="@{/js/jquery.js}"></script>
<script type="text/javascript">
$(function () {
$("#mess").focus(function () {
$("#tip").text("")
});
$("#but").click(function () {
var message = $("#mess").val();
if (message==""){
alert("please input!")
return;
}
$.ajax({
url:basepath+"/send",
data:{
message:message
},
success:function (data) {
$("#tip").text(data)
$("#mess").val("");
let date = new Date();
let dateHours = date.getHours(); //获取小时
let dateMinutes = date.getMinutes(); //获取分钟
let dateSeconds = date.getSeconds(); //获取秒
$("#message").append("myself >"+dateHours+"时"+dateMinutes+"分"+dateSeconds+"秒:",message + "<br/>");
}
})
});
})
//按enter键触发送按钮
$(window).keydown(function (e) {
if (e.keyCode == 13) {
$("#but").click()
}
});
<div th:include="commons/common :: html"></div>
<div class="row">
<div class="col-md-2 col-md-offset-5">
<h1>welcome (´▽`ʃ♡ƪ)</h1>
<input type="text" id="mess" placeholder="send you want"> <button class="btn btn-success" type="button" id="but">send</button>
<div><span id="tip" style="color: green"></span></div>
<hr>
</div>
<div id="log"></div>
</div>
</body>
</html>
发送消息服务类:
//加入spring容器
@Component
public class SendService {
@Autowired
AmqpTemplate amqpTemplate;
public void send(String exchange,String routingKey,String message){
amqpTemplate.convertAndSend(exchange,routingKey,message);
System.out.println("消息发送成功");
}
}
控制层:
@Controller
public class SendController {
@Autowired
ApplicationContext applicationContext;
@RequestMapping("/send")
@ResponseBody
public Object index(String message){
SendService sendService = (SendService) applicationContext.getBean("sendService");
sendService.send("myEx-direct","chen",message);
return "发送成功";
}
}
这里主要是在前端获取发送的信息,通过异步请求,将信息参数传递给后端控制层,控制层调用发送消息的服务,将信息发送到消息中间件的队列中
再次创建一个SpringBoot项目(接收方):
前端页面:
这里必须引入sockjs.js、stomp.js
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试接收</title>
<script th:src="@{/js/jquery.js}"></script>
<script th:src="@{/js/sockjs.js}"></script>
<script th:src="@{/js/stomp.js}"></script>
<script>
//初始化 ws 对象,使用的是rabbitmq_stomp的端口【15674】
var ws = new WebSocket('ws://192.168.2.113:15674/ws');
// 获得Stomp client对象
var client = Stomp.over(ws);
//发送频率
client.heartbeat.outgoing = 0;
//接收频率
client.heartbeat.incoming = 0;
//关闭控制台调试数据:client.debug = null
client.debug = function (str) {
$("#debug").append(str + "<br/>");
};
// 定义连接成功回调函数
var on_connect = function (x) {
//接收myqueue队列的数据
//注意 /queue/是必须的,后面填写你自己创建的队列名称
client.subscribe("/queue/myqueue", function (data) {
var msg = data.body;
$("#log").text("收到数据");
console.log(data);
$("#message").append(msg + "<br/>");
//如果后面带了参数 ack 就是指定要手动确认消息,没带就是自动确认
data.ack();
}, {
ack: 'client'});
};
// 定义错误时回调函数
var on_error = function () {
$("#log").val("error")
};
// 连接RabbitMQ
client.connect('root', '123456', on_connect, on_error, '/');
</script>
</head>
<body>
<h1 th:text="ok"></h1>
<h1>debug</h1>
<div id="debug"></div>
<hr>
<h1>data</h1>
<div id="message"></div>
<hr>
<h1>接收消息情况</h1>
<div id="log"></div>
</body>
</html>
登录RabbitMQ客户端,通过(RoutingKey)路由键将交换机与队列绑定,启动两个项目,发送方发送信息,接收方就能实时接收信息了。
总结:
这只是实现了消息的单发面发送,要想实现开始的聊天室功能(就是将两方的代码互相拷贝一下),需要再创建一个队列,让发送方监听接收方队列的消息,接收方也监听着发送方队列的信息,这样就实现了一个简单的聊天室的功能。