java版客户端:

使用开源项目java-websocket, github地址: https://github.com/TooTallNate/Java-WebSocket

github上有很多示例,具体可以去查看

此处主要是记录java-websocket实现客户端,并解决无法使用Service层方法(service为null)的问题,以及断线重连

引用包

<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.9</version>
</dependency>

第一版,使用getBean获取Service层方法,并且实现断线重连

使用的是GitHub上的demo示例

import com.alibaba.fastjson.JSONArray;import com.sensor.vibration.utils.ApplicationContextRegister;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import java.net.URI;
import java.util.Map; /** This example demonstrates how to create a websocket connection to a server. Only the most important callbacks are overloaded. */ @Slf4j
public class SensorWebSocketClient extends WebSocketClient {
@Autowired
private UserService userService; public SensorWebSocketClient(URI serverUri , Draft draft ) {
super( serverUri, draft );
} public SensorWebSocketClient(URI serverURI ) {
super( serverURI );
} public SensorWebSocketClient(URI serverUri, Map<String, String> httpHeaders ) {
super(serverUri, httpHeaders);
} @Override
public void onOpen( ServerHandshake handshakedata ) {
System.out.println( "opened connection" );
// if you plan to refuse connection based on ip or httpfields overload: onWebsocketHandshakeReceivedAsClient
} @Override
public void onMessage( String msg ) {
log.info("[websocket] 收到消息={}",msg);
} @Override
public void onClose( int code, String reason, boolean remote ) {
// The codecodes are documented in class org.java_websocket.framing.CloseFrame
System.out.println( "Connection closed by " + ( remote ? "remote peer" : "us" ) + " Code: " + code + " Reason: " + reason );
} @Override
public void onError( Exception ex ) {
ex.printStackTrace();
// if the error is fatal then onClose will be called additionally
} }

新建一个类,创建一个方法,启动websocket

import java.net.URI;
import java.net.URISyntaxException; /**
* Simple example to reconnect blocking and non-blocking.
*/ public class ReconnectClient {
public static void reconnect() throws URISyntaxException, InterruptedException{
SensorWebSocketClient c = new SensorWebSocketClient( new URI( "ws://localhost:5005/websocket" ) );
c.connectBlocking(); new Thread(new Runnable() {
public void run() {
System.out.println("Runnable running..");
}
}) {
public void run() {
while (true){
try{
Thread.sleep(3000);
c.send("");
}catch (Exception e){
c.reconnect();
}
}
};
}.start();
}
}

在新建一个类,程序启动的时候,调用上面的方法

import com.sensor.vibration.utils.Common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component; import javax.annotation.Resource;
import java.net.URISyntaxException;
import java.util.Map; @Slf4j
@Component
public class InitStart implements CommandLineRunner { @Override
public void run(String... args) throws URISyntaxException, InterruptedException{
ReconnectClient.reconnect();
} }

中间的启动类的方法可以省去,直接写在InitStart的run方法里面

现在还不能使用Service层的方法,会报service为null异常,百度后,参考别人使用getBean方法,写一个工具类

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; @Component
@Lazy(false)
public class ApplicationContextRegister implements ApplicationContextAware {
private static ApplicationContext APPLICATION_CONTEXT; /**
* 设置spring上下文 * * @param applicationContext spring上下文 * @throws BeansException
*/ @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
APPLICATION_CONTEXT = applicationContext;
} public static ApplicationContext getApplicationContext() {
return APPLICATION_CONTEXT;
} }

在 SensorWebSocketClient.java 中使用Service

@Autowired
private UserService userService; ApplicationContext act = ApplicationContextRegister.getApplicationContext();
userService=act.getBean(UserService.class);

但是 领导不让用getBean这种方法,放弃

第二版,使用Service层方法版本 + 断线重连

实现:

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import java.net.URI; /**
* Created by Chow on 2019/8/22
*/ @Slf4j
@Component
public class WebSocketClientStart {
@Autowired
private UserService userService; @Bean
public WebSocketClient webSocketClient() {
try {
WebSocketClient webSocketClient = new WebSocketClient(new URI("ws://127.0.0.1:5005/websocket")) {
@Override
public void onOpen(ServerHandshake handshakedata) {
log.info("[websocket] 连接成功");
} @Override
public void onMessage(String msg) {
try{
log.info("[websocket] 收到消息={}",msg); if (msg == null || StringUtils.isBlank(msg)){
log.error("the msg message of websocket received is null");
this.send("");
return;
}
JSONArray jsonArray = JSONArray.parseArray(msg);
if (jsonArray == null || jsonArray.size() == 0){
log.info("log: the message of websocket received is empty");
} vibrationAlarmService.alarmAnalysis(jsonArray);
this.send("");
}catch (Exception e){
log.error(e.getMessage(), e);
this.send("");
} } @Override
public void onClose(int code, String reason, boolean remote) {
log.info("[websocket] 退出连接");
} @Override
public void onError(Exception ex) {
log.info("[websocket] 连接错误={}",ex.getMessage());
}
};
webSocketClient.connect();
new Thread(new Runnable() { public void run() {
System.out.println("Runnable running..");
} }) { public void run() {
while (true){
try{
Thread.sleep(3000);
webSocketClient.send("");
}catch (Exception e){
webSocketClient.reconnect();
}
} } }.start();
return webSocketClient;
} catch (Exception e) {
e.printStackTrace();
}
return null;
} }

测试服务端代码

需要引入包

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>

server:

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint; import org.springframework.stereotype.Component; @ServerEndpoint(value = "/websocket")
@Component
public class MyWebSocket {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session; /**
* 连接建立成功调用的方法*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
try {
sendMessage("当前在线人数为" + getOnlineCount());
} catch (IOException e) {
System.out.println("IO异常");
}
} /**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
} /**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("来自客户端的消息:" + message); //群发消息
for (MyWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
} @OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
} public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
} /**
* 群发自定义消息
* */
public static void sendInfo(String message) throws IOException {
for (MyWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
} public static synchronized int getOnlineCount() {
return onlineCount;
} public static synchronized void addOnlineCount() {
MyWebSocket.onlineCount++;
} public static synchronized void subOnlineCount() {
MyWebSocket.onlineCount--;
}
}

java-websocket客户端 断线重连 注入Service问题的更多相关文章

  1. 基于TCP通信的客户端断线重连

    转载:http://www.cnblogs.com/networkcomms/p/4304362.html 源码下载 在CS程序中,断线重连应该是一个常见的功能. 此处的断线重连主要指的是服务器端因为 ...

  2. SignalR控制台自托管服务端向web客户端指定用户推送数据,客户端断线重连

    一.前言 SignalR是微软推出的开源实时通信框架.其内部使用Web Socket, Server Sent Events 和 Long Polling作为底层传输方式,SignalR会根据客户端和 ...

  3. Netty 客户端断线重连

    client 关闭后会执行 finally 代码块,可以在这里可以进行重连操作 public class NettyClient implements Runnable { private final ...

  4. 关于socket tcp 断线重连

    这个问题困扰过我几次,都没有来得及研究,今天研究一下. 首先写一个最简易的socket tcp程序,连接成功后再关闭服务器然后再用客户端各种操作看是什么情况 测试表明 (1)客户端已经连接,当服务端关 ...

  5. Netty(六):Netty中的连接管理(心跳机制和定时断线重连)

    何为心跳 顾名思义, 所谓心跳, 即在TCP长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性. 为什么需要心跳 因为网络的不可靠性, 有可 ...

  6. Spring Boot Service注入为null mapper注入为null @Component注解下@Value获取不到值 WebsocketServer类里无法注入service

    最近搞了一下websocket前台(这个网上有很多的教程这里就不班门弄斧啦) 以及前后台的交互 和后台的bug(搞了两天) 也是状态频发 bug不断 下面说一说问题. Websocket主类里面无法注 ...

  7. 如何在Java Filter 中注入 Service

    在项目中遇到一个问题,在 Filter中注入 Serivce失败,注入的service始终为null.如下所示: public class WeiXinFilter implements Filter ...

  8. 如何在Java的Filter中注入Service???

    今天在做用户使用cookie自动登录的时候,发现在LoginFilter中读取到cookie以后要进行查询数据库然后进行用户名和密码的比对,查询数据库肯定要用到Service和Dao,一开始我以为在s ...

  9. webSocket使用心跳包实现断线重连

    首先new一个webscoket的连接 let noticeSocketLink = new WebSocket(‘webSocket的地址’) 这里是连接成功之后的操作 linkNoticeWebs ...

随机推荐

  1. EnvironmentError: mysql_config not found

    Collecting MySQL-python==1.2.5 (from -r requirementsNoGit.txt (line 9)) Using cached https://files.p ...

  2. 对pdf中的图片进行自动识别

    对pdf中的图片进行自动识别 商务合作,科技咨询,版权转让:向日葵,135—4855__4328,xiexiaokui#qq.com 原理:增强扫描 效果:自动识别所有图片中的文字,可以选择.复制,进 ...

  3. 027 H5常用标签

    只记录一下比较有趣的知识点. 一:新标签 1.选项列表datalist <!DOCTYPE html> <html lang="en"> <head& ...

  4. springboot+jwt完成登录认证

    本demo用于测试jwt,通过登录验证通过后,使用jwt生成token,然后在请求header中携带token完成访问用户列表信息. 准备工作: 1. 实体类SysUser.java package ...

  5. nginx: [warn] conflicting server name "aaa.bbbb.com" on 0.0.0.0:80, ignored

    date: 2019-08-12  16:52:44 author: headsen chen notice :个人原创 故障现象: openresty -t nginx: [warn] confli ...

  6. 使用cmi工具连接服务器远程装机exsi

    使用cmi工具连接服务器远程装机exsi 网宿机房有两台服务器磁盘坏掉了,后面换了磁盘需要重新初始化系统 访问:http://192.168.48.133/cgi/url_redirect.cgi?u ...

  7. 1264 - Out of range value for column

    现象:新建数据库,字段类型是tinyint,然后插入数据,数值为128,报标题错误 原因:如果在新建数据库的时候没有指定为unsigned,那么就是有符号的,所以tinyint的范围是-128~127 ...

  8. mybatis 存储过程与游标的使用

    MyBatis还能对存储过程进行完全支持,这节开始学习存储过程.在讲解之前,我们需要对存储过程有一个基本的认识,首先存储过程是数据库的一个概念,它是数据库预先编译好,放在数据库内存中的一个程序片段,所 ...

  9. LeetCode_344. Reverse String

    344. Reverse String Easy Write a function that reverses a string. The input string is given as an ar ...

  10. [ kvm ] 学习笔记 1:Linux 操作系统及虚拟化

    1. 前言 一台计算机是由一堆硬件设备组合而成,在硬件之上是操作系统,操作系统与计算机硬件密不可分,操作系统用来管理所有的硬件资源提供服务,各个硬件设备是通过 总线 进行连接起来的: 在操作系统之上, ...