这是我参与更文挑战的第2天,活动详情查看: 更文挑战前端
本文正在参加「Java主题月 - Java 开发实战」,详情查看 活动连接java
[TOC]nginx
HTTP请求用于咱们开发以及用户之间最为普遍的一种协议,在HTTP中咱们能够简单的经过浏览器获取到咱们须要的内容(页面)。可是他也有他的局限性。今天咱们的主角websocket将为展示他的功能web
这样多多少少的形成资源的浪费。spring
HTTP是无记忆的。每次请求服务端是没法了解到客户端以前的行为的,可是咱们平时浏览器网站的时候感受浏览器是知道咱们以前作的事情的。这是网站在请求是添加的cookie这些服务端提供的数据。对咱们而言咱们感受是有记忆的。实则否则后端
HTTP1.1以后采用了短链接、长链接两种方式。HTTP请求的发送每次也须要三次握手机制。因此每次的链接耗费资源。1.1后才必定时间内HTTP其实采用的是长链接,这样能够减小资源的开销浏览器
上述说道的长链接有人可能有疑问,其实HTTP协议是基于TCP协议开发的。因此天然有长链接的特性。缓存
HTTP由于短链接的特性因此是无记忆的。为了解决这个问题每一个请求都是由General+Request Head+Request Paylaod+Response Headers组成的。其中Heads就是浏览器须要记住的东西,每次传递来传递去的非常耗费性能。安全
websocket因为是长链接特性,一次链接就能够一直的双向通讯。从载体来讲websocket关注的更少,只须要通讯当前须要的信息。历史信息双方都是有的。springboot
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
复制代码
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
复制代码
public abstract class BaseWebSocket extends BaseController{
/** * 静态变量,用来记录当前在线链接数。应该把它设计成线程安全的。 */
private int onlineCount = 0;
/** * concurrent包的线程安全Set,用来存放每一个客户端对应的MyWebSocket对象。 */
public CopyOnWriteArraySet<BaseWebSocket> webSocketSet = new CopyOnWriteArraySet<BaseWebSocket>();
/** * 与某个客户端的链接会话,须要经过它来给客户端发送数据 */
public Session session;
private Logger log = LoggerFactory.getLogger("BaseWebSocket");
/** * 链接创建成功调用的方法 * @param session */
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) throws IOException {
this.session = session;
//加入set中
webSocketSet.add(this);
//在线数加1
addOnlineCount();
log.debug("有新链接加入!当前在线人数为" + getOnlineCount());
//发送信息
MultiMap multiMap = new MultiMap();
if (null!=session.getQueryString()&&!"".equals(session.getQueryString())) {
UrlEncoded.decodeTo(session.getQueryString(), multiMap, "UTF-8");
}
sendInfo(defaultMessage(multiMap));
}
/** * 链接关闭调用的方法 */
@OnClose
public void onClose() {
//从set中删除
webSocketSet.remove(this);
//在线数减1
subOnlineCount();
log.info("有一链接关闭!当前在线人数为" + getOnlineCount());
}
/** * 收到客户端消息后调用的方法 * @param message 客户端发送过来的消息 * @param session 缓存 * @throws IOException */
@OnMessage
public void onMessage(String message, Session session) throws IOException {
this.session = session;
try {
Map paraMap = (Map) JSONObject.parse(message);
handlerMessage(paraMap);
} catch (JSONException e) {
MultiMap multiMap = new MultiMap();
UrlEncoded.decodeTo(message, multiMap, "UTF-8");
handlerMessage(multiMap);
//throw new BusinessException("传递消息格式错误(Json)");
}
}
/** * 处理消息接受 * @param paraMap 接受到map类型的参数 */
public void handlerMessage(Map paraMap) {
try {
sendInfo(defaultMessage(paraMap));
} catch (IOException e) {
e.printStackTrace();
}
}
public Object defaultMessage(Map<String, Object> paraMap) {
Object obj = new Object();
try {
obj = defauleMessage(paraMap);
} catch (BusinessException e) {
return formatReturnAppData(e.getMessage());
}
return obj;
}
/** * 默认的发送数据 * @param paraMap 链接时传递的参数 * @return */
public abstract Object defauleMessage(Map<String, Object> paraMap);
public static boolean isJson(String content) {
try {
JSONObject.parse(content);
return true;
} catch (Exception e) {
return false;
}
}
/** * 发生错误时调用 @OnError **/
public void onError(Session session, Throwable error) {
log.error("onMessage方法异常"+error.toString());
error.printStackTrace();
}
/** * 发送消息需注意方法加锁synchronized,避免阻塞报错 * 注意session.getBasicRemote()与session.getAsyncRemote()的区别 * @param message * @throws IOException */
public synchronized void sendMessage(Object message) throws IOException {
// this.session.getBasicRemote().sendText(message);
this.session.getAsyncRemote().sendText(JSONObject.toJSONString(message));
}
/** * 群发自定义消息 * */
public void sendInfo(Object message) throws IOException {
for (BaseWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public synchronized int getOnlineCount() {
return onlineCount;
}
public synchronized void addOnlineCount() {
onlineCount++;
}
public synchronized void subOnlineCount() {
onlineCount--;
}
}
复制代码
@ServerEndpoint(value = "/accident/getAccident")
@Component
public class AccidentGetAccident extends BaseWebSocket {
AccidentController accidentController;
@Override
public Object defauleMessage(Map<String, Object> paraMap) {
accidentController = ContextUtil.getApplicationContext().getBean(AccidentController.class);
return accidentController.getAccident(paraMap);
}
}
复制代码
ws = new WebSocket(wsUrl);
复制代码
ws.onclose = function () {
console.log('连接关闭');
};
ws.onerror = function() {
console.log('发生异常了');
};
ws.onopen = function () {
console.log('新建链接');
};
ws.onmessage = function (event) {
console.log("接收到服务端反馈的信息了");
}
复制代码
var lockReconnect = false;//避免重复链接
var wsUrl = "ws://127.0.0.1:8088/accident/getAccident?entId=zhonghuaxingzhong";
var ws;
var tt;
function createWebSocket() {
try {
ws = new WebSocket(wsUrl);
init();
} catch(e) {
console.log(e+'catch');
reconnect(wsUrl);
}
}
function init() {
ws.onclose = function () {
console.log('连接关闭');
reconnect(wsUrl);
};
ws.onerror = function() {
console.log('发生异常了');
reconnect(wsUrl);
};
ws.onopen = function () {
//心跳检测重置
heartCheck.start();
};
ws.onmessage = function (event) {
setMessageInnerHTML(event.data);
//拿到任何消息都说明当前链接是正常的
console.log('接收到消息');
heartCheck.start();
}
}
function reconnect(url) {
if(lockReconnect) {
return;
};
lockReconnect = true;
//没链接上会一直重连,设置延迟避免请求过多
tt && clearTimeout(tt);
tt = setTimeout(function () {
createWebSocket(url);
lockReconnect = false;
}, 4000);
}
//心跳检测
var heartCheck = {
timeout: 3000,
timeoutObj: null,
serverTimeoutObj: null,
start: function(){
}
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
createWebSocket(wsUrl);
复制代码
你们好!原创不易!springcloud系列+jvm系列正在创做中。。。。。