kafka和websocket实时数据推送
需求
已有Kafka服务,通过kafka服务数据(GPS)落地到本地磁盘(以文本文件存储)。现要根据echarts实现一个实时车辆的地图。
分析
- 前端实时展现:使用websocket技术,实现服务器端数据推送到前端展现
- 通过Java的kafka client端获取数据,并且通过websock推送到前端。
websocket
简介
websocket是HTML5开始提供的一种在单位TCP连接上进行全双工通讯的协议。在websocket api中,浏览器和服务器只需要做一次握手的动作,然后浏览器和服务器之间就形成了一条快速通道。两者之间就可以数据互相传送。
开发
- 服务器端
package com.ykkj.weiyi.socket;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.SpringConfigurator;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@ServerEndpoint(value = "/websocket")
public class CommodityServer {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
public static CopyOnWriteArraySet<CommodityServer> webSocketSet = new CopyOnWriteArraySet<CommodityServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 连接建立成功调用的方法
*
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
* @param session 可选的参数
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("来自客户端的消息:" + message);
//群发消息
for (CommodityServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
/**
* 发生错误时调用
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
/**
* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
*
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
CommodityServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
CommodityServer.onlineCount--;
}
}
复制代码
前端
<!DOCTYPE html>
<html>
<head>
<title>Java后端WebSocket的Tomcat实现</title>
</head>
<body>
Welcome<br/><input id="text" type="text"/>
<button onclick="send()">发送消息</button>
<hr/>
<button onclick="closeWebSocket()">关闭WebSocket连接</button>
<hr/>
<div id="message"></div>
</body> <script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8081/onepic/websocket");
}
else {
alert('当前浏览器 Not support websocket')
} //连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
}; //连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
} //接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
} //连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
} //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
} //将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
} //关闭WebSocket连接
function closeWebSocket() {
websocket.close();
} //发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
复制代码
测试
注意点
webSocketSet
设置为全局静态变量,为其他类提供调用public static CopyOnWriteArraySet<CommodityServer> webSocketSet = new CopyOnWriteArraySet<CommodityServer>();
复制代码服务端都是用注解实现的 @ServerEndpoint @OnOpen @OnClose @OnMessage @OnError
Tomcat7.0.47以上版本支持websocket1.0
pom中添加jar支持
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
复制代码
Kafka
简介
Kafka是一个分布式的、可分区的、可复制的消息系统。
开发
window系统搭建kafka环境,请参照我的《 kafka环境搭建(windows) 》笔记
- kafka client for java
package com.ykkj.weiyi.socket;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.io.IOException;
import java.util.Arrays;
import java.util.Properties;
import static com.ykkj.weiyi.socket.CommodityServer.webSocketSet;
public class ConsumerKafka extends Thread {
private KafkaConsumer<String, String> consumer;
private String topic = "test.topic";
public ConsumerKafka() {
}
@Override
public void run() {
//加载kafka消费者参数
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "ytna");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("session.timeout.ms", "15000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
//创建消费者对象
consumer = new KafkaConsumer<String, String>(props);
consumer.subscribe(Arrays.asList(this.topic));
//死循环,持续消费kafka
while (true) {
try {
//消费数据,并设置超时时间
ConsumerRecords<String, String> records = consumer.poll(100);
//Consumer message
for (ConsumerRecord<String, String> record : records) {
//Send message to every client
for (CommodityServer webSocket : webSocketSet) {
webSocket.sendMessage(record.value());
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
continue;
}
}
}
public void close() {
try {
consumer.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
//供测试用,若通过tomcat启动需通过其他方法启动线程
public static void main(String[] args) {
ConsumerKafka consumerKafka = new ConsumerKafka();
consumerKafka.start();
}
}
复制代码
注意topic 和 bootstrap.servers配置
- 调用类
package com.ykkj.weiyi.socket;
public class RunThread {
public RunThread() {
ConsumerKafka kafka = new ConsumerKafka();
kafka.start();
}
}
复制代码
- web.xml 配置
<listener>
<listener-class>com.ykkj.weiyi.socket.RunThread</listener-class>
</listener>
复制代码
测试
注意点
- ConsumerKafka 需要在web.xml中配置监听,不然在ConsumerKafka 类中不能获取webSocketSet变量
- 引用webSocketSet变量方式
import static com.ykkj.weiyi.socket.CommodityServer.webSocketSet;
- 注意topic 和 bootstrap.servers配置
结束语
这里只是做了技术验证,还没有真正实现。真实场景下,kafka获取到的数据需要进行数据清洗,把不符合当前规范的数据清洗掉,并且按照前端展示需要的格式组装数据。
参考网上资料
https://blog.csdn.net/lw_ghy/article/details/73252904
https://blog.csdn.net/liu857279611/article/details/70157012
作者:jinshw
链接:https://juejin.im/post/5b20e2e16fb9a01e2c698c51
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
kafka和websocket实时数据推送的更多相关文章
- 实时数据推送webSocket
实时数据推送 在Web或移动项目中,服务器向客户端实时推送消息是一种常见的业务需求. 实现方式 Polling:轮询(俗称“拉”),即定期重新请求数据. Long-Polling:长轮询,是 Poll ...
- C# ASP.NET MVC 之 SignalR 学习 实时数据推送显示 配合 Echarts 推送实时图表
本文主要是我在刚开始学习 SignalR 的技术总结,网上找的学习方法和例子大多只是翻译了官方给的一个例子,并没有给出其他一些经典情况的示例,所以才有了本文总结,我在实现推送简单的数据后,就想到了如何 ...
- C# 数据推送 实时数据推送 轻量级消息订阅发布 多级消息推送 分布式推送
前言 本文将使用一个NuGet公开的组件技术来实现数据订阅推送功能,由服务器进行推送数据,客户端订阅指定的数据后,即可以接收服务器推送过来的数据,包含了自动重连功能,使用非常方便 nuget地址:ht ...
- websocket后台数据推送
Websocket定义: 说明: 作为下一代的 Web 标准,HTML5 拥有许多引人注目的新特性,如 Canvas.本地存储.多媒体编程接口.WebSocket 等等.这其中有“Web 的 TCP ...
- 用图解&&实例讲解php是如何实现websocket实时消息推送的
WebSocket是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. 以前的推送技术使用 Ajax 轮询,浏览器需要不断地向服务器发送http请求来获取最新的数据,浪费很多的带 ...
- swoole+Redis实现实时数据推送
<?php /** * *************************************** * 单进程保护 * * ********************************* ...
- html5 websocket 实时日志推送
http://blog.csdn.net/neutrojan/article/details/46119645
- 我有 7种 实现web实时消息推送的方案,7种!
技术交流,公众号:程序员小富 大家好,我是小富- 我有一个朋友- 做了一个小破站,现在要实现一个站内信web消息推送的功能,对,就是下图这个小红点,一个很常用的功能. 不过他还没想好用什么方式做,这里 ...
- WebSocket与消息推送
B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链 ...
随机推荐
- iOS开发-UILabel和UIButton添加下划线
关于UILabel和UIButton有的时候需要添加下划线,一般有两种方式通过默认的NSMutableAttributedString设置,第二种就是在drawRect中画一条下划线,本文就简单的选择 ...
- Minimum Path Sum leetcode java
题目: Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right w ...
- javaScript:让文本框内的最后一个文字的后面获得焦点
//当失去交点以后 让文本框内的文字获得焦点 并且光标移到最后一个字后面 function myfocus(myid) { if(isNav){ document.getElementById(myi ...
- vc2008中mfc菜单、控件等汉字显示为问号或乱码的解决方法
在vc2008中建立基于mfc的project.在向导的Application type页面中如果在resource language选项中选择"英语(美国)"(图一),那么在pr ...
- express统一输出404页面
不玩不知道,一玩吓一跳,还真是,nodejs全局404怎么搞? 直接,res.render("404.html")有可能会报错:Node.js : Cannot find modu ...
- Ajax:HyperText/URI, HTML, Javascript, frame, frameset, DHTML/DOM, iframe, XMLHttp, XMLHttpRequest
本文内容 Ajax 诞生 促使 Ajax 产生的 Web 技术演化 真正 Ajax Ajax 与 Web 2.0 Ajax 背后的技术 2008 年毕业,2011 年看了<Ajax 高级程序设计 ...
- java class 文件
class 文件是什么 1).是对一个java类或一个java接口的全面描述:2).是对java程序二进制文件格式的精确定义:3).一个class文件中只能包含一个类或接口:4).作为程序传给jvm的 ...
- iOS运用keychain 把identifierForVendor当成唯一标识。替换advertisingIdentifier
iOS运用keychain 结合[[[UIDevice currentDevice] identifierForVendor] UUIDString] 取得设备唯一标识 NSString *ident ...
- VS2015 之 常用快捷键
调试执行 F5,终止调试执行 Shift+F5 启动执行 Ctrl+F5 查找下一个 F3,查找上一个 Shift+F3 附加到进程 Ctrl+Alt+P,逐过程 F10,逐语句执行 F11 切换断点 ...
- NetCore的控制台应用中搭建WebServer的方法
一.新建NetCore控制台项目,并引入下列Nuget包: Microsoft.AspNetCore.StaticFiles.Microsoft.AspNetCore.Http.Microsoft.A ...