引言:

  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 对象:

事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发

  WebSocket 方法

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

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

    客户端实例:   

<%--
Created by IntelliJ IDEA.
User: zhen
Date: //
Time: :
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 onclick="send()">发送消息</button>
<hr/>
<button onclick="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);
} }

服务端实例

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

  

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, , );
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 = ;
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" ondragstart="drag(event);" >
<img src="resources/stickers/chicken.png"
data-sticker="chicken.png"
style="float:left"
draggable="true" ondragstart="drag(event);" >
<img src="resources/stickers/leopard.png"
data-sticker="leopard.png"
style="float:left"
draggable="true" ondragstart="drag(event);" >
<img src="resources/stickers/monkey.png"
data-sticker="monkey.png"
style="float:left"
draggable="true" ondragstart="drag(event);" >
<img src="resources/stickers/horse.png"
data-sticker="horse.png"
style="float:left"
draggable="true" ondragstart="drag(event);" >
<img src="resources/stickers/tiger.png"
data-sticker="tiger.png"
style="float:left"
draggable="true" ondragstart="drag(event);" >
</div>
</aside>
<div id="content">
<canvas id="board" width="" height="" ondrop="drop(event);"
ondragover="allowDrop(event);">
Canvas Not Supported.
</canvas>
<img src="resources/canvas2.png" id="background_img"
width="" height="" style="display:none;"/>
</div>
<footer>
<small>Made with HTML5 + WebSockets and JSON</small>
<ol>
<li onclick="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.</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.</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.</version>
</dependency> </dependencies> <build>
<plugins>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-</encoding>
</configuration>
</plugin> <!-- tomcat 插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port></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(); 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="#" onclick="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="" cols=""></textarea>
</span> <input type="button" class="button" value="Add" onclick="formSubmit();">
<input type="reset" class="button" value="Cancel" onclick="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: %;
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[];
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.</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.</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.</version>
</dependency> </dependencies> <build>
<plugins>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-</encoding>
</configuration>
</plugin> <!-- tomcat 插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port></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, );
};
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

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

java websocket学习的更多相关文章

  1. WebSocket学习记录

    参考资料: Java后端WebSocket的Tomcat实现 基于Java的WebSocket推送 java WebSocket的实现以及Spring WebSocket 利用spring-webso ...

  2. Java的学习之路

    记事本 EditPlus eclipse Java的学习软件,已经系统性学习Java有一段时间了,接下来我想讲一下我在Java学习用到的软件. 1.第一个软件:记事本 记事本是Java学习中最基础的编 ...

  3. Java多线程学习笔记

    进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...

  4. Java Web 学习路线

    实际上,如果时间安排合理的话,大概需要六个月左右,有些基础好,自学能力强的朋友,甚至在四个月左右就开始找工作了.大三的时候,我萌生了放弃本专业的念头,断断续续学 Java Web 累计一年半左右,总算 ...

  5. Java基础学习-- 继承 的简单总结

    代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...

  6. 20145213《Java程序设计学习笔记》第六周学习总结

    20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...

  7. [原创]java WEB学习笔记95:Hibernate 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  8. Java多线程学习(转载)

    Java多线程学习(转载) 时间:2015-03-14 13:53:14      阅读:137413      评论:4      收藏:3      [点我收藏+] 转载 :http://blog ...

  9. java基础学习总结——java环境变量配置

    前言 学习java的第一步就要搭建java的学习环境,首先是要安装JDK,JDK安装好之后,还需要在电脑上配置"JAVA_HOME”."path”."classpath& ...

随机推荐

  1. tomcat ----> 启动,关闭和配置等等

    1.启动 在tomcat安装目录的bin文件中双击startup.bat. 2.关闭 在tomcat安装目录的bin文件中双击shutdown.bat. 3.配置tomcat-user.xml文件 ( ...

  2. python hashable

    判断一个对象是否hashable: hash(obj) 或 obj.__hash__() ,返回 hash 值 hashable 的有: int / float / tuple / str/  obj ...

  3. wpf 使用DocumentViewer打印

    https://blog.csdn.net/duanzi_peng/article/details/14118937?locationNum=15 https://www.cnblogs.com/zl ...

  4. LeetCode--458--可怜的小猪

    问题描述: 有1000只水桶,其中有且只有一桶装的含有毒药,其余装的都是水.它们从外观看起来都一样.如果小猪喝了毒药,它会在15分钟内死去. 问题来了,如果需要你在一小时内,弄清楚哪只水桶含有毒药,你 ...

  5. 关于Android如何创建空文件夹,以及mkdir和mkdirs的区别

    File().mkdir 和File().mkdirs的区别 mkdir是只能建立一级目录 比如 /sdcard/test/pp 就只能建立test 而mkdirs 则可以全部建立

  6. 『Github』本地项目更新到服务器

    对于已经新建到服务器的项目,我们在本地有了新的修改之后,想要同步到服务器时的操作. 1.clone代码 1.把目标工程clone到本地,使用指令: >git clone https://gith ...

  7. spring boot(一)入门

    什么是spring boot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员 ...

  8. java把list分成几个list

    public static void main(String[] args) { List<String> list=new ArrayList<>(); list.add(& ...

  9. python中lambda的用法

    一.lambda函数也叫匿名函数,即,函数没有具体的名称.先来看一个最简单例子: def f(x):return x**2print f(4) Python中使用lambda的话,写成这样 g = l ...

  10. 函数使用三:采购过账BAPI_GOODSMVT_CREATE

    一.货物移动.bapi  BAPI_GOODSMVT_CREATE其中 参数 : GOODSMVT_CODE 有 GMCODE Table T158G - 01 - MB01 - Goods Rece ...