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

淩亂°似流年 2022-03-02 10:42 636阅读 0赞

今天在这里跟大家分享一下springboot项目集成socketIo实现实时推送功能。不多说什么直接上代码,然后慢慢讲解。

第一步项目中准备socketIo的运行环境

  1. <dependency>
  2. <groupId>com.corundumstudio.socketio</groupId>
  3. <artifactId>netty-socketio</artifactId>
  4. <version>1.7.11</version>
  5. </dependency>

第二步 socketIo的运行类,和启动类。

@Configuration public class NettySocketConfig {
private String ipWin;
private String ipLinxu;
private int port;

  1. @Bean
  2. public SocketIOServer socketIOServer() throws Exception{
  3. ipWin = (String)YmlUtil.getValue("socketIo.win");
  4. ipLinxu = (String)YmlUtil.getValue("socketIo.linxu");
  5. port = (Integer) YmlUtil.getValue("socketIo.port");
  6. com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
  7. String os = System.getProperty("os.name");
  8. if(os.toLowerCase().startsWith("win")){
  9. //在本地window环境测试时用localhost
  10. config.setHostname(ipWin);
  11. } else {
  12. //部署到你的远程服务器正式发布环境时用服务器公网ip
  13. config.setHostname(ipLinxu);
  14. }
  15. // 端口,任意
  16. config.setPort(port);
  17. config.setMaxFramePayloadLength(1024 * 1024);
  18. config.setMaxHttpContentLength(1024 * 1024);
  19. //该处进行身份验证h
  20. config.setAuthorizationListener(handshakeData -> {
  21. //http://localhost:8081?username=test&password=test
  22. //例如果使用上面的链接进行connect,可以使用如下代码获取用户密码信息
  23. //String username = data.getSingleUrlParam("username");
  24. //String password = data.getSingleUrlParam("password");
  25. return true;
  26. });
  27. final SocketIOServer server = new SocketIOServer(config);
  28. return server;
  29. }
  30. @Bean
  31. public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
  32. return new SpringAnnotationScanner(socketServer);
  33. } }

读取配置文件的util类,用于读取yml文件中的配置

public class YmlUtil {

  1. /**
  2. * key:文件名索引
  3. * value:配置文件内容
  4. */
  5. private static Map<String, LinkedHashMap> ymls = new HashMap<>();
  6. /**
  7. * string:当前线程需要查询的文件名
  8. */
  9. private static ThreadLocal<String> nowFileName = new ThreadLocal<>();
  10. /**
  11. * 加载配置文件
  12. * @param fileName
  13. */
  14. public static void loadYml(String fileName) {
  15. nowFileName.set(fileName);
  16. if (!ymls.containsKey(fileName)) {
  17. ymls.put(fileName, new Yaml().loadAs(YmlUtil.class.getResourceAsStream("/" + fileName),

LinkedHashMap.class));
}
}

  1. public static Object getValueByKey(String key) throws Exception {
  2. // 首先将key进行拆分
  3. String[] keys = key.split("[.]");
  4. // 将配置文件进行复制
  5. Map ymlInfo = (Map) ymls.get(nowFileName.get()).clone();
  6. for (int i = 0; i < keys.length; i++) {
  7. Object value = ymlInfo.get(keys[i]);
  8. if (i < keys.length - 1) {
  9. ymlInfo = (Map) value;
  10. } else if (value == null) {
  11. throw new Exception("key不存在");
  12. } else {
  13. return value;
  14. }
  15. }
  16. throw new RuntimeException("不可能到这里的...");
  17. }
  18. public static Object getValue(String key) throws Exception {
  19. // 首先加载配置文件
  20. loadYml("application.yml");
  21. return getValueByKey(key);
  22. } }

socketIo启动类

@Component @Order(value=1) public class ServerRunner implements
CommandLineRunner {
private final SocketIOServer server;

  1. @Autowired
  2. public ServerRunner(SocketIOServer server) {
  3. this.server = server;
  4. }
  5. @Override
  6. public void run(String... args) throws Exception {
  7. server.start();
  8. System.out.println("socket.io启动成功!");
  9. } }

socketIo的前后端交互

@Component public class SocketIoServer {

  1. public static SocketIOServer socketIoServer;
  2. @Autowired
  3. public SocketIoServer(SocketIOServer server) {
  4. this.socketIoServer = server;
  5. }
  6. @OnConnect
  7. public void onConnect(SocketIOClient client) {
  8. // TODO Auto-generated method stub
  9. String sa = client.getRemoteAddress().toString();
  10. String clientIp = sa.substring(1, sa.indexOf(":"));// 获取设备ip
  11. System.out.println(clientIp + "-------------------------" + "客户端已连接");
  12. Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
  13. SocketIoServerMapUtil.put(clientIp, client);
  14. }
  15. @OnDisconnect
  16. public void onDisconnect(SocketIOClient client) {
  17. // TODO Auto-generated method stub
  18. String sa = client.getRemoteAddress().toString();
  19. String clientIp = sa.substring(1, sa.indexOf(":"));// 获取设备ip
  20. System.out.println(clientIp + "-------------------------" + "客户端已断开连接");
  21. SocketIoServerMapUtil.remove(clientIp);
  22. }
  23. @OnEvent(value = "text")
  24. public void onEvent(SocketIOClient client, AckRequest ackRequest, String data) {
  25. // TODO Auto-generated method stub
  26. // 客户端推送advert_info事件时,onData接受数据,这里是string类型的json数据,还可以为Byte[],object其他类型
  27. String sa = client.getRemoteAddress().toString();
  28. String clientIp = sa.substring(1, sa.indexOf(":"));// 获取客户端连接的ip
  29. Map<String, List<String>> params = client.getHandshakeData().getUrlParams();// 获取客户端url参数
  30. System.out.println(clientIp + ":客户端:************" + data);
  31. JSONObject gpsData = (JSONObject) JSONObject.parse(data);
  32. String userIds = gpsData.get("userName") + "";
  33. String taskIds = gpsData.get("password") + "";
  34. client.sendEvent("text1", "后台得到了数据");
  35. } }

存放前端连接的设备ip SocketIoServerMapUtil 类

public class SocketIoServerMapUtil {
public static ConcurrentMap webSocketMap = new ConcurrentHashMap<>();

  1. public static void put(String key, SocketIOClient SocketIOClient) {
  2. webSocketMap.put(key, SocketIOClient);
  3. }
  4. public static SocketIOClient get(String key) {
  5. return webSocketMap.get(key);
  6. }
  7. public static void remove(String key) {
  8. webSocketMap.remove(key);
  9. }
  10. public static Collection<SocketIOClient> getValues() {
  11. return webSocketMap.values();
  12. }
  13. public static ConcurrentMap<String, SocketIOClient> getWebSocketMap() {
  14. return webSocketMap;
  15. } }

前端代码,这里需要我们前端项目中引进socket.io.js这个类。我这边介绍vue引入socket:

npm install —save socket.io,不是vue环境的直接去下载一个js文件

Document

现在所有的代码已经都准备好了,开始讲解详细步骤了。

开始导入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中的配置。

#网络ip socketIo: 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);
});

本次分享到此结束。。。欢迎大家留言评论和互相交流。

发表评论

表情:
评论列表 (有 0 条评论,636人围观)

还没有评论,来说两句吧...

相关阅读

    相关 socketio 服务器

    如果面试官问你:要把服务器端的数据时时显示在浏览器上怎么实现?我想有很多人会回答使用Ajax技术定时去访问一个资源,没错,使用Ajax的确能实现,但面试官要的绝对不是这个答案。

    相关 socketio 服务器

    如果面试官问你:要把服务器端的数据时时显示在浏览器上怎么实现?我想有很多人会回答使用Ajax技术定时去访问一个资源,没错,使用Ajax的确能实现,但面试官要的绝对不是这个答案。