java中springboot项目集成socketIo实现实时推送
今天在这里跟大家分享一下springboot项目集成socketIo实现实时推送功能。不多说什么直接上代码,而后慢慢讲解。
第一步项目中准备socketIo的运行环境
<!--socketio--> <dependency> <groupId>com.corundumstudio.socketio</groupId> <artifactId>netty-socketio</artifactId> <version>1.7.11</version> </dependency>
第二步 socketIo的运行类,和启动类。
@Configurationpublic class NettySocketConfig { private String ipWin; private String ipLinxu; private int port; @Bean public SocketIOServer socketIOServer() throws Exception{ ipWin = (String)YmlUtil.getValue("socketIo.win"); ipLinxu = (String)YmlUtil.getValue("socketIo.linxu"); port = (Integer) YmlUtil.getValue("socketIo.port"); com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration(); String os = System.getProperty("os.name"); if(os.toLowerCase().startsWith("win")){ //在本地window环境测试时用localhost config.setHostname(ipWin); } else { //部署到你的远程服务器正式发布环境时用服务器公网ip config.setHostname(ipLinxu); } // 端口,任意 config.setPort(port); config.setMaxFramePayloadLength(1024 * 1024); config.setMaxHttpContentLength(1024 * 1024); //该处进行身份验证h config.setAuthorizationListener(handshakeData -> { //http://localhost:8081?username=test&password=test //例假如使用上面的链接进行connect,可以使用如下代码获取客户密码信息 //String username = data.getSingleUrlParam("username"); //String password = data.getSingleUrlParam("password"); return true; }); final SocketIOServer server = new SocketIOServer(config); return server; } @Bean public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) { return new SpringAnnotationScanner(socketServer); }}
读取配置文件的util类,用于读取yml文件中的配置
public class YmlUtil { /** * key:文件名索引 * value:配置文件内容 */ private static Map<String, LinkedHashMap> ymls = new HashMap<>(); /** * string:当前线程需要查询的文件名 */ private static ThreadLocal<String> nowFileName = new ThreadLocal<>(); /** * 加载配置文件 * @param fileName */ public static void loadYml(String fileName) { nowFileName.set(fileName); if (!ymls.containsKey(fileName)) { ymls.put(fileName, new Yaml().loadAs(YmlUtil.class.getResourceAsStream("/" + fileName), LinkedHashMap.class)); } } public static Object getValueByKey(String key) throws Exception { // 首先将key进行拆分 String[] keys = key.split("[.]"); // 将配置文件进行复制 Map ymlInfo = (Map) ymls.get(nowFileName.get()).clone(); for (int i = 0; i < keys.length; i++) { Object value = ymlInfo.get(keys[i]); if (i < keys.length - 1) { ymlInfo = (Map) value; } else if (value == null) { throw new Exception("key不存在"); } else { return value; } } throw new RuntimeException("不可能到这里的..."); } public static Object getValue(String key) throws Exception { // 首先加载配置文件 loadYml("application.yml"); return getValueByKey(key); }}
socketIo启动类
@Component@Order(value=1)public class ServerRunner implements CommandLineRunner { private final SocketIOServer server; @Autowired public ServerRunner(SocketIOServer server) { this.server = server; } @Override public void run(String... args) throws Exception { server.start(); System.out.println("socket.io启动成功!"); }}
socketIo的前后台交互
@Componentpublic class SocketIoServer { public static SocketIOServer socketIoServer; @Autowired public SocketIoServer(SocketIOServer server) { this.socketIoServer = server; } @OnConnect public void onConnect(SocketIOClient client) { // TODO Auto-generated method stub String sa = client.getRemoteAddress().toString(); String clientIp = sa.substring(1, sa.indexOf(":"));// 获取设施ip System.out.println(clientIp + "-------------------------" + "用户端已连接"); Map<String, List<String>> params = client.getHandshakeData().getUrlParams(); SocketIoServerMapUtil.put(clientIp, client); } @OnDisconnect public void onDisconnect(SocketIOClient client) { // TODO Auto-generated method stub String sa = client.getRemoteAddress().toString(); String clientIp = sa.substring(1, sa.indexOf(":"));// 获取设施ip System.out.println(clientIp + "-------------------------" + "用户端已断开连接"); SocketIoServerMapUtil.remove(clientIp); } @OnEvent(value = "text") public void onEvent(SocketIOClient client, AckRequest ackRequest, String data) { // TODO Auto-generated method stub // 用户端推送advert_info事件时,onData接受数据,这里是string类型的json数据,还可以为Byte[],object其余类型 String sa = client.getRemoteAddress().toString(); String clientIp = sa.substring(1, sa.indexOf(":"));// 获取用户端连接的ip Map<String, List<String>> params = client.getHandshakeData().getUrlParams();// 获取用户端url参数 System.out.println(clientIp + ":用户端:************" + data); JSONObject gpsData = (JSONObject) JSONObject.parse(data); String userIds = gpsData.get("userName") + ""; String taskIds = gpsData.get("password") + ""; client.sendEvent("text1", "后端得到了数据"); }}
存放前台连接的设施ip SocketIoServerMapUtil 类
public class SocketIoServerMapUtil { public static ConcurrentMap<String, SocketIOClient> webSocketMap = new ConcurrentHashMap<>(); public static void put(String key, SocketIOClient SocketIOClient) { webSocketMap.put(key, SocketIOClient); } public static SocketIOClient get(String key) { return webSocketMap.get(key); } public static void remove(String key) { webSocketMap.remove(key); } public static Collection<SocketIOClient> getValues() { return webSocketMap.values(); } public static ConcurrentMap<String, SocketIOClient> getWebSocketMap() { return webSocketMap; }}
前台代码,这里需要我们前台项目中引进socket.io.js这个类。我这边详情vue引入socket:npm install –save socket.io,不是vue环境的直接去下载一个js文件。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="./socket.io.js"></script></head><body> <script> //创立socket var socket = io('http://localhost:9092');//用于连接后台的服务 /* 创立自己设置事件 'news' 作用:接受服务端 socket.emit('news', 数据); 发出的数据 */ socket.on('connect', function () { socket.emit('text', JSON.stringify({userName:"caiyy",passWord:"123456"})); }); socket.on('text1', function (data) { //输出服务端响应了数据 console.log(data); }); </script></body></html>
现在所有的代码已经都准备好了,开始讲解详细步骤了。
开始导入socketIo的jar包,因为springboot存在一个启动类,我们这边的socketIo的配置尽管可以放在springboot的启动类中,但是一般情况下还是提取起来到一个类中。
public static void main(String[] args) { SpringApplication.run(EventApplication.class,args); }
这里定义的是NettySocketConfig类。这个类中是socketIo的配置项,ipWin是window系统的ip,一般也就是本机测试的ip127.0.0.1;ipLinxu是linxu环境的ip,一般是我们正式环境的ip;port是socket的端口号,一般是9092,这些都是可以在application.yml中配置的,下面就是我在yml中的配置。
#网络ipsocketIo: win: localhost linxu: 各自linxu环境的ip port: 9092
而后就是配置socketIo的启动项即ServerRunner类。@Order(value=1)这个配置很重要,
这个标记包含一个value属性。属性接受整形值。如:1,2 等等。值越小拥有越高的优先级。就是由于我们springboot自带一个启动类,所以在这里配置启动的value值为1.就是在springboot启动之后在启动socketIo.启动完成配置也搞定了 ,现在就是要进行前后台的交互了。
@OnConnect用于监听用户端连接信息的,
@OnDisconnect客户监听用户端断开信息的。
@OnEvent(value = “text”)客户后台监听前台的请求事件的。value值就是前台请求的唯一标识,前台携带这个请求的唯一标识进行请求后端,而后后端监听到这个请求,而后进行一系列操作。
client.sendEvent(“text1”, “后端得到了数据”);用于后台响应前台数据。text1就是后端给前台的唯一标识,前台通过这个唯一标识来挑选后台给的数据能否是这个自己这个连接中所需要的。来确保消息不会发送给错误的前台连接者。
当后端服务启动之后,通过浏览器访问我们写的那个页面,后端就是看到想对应的ip连到后端服务当中,前台也会相对应的打印出“后端得到了数据”。
现在就在讲一个中间写了的一个没用用到的util类,SocketIoServerMapUtil 类。
这个类客户存储前台正在存于连接的ip,我们可以用这个类进行集体推送消息。只需前台连接到我们这个服务,在SocketIoServer里面的监听里面就用到了这个类的put方法。SocketIoServerMapUtil.put(clientIp, client);存入了用户端的ip。当我们的程序中某一个步骤启动了,要触发到集体推送消息的时候,我们可以在这个步骤中增加一段代码:
for (SocketIOClient client: SocketIoServerMapUtil.getValues()) { client.sendEvent("quntui", "新年快乐"); }
而后在前台代码需要接受这个群推的登录者中加入以下代码即可以得到这个消息:
socket.on('quntui', function (data) { //输出服务端响应了数据 alert(data); });
本次分享到此结束。。。欢迎大家留言评论和互相交流。
原文作者技术博客:https://www.songma.com/u/ac4daaeecdfe
95后前台妹子一枚,爱阅读,爱交友,将工作中遇到的问题记录在这里,希望给每一个看到的你能带来一点帮助。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » java中springboot项目集成socketIo实现实时推送