java中springboot项目集成socketIo实现实时推送

  • 时间:2019-02-01 20:43 作者:菜菜___ 来源:菜菜___ 阅读:443
  • 扫一扫,手机访问
摘要:今天在这里跟大家分享一下springboot项目集成socketIo实现实时推送功能。不多说什么直接上代码,而后慢慢讲解。第一步项目中准备socketIo的运行环境 ! socketio dependency groupId com.corundum

今天在这里跟大家分享一下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.jianshu.com/u/ac4daaeecdfe
95后前台妹子一枚,爱阅读,爱交友,将工作中遇到的问题记录在这里,希望给每一个看到的你能带来一点帮助。

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】你是HTML 5的一员吗?(2019-08-15 11:58)
【系统环境|】Web前端基础怎么学?html、css、JavaScript 知识架构图(2019-08-14 17:55)
【系统环境|】零基础小白走Web前端之路是否可行?答案是yes!(2019-08-13 11:44)
【系统环境|】你知道Web前端与HTML5技术的区别吗?(2019-08-12 14:10)
【系统环境|】移动前端开发和web前端开发的区别(2019-08-11 16:49)
【系统环境|】给新手的锦囊:Web前端开发小白的学习建议和路线图(2019-08-10 16:34)
【系统环境|】都说web前端开发薪资高,入行就有上万月薪,转行难吗?(2019-08-09 14:55)
【系统环境|】干货教程 | Web前端开发学习入门指南(2019-08-08 18:27)
【系统环境|】前端开发:vue路由之前端路由的原理(2019-08-07 13:17)
【系统环境|】你不知道的web前端那些事(2019-08-06 12:29)
手机二维码手机访问领取大礼包
返回顶部