国外档案网站建设,高端网页设计培训,网站色调代号,网上推广什么比较赚钱需求背景 在某个资产平台#xff0c;在不了解需求的情况下#xff0c;我突然接到了一个任务#xff0c;让我做某个页面窗口的即时通讯#xff0c;想到了用websocket技术#xff0c;我从来没用过#xff0c;被迫接受了这个任务#xff0c;我带着浓烈的兴趣#xff0c;就…需求背景 在某个资产平台在不了解需求的情况下我突然接到了一个任务让我做某个页面窗口的即时通讯想到了用websocket技术我从来没用过被迫接受了这个任务我带着浓烈的兴趣就去研究了一下网上资料那么多我们必须找到适合自己的方案我们开发的时候一定要基于现有框架的基础上去做扩展不然会引发很多问题比如运行不稳定、项目无法启动等废话不多说直接上代码 WebScoekt介绍
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单允许服务端主动向客户端推送数据。在WebSocket API中浏览器和服务器只需要完成一次握手两者之间就直接可以创建持久性的连接并进行双向数据传输。
特点
较少的控制开销。在连接创建后服务器和客户端之间交换数据时用于协议控制的数据包头部相对较小。在不包含扩展的情况下对于服务器到客户端的内容此头部大小只有2至10字节和数据包长度有关对于客户端到服务器的内容此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部此项开销显著减少了。更强的实时性。由于协议是全双工的所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应延迟明显更少即使是和Comet等类似的长轮询比较其也能在短时间内更多次地传递数据。 保持连接状态。与HTTP不同的是Websocket需要先创建连接这就使得其成为一种有状态的协议之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息如身份认证等。更好的二进制支持。Websocket定义了二进制帧相对HTTP可以更轻松地处理二进制内容。 可以支持扩展。Websocket定义了扩展用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。更好的压缩效果。相对于HTTP压缩Websocket在适当的扩展支持下可以沿用之前内容的上下文在传递类似的数据时可以显著地提高压缩率。
解决方案介绍 PS基于websocket的特点我们打算放弃Ajax轮询因为当客户端过多的时候会导致消息收发有延迟、服务器压力增大。
API介绍 思路解析
首先我们既然要发送消息客户端和客户端是无法建立连接的我们可以这样做我们搭建服务端所有的客户端都在服务端注册会话我们把消息发送给服务端然后由服务端转发给其他客户端这样就可以和其他用户通讯了。
示例代码
服务端配置
package unicom.assetMarket.websocket.config;import org.springframework.context.annotation.Configuration;
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 unicom.assetMarket.websocket.handler.MyMessageHandler;
import unicom.assetMarket.websocket.interceptor.WebSocketInterceptor;/*** Author 庞国庆* Date 2023/02/15/15:36* Description*/
Configuration
EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {webSocketHandlerRegistry.addHandler(new MyMessageHandler(), /accept).addInterceptors(new WebSocketInterceptor())//允许跨域.setAllowedOrigins(*);webSocketHandlerRegistry.addHandler(new MyMessageHandler(),/http/accept).addInterceptors(new WebSocketInterceptor()).setAllowedOrigins(*).withSockJS();}}Interceptor
package unicom.assetMarket.websocket.interceptor;import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import java.util.Map;/*** Author 庞国庆* Date 2023/02/15/15:52* Description*/
Slf4j
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor {Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, MapString, Object attributes) throws Exception {if (request instanceof ServletServerHttpRequest) {ServletServerHttpRequest request1 (ServletServerHttpRequest) request;String userId request1.getServletRequest().getParameter(userId);attributes.put(currentUser, userId);log.info(用户{}正在尝试与服务端建立链接········, userId);}return super.beforeHandshake(request, response, wsHandler, attributes);}Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {super.afterHandshake(request, response, wsHandler, ex);}
}
Handler
package unicom.assetMarket.websocket.handler;import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import unicom.assetMarket.assetChat.service.CamsMarketChatMessageService;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** Author 庞国庆* Date 2023/02/15/15:52* Description*/
Slf4j
Component
public class MyMessageHandler extends TextWebSocketHandler {//存储所有客户端的会话信息线程安全private final static MapString, WebSocketSession sessions new ConcurrentHashMap();Autowired(required false)private CamsMarketChatMessageService service;Overridepublic void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {String userId this.getUserId(webSocketSession);if (StringUtils.isNotBlank(userId)) {sessions.put(userId, webSocketSession);log.info(用户{}已经建立链接, userId);}}Overridepublic void handleMessage(WebSocketSession webSocketSession, WebSocketMessage? webSocketMessage) throws Exception {String message webSocketMessage.toString();String userId this.getUserId(webSocketSession);log.info(服务器收到用户{}发送的消息:{}, userId, message);//webSocketSession.sendMessage(webSocketMessage);if (StringUtils.isNotBlank(message)) {//保存用户发送的消息数据service.saveData(message);//发送消息给指定用户doMessage(message);}}Overridepublic void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {WebSocketMessage message new TextMessage(发送异常 throwable.getMessage());//webSocketSession.sendMessage(message);}Overridepublic void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {String userId this.getUserId(webSocketSession);if (StringUtils.isNotBlank(userId)) {sessions.remove(userId);log.info(用户{}已经关闭会话, userId);} else {log.error(没有找到用户{}的会话, userId);}}Overridepublic boolean supportsPartialMessages() {return false;}/*** 根据会话查找已经注册的用户id** param session* return*/private String getUserId(WebSocketSession session) {String userId (String) session.getAttributes().get(currentUser);return userId;}/*** 发送消息给指定用户** param userId* param contents*/public void sendMessageUser(String userId, String contents) throws Exception {WebSocketSession session sessions.get(userId);if (session ! null session.isOpen()) {WebSocketMessage message new TextMessage(contents);session.sendMessage(message);}}/*** 接收用户消息转发给指定用户* param msg* throws Exception*/public void doMessage(String msg) throws Exception {JSONObject jsonObject JSONObject.parseObject(msg);String sendStaffId jsonObject.getString(sendStaffId);String reciveStaffId jsonObject.getString(reciveStaffId);String message jsonObject.getString(message);//替换敏感字message service.replaceSomething(message);this.sendMessageUser(reciveStaffId,message);}}JSP代码
% page languagejava pageEncodingUTF-8 %
% include file/WEB-INF/jsp/common/common.jsp %
% page contentTypetext/html;charsetUTF-8 languagejava %html
headtitle聊天窗口/title
/head
body stylebackground: #f0f3fa
div classdividerBox dividerBox-spinner dividerBox-blue rightBox-bluediv classright-container-headerdiv classdividerBox-titlespan${name}/span/div/divdiv classdividerBox-body rightBox-bodydiv classrowdiv classcol-md-4 col-sm-4 padding-r-0div classform-groupdiv classcol-md-9 col-sm-8div classdata-parentinput typetext classform-control input-sm idmessage maxlength200 /button typebutton classbtn btn-primary btn-sm onclicksendMessage()发 送/button/div/div/div/div/div/div
/div
div classtableWrapper rightBox-tablediv classtable-contentul idtalkcontent/ul/div
/div
!-- 消息发送者id--
input typehidden idsendStaffId value${sendStaffId}/
!-- 消息接收者id--
input typehidden idreciveStaffId value${reciveStaffId} /
script src${prcs}/js/unicom/assetMarket/assetChat/talk.js?time%new Date().getTime() %/script
/bodyJS代码
$(function() {connectWebSocket();
});/*** 和服务器建立链接*/
function connectWebSocket() {let userId $(#sendStaffId).val();let host window.location.host;if (WebSocket in window) {if (userId) {websocketClient new WebSocket( ws://host/frm/websocket/accept?userId userId);connecting();}}
}function connecting() {websocketClient.onopen function (event) {console.log(连接成功);}websocketClient.onmessage function (event) {appendContent(false,event.data);}websocketClient.onerror function (event) {console.log(连接失败);}websocketClient.onclose function (event) {console.log(与服务器断开连接状态码 event.code ,原因 event.reason);}
}/*** 发送消息*/
function sendMessage() {if (websocketClient) {let message $(#message).val();if(message) {let sendMsg concatMsg(message);sendMsg JSON.stringify(sendMsg)websocketClient.send(sendMsg);appendContent(true,message);}} else {console.log(发送失败);}
}/*** 在消息框内追加消息* param flag*/
function appendContent(flag,data){if(flag){$(#talkcontent).append(li stylefloat: right data /libr/);}else{$(#talkcontent).append(li stylefloat: left data /libr/);}
}
/*** 组装消息*/
function concatMsg(message) {//发送人let sendStaffId $(#sendStaffId).val();//接收人let reciveStaffId $(#reciveStaffId).val();let json {sendStaffId: sendStaffId ,reciveStaffId: reciveStaffId ,message: message };return JSON.parse(json);
}PS这里我遇到了1个坑就是在连接服务端的时候老是连接不上我们在配置的代码中指定的匹配URL为 /accept但是我发现就是连不上后来找了很多资料原来是忘了加个url这个url就是我们在web.xml中配置的DispatcherServlet的拦截url如下 运行效果如下 PS项目框架中配置的过滤器、拦截器都有可能把webscoket建立连接的请求作处理尤其是权限验证的过滤器所以记得要对websocket的请求加白名单。
运行效果 PS有啥问题欢迎大家留言我非常乐意帮助大家解决问题。