一 配置集成
1.集成相关的jar
<dependency>
<groupId>org.yeauty</groupId>
<artifactId>netty-websocket-spring-boot-starter</artifactId>
<version>0.9.5</version>
</dependency>
<!-- consul 注册组件 -->
<dependency>
<groupId>com.ecwid.consul</groupId>
<artifactId>consul-api</artifactId>
</dependency>
netty-websocket-spring-boot-starter
这是个开源的框架。通过它,我们可以像spring-boot-starter-websocket一样使用注解进行开发,只需关注需要的事件(如OnMessage)。并且底层是使用Netty,当需要调参的时候只需要修改配置参数即可,无需过多的关心handler的设置。
2.配置webSocket
new一个ServerEndpointExporter对象,交给Spring容器,表示要开启WebSocket功能:
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
在端点类上加上@ServerEndpoint、@Component注解,并在相应的方法上加上@OnOpen、@OnClose、@OnError、@OnMessage注解(不想关注某个事件可不添加对应的注解):
@ServerEndpoint(path = "/ws/lchl/demo/{arg}",host ="${xxxpriv.websocket.host}", port = "${xxxpriv.websocket.port}")
public class WebSocketDemo {
/** 记录当前在线连接数 */
private static AtomicInteger onlineCount = new AtomicInteger(0);
private Session session;
private String id;
private static ConcurrentHashMap<String, WebSocketDemo> webSocketSet = new ConcurrentHashMap<String, WebSocketDemo>();
@SneakyThrows
@OnOpen
public void onOpen(Session session, HttpHeaders headers, @RequestParam MultiValueMap reqMap,
@RequestParam String orgnCode, @RequestParam String orgnName,
@RequestParam String userCode, @RequestParam String userName,
@RequestParam String token,
@PathVariable Map pathMap,@PathVariable(value = "arg") String id) throws IOException {
this.session = session;
this.id = id;//接收到发送消息的人员编号
ResponseMessage result = new ResponseMessage();
result.setMessage("连接成功");
result.setCode("success");
result.setMessage("{'connect':'true'}");
this.sendMessage(JSONObject.toJSONString(result));
for (int i = 0; i < 3; i++) {
ResponseMessage result1 = new ResponseMessage();
result.setMessage("处理进度为"+i+1+"/3;当前处理病人为王五\n" +
"处理失败医嘱\n" +
"[张三 葡萄糖注射液0.1% 库存量不足,执行失败!,\n" +
"张三 氯化钠注射液0.1% 未做皮试,执行失败!]\n" +
"[李三 氯化钠注射液0.1% 库存量不足,执行失败!]");
Thread.sleep(3000);
this.sendMessage(JSONObject.toJSONString(result));
}
}
@OnClose
public void onClose(Session session) throws IOException {
System.out.println("one connection closed");
}
@OnError
public void onError(Session session, Throwable throwable) {
throwable.printStackTrace();
}
@OnMessage
public void onMessage(Session session, String message) throws IOException {
ResponseMessage result = new ResponseMessage();
result.setMessage("XXXXXXXXXX");
this.sendMessage(JSONObject.toJSONString(result));
}
@OnBinary
public void onBinary(Session session, byte[] bytes) {
for (byte b : bytes) {
System.out.println(b);
}
// session.sendBinary(bytes);
}
@OnEvent
public void onEvent(Session session, Object evt) {
if (evt instanceof IdleStateEvent) {
IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
switch (idleStateEvent.state()) {
case READER_IDLE:
System.out.println("read idle");
break;
case WRITER_IDLE:
System.out.println("write idle");
break;
case ALL_IDLE:
System.out.println("all idle");
break;
default:
break;
}
}
}
public void sendMessage(String message) throws IOException {
this.session.sendText(message);
}
}
3.springboot2 集成webSocket+consul
xxxpri:
host: 172.16.0.121 #应用ip
server:
port: 10050
servlet:
context-path: /websocket #websocket
application:
name: websocket-application
websocket:
name: websocket-server #websocket程序名称 注册中心使用
host: ${spring.cloud.client.ip-address} #websocket ip 地址
port: 10051
path: /ws
consul:
host: ${xxxpri.consul.host}
port: ${xxxpri.consul.port}
name: ${xxxpri.websocket.name}
instance: ${xxxpri.websocket.name}-${xxxpri.websocket.host}-${xxxpri.websocket.port}
healthCheckPath: ${server.servlet.context-path}/actuator/health
4.将websocket-server注册服务到Consul
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(LchlApplication.class, args);
//注册netty - websocket 服务到consul
regWebSocketConsul(context);
// SpringApplication.run(LchlApplication.class, args);
LOG.info("application started!");
}
/**
* websocket-server注册服务到Consul
* @param context
*/
private static void regWebSocketConsul(ConfigurableApplicationContext context) {
//consul 注册中心地址
String consulEnable = context.getEnvironment().getProperty("xxxpri.consul.enabled");
if (("true").equals(consulEnable.toLowerCase())){
String consulAddress = context.getEnvironment().getProperty("xxxpri.websocket.consul.host") + ":" + context.getEnvironment().getProperty("xxxpri.websocket.consul.port");
String websocketServerName = context.getEnvironment().getProperty("xxxpri.websocket.name");
String websocketServerHost = context.getEnvironment().getProperty("xxxpri.websocket.host");
String websocketServerPort = context.getEnvironment().getProperty("xxxpri.websocket.port");
String websocketServerPath = context.getEnvironment().getProperty("xxxpri.websocket.path");
String consulInstanceId = context.getEnvironment().getProperty("xxxpri.websocket.consul.instance");
String springBootServerPort = context.getEnvironment().getProperty("xxxpri.server.port");
String springBootServerContentPath = context.getEnvironment().getProperty("xxxpri.server.servlet.context-path");
String checkUrl = "http://" + websocketServerHost + ":" + springBootServerPort
+ springBootServerContentPath+"/actuator/health";
ConsulClient client = new ConsulClient(consulAddress);
NewService newService = new NewService();
newService.setId(consulInstanceId);
List<String> tagList = new ArrayList<>();
tagList.add("secure=false");
tagList.add("contextPath=" + websocketServerPath);
newService.setTags(tagList);
newService.setName(websocketServerName);
newService.setAddress(websocketServerHost);
newService.setPort(Integer.valueOf(websocketServerPort));
//服务检测,使用 spring-boot 项目
NewService.Check serviceCheck = new NewService.Check();
serviceCheck.setHttp(checkUrl);
serviceCheck.setInterval("10s");
newService.setCheck(serviceCheck);
client.agentServiceRegister(newService);
}
}
在consul上注册成功后会显示Web-Socket的注册服务名称
二 webSocket 在线测试工具
http://ws.douqq.com/
http://www.jsons.cn/websocket/
三 注意问题
Websocker注入Bean问题
https://blog.csdn.net/moshowgame/article/details/83415545
WebSocket注入@Bean@Autowired
在WebSocket也是这样注入,因 SpringBoot+WebSocket 对每个客户端连接都会创建一个 WebSocketServer(@ServerEndpoint 注解对应的) 对象,Bean 注入操作会被直接略过,因而手动注入一个全局变量
因而一般通过
SpringUtils.getBean
根据上下文获取beanConfigurableListableBeanFactory.getBean(),可以有两种参数类型:
传入String格式的类名
传入类.Class的类
动态调用spring容器中的bean 实现数据库的操作