一,Websocket是一個基於TCP、對傳統HTTP協議(短連接)的升級版,它實現了瀏覽器與服務器的全雙工通信,擴展了瀏覽器與服務端的通信功能,使服務端也能主動向客戶端發送數據。
解決的問題:
1.解決了多次握手的問題(長連接),提高效率
2.服務器可以推送數據給客戶端,不需要客戶端輪詢等low操作
客戶端實現方式
JavaScript對WebSocket的支持:
2.1.創建客戶端連接的方式:
websocket = new WebSocket(“ws://localhost:9090/websocket”);
2.2.websocket對象常用事件:
onerror: 連接到服務端錯誤時觸發
onmessage: 收到服務器推送的消息時觸發
onclose: 連接關閉時觸發
onopen: 連接到服務端成功後觸發
二.WebSocket示例(實現簡單的信息交互)
2.1.新建WebSocket示例(網頁版QQ聊天實現)
在pom.xml中添加Jar包依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
2.2.spring整合websocket方法
spring整合,此方式基於spring mvc框架
WebSocketConfig.java
這個類是配置類,所以需要在spring mvc配置文件中加入對這個類的掃描,第一個addHandler是對正常連接的配置,第二個是如果瀏覽器不支持websocket,使用socketjs模擬websocket的連接。
package com.ssm.websocket;
import org.springframework.context.annotation.Bean;
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;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
/*
@Configuration的作用
聲明當前類是一個配置類
@Configuration不可以是final類型;
@Configuration不可以是匿名類;
嵌套的configuration必須是靜態類。
@EnableWebSocket 聲明該類支持WebSocket
*/
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
//websocket入口,允許訪問的域、註冊Handler、SockJs支持和攔截器。
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(),"/websocket")//入口路徑爲websocket
.addInterceptors(new SpringWebSocketHandler())
.setAllowedOrigins("*");
registry.addHandler(myHandler(), "/wbsockjs/webSocketServer")
.addInterceptors(new SpringWebSocketHandler()).withSockJS();
//setAllowedOrigins()方法的支持spring4.1.5之後的版本才支持
//setAllowedOrigins(String... val),允許指定的域名或IP(含端口號)建立長連接,
// 可以只設置允許自家域名訪問,如果不限時使用"*"號,如果指定了域名,
// 則必須要以http或https開頭。
}
@Bean
public WebSocketHandler myHandler(){
return new MySocketHandler();
}
@Bean
public HttpSessionHandshakeInterceptor myHandlerInterceptor(){
return new SpringWebSocketHandler();
}
}
SpringWebSocketHandler.java
這個類的作用就是在連接成功前和成功後增加一些額外的功能,Constants.java類是一個工具類,兩個常量。
package com.ssm.websocket;
import com.lingdian.pojo.User;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.*;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import javax.servlet.http.HttpSession;
import java.util.Map;
/*
握手攔截器類
*/
public class SpringWebSocketHandler extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
System.out.println("Before Handshake");
//在握手之前將HttpSession中的用戶,copy放到WebSocket Session中
if (request instanceof ServletServerHttpRequest){
ServletServerHttpRequest servletServerHttpRequest=
(ServletServerHttpRequest) request;
HttpSession session=
servletServerHttpRequest.getServletRequest().getSession(true);
if (null!=session){
User user=(User)session.getAttribute("user");
//WebSocket Session
attributes.put("user",user);
}
}
return super.beforeHandshake(request,response,wsHandler,attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response
, WebSocketHandler wsHandler, Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
}
MySocketHandler .java
這個類是對消息的一些處理,比如是發給一個人,還是發給所有人,並且前端連接時觸發的一些動作
package com.ssm.websocket;
import com.lingdian.pojo.Message;
import com.lingdian.pojo.User;
import com.lingdian.service.MessageService;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CopyOnWriteArraySet;
/***
* 消息處理類
*/
public class MySocketHandler extends TextWebSocketHandler {
//使用CopyOnWriteArraySet,保證線程安全,當一個用戶
// 退出時,這邊的用戶查看用戶列表時不會出現安全失敗
private static CopyOnWriteArraySet<WebSocketSession> users=new CopyOnWriteArraySet<WebSocketSession>();;
@Resource
private MessageService messageService;
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
//super.handleTextMessage(session, message);
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = sd.format(new Date());
//從 WebSocket Session中取得用戶
User user=(User) session.getAttributes().get("user");
Message message1=new Message();
message1.setUid(user.getId());
message1.setMessage(message.getPayload());
message1.setSendTime(new Date());
//將消息保存到數據庫
messageService.insertMessage(message1);
//封裝要輸出的消息到TextMessage,姓名,時間,消息
TextMessage returnMessage =
new TextMessage(user.getName()+":" +
""+time+"<br/>"+message.getPayload());
for (WebSocketSession session1 : users) {
try{
//使用sendMessage()方法輸出消息到客戶端
session1.sendMessage(returnMessage);
}catch (Exception e){
e.printStackTrace();
continue;
}
}
}
/**
* 加入一個用戶 add進集合
* @param session
* @throws Exception
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
users.add(session);
System.out.println("connect to the websocket success......當前數量:"+users.size());
}
/**
* 當用戶退出時,將用戶從集合remove
* @param session
* @param status
* @throws Exception
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
users.remove(session);
System.out.println("剩餘在線用戶"+users.size());
}
public static CopyOnWriteArraySet<WebSocketSession> getUsers() {
return users;
}
public static void setUsers(CopyOnWriteArraySet<WebSocketSession> users) {
MySocketHandler.users = users;
}
public MessageService getMessageService() {
return messageService;
}
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}
}
spring-mvc.xml
正常的配置文件,同時需要增加對WebSocketConfig.java類的掃描,並且增加
<!--配置握手攔截器-->
<websocket:handlers>
<!--path=websocket-->
<websocket:mapping path="/websocket" handler="websocket"/>
<websocket:handshake-interceptors>
<bean class="com.ssm.websocket.SpringWebSocketHandler"/>
</websocket:handshake-interceptors>
</websocket:handlers>
jsp簡單聊天界面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<html>
<head>
<title>聊天室</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/Css/chat.css" />
<script src="${pageContext.request.contextPath}/Js/jquery-1.8.2.min.js"></script>
<script src="${pageContext.request.contextPath}/Js/chat.js"></script>
<script type="text/javascript">
//獲取當前用戶
function getUser(){
$("#chat-user-con ul").html("");
$.post("${pageContext.request.contextPath}/user/getAll",{},
function(data){
var temp;
for(temp=0;temp<data.length;temp++){
$("#chat-user-con ul").append("<li>"+data[temp].name+"</li>");
}
},"json");
}
//下線
function downLine(){
$.post("${pageContext.request.contextPath}/user/downLine",{},
function(){});
}
</script>
</head>
<body>
<span id="message"></span>
<div id="chat">
<div id="chat-top">
<div id="chat-dialog">
<div id="chat-dialog-t">聊天室</div>
<div id="chat-dialog-con">
<ul>
</ul>
</div>
</div>
<div id="chat-user">
<div id="chat-user-t">當前在線用戶</div>
<div id="chat-user-con">
<ul>
</ul>
</div>
</div>
</div>
<div id="chat-bottom">
<div id="chat-input">
<div id="chat-input-expr">
<!--<img src="Images/1.gif" id="1" /><img src="Images/2.gif" id="2" /><img src="Images/3.gif" id="3" /><img src="Images/4.gif" id="4" /><img src="Images/5.gif" id="5" /><img src="Images/6.gif" id="6" /><img src="Images/7.gif" id="7" /><img src="Images/8.gif" id="8" /><img src="Images/9.gif" id="9" /><img src="Images/10.gif" id="10" />-->
</div>
<div id="chat-input-edit">
<div id="input-field">
<textarea id="txtInput"></textarea>
</div>
<div id="input-btn">
<input id="btnSend" type="button" value="發送" />
</div>
</div>
<div id="chat-input-tip">發送內容不能爲空</div>
</div>
</div>
</div>
<div id="chat-msg"></div>
</body>
</html>
List item
注意導入wbsockjs時要使用地址全稱,並且連接使用的是http而不是websocket的ws
聲明: 整理本文僅供參考,若有疑問可以同時參考原文。