当前位置: 首页 > news >正文

java websocket学习

引言:

  websocket,webservice傻傻分不清楚,都觉得是很高深的东西,理解中的webservice是一种协议,通信协议,类似http协议的那种,比如使用webservice协议调后台接口,而websocket呢?与socket挂钩?长连接?对未知的东西总是恐惧的,所以默默不敢说话

启航:

  学习过程中突然接触到了websocket的简单讲解,哦,websocket也是一种协议,它类似ajax,但连接不中断,接到消息就响应。叫什么双端通信。websocket请求头是ws://或者wss://开头,非安全与安全,后面就和http请求类似。后台写法当然与默认的http servlet有些不同,但变化不大,与springMVC的requestMapping有些相似,接受到请求可以进行拦截等处理,当然也可以限制接收请求的具体参数。

 

概念来一波:

  

  

  

原先实现模拟双端通信的手段:  

在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)Comet技术。其实后者本质上也是一种轮询,只不过有所改进。

  轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。

  Comet技术又可以分为长轮询流技术长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。

  这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。

特点:

  1、双端通信

  2、建立在TCP之上

  3、协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

 

接入:

  注意:JavaEE 7中出了JSR-356:Java API for WebSocket规范。不少Web容器,如Tomcat,Nginx,Jetty等都支持WebSocket。Tomcat从7.0.27开始支持 WebSocket,从7.0.47开始支持JSR-356

websocket客户端:

  在客户端,没有必要为 WebSockets 使用 JavaScript 库。实现 WebSockets 的 Web 浏览器将通过 WebSockets 对象公开所有必需的客户端功能(主要指支持 Html5 的浏览器)。

客户端API:  

  以下 API 用于创建 WebSocket 对象。

  var Socket = new WebSocket(url, [protocol] );

  以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。

  WebSocket 属性

  以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:

属性描述
Socket.readyState只读属性 readyState 表示连接状态,可以是以下值:0 - 表示连接尚未建立。1 - 表示连接已建立,可以进行通信。2 - 表示连接正在进行关闭。3 - 表示连接已经关闭或者连接不能打开。
Socket.bufferedAmount只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

  WebSocket 事件

  以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:

事件事件处理程序描述
openSocket.onopen连接建立时触发
messageSocket.onmessage客户端接收服务端数据时触发
errorSocket.onerror通信发生错误时触发
closeSocket.onclose连接关闭时触发

  WebSocket 方法

  以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:

方法描述
Socket.send()使用连接发送数据
Socket.close()关闭连接

    客户端实例:   

<%--
  Created by IntelliJ IDEA.
  User: zhen
  Date: 2018/12/10
  Time: 17:36
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>welcome page</title>
</head>
<body>
    welcome to ssm all annotation project!

    <input id="text" type="text"/>
    <button οnclick="send()">发送消息</button>
    <hr/>
    <button οnclick="closeWebSocket()">关闭webSocket连接</button>
    <hr/>
    <div id="message"></div>
    </body>

    <script type="text/javascript">
        var webSocket = null;
        //判断当前浏览器是否支持webSocket
        if ('WebSocket' in window) {
            webSocket = new WebSocket("ws://localhost:8080/spring4webSocket/myHandler")
        } else {
            alert("当前浏览器 Not support webSocket");
        }

        webSocket.onerror = onError;
        webSocket.onopen = onOpen;
        webSocket.onmessage = onMessage;
        webSocket.onclose = onClose;

        function onError() {
            setMessageInnerHTML("WebSocket连接发生错误");
        }

        function onOpen() {
            setMessageInnerHTML("WebSocket连接成功");
        }

        function onMessage(event){
            //将接受到的数据直接输出
            setMessageInnerHTML(event.data);
        }

        function onClose() {
            setMessageInnerHTML("webSocket连接关闭");
        }

        function setMessageInnerHTML(message) {
            var messageDiv = document.getElementById("message");
            messageDiv.innerHTML = messageDiv.innerHTML + "<br/>" + message;
        }

        //监听串口关闭事件,当窗口关闭时,主动去关闭webSocket连接,防止还没断开就关闭窗口,srever端会抛异常
        window.onbeforeunload = function (ev) {
            closeWebSocket();
        }

        function closeWebSocket(){
            webSocket.close();
        }


        //发送消息
        function send() {
            var message = document.getElementById("text").value;
            webSocket.send(message);
        }

    </script>
</html>
客户端实例

 

服务端(java):

  基于servlet api:

    1、导入有关jar包     

        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>

  API:

    @ServerEnpoint 声明webSocket服务端,指明映射url

    @OnMessage 标注接收到消息执行监听方法

    @OnOpen 标注打开连接时候执行监听方法

    @OnClose 标注关闭连接时执行监听方法

    @OnError 标注连接异常时执行监听方法

  服务端实例:

package com.zhen.websocket;

/**
 * @author zhen
 * @Date 2018/12/6 10:29
 */

import java.io.*;
import java.util.*;
import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;

 // @ServerEndpoint 注解允许你声明一个WeoSocket,定义url映射,定义编码和解码
@ServerEndpoint(
    value="/story/notifications",
    encoders={StickerEncoder.class},
    decoders={StickerDecoder.class}
   )
public class StoryWebSocket {


    private static final List<Sticker> stickers = Collections.synchronizedList(new LinkedList<Sticker>());
    private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());

     @OnMessage
     public void onMessage(Session session, Sticker sticker){
         // 有消息从客户端发送过来,保存到列表中,然后通知所有的客户端
         stickers.add(sticker);
         for(Session openSession : sessions){
             try {
                 openSession.getBasicRemote().sendObject(sticker);
             } catch (IOException | EncodeException e) {
                 sessions.remove(openSession);
             }
         }
     }

     @OnOpen
     public void onOpen(Session session) throws IOException, EncodeException{
         // 有新的客户端连接时,保存此客户端的session,并且把当前所有的sticker发送给它
         sessions.add(session);
         for(Sticker sticker : stickers){
             session.getBasicRemote().sendObject(sticker);
         }
     }

     @OnClose
     public void onClose(Session session){
         // 有客户端断开连接时 ,从session列表中移除此客户端的session
         sessions.remove(session);
     }


}
服务端实例

看的有些混乱不能很好理解的时候就敲一些例子,功能出来就更容易理解了。

  

跟着下面两篇教程的案例

  • Using WebSocket for Real-Time Communication in Java Platform, Enterpise Edition 7
  • Java EE 7: Building Web Applications with WebSocket, JavaScript and HTML5
package com.zhen.websocket;

/**
 * @author zhen
 * @Date 2018/12/6 10:28
 */
public class Sticker {

    private int x;
    private int y;
    private String image;

    public Sticker() {
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }
}

package com.zhen.websocket;

import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.spi.JsonProvider;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import java.io.IOException;
import java.io.Reader;


/**
 * @author zhen
 * @Date 2018/12/6 11:08
 * 用来读取webSocket流中的数据使用Decode.TextStream接口。 这个接口允许你读取数据从socket中通过JsonReader对象,构造传入Reader对象,并且转换客户端返回文本JSON数据
 */
public class StickerDecoder implements Decoder.TextStream<Sticker>{

    // Do not create a JsonReader object. To create readers and writes, use the
    // JsonProvider class.

    @Override
    public void init(EndpointConfig config) {
        // TODO Auto-generated method stub
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

    @Override
    public Sticker decode(Reader reader) throws DecodeException, IOException {
        JsonProvider provider = JsonProvider.provider();
        JsonReader jsonReader = provider.createReader(reader);
        JsonObject jsonSticker = jsonReader.readObject();

        Sticker sticker = new Sticker();
        sticker.setX(jsonSticker.getInt("x"));
        sticker.setY(jsonSticker.getInt("y"));
        sticker.setImage(jsonSticker.getString("sticker"));
        return sticker;
    }

}

package com.zhen.websocket;

import javax.json.JsonObject;
import javax.json.JsonWriter;
import javax.json.spi.JsonProvider;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import java.io.IOException;
import java.io.Writer;

/**
 * @author zhen
 * @Date 2018/12/6 10:59
 * 这个类编码Sticker对象并且传递给WebSocket服务器通过写入流中
 */
public class StickerEncoder implements Encoder.TextStream<Sticker> {

    @Override
    public void init(EndpointConfig config) {
        // TODO Auto-generated method stub
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

    @Override
    public void encode(Sticker sticker, Writer writer) throws EncodeException, IOException {
        JsonProvider provider = JsonProvider.provider();
        JsonObject jsonSticker = provider.createObjectBuilder()
            .add("action", "add")
            .add("x", sticker.getX())
            .add("y", sticker.getY())
            .add("sticker", sticker.getImage())
            .build();
        JsonWriter jsonWriter = provider.createWriter(writer);
        jsonWriter.write(jsonSticker);
    }

}

package com.zhen.websocket;

/**
 * @author zhen
 * @Date 2018/12/6 10:29
 */

import java.io.*;
import java.util.*;
import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;

 // @ServerEndpoint 注解允许你声明一个WeoSocket,定义url映射,定义编码和解码
@ServerEndpoint(
    value="/story/notifications",
    encoders={StickerEncoder.class},
    decoders={StickerDecoder.class}
   )
public class StoryWebSocket {


    private static final List<Sticker> stickers = Collections.synchronizedList(new LinkedList<Sticker>());
    private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());

     @OnMessage
     public void onMessage(Session session, Sticker sticker){
         // 有消息从客户端发送过来,保存到列表中,然后通知所有的客户端
         stickers.add(sticker);
         for(Session openSession : sessions){
             try {
                 openSession.getBasicRemote().sendObject(sticker);
             } catch (IOException | EncodeException e) {
                 sessions.remove(openSession);
             }
         }
     }

     @OnOpen
     public void onOpen(Session session) throws IOException, EncodeException{
         // 有新的客户端连接时,保存此客户端的session,并且把当前所有的sticker发送给它
         sessions.add(session);
         for(Sticker sticker : stickers){
             session.getBasicRemote().sendObject(sticker);
         }
     }

     @OnClose
     public void onClose(Session session){
         // 有客户端断开连接时 ,从session列表中移除此客户端的session
         sessions.remove(session);
     }


}




var socket = null;
function initialize() {
    var canvas = document.getElementById("board");
    var ctx = canvas.getContext("2d");
    var img = document.getElementById("background_img");
    ctx.drawImage(img, 0, 0);
    socket = new WebSocket("ws://localhost:8080/stickStory/story/notifications");
    socket.onmessage = onSocketMessage;
}

function drag(ev) {
    var bounds = ev.target.getBoundingClientRect();
    var draggedSticker = {
        sticker: ev.target.getAttribute("data-sticker"),
        offsetX: ev.clientX - bounds.left,
        offsetY: ev.clientY - bounds.top
    };
    var draggedText = JSON.stringify(draggedSticker);
    ev.dataTransfer.setData("text", draggedText);
}

function drop(ev) {
    ev.preventDefault();
    var bounds = document.getElementById("board").getBoundingClientRect();
    var draggedText = ev.dataTransfer.getData("text");
    var draggedSticker = JSON.parse(draggedText);
    var stickerToSend = {
        action: "add",
        x: ev.clientX - draggedSticker.offsetX - bounds.left,
        y: ev.clientY - draggedSticker.offsetY - bounds.top,
        sticker: draggedSticker.sticker
    };
    socket.send(JSON.stringify(stickerToSend));
    log("Sending Object " + JSON.stringify(stickerToSend));
}

function allowDrop(ev) {
    ev.preventDefault();
}

function onSocketMessage(event) {
    if (event.data) {
        var receivedSticker = JSON.parse(event.data);
        log("Received Object: " + JSON.stringify(receivedSticker));
        if (receivedSticker.action === "add") {
            var imageObj = new Image();
            imageObj.onload = function() {
                var canvas = document.getElementById("board");
                var context = canvas.getContext("2d");
                context.drawImage(imageObj, receivedSticker.x, receivedSticker.y);
            };
            imageObj.src = "resources/stickers/" + receivedSticker.sticker;
        }
    }
}

function toggleLog() {
    var log = document.getElementById("logContainer");
    if (!log.getAttribute("style")) {
        log.setAttribute("style", "display:block;");
    } else {
        log.setAttribute("style", "");
    }
}

var logCount = 0;
function log(logstr) {
    var logElement = document.getElementById("log");
    logElement.innerHTML = "<b>[" + logCount + "]: </b>" + logstr + "<br>" + logElement.innerHTML;
    logCount++;
}

window.onload = initialize;


<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html>
<head>
    <title>Sticker Story</title>
    <link href="resources/styles.css" rel="stylesheet" type="text/css" >
    <script src="resources/story-page.js" type="text/javascript"></script>
</head>
<body>
<header>
    <h1>Sticker Story Book</h1>
</header>
<nav>
    Drag stickers from the left bar to the canvas.
</nav>
<aside>
    <h2>Stickers</h2>
    <div id="stickerContainer">
        <img src="resources/stickers/bear.png"
             data-sticker="bear.png"
             style="float:left"
             draggable="true" οndragstart="drag(event);" >
        <img src="resources/stickers/chicken.png"
             data-sticker="chicken.png"
             style="float:left"
             draggable="true" οndragstart="drag(event);" >
        <img src="resources/stickers/leopard.png"
             data-sticker="leopard.png"
             style="float:left"
             draggable="true" οndragstart="drag(event);" >
        <img src="resources/stickers/monkey.png"
             data-sticker="monkey.png"
             style="float:left"
             draggable="true" οndragstart="drag(event);" >
        <img src="resources/stickers/horse.png"
             data-sticker="horse.png"
             style="float:left"
             draggable="true" οndragstart="drag(event);" >
        <img src="resources/stickers/tiger.png"
             data-sticker="tiger.png"
             style="float:left"
             draggable="true" οndragstart="drag(event);" >
    </div>
</aside>
<div id="content">
    <canvas id="board" width="1000" height="580" οndrοp="drop(event);"
            ondragover="allowDrop(event);">
        Canvas Not Supported.
    </canvas>
    <img src="resources/canvas2.png" id="background_img"
         width="1000" height="580" style="display:none;"/>
</div>
<footer>
    <small>Made with HTML5 + WebSockets and JSON</small>
    <ol>
        <li οnclick="toggleLog();">Log</li>
    </ol>
</footer>
<div id="logContainer">
    <h2>log</h2>
    <div id="log"></div>
</div>
</body>
</html>


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zhen</groupId>
    <artifactId>StickStory</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>


    <dependencies>

        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>


        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSON工具包 -->
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.json</artifactId>
            <version>1.0.4</version>
        </dependency>




    </dependencies>

    <build>
        <plugins>
            <!-- 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!-- tomcat 插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/stickStory</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
第一篇敲的项目代码

这里接受返回消息用到了转换器,接受对象类型json返回对象类型json

实现发布订阅模式

项目目录如下:

第二篇敲的项目代码:

package com.zhen.model;

/**
 * @author zhen
 * @Date 2018/12/6 15:30
 */
public class Device {

    private int id;
    private String name;
    private String status;
    private String type;
    private String description;

    public Device() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}


package com.zhen.websocket;

import com.zhen.model.Device;

import javax.enterprise.context.ApplicationScoped;
import javax.json.JsonObject;
import javax.json.spi.JsonProvider;
import javax.websocket.Session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author zhen
 * @Date 2018/12/6 15:50
 */
@ApplicationScoped
public class DeviceSessionHandler {

    private final Set<Session> sessions = new HashSet<>();
    private final Set<Device> devices = new HashSet<>();
    private static AtomicInteger deviceId = new AtomicInteger(0);

    public void addSession(Session session) {
        sessions.add(session);
        for (Device device : devices) {
            JsonObject addMessage = createAndMessage(device);
            sendToSession(session, addMessage);
        }
    }

    public void removeSession(Session session) {
        sessions.remove(session);
    }

    public void addDevice(Device device) {
        device.setId(deviceId.incrementAndGet());
        devices.add(device);
        JsonObject addMessage = createAndMessage(device);
        sendToAllConnectedSessions(addMessage);
    }

    public void removeDevice(int id) {
        Device device = getDeviceById(id);
        if (device != null) {
            devices.remove(device);
            JsonProvider provider = JsonProvider.provider();
            JsonObject removeMessage = provider.createObjectBuilder()
                .add("action", "remove")
                .add("id", id)
                .build();
            sendToAllConnectedSessions(removeMessage);
        }
    }

    public void toggleDevice(int id) {
        JsonProvider provider = JsonProvider.provider();
        Device device = getDeviceById(id);
        if (device != null) {
            if ("On".equals(device.getStatus())) {
                device.setStatus("Off");
            } else {
                device.setStatus("On");
            }
            JsonObject updateDevMessage = provider.createObjectBuilder()
                .add("action", "toggle")
                .add("id", device.getId())
                .add("status", device.getStatus())
                .build();
                sendToAllConnectedSessions(updateDevMessage);
        }
    }

    public List<Device> getDevices(){
        return new ArrayList<>(devices);
    }

    public Device getDeviceById(int id) {
        for (Device device : devices) {
            if (device.getId() == id) {
                return device;
            }
        }
        return null;
    }

    public JsonObject createAndMessage(Device device) {
        JsonProvider provider = JsonProvider.provider();
        JsonObject addMessage = provider.createObjectBuilder()
            .add("action", "add")
            .add("name", device.getName())
            .add("type", device.getType())
            .add("status", device.getStatus())
            .add("description", device.getDescription())
            .build();
        return addMessage;
    }

    private void sendToAllConnectedSessions(JsonObject message) {
        for (Session session : sessions) {
            sendToSession(session, message);
        }
    }

    private void sendToSession(Session session, JsonObject message) {
        try{
            session.getBasicRemote().sendText(message.toString());
        } catch (IOException ex) {
            sessions.remove(session);
            Logger.getLogger(DeviceSessionHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


}

package com.zhen.websocket;

import com.zhen.model.Device;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author zhen
 * @Date 2018/12/6 15:32
 */
@ApplicationScoped
@ServerEndpoint("/actions")
public class DeviceWebSocketServer {

    @Inject
    private DeviceSessionHandler sessionHandler = new DeviceSessionHandler();

    @OnOpen
    public void open(Session session) {
        sessionHandler.addSession(session);
    }

    @OnClose
    public void close(Session session) {
        sessionHandler.removeSession(session);
    }

    @OnError
    public void onError(Throwable error) {
        Logger.getLogger(DeviceWebSocketServer.class.getName()).log(Level.SEVERE, null, error);
    }

    @OnMessage
    public void handleMessage(Session session, String message) {
        try(JsonReader reader = Json.createReader(new StringReader(message))){
            JsonObject jsonMessage = reader.readObject();

            if ("add".equals(jsonMessage.getString("action"))) {
                Device device = new Device();
                device.setName(jsonMessage.getString("name"));
                device.setDescription(jsonMessage.getString("description"));
                device.setType(jsonMessage.getString("type"));
                device.setStatus("Off");
                sessionHandler.addDevice(device);
            }

            if ("remove".equals(jsonMessage.getString("action"))) {
                int id = (int) jsonMessage.getInt("id");
                sessionHandler.removeDevice(id);
            }

            if ("toggle".equals(jsonMessage.getString("action"))) {
                int id = (int) jsonMessage.getInt("id");
                sessionHandler.toggleDevice(id);
            }
        }
    }
}


<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html>
<head>
    <title>Index</title>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <link rel="stylesheet" href="style.css">
    <script src="websocket.js"></script>
</head>
<body>
<div id="wrapper">
    <h1>Java WebSocket Home</h1>
    <p>Welcome to the Java WebSocket Home. Click the Add a device button to start adding devices.</p>
    <br/>
    <div id="addDevice">
        <div class="button"><a href="#" οnclick="showForm()">Add a device</a> </div>
        <form id="addDeviceForm">
            <h3>Add a new device</h3>
            <span>Name: <input type="text" name="device_name" id="device_name"></span>
            <span>
                Type:
                <select id="device_type">
                    <option name="type" value="Appliance">Appliance</option>
                    <option name="type" value="Electronics">Electronics</option>
                    <option name="type" value="Lights">Lights</option>
                    <option name="type" value="Other">Other</option>
                </select>
            </span>

            <span>
                Description:<br/>
                <textarea name="description" id="device_description" rows="2" cols="50"></textarea>
            </span>

            <input type="button" class="button" value="Add" οnclick="formSubmit();">
            <input type="reset" class="button" value="Cancel" οnclick="hideForm();">
        </form>
    </div>
    <br/>
    <h3>Currently connected devices:</h3>
    <div id="content"></div>
</div>
</body>
</html>


body {
    font-family: Arial, Helvetica, sans-serif;
    font-size: 80%;
    background-color: #1f1f1f;
}

#wrapper {
    width: 960px;
    margin: auto;
    text-align: left;
    color: #d9d9d9;
}

p {
    text-align: left;
}

.button {
    display: inline;
    color: #fff;
    background-color: #f2791d;
    padding: 8px;
    margin: auto;
    border-radius: 8px;
    -moz-border-radius: 8px;
    -webkit-border-radius: 8px;
    box-shadow: none;
    border: none;
}

.button:hover {
    background-color: #ffb15e;
}
.button a, a:visited, a:hover, a:active {
    color: #fff;
    text-decoration: none;
}

#addDevice {
    text-align: center;
    width: 960px;
    margin: auto;
    margin-bottom: 10px;
}

#addDeviceForm {
    text-align: left;
    width: 400px;
    margin: auto;
    padding: 10px;
}

#addDeviceForm span {
    display: block;
}

#content {
    margin: auto;
    width: 960px;
}

.device {
    width: 180px;
    height: 110px;
    margin: 10px;
    padding: 16px;
    color: #fff;
    vertical-align: top;
    border-radius: 8px;
    -moz-border-radius: 8px;
    -webkit-border-radius: 8px;
    display: inline-block;
}

.device.off {
    background-color: #c8cccf;
}

.device span {
    display: block;
}

.deviceName {
    text-align: center;
    font-weight: bold;
    margin-bottom: 12px;
}

.removeDevice {
    margin-top: 12px;
    text-align: center;
}

.device.Appliance {
    background-color: #5eb85e;
}

.device.Appliance a:hover {
    color: #a1ed82;
}

.device.Electronics {
    background-color: #0f90d1;
}

.device.Electronics a:hover {
    color: #4badd1;
}

.device.Lights {
    background-color: #c2a00c;
}

.device.Lights a:hover {
    color: #fad232;
}

.device.Other {
    background-color: #db524d;
}

.device.Other a:hover {
    color: #ff907d;
}

.device a {
    text-decoration: none;
}

.device a:visited, a:active, a:hover {
    color: #fff;
}

.device a:hover {
    text-decoration: underline;
}


window.onload = init;
var socket = new WebSocket("ws://localhost:8080/webSocketHome/actions");
socket.onmessage = onMessage;

function onMessage(event) {
    var device = JSON.parse(event.data);
    if (device.action === "add") {
        printDeviceElement(device);
    }
    if (device.action === "remove") {
        document.getElementById(device.id).remove();
        //device.parentNode.removeChild(device);
    }
    if (device.action === "toggle") {
        var node = document.getElementById(device.id);
        var statusText = node.children[2];
        if (device.status === "On") {
            statusText.innerHTML = "Status: " + device.status + " (<a href=\"#\" OnClick=toggleDevice(" + device.id + ")>Turn off</a>)";
        } else if (device.status === "Off") {
            statusText.innerHTML = "Status: " + device.status + " (<a href=\"#\" OnClick=toggleDevice(" + device.id + ")>Turn on</a>)";
        }
    }
}

function addDevice(name, type, description) {
    var DeviceAction = {
        action: "add",
        name: name,
        type: type,
        description: description
    };
    socket.send(JSON.stringify(DeviceAction));
}

function removeDevice(element) {
    var id = element;
    var DeviceAction = {
        action: "remove",
        id: id
    };
    socket.send(JSON.stringify(DeviceAction));
}

function toggleDevice(element) {
    var id = element;
    var DeviceAction = {
        action: "toggle",
        id: id
    };
    socket.send(JSON.stringify(DeviceAction));
}

function printDeviceElement(device) {
    var content = document.getElementById("content");

    var deviceDiv = document.createElement("div");
    deviceDiv.setAttribute("id", device.id);
    deviceDiv.setAttribute("class", "device " + device.type);
    content.appendChild(deviceDiv);

    var deviceName = document.createElement("span");
    deviceName.setAttribute("class", "deviceName");
    deviceName.innerHTML = device.name;
    deviceDiv.appendChild(deviceName);

    var deviceType = document.createElement("span");
    deviceType.innerHTML = "<b>Type:</b> " + device.type;
    deviceDiv.appendChild(deviceType);

    var deviceStatus = document.createElement("span");
    if (device.status === "On") {
        deviceStatus.innerHTML = "<b>Status:</b> " + device.status + " (<a href=\"#\" OnClick=toggleDevice(" + device.id + ")>Turn off</a>)";
    } else if (device.status === "Off") {
        deviceStatus.innerHTML = "<b>Status:</b> " + device.status + " (<a href=\"#\" OnClick=toggleDevice(" + device.id + ")>Turn on</a>)";
        //deviceDiv.setAttribute("class", "device off");
    }
    deviceDiv.appendChild(deviceStatus);

    var deviceDescription = document.createElement("span");
    deviceDescription.innerHTML = "<b>Comments:</b> " + device.description;
    deviceDiv.appendChild(deviceDescription);

    var removeDevice = document.createElement("span");
    removeDevice.setAttribute("class", "removeDevice");
    removeDevice.innerHTML = "<a href=\"#\" OnClick=removeDevice(" + device.id + ")>Remove device</a>";
    deviceDiv.appendChild(removeDevice);
}

function showForm() {
    document.getElementById("addDeviceForm").style.display = '';
}

function hideForm() {
    document.getElementById("addDeviceForm").style.display = "none";
}

function formSubmit() {
    var form = document.getElementById("addDeviceForm");
    var name = form.elements["device_name"].value;
    var type = form.elements["device_type"].value;
    var description = form.elements["device_description"].value;
    hideForm();
    document.getElementById("addDeviceForm").reset();
    addDevice(name, type, description);
}

function init() {
    hideForm();
}

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zhen</groupId>
    <artifactId>WebSocketHome</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>


    <dependencies>

        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>


        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSON工具包 -->
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.json</artifactId>
            <version>1.0.4</version>
        </dependency>




    </dependencies>

    <build>
        <plugins>
            <!-- 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!-- tomcat 插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/webSocketHome</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
第二篇敲的代码

此案例利用websocket实现了一套增删改查

项目中使用了CDI注解,如@ApplicationScope,@Inject进行注入功能

项目结构:

 

 spring的websocket支持:

  spring4提供了对websocket的支持

<!-- spring-webSocket,不使用javaee7的api里面了,使用spring的封装 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>${spring.version}</version>
        </dependency>

服务端配置:

package com.zhen.spring_websocket.config;

import com.zhen.spring_websocket.service.MyHandler;
import com.zhen.spring_websocket.service.MyHandler1;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

/**
 * @author zhen
 * @Date 2018/12/10 18:34
 */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(),"/myHandler");
        registry.addHandler(myHandler1(),"/myHandler1").withSockJS();
    }

    public WebSocketHandler myHandler() {
        return new MyHandler();
    }

    public WebSocketHandler myHandler1() {
        return new MyHandler1();
    }
}
package com.zhen.spring_websocket.service;

import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

/**
 * @author zhen
 * @Date 2018/12/10 18:32
 * 此类实现WebSocketHandler,执行处理请求等操作,这里只是接受请求然后再将请求转发回去的功能
 */
public class MyHandler1 extends AbstractWebSocketHandler {
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) {
        try{
            session.sendMessage(message);
        }catch (IOException e){
            e.printStackTrace();
        }

    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        super.afterConnectionEstablished(session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
    }
}

Handler并不一定是继承abstractWebSocketHandler,只要是WebSocketHandler的子类即可。

和servlet的websocket api差不多吧

 

这句代码:

registry.addHandler(myHandler1(),"/myHandler1").withSockJS();

是表示接受的是前端sockJs对象发送的请求。是spring-websocket模块的一个封装功能。

 

sockJs是什么呢?

在不支持WebSocket的情况下,也可以很简单地实现WebSocket的功能的,方法就是使用 SockJS。

它会优先选择WebSocket进行连接,但是当服务器或客户端不支持WebSocket时,会自动在 XHR流、XDR流、iFrame事件源、iFrame HTML文件、XHR轮询、XDR轮询、iFrame XHR轮询、JSONP轮询 这几个方案中择优进行连接。

它是websocket客户端的拓展与补充。

使用sockJs之后,spring注册websocket链接就上面代码这样既可。

 

 

客户端:

  引入sockjs.min.js

  使用sockJs对象替代WebSocket对象发送请求,它的语法和原生几乎一致

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page session="false" %>
<html>
<head>
    <title>WebSocket with SockJS</title>
</head>
<body>
<h1>Welcome!</h1>
<ul id="ul">
</ul>
<script src="${pageContext.request.contextPath}/static/js/sockjs.min.js"></script>
<script>
    // SockJS与原生的WebSocket的方法基本是一致的,
    // 所以只需要将 new WebSocket(url); 换成 new SockJS(url); 就可以了
    var url = "/spring4webSocket/myHandler1";
    var sock = new SockJS(url);
    sock.onopen = function (ev) {
        console.log("opening");
        sayHey();
    };
    sock.onmessage = function (ev) {
        console.log(ev.data);
        var li = document.createElement("li");
        li.innerText = ev.data;
        document.getElementById("ul").appendChild(li);
        setTimeout(sayHey, 2000);
    };
    sock.onclose = function (ev) {
        console.log("closed");
    };
    function sayHey() {
        console.log("sending 'Hey guy!'");
        sock.send("Hey guy!");
    };
</script>
</body>
</html>

 

spring的封装还有基于stomp的部分:

  这个没理解好,以后再做研究。与spring配置请求的也涉及到再做补充。虽然写过demo,但是不太理解,用的springbot,使用了spring security的例子,暂过。

 

参考链接:https://www.jianshu.com/p/942a2b16e26c

参考链接:https://baike.baidu.com/item/WebSocket/1953845?fr=aladdin

参考链接:https://www.cnblogs.com/jingmoxukong/p/7755643.html

参考链接:http://www.ruanyifeng.com/blog/2017/05/websocket.html

参考链接:http://www.cnblogs.com/xdp-gacl/p/5193279.html

参考链接:https://blog.csdn.net/john_62/article/details/78208177

参考链接:https://blog.csdn.net/dadiyang/article/details/83715569

 

此学习得出的经验之谈:如果暂时理解不了,就先使用他,然后再理解  

 

相关文章:

  • 1600802047 android 第三次作业(音乐播放器)
  • bzoj 2555 SubString——后缀自动机+LCT
  • BZOJ3238 [Ahoi2013]差异
  • 使用Java代码自定义Ribbon配置
  • CephFS 文件系统应用
  • 第二冲刺阶段第十三天
  • 近似推断---期望传播
  • 联合国儿童基金会投资六家区块链初创企业,目标是解决“全球性挑战”
  • MaxCompute新功能发布
  • 127.0.0.1 和 0.0.0.0 地址的区别
  • k8s环境部署及使用方式
  • Django2.0——中间件
  • 蔚来总裁秦力洪:不要贴标签说ES8不好 短期压力是做好服务
  • 菜鸟问题
  • python之dict与set实现原理之hash算法
  • 【React系列】如何构建React应用程序
  • Angular6错误 Service: No provider for Renderer2
  • canvas 绘制双线技巧
  • CAP 一致性协议及应用解析
  • ECMAScript入门(七)--Module语法
  • es6--symbol
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • Java Agent 学习笔记
  • Java 多线程编程之:notify 和 wait 用法
  • java概述
  • JS笔记四:作用域、变量(函数)提升
  • js递归,无限分级树形折叠菜单
  • mysql外键的使用
  • SQLServer之索引简介
  • ucore操作系统实验笔记 - 重新理解中断
  • 产品三维模型在线预览
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 蓝海存储开关机注意事项总结
  • 设计模式 开闭原则
  • 异常机制详解
  • # include “ “ 和 # include < >两者的区别
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • (07)Hive——窗口函数详解
  • (1)(1.9) MSP (version 4.2)
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (6)添加vue-cookie
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转)重识new
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .NET企业级应用架构设计系列之应用服务器