webSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
本次介绍的是websocket客户端的编写,至于websocket服务端的编写可以看我之前写的websockt+redis实现动态订阅和取消订阅
的博客
<dependency>
<groupId>org.java-websocketgroupId>
<artifactId>Java-WebSocketartifactId>
<version>1.4.0version>
dependency>
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.net.URI;
import java.util.Map;
/**
* @Author Curtain
* @Date 2021/11/1 9:49
* @Description
*/
@Slf4j
public class BaseWebsocketClient extends WebSocketClient {
//客户端标识
private String clientName;
//客户端连接状态
private boolean isConnect = false;
//spring包下的线程池类
private ThreadPoolTaskExecutor workPoolScheduler;
public BaseWebsocketClient(URI serverUri, Map<String, String> httpHeaders,
String clientName,
ThreadPoolTaskExecutor workPoolScheduler) {
super(serverUri, new Draft_6455(), httpHeaders, 0);
this.clientName = clientName;
this.workPoolScheduler = workPoolScheduler;
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
}
@Override
public void onMessage(String s) {
}
/***检测到连接关闭之后,会更新连接状态以及尝试重新连接***/
@Override
public void onClose(int i, String s, boolean b) {
log.info("------ {} onClose ------{}", clientName, b);
setConnectState(false);
recontact();
}
/***检测到错误,更新连接状态***/
@Override
public void onError(Exception e) {
log.info("------ {} onError ------{}", clientName, e);
setConnectState(false);
}
public void setConnectState(boolean isConnect) {
this.isConnect = isConnect;
}
public boolean getConnectState(){
return this.isConnect;
}
public ThreadPoolTaskExecutor getWorkPoolScheduler() {
return workPoolScheduler;
}
/**
* 重连
*/
public void recontact() {
workPoolScheduler.execute(() -> {
Thread.currentThread().setName( "ReconnectThread-" + Thread.currentThread().getId() );
try {
Thread.sleep(10000);
log.info("重连开始");
if (isConnect) {
log.info("{} 重连停止", clientName);
return;
}
this.reconnect();
log.info("重连结束");
} catch (Exception e) {
log.info("{} 重连失败", clientName);
}
});
}
}
package com.supconit.ctrl.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author Curtain
* @date 2021/11/1
*/
@Configuration
public class WorkPoolConfig {
@Value("${settings.work-pool.core-pool-size}")
private Integer workPoolCoreSize;
@Value("${settings.work-pool.max-pool-size}")
private Integer workPoolMaxSize;
@Value("${settings.work-pool.queue-capacity}")
private Integer queueCapacity;
@Bean("workPoolScheduler")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(workPoolCoreSize);
executor.setMaxPoolSize(workPoolMaxSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("-device-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
return executor;
}
}
这里我编写了一个收集用户信息的websocket客户端。
package com.supconit.ctrl.client.wsclient;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.supconit.ctrl.service.crossmodule.DeviceService;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.net.URI;
import java.util.Map;
/**
* @Author Curtain
* @Date 2021/12/3 16:51
* @Description
*/
@Slf4j
public class DeviceWebsocketClient extends BaseWebsocketClient{
private static final String ACS_CTRL_RESULT = "deviceWebsocketClient";
private static final String SUBSCRIBE = "subscribe";
private DeviceService deviceService;
/*这个订阅格式是实现约定好的,可以具体情况具体分析*/
private String sendStr = "{\n" +
" \"method\": \"subscribe\",\n" +
" \"params\": \"device\"\n" +
"}";
public DeviceWebsocketClient(URI serverUri, Map<String, String> httpHeaders, ThreadPoolTaskExecutor workPoolScheduler, DeviceService deviceService) {
super(serverUri, httpHeaders, ACS_CTRL_RESULT, workPoolScheduler);
this.deviceService = deviceService;
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
log.info("------ {} onOpen ------", ACS_CTRL_RESULT);
this.send(sendStr);
setConnectState(true);
}
@Override
public void onMessage(String msg) {
log.info("-------- receive acs ctrl result: " + msg + "--------");
Device device = new ObjectMapper().readValue(msg, Device.class);
deviceService.insertOne(device);
}
}
package com.supconit.ctrl.service.web.impl;
import com.supconit.ctrl.client.wsclient.DeviceWebsocketClient;
import com.supconit.ctrl.service.crossmodule.DeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
/**
* @Author Curtain
* @Date 2021/12/3 17:04
* @Description
*/
@Service
@Slf4j
public class DeviceWebsocketClientService {
@Resource
private DeviceService deviceService;
@Resource
private ThreadPoolTaskExecutor workPoolScheduler;
@PostConstruct
public void start() {
try {
log.info("start to receive device data");
URI uri = new URI("填ws的地址");
Map<String, String> httpHeaders = new HashMap<>(4);
httpHeaders.put("Origin", "http://" + uri.getHost());
DeviceWebsocketClient deviceWebsocketClient = new DeviceWebsocketClient(uri, httpHeaders, workPoolScheduler, deviceService);
deviceWebsocketClient.connect();
}catch (Exception e){
log.error("start to receive device data failed", e);
}
}
}
到此,一个简单的收集websocket服务端推送过来的设备信息数据的websocket客户端就已经实现啦~