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

荣添创意网站建设涿州网站建设有限公司

荣添创意网站建设,涿州网站建设有限公司,桂林网站建设凡森网络,静态网站建设参考文献一、引言 1. 问题引入 Hypertext Transfer Protocol (HTTP) 协议 一种无状态的、应用层的、以请求/应答方式运行的协议#xff0c;它使用可扩展的语义和自描述消息格式#xff0c;与基于网络的超文本信息系统灵活的互动. 因为http 通信只能由客户端发起,服务器返回查询结果…一、引言 1. 问题引入 Hypertext Transfer Protocol (HTTP) 协议 一种无状态的、应用层的、以请求/应答方式运行的协议它使用可扩展的语义和自描述消息格式与基于网络的超文本信息系统灵活的互动. 因为http 通信只能由客户端发起,服务器返回查询结果,HTTP 协议做不到服务器主动向客户端推送信息, 服务器有连续的状态变化客户端要获知就非常麻烦。 我们只能使用轮询每隔一段时候就发出一个询问了解服务器有没有新的信息。最典型的场景就是聊天室。 轮询的效率低非常浪费资源因为必须不停连接或者 HTTP 连接始终打开; 2. 消息推送常见方式 常见的消息推送发送轮询长轮询SSEWebSocket 轮询方式 SSEserver-sent event服务器发送事件 SSE在服务器和客户端之间打开一个单向通道服务端响应的不再是一次性的数据包而是text/event-stream类型的数据流信息服务器有数据变更时将数据流式传输到客户端 二、WebSocket 1. WebSocket介绍 WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起服务端对请求做出应答处理。 这种通信模型有一个弊端HTTP 协议无法实现服务器主动向客户端发起消息。 这种单向请求的特点注定了如果服务器有连续的状态变化客户端要获知就非常麻烦。大多数 Web 应用程序将通过频繁的异步 AJAX 请求实现长轮询。轮询的效率低非常浪费资源因为必须不停连接或者 HTTP 连接始终打开。 http协议 websocket协议 2. websocket协议 本协议有两部分握手和数据传输。 握手是基于http协议的。 来自客户端的握手看起来像如下形式 GET ws://localhost/chat HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ Sec-WebSocket-Extensions: permessage-deflate Sec-WebSocket-Version: 13来自服务器的握手看起来像如下形式 HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbKxOo Sec-WebSocket-Extensions: permessage-deflate字段说明 头名称说明ConnectionUpgrade标识该HTTP请求是一个协议升级请求Upgrade: WebSocket协议升级为WebSocket协议Sec-WebSocket-Version: 13客户端支持WebSocket的版本Sec-WebSocket-Key客户端采用base64编码的24位随机字符序列服务器接受客户端HTTP协议升级的证明。要求服务端响应一个对应加密的Sec-WebSocket-Accept头信息作为应答Sec-WebSocket-Extensions协议扩展类型 3. 客户端浏览器实现 3.1 websocket对象 实现 WebSockets 的 Web 浏览器将通过 WebSocket 对象公开所有必需的客户端功能主要指支持 Html5 的浏览器。 以下 API 用于创建 WebSocket 对象 var ws new WebSocket(url);参数url格式说明 ws://ip地址:端口号/资源名称 3.2 websocket事件 WebSocket 对象的相关事件 事件事件处理程序描述openwebsocket对象.onopen连接建立时触发messagewebsocket对象.onmessage客户端接收服务端数据时触发errorwebsocket对象.onerror通信发生错误时触发closewebsocket对象.onclose连接关闭时触发 3.3 WebSocket方法 WebSocket 对象的相关方法: 方法描述send()使用连接发送数据 4. 服务端实现 Tomcat的7.0.5 版本开始支持WebSocket,并且实现了Java WebSocket规范(JSR356)。 Java WebSocket应用由一系列的WebSocketEndpoint组成。Endpoint 是一个java对象代表WebSocket链接的一端对于服务端我们可以视为处理具体WebSocket消息的接口 就像Servlet之与http请求一样。 我们可以通过两种方式定义Endpoint: 第一种是编程式 即继承类 javax.websocket.Endpoint并实现其方法。第二种是注解式, 即定义一个POJO, 并添加 ServerEndpoint相关注解。 Endpoint实例在WebSocket握手时创建并在客户端与服务端链接过程中有效最后在链接关闭时结束。在Endpoint接口中明确定义了与其生命周期相关的方法 规范实现者确保生命周期的各个阶段调用实例的相关方法。生命周期方法如下 方法含义描述onClose当会话关闭时调用。onOpen当开启一个新的会话时调用, 该方法是客户端与服务端握手成功后调用的方法。onError当连接过程中异常时调用。 服务端如何接收客户端发送的数据呢 编程式 通过添加 MessageHandler 消息处理器来接收消息 注解式 在定义Endpoint时通过OnMessage注解指定接收消息的方法 服务端如何推送数据给客户端呢 发送消息则由 RemoteEndpoint 完成 其实例由 Session (websocket.Session) 维护。发送消息有2种方式发送消息通过session.getBasicRemote 获取同步消息发送的实例 然后调用其 sendXxx()方法发送消息通过session.getAsyncRemote 获取异步消息发送实例然后调用其 sendXxx() 方法发送消息 服务端代码 三、基于WebSocket的网页聊天室 完整项目地址 https://gitee.com/lxxkobe/lxx_chat.git 1. 需求 通过 websocket 实现一个简易的聊天室功能 。 1. 登陆聊天室 2. 登陆之后进入聊天界面进行聊天 登陆成功后呈现出以后的效果 当我们想和李四聊天时就可以点击 好友列表 中的 李四效果如下 接下来就可以进行聊天了张三 的界面如下 李四 的界面如下 2. 实现流程 3. 消息格式 张三 给李四发消息 客户端 -- 服务端 {“toName”:“李四”,“message”:“你好”} 服务端 -- 客户端 推送给某一个的消息格式{“isSystem”:false,“fromName”:“张三”,“message”“你好”} 系统消息格式{“isSystem”:true,“fromName”:null,“message”[“李四”,“王五”]} 4. 功能实现 4.1 创建项目导入相关jar包的坐标 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.17/versionrelativePath/ /parentgroupIdcom.lxx/groupIdartifactIdlxx_chat/artifactIdversion0.0.1-SNAPSHOT/versionnamelxx_chat/namedescriptionlxx_chat/descriptionpropertiesjava.version11/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.78/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project 4.2 引入静态资源文件 4.3 引入公共资源 pojo类 package com.lxx.pojo;import lombok.Data; //用于登陆响应回给浏览器的数据 Data public class Result {private boolean flag;private String message; }package com.lxx.pojo;import lombok.Data;Data public class User {private String userId;private String username;private String password; }package com.lxx.ws.pojo;import lombok.Data;//浏览器发送给服务器的websocket数据 Data public class Message {private String toName;private String message; }package com.lxx.ws.pojo;import lombok.Data;//服务器发送给浏览器的websocket数据 Data public class ResultMessage {private boolean isSystem;private String fromName;private Object message;//如果是系统消息是数组 }MessageUtils工具类 package com.lxx.utils;import com.alibaba.fastjson.JSON; import com.lxx.ws.pojo.ResultMessage;//用来封装消息的工具类 public class MessageUtils {public static String getMessage(boolean isSystemMessage, String fromName, Object message) {ResultMessage result new ResultMessage();result.setSystem(isSystemMessage);result.setMessage(message);if (fromName ! null) {result.setFromName(fromName);}return JSON.toJSONString(result);} }4.4 登陆功能实现 login.html !DOCTYPE html html langen headtitle登录/titlemeta nameviewport contentwidthdevice-width, initial-scale1/meta http-equivContent-Type contenttext/html; charsetutf-8/meta namekeywordscontentTransparent Sign In Form Responsive Widget,Login form widgets, Sign up Web forms , Login signup Responsive web form,Flat Pricing table,Flat Drop downs,Registration Forms,News letter Forms,Elements/script typeapplication/x-javascriptaddEventListener(load, function () {setTimeout(hideURLbar, 0);}, false);function hideURLbar() {window.scrollTo(0, 1);}/scriptlink relicon hrefimg/chat.ico typeimage/x-icon/link relstylesheet hrefcss/font-awesome.css/ !-- Font-Awesome-Icons-CSS --link relstylesheet hrefcss/login.css typetext/css mediaall/ !-- Style-CSS -- /headbody classbackground div classheader-w3lh1畅聊/h1 /div div classmain-content-agile idappdiv classsub-main-w3h2登录/h2form idloginFormdiv classicon1input placeholder用户名 idusername v-modeluser.username typetext//divdiv classicon2input placeholder密码 idpassword v-modeluser.password typepassword//divdiv classclear/divinput typebutton idbtn1 clicklogin value登录/div classicon1span iderr_msg stylecolor: red; {{errMessage}}/span/div/form/div /div div classfooterpxxx教育科技有限公司 版权所有Copyright 2006-2019 All Rights Reserved /p /div script srcjs/vue.js/script script srcjs/axios-0.18.0.js/script scriptnew Vue({el: #app,data() {return {errMessage: ,user: {username: ,password: }}},methods: {login() {axios.post(user/login, this.user).then(res {//判断登陆是否成功if (res.data.flag) {location.href main.html} else {this.errMessage res.data.message;}});}}}); /script /body /htmlUserController进行登陆逻辑处理 package com.lxx.controller;import com.lxx.pojo.Result; import com.lxx.pojo.User; import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpSession;RestController RequestMapping(user) public class UserController {/*** 登陆** param user 提交的用户数据包含用户名和密码* param session* return*/PostMapping(/login)public Result login(RequestBody User user, HttpSession session) {Result result new Result();if (user ! null 123.equals(user.getPassword())) {result.setFlag(true);//将数据存储到session对象中session.setAttribute(user, user.getUsername());} else {result.setFlag(false);result.setMessage(登陆失败);}return result;} } 4.5 获取当前登录的用户名 main.html页面加载完毕后发送请求获取当前登录的用户名 await axios.get(user/getUsername).then(res {this.username res.data;});UserController 在UserController中添加一个getUsername方法用来从session中获取当前登录的用户名并响应回给浏览器 /*** 获取用户名** param session* return*/GetMapping(/getUsername)public String getUsername(HttpSession session) {String username (String) session.getAttribute(user);return username;}4.6 聊天室功能 客户端实现 在main.html页面实现前端代码 !DOCTYPE html html langen headmeta charsetutf-8meta http-equivX-UA-Compatible contentIEedgemeta nameformat-detection contenttelephonenometa http-equivX-UA-Compatible contentIEedge,chrome1meta nameviewportcontentwidthdevice-width, initial-scale1.0, user-scalable0, minimum-scale1.0, maximum-scale1.0meta namemobile-web-app-capable contentyesmeta nameapple-mobile-web-app-capable contentyesmeta contentyes nameapple-mobile-web-app-capablemeta contentyes nameapple-touch-fullscreenmeta namefull-screen contentyesmeta contentdefault nameapple-mobile-web-app-status-bar-stylemeta namescreen-orientation contentportraitmeta namebrowsermode contentapplicationmeta namemsapplication-tap-highlight contentnometa namex5-orientation contentportraitmeta namex5-fullscreen contenttruemeta namex5-page-mode contentappbase target_blanktitle聊天室/titlelink hrefcss/bootstrap.min.css relstylesheet typetext/css/link relstylesheet hrefcss/chat.css /headbody img stylewidth:100%;height:100% srcimg/chat_bg.jpgdiv classabs cover contaniner idappdiv classabs cover pnldiv classtop pnl-head stylepadding: 20px ; color: white;div iduserName用户{{username}}span stylefloat: right;color: green v-ifisOnline在线/spanspan stylefloat: right;color: red v-else离线/span/divdiv idchatMes v-showchatMes styletext-align: center;color: #6fbdf3;font-family: 新宋体正在和 font face楷体{{toName}}/font 聊天/div/div!--聊天区开始--div classabs cover pnl-body idpnlBodydiv classabs cover pnl-left idinitBackground stylebackground-color: white; width: 100%div classabs cover pnl-left idchatArea v-showisShowChatdiv classabs cover pnl-msgs scroll idshowdiv classpnl-list idhists!-- 历史消息 --/divdiv classpnl-list idmsgs v-formessage in historyMessage!-- 消息这展示区域 --div classmsg guest v-ifmessage.toNamediv classmsg-rightdiv classmsg-host headDefault/divdiv classmsg-ball{{message.message}}/div/div/divdiv classmsg robot v-elsediv classmsg-left workerdiv classmsg-host photostylebackground-image: url(img/avatar/Member002.jpg)/divdiv classmsg-ball{{message.message}}/div/div/div/div/divdiv classabs bottom pnl-textdiv classabs cover pnl-inputtextarea classscroll idcontext_text keyup.entersubmit wraphardplaceholder在此输入文字信息...v-modelsendMessage.message/textareadiv classabs atcom-pnl scroll hide idatcomPnlul classatcom idatcom/ul/div/divdiv classabs br pnl-btn idsubmit clicksubmitstylebackground-color: rgb(32, 196, 202); color: rgb(255, 255, 255);发送/divdiv classpnl-support idcopyrighta hrefhttp://www.itcast.cn传智播客,版本所有/a/div/div/div!--聊天区 结束--div classabs right pnl-rightdiv classslider-container hide/divdiv classpnl-right-contentdiv classpnl-tabsdiv classtab-btn active idhot-tab好友列表/div/divdiv classpnl-hotul classrel-list unselectli classrel-item v-forfriend in friendsLista clickshowChat(friend){{friend}}/a/li/ul/div/divdiv classpnl-right-contentdiv classpnl-tabsdiv classtab-btn active系统广播/div/divdiv classpnl-hotul classrel-list unselect idbroadcastListli classrel-item stylecolor: #9d9d9d;font-family: 宋体v-forname in systemMessages您的好友{{name}} 已上线/li/ul/div/div/div/div/div/div /div script srcjs/vue.js/script script srcjs/axios-0.18.0.js/script scriptlet ws;new Vue({el: #app,data() {return {isShowChat: false,chatMes: false,isOnline: true,username: ,toName: ,sendMessage: {toName: ,message: },inputMessage: ,historyMessage: [/*{toName: 李四, message: 你好,张三},{toName: 李四, message: 在吗},{toName: 李四, message: 怎么不说话},{fromName: 张三, message: 你好,李四}*/],friendsList: [/* 李四,王五*/],systemMessages: [/*张三,李四*/]}},created() {this.init();},methods: {async init() {await axios.get(user/getUsername).then(res {this.username res.data;});//创建webSocket对象ws new WebSocket(ws://localhost/chat);//给ws绑定事件ws.onopen this.onopen;//接收到服务端推送的消息后触发ws.onmessage this.onMessage;ws.onclose this.onClose;},showChat(name) {this.toName name;//清除聊天区的数据let history sessionStorage.getItem(this.toName);if (!history) {this.historyMessage [];} else {this.historyMessage JSON.parse(history);}//展示聊天对话框this.isShowChat true;//显示“正在和谁聊天”this.chatMes true;},submit() {this.sendMessage.toName this.toName;this.historyMessage.push(JSON.parse(JSON.stringify(this.sendMessage)));sessionStorage.setItem(this.toName, JSON.stringify(this.historyMessage));ws.send(JSON.stringify(this.sendMessage));this.sendMessage.message ;},onOpen() {this.isOnline true;},onClose() {this.isOnline false;},onMessage(evt) {//获取服务端推送过来的消息var dataStr evt.data;//将dataStr 转换为json对象var res JSON.parse(dataStr);//判断是否是系统消息if (res.system) {//系统消息 好友列表展示var names res.message;this.friendsList [];this.systemMessages [];for (let i 0; i names.length; i) {if (names[i] ! this.username) {this.friendsList.push(names[i]);this.systemMessages.push(names[i]);}}} else {//非系统消息var history sessionStorage.getItem(res.fromName);if (!history) {this.historyMessage [res];} else {this.historyMessage.push(res);}sessionStorage.setItem(res.fromName, JSON.stringify(this.historyMessage));}}}});/script /body /html服务端代码实现 WebSocketConfig 类实现 package com.lxx.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;Configuration public class WebSocketConfig {Bean//注入ServerEndpointExporter自动注册使用ServerEndpoint注解的public ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();} }GetHttpSessionConfig 类实现 package com.lxx.config;import javax.servlet.http.HttpSession; import javax.websocket.HandshakeResponse; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpointConfig;public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {Overridepublic void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {HttpSession httpSession (HttpSession) request.getHttpSession();config.getUserProperties().put(HttpSession.class.getName(),httpSession);} }ChatEndpoint 类实现 package com.lxx.ws;import com.alibaba.fastjson.JSON; import com.lxx.config.GetHttpSessionConfig; import com.lxx.utils.MessageUtils; import com.lxx.ws.pojo.Message; import org.springframework.stereotype.Component;import javax.servlet.http.HttpSession; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap;ServerEndpoint(value /chat, configurator GetHttpSessionConfig.class) Component public class ChatEndpoint {//用来存储每一个客户端对象对应的Session对象private static final MapString, Session onlineUsers new ConcurrentHashMap();private HttpSession httpSession;/*** 建立websocket连接后被调用** param session*/OnOpenpublic void onOpen(Session session, EndpointConfig config) {//1将websocket.Session进行保存this.httpSession (HttpSession) config.getUserProperties().get(HttpSession.class.getName());String user (String) this.httpSession.getAttribute(user);onlineUsers.put(user, session);//2广播消息。需要将登陆的所有的用户推送给所有的用户String message MessageUtils.getMessage(true, null, getFriends());broadcastAllUsers(message);}public Set getFriends() {SetString set onlineUsers.keySet();return set;}private void broadcastAllUsers(String message) {try {//遍历map集合SetMap.EntryString, Session entries onlineUsers.entrySet();for (Map.EntryString, Session entry : entries) {//获取到所有用户对应的session对象Session session entry.getValue();//发送消息session.getBasicRemote().sendText(message);}} catch (Exception e) {//记录日志}}/*** 浏览器发送消息到服务端该方法被调用* p* 张三 -- 李四* 客户端 -- 服务端 {toName:李四,message:你好}* 服务端 -- 客户端 {isSystem:false,fromName:张三,message你好}** param message*/OnMessagepublic void onMessage(String message) {try {//将消息推送给指定的用户// {toName:李四,message:你好}Message msg JSON.parseObject(message, Message.class);//获取 消息接收方的用户名// 李四String toName msg.getToName();// 你好String sendMsg msg.getMessage();//获取消息接收方用户对象的websocket.Session对象Session session onlineUsers.get(toName);// 发送消息给接收方// 张三String user (String) this.httpSession.getAttribute(user);// {isSystem:false,fromName:张三,message你好}String msg1 MessageUtils.getMessage(false, user, sendMsg);session.getBasicRemote().sendText(msg1);} catch (Exception e) {//记录日志}}/*** 断开 websocket 连接时被调用** param session*/OnClosepublic void onClose(Session session) {//1,从onlineUsers中剔除当前用户的session对象String user (String) this.httpSession.getAttribute(user);onlineUsers.remove(user);//2,通知其他所有的用户当前用户下线了String message MessageUtils.getMessage(true, null, getFriends());broadcastAllUsers(message);} }
http://www.tj-hxxt.cn/news/220163.html

相关文章:

  • 北京手机网站建设外包wordpress 伪静态实现
  • 网站建设价格差异好大网站建设经济可行性
  • 温州公司做网站wordpress数据库说明
  • 兼职网站制作网站svg使用
  • 网站开发人员保密建网站做优化
  • 通州区网站建设公司公司网站管理制度
  • 北京通网站建设网站开发的数据
  • 广州网站开发哪家强百度网络营销的概念与含义
  • 建网站选哪个wordpress破解汉化版
  • n怎样建立自己的网站旅游景点网站模板大全
  • 创建自己的网站要钱吗腾讯云wordpress安装教程
  • 淄博云天网站建设推广河北中保建设集团网站
  • 电脑无法登录建设银行网站nginx安装wordpress
  • 黄骅网站建设价格百度竞价广告怎么收费
  • 香河做网站公司枣庄网站建设枣庄
  • 网博士智能建站做黄金理财的网站
  • 钓鱼网站搭建教程app开发公司资质
  • 做网站用的图标seo关键词选择及优化
  • 免费网站源码关键词优化难易
  • 做推文封面的网站电子商务行业的发展趋势
  • 淘宝网站优惠券统一修改怎么做建筑设计公司属于什么行业类别
  • 丰润网站建设手机网站建设专业服务公司
  • 中国互联网百强企业名单海东地区谷歌seo网络优化
  • 石家庄平山网站推广优化百度指数排名
  • 商标注册查询平台百度seo关键词优化排名
  • 做网站平台多少钱织梦网站修改使用教程
  • 哪些网站容易做做微网站的第三方登录界面
  • 东莞快速做网站wordpress博客视频教程
  • 产品网站策划广州网站建设方案维护
  • 做外贸用什么网站比较好巨野网站建设