基于Struts2和hibernate的WebSocket聊天室的实现教程六:界面原型及通信请求
2017-11-23 14:41
681 查看
当你看到这篇文章的时候,相信对点对点聊天室的后台结构已经了解的差不多了。这里我们将实现前端QQ的聊天界面效果,以及如何使用ajax和webSocket进行通信请求。
Intellij项目下载:
http://download.csdn.net/download/csu_passer/10125210
登录界面:这里我们登录了两个用户(google浏览器和firefox浏览器),可以看到有系统消息提示和在线列表展示
未连接用户时发送消息,将消息转发给自己
点击在线列表中的用户名,连接用户
用户下线通知
用户下线之后再发送消息
后台日志记录
至于为什么采用gif动态图展示效果而不是用网址自行演示,主要是因为我的服务器是腾讯云的Linux服务器。项目已经上传到服务器上去了,但是在测试的时候websocket连接请求一直被拒绝。可能是因为我的服务器还没有开启这部分协议吧—-后来又有各种事情也就搁置了。
总的css代码量不是很多,也就300多行。
先看一下Html布局:
剩余的CSS:
请求成功后 开始与后台建立websocket连接 此时会在后台进行httpSession和websocket session获取
建立ws连接以后 接受来自后台的json数据 并且判断是在线列表数据还是聊天数据
聊天数据也要判断是不是系统消息
绑定发送消息的方法
然后在聊天记录框中显示自己的消息 、系统消息、对方发过来的消息
加载背景音乐的方法也很简单 直接调用系统自带的play方法
有难度的是如何在光标处插入表情
IE用
非IE
Intellij项目下载:
http://download.csdn.net/download/csu_passer/10125210
效果演示
打开界面,请求输入用户名(登录凭证)登录界面:这里我们登录了两个用户(google浏览器和firefox浏览器),可以看到有系统消息提示和在线列表展示
未连接用户时发送消息,将消息转发给自己
点击在线列表中的用户名,连接用户
用户下线通知
用户下线之后再发送消息
后台日志记录
至于为什么采用gif动态图展示效果而不是用网址自行演示,主要是因为我的服务器是腾讯云的Linux服务器。项目已经上传到服务器上去了,但是在测试的时候websocket连接请求一直被拒绝。可能是因为我的服务器还没有开启这部分协议吧—-后来又有各种事情也就搁置了。
前端界面分析
前端界面初看起来布局十分简单,但是这里面也是蕴含了部分有趣的知识的。为了便于复用和兼容,我们尽量使用css来实现以前需要用Js才能实现的效果。总的css代码量不是很多,也就300多行。
先看一下Html布局:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>仿QQ在线聊天室</title> <link href="resource/css/QQ.css" rel="stylesheet" type="text/css"/><!--导入css样式--> <script type="text/javascript" src="resource/js/jquery.js"></script><!--导入js文件--> <script type="text/javascript" src="resource/js/socket.js"></script> </head> <body> <div class="loading"> 加载中... <img src="resource/images/icon/loading.gif" alt="loading"> </div><!--页面加载动画--> <main class="flex hide"><!--html5实义标签--> <div class="flex personal-info"> 个人信息--样式待定 </div> <div class="flex chat-room"> <div class="flex chat"> <div class="flex records-area"> <div class="flex left-center to-who"> p2p聊天室欢迎你! </div> <div class="records"><!--聊天记录区域--> </div> </div> <div class="flex text-area"> <!--绝对定位选择气泡--文本---表情--> <div class="flex helps"> <div class="text-tips"> 字体工具栏 </div> <div class="flex center-center texts" title="字体选择工具栏"> </div> <div class="flex center-center expressions" title="选择表情"> <div class="expressions-list"> <!--表情,支持动态加载,可从数据库导入--> <img class="expression" src="resource/images/expression/angry.png" data-name="/sq" title="/生气"/> <img class="expression" src="resource/images/expression/smile.png" data-name="/wx" title="/微笑"/> <img class="expression" src="resource/images/expression/anguished.png" data-name="/jy" title="/惊讶"/> <img class="expression" src="resource/images/expression/blush.png" data-name="/ka" title="/可爱"/> <img class="expression" src="resource/images/expression/confused.png" data-name="/yw" title="/疑问"/> <img class="expression" src="resource/images/expression/grin.png" data-name="/lzx" title="/咧嘴笑"/> <img class="expression" src="resource/images/expression/grinning.png" data-name="/dx" title="/大笑"/> <img class="expression" src="resource/images/expression/heart_eyes.png" data-name="/se" title="/色"/> <img class="expression" src="resource/images/expression/kissing_heart.png" data-name="/an" title="/爱你"/> <img class="expression" src="resource/images/expression/mask.png" data-name="/gm" title="/感冒"/> <img class="expression" src="resource/images/expression/pensive.png" data-name="/sx" title="/伤心"/> <img class="expression" src="resource/images/expression/relaxed.png" data-name="/fs" title="/放松"/> <img class="expression" src="resource/images/expression/sunglasses.png" data-name="/ku" title="/酷"/> <img class="expression" src="resource/images/expression/wink.png" data-name="/zy" title="/眨眼"/> <img class="expression" src="resource/images/expression/yum.png" data-name="/kx" title="/开心"/> </div> </div> </div> <!--组合键--> <!--聊天文本输入区域--> <div class="text-input" id="text-input" contenteditable="true" onkeypress="if (event.keyCode==13){ sendText();return false;}" title="聊天区域"></div> <div class="flex button"> <button>关闭</button> <button onclick="sendText()">发送</button> </div> </div> </div> <div class="flex online-users"><!--在线列表--> <p class="tips" title="点击用户即可连接聊天">在线列表</p> <div class="flex online-users-list"> </div> </div> </div> </main> <!--发送消息和接收消息 背景声音提示--> <audio id="receive"> <source src="resource/audio/receive.wav" type="audio/wav"> </audio> <audio id="send"> <source src="resource/audio/send.wav" type="audio/wav"> </audio> <!--聊天记录展示--> <div class="history"> <div class="history-loading"> 加载中... <img src="resource/images/icon/loading.gif" alt="loading"> </div> </div> </body> <script type="text/javascript"> var host = window.location.host; var socket = null; var me=""; var self; $(document).ready(function() { me = prompt("请输入您的名称:", ""); while (me == "" || me == null) { me = prompt("请输入您的名称:", ""); } //登录 $.ajax({ type : "GET", //提交方式 url : "user/login?username="+me,//测试路径 async:false, beforeSend: function () { console.log("准备发送登录请求...") }, complete: function () { $(".loading").remove(); $("main").removeClass("hide"); }, success : function(result) {//返回数据根据结果进行相应的处理 console.log(result); if (result.code==200){ //请求ws显示在线列表 var url = "ws://"+host+"/chatRoom/null"; loadWS(url); } }, //异常处理 error:function (XMLHttpRequest, textStatus, errorThrown) { console.log(XMLHttpRequest+"---"+textStatus+"---"+errorThrown) } }); }); function loadWS(url) { socket = getSocket(url); bindMethod(socket); socket.onmessage=function (e) { var data= $.parseJSON(e.data); console.log(data); //判断是在线列表还是聊天记录 if(data.content==null){ $(".online-users-list").empty(); $.each(data,function (index, item) { if (item.name==me){ self=item;//将对象保存 } displayOnlineUsers(item) }) }else if (data.sender.avatar=="000"){ displaySystemRecords(data.content,data.time); }else{ loadBgMusic("receive"); addRecordsFromUser(data.sender,data.content); } }; } $(".texts").click(function () { if ($(".text-tips").css("display")=="none"){ $(".text-tips").css("display","block"); }else{ $(".text-tips").css("display","none"); } }); /** * 发送消息 */ function sendText() { var msg = $(".text-input").html(); console.log(msg); if (!isNull(msg)&&socket!=null) { addSelfChatRecords(self,msg); //发送消息 loadBgMusic("send"); socket.send(msg); } $(".text-input").html("");//清空输入框 } /** * 显示自己发送的消息 * @param msg 消息 * @param user 发送者 */ function addSelfChatRecords(user,msg) { var self="<div class='row'>"+ "<div class='flex right'>"+ "<div class='bubble'>"+msg+"</div>"+ "<img class='avatar' src='"+user.avatar+"' alt='头像'>"+ "</div>"+ "</div>"; $(".records").append($(self)); $(".records").scrollTop($(".records").scrollHeight) } /** * 显示对方发送过来的消息 * @param user * @param chats */ function addRecordsFromUser(user, chats) { var msg="<div class='row'>"+ "<div class='flex left'>"+ "<img class='avatar' src='"+user.avatar+"' alt='头像'>"+ "<div class='bubble'>"+chats+"</div>"+ "</div>"+ "</div>"; $(".records").append($(msg)); $(".records").scrollTop($(".records").scrollHeight) } /** * 显示在线列表---并且绑定连接函数 */ function displayOnlineUsers(user) { var str = "<div class='flex left-center users'> "+ "<img class='avatar' src='"+user.avatar+"' alt='头像'>"+ "<a href='#!' class='user-link' data-name='"+user.name+"'>"+user.name+"</a>"+ "</div>"; $(".online-users-list").append($(str)); $(".user-link").bind('click',function () { var name = $(this).attr("data-name"); Log("关闭当前连接,连接target:"+name); socket.close(); var url = "ws://"+host+"/chatRoom/"+name; $(".to-who").text(name); loadWS(url); }) } /** * 加载系统消息 */ function displaySystemRecords(content,time) { var str = "<p class='sys-records'>系统消息:"+content+" "+(time.month+1)+"月"+time.date+"号 "+time.hours+":"+time.minutes+":"+time.seconds+"</p>"; $(".records").append($(str)); $(".records").scrollTop($(".records").scrollHeight) } /** * 加载背景音乐 * @param id */ function loadBgMusic(id) { var audio = document.getElementById(id); audio.play(); } /** * 获取插入光标的位置,在光标处添加表情 */ $(".expression").click(function () { if (!$("#text-input").is(":focus")){ $("#text-input").focus();//如果文本编辑器没有获取焦点则自动获取 } var emoj = "<img class='expression' src='"+$(this).attr('src')+"' data-name='"+$(this).attr('data-name')+"' title='"+$(this).attr('title')+"'/>"; var editor = document.getElementById("text-input"); var cursorPosition=-1; if(document.selection && document.selection.createRange){//IE浏览器 var range = document.selection.createRange(); range.moveStart("character",-editor.innerText.length); range.pasteHTML( emoj ) ; }else{//非IE cursorPosition= editor.selectionStart; // // var str = editor.innerText.substr(0,cursorPosition-1); // var str1=editor.innerText.substr(cursorPosition); document.execCommand( 'InsertHtml' , '' , emoj );//会插入到哪里 } }); /** * 判断字符串是否全由空格组成 * @param str * @returns {boolean} */ function isNull( str ){ if ( str == ""||str==null ) return true; var regu = "^[ ]+$"; var re = new RegExp(regu); return re.test(str); } </script> </html>
css布局实现
定义了几个常用的全局属性和css类,比如flex@charset "UTF-8"; *{ margin:0; padding:0; font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif; transition: all 0.5s; box-sizing: border-box; } ::selection{ background: #000000; color: #ffffff; } input{ background: transparent; padding:5px; } *:focus{ outline: none;/*消除谷歌浏览器控件选中时的边框*/ } /*以下修改标签的默认样式*/ a{ text-decoration: none; color: #000; } a:hover{ color: #fc311e; } button{ border:1px solid #eee; padding:5px 10px; color: #000; background: #ffffff; } button:hover{ background-color: #3d9cd4; color: #ffffff; } .flex{ display: flex; flex-wrap: wrap; }/*定义flex布局*/ /*下面定义几种对齐方式*/ .center-center{ justify-content: center; align-items: center; align-content: center; } .left-center{ justify-content: flex-start; align-items: center; align-content: center; } /*圆形头像样式*/ img.avatar{ width:50px; height: 50px; border-radius:50%; object-fit: cover;/*图片覆盖填充*/ }
剩余的CSS:
main{ width:70%; min-height:600px; /*padding:20px;*/ margin:20px auto; border:1px solid rgba(0,0,0,.15); box-shadow: 0 0 10px 2px rgba(0,0,0,.2); background: #fcfcfc; } .hide{ display: none !important; } .loading{ width:100px; height:50px; margin:100px auto; } .personal-info{ padding:20px; width:20%; height:inherit; background-color: #8fd499; } .chat-room{ width:80%; height:inherit; } .chat{ width:80%; flex-direction: column; } .chat .records-area{ width:100%; height:80%; flex:0 0 auto; flex-direction: column; align-items: flex-start; border-bottom: 1px solid #e8e8e8; } .chat .records-area .to-who{ width:100%; flex:0 0 auto; height:80px; padding:20px; border-bottom: 1px solid #eeeeee; } .chat .records-area .records{ width:100%; flex:1 0 auto; max-height:390px; overflow-y: auto; /*background-color: #d4582d;*/ } .chat .records-area .records .sys-records{ padding:0 10px; color: #7f7f7f; font-size:14px; } .chat .text-area{ width:100%; padding: 5px 0; flex:1 0 auto; flex-direction: column; position: relative; } .chat .text-area .helps{ height:25px; padding:0 10px; flex:0 0 auto; position: relative; } .chat .text-area .helps>div{ width:24px; margin-right: 5px; background: center no-repeat; background-size: contain; } .chat .text-area .helps>div:not(:first-child):hover{ background-color: rgba(0,0,0,.1); } /*字体选择工具栏*/ .chat .text-area .helps .text-tips{ position: absolute; top:-120%; left:0; display: none; width:100%; height:30px; line-height:30px; } .chat .text-area .helps .texts{ background-image: url("../images/expression/font.png"); } .chat .text-area .helps .expressions{ background-image: url("../images/expression/expression.png"); position: relative; } .chat .text-area .helps .expressions:hover .expressions-list{ display: flex; } .chat .text-area .helps .expressions .expressions-list:hover{ display: flex; } .chat .text-area .helps .expressions .expressions-list{ display: none; position: absolute; left:0; width:200px; height:100px; background: #deffeb; border:1px solid #eeeeee; transform: translateY(-60%); overflow-y: auto; flex-wrap: wrap; justify-content: flex-start; } img.expression{ display: inline; width:30px; height:30px; border-radius:50%; object-fit: contain; background-color: rgba(0,0,0,.1); } .chat .text-area .text-input{ flex:1 0 auto; border:none; font-size:14px; padding:0 10px; overflow-y: auto; border-radius: 4px; /*background-color: hsla(0,0%,71%,.1);*/ background-color:transparent; resize: none; display: inline-block; vertical-align: top; outline-style: none; } .chat .text-area .button{ height: 30px; padding:0 10px; flex:0 0 auto; justify-content: flex-end; } .chat .text-area .button button{ width:80px; background-color: #8fd499; margin-left:5px; } .online-users{ width:20%; height:inherit; flex-direction: column; background-color: #d4c38d } .online-users .tips{ flex: 0 0 auto; padding:20px; height:50px; border-bottom: 1px solid #eeeeee; cursor: default; } .online-users .online-users-list{ width:100%; padding-top:10px; flex: 1 0 auto; max-height:500px; flex-direction: column; overflow-y: auto; } .online-users .online-users-list .users{ width:100%; padding:0 10px; margin-bottom: 20px; height:50px; text-overflow:ellipsis; white-space:nowrap; overflow:hidden; } .online-users .online-users-list .users img{ margin-right:10px; } .online-users .online-users-list .users a{ width:70px; } /*聊天气泡*/ .row{ width:100%; min-height:60px; padding:10px; } .row>div{ height:inherit; } .left{ justify-content: flex-start; } .right{ justify-content: flex-end; } /*气泡*/ .bubble{ max-width:40%; font-size: 14px; border-radius:8px; padding:0 10px; margin:0 12px; background: #7ac2ff; border:1px solid #7ac2ff; line-height: 14px; display: flex; justify-content: flex-start; flex-wrap: wrap; align-items: center; /*align-content: center;*/ position: relative; } .right .bubble:after{ content: ''; position: absolute; right:0; top:12%; transform: translateX(100%) translateY(0%); width:0; height:0; border: 8px solid transparent; /*float: right;*/ /*transform: translateX(60%) translateY(-20%);*/ border-left-color: inherit; } .left .bubble:before{ content: ''; width:0; height:0; border: 8px solid transparent; position: absolute; left:0; top:10%; transform: translateX(-100%) translateY(0%); border-right-color: inherit; }
js解释
在页面加载的时候询问登录名称 向后台发送登录请求请求成功后 开始与后台建立websocket连接 此时会在后台进行httpSession和websocket session获取
建立ws连接以后 接受来自后台的json数据 并且判断是在线列表数据还是聊天数据
聊天数据也要判断是不是系统消息
绑定发送消息的方法
然后在聊天记录框中显示自己的消息 、系统消息、对方发过来的消息
加载背景音乐的方法也很简单 直接调用系统自带的play方法
有难度的是如何在光标处插入表情
IE用
非IE
相关文章推荐
- 基于Struts2和hibernate的WebSocket聊天室的实现教程三:Hibernate个人信息管理
- 基于Struts2和hibernate的WebSocket聊天室的实现教程五:聊天机制
- 基于Struts2和hibernate的WebSocket聊天室的实现教程四:实现登录接口
- 基于Struts2和hibernate的WebSocket聊天室的实现教程一:环境搭建
- 基于Struts2和hibernate的WebSocket聊天室的实现教程二:发送在线列表
- web即时通信2--基于Spring websocket实现web聊天室
- web即时通信2--基于Spring websocket实现web聊天室
- 基于websocket实现的web聊天室
- 一个基于webSocket实现前后端通信的小demo
- 基于HTML5和Tomcat WebSocketServlet的聊天室简单实现
- 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。
- 基于struts2和hibernate实现登录和注册功能
- JAVA基于websocket实时通信的实现—GoEasy
- 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。
- php+html5基于websocket实现聊天室的方法
- Golang基于websocket实时通信的实现—GoEasy
- 基于HTML5和Tomcat WebSocketServlet的聊天室简单实现
- PHP基于websocket实时通信的实现—GoEasy
- Unity3D教程:实现基于Socket通讯的公共聊天室
- Ruby基于websocket实时通信的实现—GoEasy