一、概述
本节主要讲解在SMB中如何进行websocket快速开发,实现客户端连接、关闭、消息通讯等功能。
示例下载:https://download.csdn.net/download/lllllllllluoyi/88949743
二、创建WebSocket服务器
1、在csdnProject工程中新建一个消息流。
添加WebSocket Server和四个Java计算节点组件,具体流程如图:
2、各组件说明
WebSocket1:websocket服务器组件,端口设置8100;
route:主要作用是路由。因为WebSocket1会产生open、close、onMessage动作,需要在这里进行逻辑分流,具体代码是:
java
package sashulin.apps;
import sashulin.Models.MessageModel;
import sashulin.applications.FlowApi;
import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.*;
public class csdn_websocketServer_route {
private String routeLabels = "";
public String execute(MessageModel messageModel,String message){
String eventName = messageModel.eventName;
switch(eventName){
case "open":
routeLabels = "openWebSocket";
break;
case "close":
routeLabels = "closeWebSocket";
break;
default:
routeLabels = "processWebSocket";
break;
}
return message;
}
public String getRouteLabels(){
return routeLabels;
}
}
openWebSocket:客户端连接服务器的处理逻辑。
java
package sashulin.apps;
import sashulin.Models.MessageModel;
import sashulin.applications.FlowApi;
import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.*;
import sashulin.websocket.SashulinWebSocket;
public class csdn_websocketServer_openWebSocket {
private String routeLabels = "";
public String execute(MessageModel messageModel,String message){
System.out.println("已连接webSocket服务器,参数信息:"+message);
//在内存中保存IP对应的websocket对象
SashulinWebSocket webSocket = (SashulinWebSocket)messageModel.object;
JSONObject msgJson = new JSONObject(message);
String ip = msgJson.getString("clientIP");
if (!webSocket.clients.containsKey(ip)){
webSocket.clients.put(ip, messageModel.object2);
}
return "ok";
}
public String getRouteLabels(){
return routeLabels;
}
}
closeWebSocket:客户端关闭的逻辑处理。
java
package sashulin.apps;
import sashulin.Models.MessageModel;
import sashulin.applications.FlowApi;
import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.*;
import sashulin.websocket.SashulinWebSocket;
public class csdn_websocketServer_closeWebSocket {
private String routeLabels = "";
public String execute(MessageModel messageModel,String message){
System.out.println("已断开与webSocket服务器的连接,参数信息:"+message);
SashulinWebSocket webSocket = (SashulinWebSocket)messageModel.object;
String ip = message;
if (webSocket.clients.containsKey(ip)){
webSocket.clients.remove(ip);
}
return "ok";
}
public String getRouteLabels(){
return routeLabels;
}
}
processWebSocket:消息收到后的处理逻辑。
java
package sashulin.apps;
import sashulin.Models.MessageModel;
import sashulin.applications.FlowApi;
import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.*;
public class csdn_websocketServer_processWebSocket {
private String routeLabels = "";
public String execute(MessageModel messageModel,String message){
System.out.println("收到消息:"+message);
return "ok";
}
public String getRouteLabels(){
return routeLabels;
}
}
三、JavaScript向websocket发送消息
通过JavaScript中向websocket服务器连接,发送消息、关闭动作。本例示使用HtmlVCL前端框架进行开发,也可以自己写测试界面代码。界面效果如图:
本示例中包含了两个文件:index.html和websocket.html。
index.html代码
javascript
<meta charset="utf-8">
<link rel="stylesheet" href="css/vcl.css">
<script type="text/javascript" src="js/vcl.js"></script>
<script type="text/javascript">
function main() {
var form = new HtmlForm(null);
form.align = "center";
form.color = "blue";
form.Refresh();
var popupMenu1 = new HtmlPopupMenu(form);
popupMenu1.items = [{id:1,text:"copy"},{id:2,text:"paste"},{id:-1,text:"-"},{id:3,text:"cut"}];
popupMenu1.onclick = function(obj,evt){
alert(obj.text);
alert(evt.id);
alert(evt.text);
}
var topPanel = new HtmlPanel(form);
topPanel.align = "top";
topPanel.alignment = "center";
topPanel.color = "#333";
topPanel.fontSize = 14;
topPanel.fontColor = "White";
topPanel.name="topPanel1";
//topPanel.text = "<h1>ChromeWebBrowser.net User Guide</h1>";
topPanel.Refresh();
var logoPanel = new HtmlPanel(topPanel);
logoPanel.align = "left";
logoPanel.width = 200;
logoPanel.Refresh();
var logoImg = new HtmlImage(logoPanel);
logoImg.imageUrl = "img/sashulin.png";
logoImg.left = 18;
logoImg.top = 15;
logoImg.width = 32;
logoImg.height = 32;
logoImg.Refresh();
var top_right_panel = new HtmlPanel(topPanel);
top_right_panel.align = "right";
top_right_panel.width = 200;
top_right_panel.Refresh();
var userImg = new HtmlImage(top_right_panel);
userImg.imageUrl = "img/p.png";
userImg.left = 10;
userImg.top = 20;
userImg.width = 20;
userImg.height = 20;
userImg.Refresh();
var userLabel = new HtmlLabel(top_right_panel);
userLabel.alignment = "left";
userLabel.left = 40;
userLabel.top = 23;
userLabel.width = "auto";
userLabel.height = 25;
userLabel.text = "Hi,Roy";
userLabel.fontColor = "white";
userLabel.fontSize = 14;
userLabel.Refresh();
var quitButton = new HtmlLinkButton(top_right_panel);
quitButton.top = 20;
quitButton.left = 120;
quitButton.width = "auto";
quitButton.height = 25;
quitButton.text = "退出";
quitButton.fontColor = "white";
quitButton.fontSize = 14;
quitButton.setUrl("index.html");
quitButton.Refresh();
var top_center_panel = new HtmlPanel(topPanel);
top_center_panel.align = "center";
top_center_panel.Refresh();
var popupMenu2 = new HtmlPopupMenu(form);
popupMenu2.items = [{id:1,text:"白血病"},{id:2,text:"肺炎"},{id:-1,text:"-"},{id:3,text:"流感"}];
popupMenu2.onclick = function(obj,evt){
alert(obj.text);
alert(evt.id);
alert(evt.text);
}
var titleLabel = new HtmlLabel(logoPanel);
titleLabel.alignment = "left";
titleLabel.left = 60;
titleLabel.top = 20;
titleLabel.width = 300;
titleLabel.height = 25;
titleLabel.text = "Sashulin Message Broker示例";
titleLabel.fontColor = "#00ffe2";
titleLabel.fontSize = 16;
titleLabel.Refresh();
var leftPanel = new HtmlPanel(form);
leftPanel.name = "leftPanel1";
leftPanel.align = "left";
leftPanel.color = "#e6e6e6";
leftPanel.width = "200";
leftPanel.Refresh();
var frame = new HtmlFrame(form);
frame.align = "center";
frame.color = "White";
// frame.setUrl("pages/method-EN.html");
frame.setUrl("pages/tabs.html");
frame.Refresh();
var bottomPanel = new HtmlPanel(form);
bottomPanel.align = "bottom";
bottomPanel.alignment = "center";
bottomPanel.color = "#000";
bottomPanel.height = 25;
bottomPanel.fontColor = "White";
bottomPanel.text = "@Author: Roy (173783000@qq.com)";
bottomPanel.Refresh();
var navBar = new HtmlNavBar(leftPanel);
navBar.name = "navBar1";
navBar.align = "center";
navBar.width = "200";
navBar.alignment = "center";
navBar.color = "#393D49";
navBar.items = [
{"title":"WebSocket","items":[{"id":"1","caption":"WebSocket","img":"img/p.png"}]}
];
navBar.onGroupItemClick = function(event){
//alert(event.control.id+":"+event.control.text);
var url = "";
switch(event.control.id){
case "1":
url = "pages/websocket.html";
break;
default:
url = "pages/method-EN.html";
break;
}
frame.setUrl(url);
}
navBar.Refresh();
}
</script>
websocket.html代码
javascript
<!DOCTYPE html>
<script type="text/javascript" src="../js/vcl.js"></script>
<script type="text/javascript">
function main() {
var websocket;
var form = new HtmlForm(null);
form.align = "center";
form.color = "#eee";
form.Refresh();
//第一排
var button1 = new HtmlButton(form);
button1.left = 380;
button1.top = 50;
button1.width = 100;
button1.height = 30;
button1.text = "连接"
button1.onclick = function () {
websocket = new WebSocket(edit1.text);
websocket.onerror = (event)=>{
label_status.setText("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = (event) => {
label_status.setText("已连接");
}
//接收到消息的回调方法
websocket.onmessage = (event) => {
edit_content.setText(event.data);
}
//连接关闭的回调方法
websocket.onclose = (event) => {
label_status.setText("已关闭");
}
}
button1.Refresh();
var closeButton = new HtmlButton(form);
closeButton.left = 500;
closeButton.top = 50;
closeButton.width = 100;
closeButton.height = 30;
closeButton.text = "关闭"
closeButton.onclick = function () {
websocket.close();
}
closeButton.Refresh();
var label_status = new HtmlLabel(form);
label_status.text = "--";
label_status.left = 100;
label_status.top = 20;
label_status.Refresh();
var label1 = new HtmlLabel(form);
label1.text = "服务器";
label1.left = 100;
label1.top = 50;
label1.Refresh();
var edit1 = new HtmlEdit(form);
edit1.text = "ws://127.0.0.1:8100";
edit1.left = 160;
edit1.top = 50;
edit1.width = 200;
edit1.Refresh();
//第二排
var button2 = new HtmlButton(form);
button2.left = 380;
button2.top = 100;
button2.width = 100;
button2.height = 30;
button2.text = "发送"
button2.onclick = function () {
}
button2.Refresh();
var label2 = new HtmlLabel(form);
label2.text = "发送内容";
label2.left = 100;
label2.top = 100;
label2.Refresh();
var edit2 = new HtmlEdit(form);
edit2.text = "测试消息";
edit2.left = 160;
edit2.top = 100;
edit2.width = 200;
edit2.Refresh();
var label3 = new HtmlLabel(form);
label3.text = "收到内容";
label3.left = 100;
label3.top = 150;
label3.Refresh();
var edit_content = new HtmlEdit(form);
edit_content.text = "";
edit_content.left = 160;
edit_content.top = 150;
edit_content.width = 200;
edit_content.Refresh();
}
</script>
运行的效果:
四、两个客户端通讯
在真实场景中是进行消息推送。我们在csdnProject工程进行以下先改:
1、增加一个api接口
这个消息流的逻辑是:开放一个api接口,用户调用接口后向服务器发送websocket消息。在action组件中进行对websocketClient组件的操控,代码如:
java
package sashulin.apps;
import sashulin.Models.MessageModel;
import sashulin.applications.FlowApi;
import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.*;
public class csdn_HttpFlow_action {
private String routeLabels = "";
public String execute(MessageModel messageModel,String message){
JSONObject json = new JSONObject(message);
String action = json.getString("action");
String text = json.getString("text");
switch(action){
case "send":
FlowApi.execute(this,"WebSocketClient1","send",message);
break;
case "close":
FlowApi.execute(this,"WebSocketClient1","close",text);
break;
}
return "ok";
}
public String getRouteLabels(){
return routeLabels;
}
}
FlowApi.execute(this,"WebSocketClient1","send",message); //执行websocketClient的Send操作。
FlowApi.execute(this,"WebSocketClient1","close",text); //执行websocketClient的Close操作。
2、修改processWebSocket组件代码
修改服务器的消息接收后的逻辑处理。即向指定的客户发送消息:
java
package sashulin.apps;
import sashulin.Models.MessageModel;
import sashulin.applications.FlowApi;
import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.*;
import sashulin.websocket.SashulinWebSocket;
import org.java_websocket.WebSocket;
public class csdn_websocketServer_processWebSocket {
private String routeLabels = "";
public String execute(MessageModel messageModel,String message){
System.out.println("收到消息:"+message);
JSONObject json = new JSONObject(message);
String destIP = json.getString("destIP");
String text = json.getString("text");
SashulinWebSocket webSocket = (SashulinWebSocket)messageModel.object;
if (webSocket.clients.containsKey(destIP)){
Object obj = webSocket.clients.get(destIP);
WebSocket conn = (WebSocket)obj;
conn.send(text);
}
return "ok";
}
public String getRouteLabels(){
return routeLabels;
}
}
3、测试消息发送
首先在SashulinMessageBroker示例中连接服务器;
然后再PostMan中发送消息:
SMB示例中收到来自于postman的消息:
结束语:应用于生产环境中会更复杂,但核心点还是在ProcessMessage组件这里,把消息推送何处?推送几次?这些可以做成策略。目前我们全院消息通讯平台也是按这个逻辑进行开发,在国内西南某大型儿童医院为例,进行了2000个客户端,20几个系统的消息对接和众多业务场景设计,稳定、准确运行。