python2.0_day22_web聊天室二
上节内容已经实现了客户端使用长轮询的方式获取消息的功能.
但是还没有展现到前端.本节内容将实现
1.展现消息到前端窗口.
2.客户端之间发送图片和文件.
3.文件上传时显示进度条 下面我们来实现上面3个功能.
1.展现消息到前端窗口.在展示前我们要解决一个问题.
问题1:我们先看看前端现在虽说能点击左边好友列表,发送消息给选择的好友,但是右边的消息窗口却一直不变.
如下.我给大神发一个111, 显示在这个window窗口,我在给小雨发一个 还是显示在这个窗口.这个肯定是不对的.应该实现得像webQQ和微信一样.点击到指定好友时,只显示和这个好友的消息纪录.
引入
和
那么我们先来解决这个问题
后端实现思路: 1.将所有的消息存到数据库里,切换到指定用户的时候,从数据库里把消息展示出来.这种方式是后台做的.对于聊天好像不太实用,占用空间.
前端实现思路: 1.为每一个好友创建一个消息窗口的div,默认都是hide隐藏.当选择指定的好友时,removeClass(hide)即可.这种方式可以,实现起来也不难.
2.使用jquery中的data.每一个元素有一个data属性,可以给data属性设置值也可以取 data属性的值.如图
引入
这种方式可以使用.老师觉得这个data属性有些鸡肋!为什么说是鸡肋呢?因为你都用了jquery了,使用给消息窗口这个div元素设置data属性.存储 用户id:聊天内容 ,这个和创建一个字典没有任何区别.
3. 在js中创建一个全局字典.存储 消息类型:用户id:聊天内容 ,切换不同好友的时候,先把现有的消息内容dump到字典,然后loads 新好友的内容.
我们就采用前端实现思路的第3种方式. 在js中创建一个字典.
那么问题来了,从哪里入手.
当然从请求源开始.点击切换用户的函数.
我们看这个函数要做哪些?如图
功能是要实现如上图,但是顺序要调整下.我们应该在更改title之前把消息存起来.所以合理的函数应该是下面这样的.
结构理清楚了.开始实现.
现写一个全局字典,字典写到哪里都行.这里我们就写在$(document).ready(function{}) 的上面,如图:
接下来先把老的信息存到这个全局字典.新的消息取出来.
代码实现如图:
这时候我们来访问测试下:
和
这样我们就解决了问题1了.下面我们就把接收到的消息展示在前端
首先看下现在收到消息的处理方法:
function GetNewMsgs(){
$.getJSON("{% url 'get_new_msgs' %}",function(callback){
console.log(callback);
GetNewMsgs();
});
}
只是打印.现在前端看下:
所以我们展示数据要有以下几步:
1.遍历上图中array[3]这个数组
2.分析每一个object里的from
3.判断如果from消息来源是我正在聊的对象也就是chat-box-window正在打开的对象,就把消息append到chat-box-window的html中
如果不是正在打开的聊天对象,那么就把消息append到全局字典消息from来源的ID下.
4.在消息展示之前还要把每一个object拼接成html的代码.
就是把饭回来的object 字典,整理成html代码
鉴于把object字典整理成html代码,需要一定的代码量,那我们就把这个写成一个函数.叫做ParseNewMsgs(),于是GetNewMsgs()函数如下:
上图说是for循环字典,其实不是的,这里后端返回来的是一个object的列表.for循环列表时取到的是下表
我们这里要温故下html中for循环的知识了.自己看
最终代码如下
然后前端接收信息看下结果如图:
接下来就是把拼接html.
我们先处理正在聊天对象发过来的消息拼接.代码如图:
我们先来测试下:
我们看上图聊天已经展示到消息窗口了,但还存在上图所述问题.
除了上面的问题,你如果是在windows下进行测试,会经常出现一方发给另外一方能收到,而另外一方发给你收不到.
查看后台你会发现一个规律,页面刷新一次,然后在发送消息,后台就会有断开报错.报错原因就是socket断开了,你在发送消息.
这个原因可能是windows,具体不详.记住就好.在Linux下没有这种问题.
我们来看看前端代码改的两处. 下面我们来拼接处理,不是正在聊的对象,如何把消息存储在全局字典里.
我们测试看下结果:
首先大神的账户和小雨聊.这时候说明大神聊天的对象不是"测试账户",如图
在用测试账户给大神发信息如图:
这时候大神的账户把聊天对象切换到测试账户,看看能不能收到消息,如图
我们看成功了.那么我们还要实现一个功能,就是显示新消息的个数.如图:
实现思路:
<li contact-type='single' contact-id='{{friend.id}}' onclick="OpenChatWindow(this)" class="list-group-item">
<span class="badge">14</span>
<span class="contact-name">{{friend.name}}</span>
</li>
我们可以把 <span class="badge">14</span> 默认添加hide隐藏样式,另外把缺省14改成0.
我们找到了元素,记得是元素,不是docment对象,所以不能是使用jquery的方法.要把找到的元素变成docment对象,之前我们用过就是加上$()即可
于是我们可以这样实现:
你可能会问既然元素都找到了,为啥还要转换成docment类呢?
因为我们要用的不是这个li元素 ,而是li元素下的span元素,我们要对这个元素进行更改.
我们总结下:
var li_ele = $(".list-group li[contact-type='single']").filter("li[contact-id='3']")[0]
$(li_ele).find(".badge")
我们接下来就是对这找到的内容进行操作.
接下来我们发送测试看看效果.
至此消息数量的提示已经完成.但是当我们切换有消息的好友的时候,是不是应该把消息数从新改成 hide并且数量改成0.
因此我们应该修改OpenChatWindow()函数来实现
接下来测试如下:
和
至此单对单的聊天的几本功能实现了,下面我们来实现下群组聊天是该如何实现?
群组聊天和单人聊天有什么不一样.
后台,处理后发给群里所有人
前端,收消息时前端展示时逻辑有些不一样
我们1对1 时,消息展示在好友处是根据后台返回的object 字典里的from id取到的.
而群组我们就不能根据from id来取了.而是根据to 的id来取到群组的id,from只是发消息的人.
因此我们改动两处,1,是sendmsg调用的后台视图函数send_msg.
2.是前端获取消息里的消息拼接处理方法
function GetNewMsgs(){
$.getJSON("{% url 'get_new_msgs' %}",function(callback){
console.log(callback);
ParseNewMsgs(callback); //重点是要改这个函数
GetNewMsgs();
});
}
我们先来修改后台的视图函数,我们先看看现在send_msg视图函数是怎么处理消息的.
我们把视图函数修改成如下:
后端的视图函数就做这些修改.
接下来就是前端取数据了.
前端取数据需要注意的就是 消息object里的key to是消息展示的位置.from只是显示在群租聊天框的人员姓名.
我们先看下目前的消息处理函数
于是把前端函数改成如下:
下面我们进行测试
至此分组聊天的功能我们已经实现了.
但是有一个问题我们要解决,就是在消息框中显示的发消息的人是ID而不是人员名称。这里要改成人员名称。
简单,我们可以在发送消息时,消息字典里加入发送人员的from_name属性。
如下:
然后,前端在拼接消息时也修改如下:
上面的问题解决了,几本是可以聊天了,但是实际测试下 来感觉会丢失消息,原因可能是socket的也可能是长轮询的方式有点问题,具体没有深入研究。
先不管,我们在来实现一个功能,文件上传.
思路: 上传用post 用ajax .后台处理的URL和和处理消息的URL是同一个。为什么可以是同一个。因为对于用户来说都是发送消息。
那么我们就要修改后台处理get_msgs()函数了。判断前端传来的是图片还是文本信息。如果是文本就不用说了,存到队列中。
如果是图片那么就把图片的url存到信息中。为了好判断是图片还是文本,我们就在object消息字典中再加一个key,来表示发送消息到底是什么类型。 那么我们开始动手,顺序依然是从请求源开始。 触发这个上传文件请求的是哪里。是在消息页面中。我们想图片就不在消息里写入了。我们在emoj处写一个文件上传的前端代码。
如图:
代码如下:
显示的样式很不好看,如下:
看到小图标的样式了把,但是上面加了input的样子很丑,jquery里肯定有具有input type="file"的代码,并且好看点的。
我们稍微调整下,让它不那么难看,然后在实现功能。
然后在看看样子:
然后把上面代码加上onclock事件
<div class="chat-box-emoj">
<!--emoj-->
<div class="col-md-3">
<input name="filename" type="file">
</div>
<div class="col-md-2">
<span class="glyphicon glyphicon-upload" onclick="FileUpload()"></span>
</div>
</div>
接下来我们就来写 FileUpload()函数,写之前我们来会想下:
我们在bbs系统里上传图片用的form表单。form表单会有一个问题,就是上传成功后会刷新页面。
这里我们当然不希望它刷新页面了。那么应该怎么办?就是不用form表单二用ajax异步提交文件。
什么是ajax异步提交文件。之前ajax不支持提交文件。那时候采用在页面用一个afreem,就是在页面里搞一个其他页面框架,内连东西。这个内连框架和服务器端保持长连接,总之浪费资源又恶心。
但是现在jquery的ajax支持异步传输文件了。
我们就把下面这段代码作为,ajax异步上传文件的范例记住。不会就来找把。
在写之前,我们来回忆下,之前在使用form上传文件时,前端form又两点需要注意的:1.必须是post形式才能上传文件 2。必须又一个enctype="multipart/form-data" 才能进行文件上传。
如图:
同样我们用ajax上传是不是也要又这两个限制条件?是的,顺便我们来说明下ajax如何实现异步文件上传的。
首先我们知道form是可以上传文件的。那么ajax实现文件上传的思路就是,在js中实例化一个form对象,把相关数据都塞进这个form实例中。
然后在通过ajax把这个form对象传到服务器上。
于是范例代码如下:
看看上图,思路是不是清晰了很多
下面我们来看看到底塞进formdata实例中的是什么东西。
首先要知道 $("#file_test")其实查找的是input type="file"这个标签。所以我们先给之前代码的input加一个id="file_upload"
<input id="file_upload" name="filename" type="file">
然后访问,打印下看看到底是个什么东西,
就是把上面的对象给放到formdata实例里。
上图内容要仔细看了。对于理解后面的操作有帮助。
我们在看下ajax异步上传文件代码中有一句需要理解的:
而上面我们提到的form表单提交后台的两个条件。就是通过下图中的两处实现的。你就记住这是必须加的
最终前端ajax上传文件的代码如下:
function UploadFile(){
var formDate = new FormData();
console.log($("#file_upload")[0].files[0]);
formDate.append('file',$('#file_upload')[0].files[0]); $.ajax({
url: "{% url 'file_upload' %}",
type: 'POST',
data : formDate,
processDate: false, //tell jQuery not to process the data
// 默认提交的post或者get请求会把后面的参数压缩成url参数专用的urlinto的格式,然后发送给后台。
// 但是我们这里发送的是文件,所以就上面的设置就告诉浏览器不用压缩了
contentType: false, //tell jQuery not to set contentType
// 不要加什么请求头,说白了就是原来是什么样就是什么样,不要给formDate加其他内容了。
success: function(data){
console.log(data);
//alert(data);
}
});
}
这个时候你就通过ajax提交了,提交后后台如何处理呢?必定它和form 提交的方式不一样。
下面是不是该修改URL了, 请求源 -> url -> 视图函数 -> 前端html
urlpatterns = [
# url(r'^$/', views.acc_login,name='login' ), 这种写法错误,r'^$/'要改成r'^$'
url(r'^$', views.dashboard,name='chat_dashboard' ),
url(r'^msg_send/$',views.send_msg,name='send_msg' ),
url(r'^new_msgs/$',views.get_new_msgs,name='get_new_msgs' ),
url(r'^file_upload/$',views.file_upload,name='file_upload' ),
]
然后在views.py中写一个file_upload视图
def file_upload(request):
print(request.POST)
return HttpResponse('dddddd')
先上传一个文件,查看下打印结果:
function UploadFiles(){
var formData = new FormData();
console.log($('#file_upload')[0].files[0]);
formData.append('file',$('#file_upload')[0].files[0]);
$.ajax({
url: "{% url 'file_uploads' %}",
type: 'POST',
data : formData,
processDate: false, //tell jQuery not to process the data
contentType: false, //tell jQuery not to set contentType
success: function(data){
console.log(data);
//alert(data);
}
});
}
结果我们测试有报错,chrome报错如下:
火狐浏览器报错如下:
按照火狐浏览器报出的错误查找到一片文章如下: 平时做表单都是跳转提交的,但是今天要做一个ajax图片异步上传, 网上搜索了下,方法都比较老了,居然还有用flash的, 普通的表单上传通过jquery的serialize()转换成querystring后就可以直接ajax post 上传,但是碰到文件上传就不奏效了,型号html5有个方法FormData()可以实现上传, 我写的代码如下: function upThumbSubmit() {
if(!window.FormData) {
alert('your brower is too old');
return false;
}
var formData = new FormData($( "#upForm" )[0]); $.ajax({
url:'?c=api&a=upload',
type:'post',
data:formData,
dataType:'json',
success:function(data){
alert(data);
return false; }
}); } 但是报错了,错误如下 TypeError: 'append' called on an object that does not implement interface FormData. 既然浏览器明明显示支持formdata,为何这里显示append不是formdata接口呢? 答案只可能是jquery重载了formdata 在里面加上2个option,就好了,正确代码如下 function upThumbSubmit() {
if(!window.FormData) {
alert('your brower is too old');
return false;
}
var formData = new FormData($( "#upForm" )[0]); $.ajax({
url:'?c=api&a=upload',
type:'post',
data:formData,
processData: false,
contentType: false,
dataType:'json',
success:function(data){
alert(data);
return false; }
}); }
才发现自己写错了,如下:
这个小错误,我整了3小时。
还好解决了,更改后,上传文件测试,看看后台打印什么?
结果为空,那是不是ajax没把文件传过来。当然不是,是文件不能用request.POST获取,而是用request.FILES
更改视图函数如下:
def file_upload(request):
print(request.POST,request.FILES)
print("22222")
return HttpResponse('dddddd')
在此上传打印如下:
我们看文件句柄已经传给后台了。那么接下来就修改视图函数把文件存下来就行了。
def file_upload(request):
print(request.POST,request.FILES)
file_obj = request.FILES.get('file')
new_file_name = "uploads/%s"%file_obj.name
with open(new_file_name,"wb+") as new_file_obj:
for chunk in file_obj.chunks():
new_file_obj.write(chunk)
return HttpResponse('--upload success---')
后台异步接收文件,请参照《python2.0_day21_bbs系统评论自动加载+文章创建》一节中的解释。
然后我们前端上传,看看后端uploads目录下有没有该文件。如图
哈哈,文件已经上传成功了。
现在是实现了异步上传文件。但是我们是不是想看到文件上传的进度。如何实现呢?
接下来还有两个功能,一个是上传文件的进度条显示,
一个是把图片显示到聊天窗口,这里不想看了。2周后再补上。因为我已经等不及看主机管理章节了。因为那是我现在能用到的
废话不多说,咱开始。
python2.0_day22_web聊天室二的更多相关文章
- python2.0_day21_web聊天室一
bbs系统项目中我们用到的ajax不多,但是在聊天室里用到的全是ajax,所以本项目的主要内容就是:前端使用ajax传输json格式的数据是本节的重点以及 前端函数的的使用.http协议的特点是:短链 ...
- python2.0_s12_day21_web聊天室一
本节内容: 项目实战:开发一个WEB聊天室 功能需求: 用户可以与好友一对一聊天 可以搜索.添加某人为好友 用户可以搜索和添加群 每个群有管理员可以审批用户的加群请求,群管理员可以用多个,群管理员可以 ...
- python tornado websocket 多聊天室(返回消息给部分连接者)
python tornado 构建多个聊天室, 多个聊天室之间相互独立, 实现服务器端将消息返回给相应的部分客户端! chatHome.py // 服务器端, 渲染主页 --> 聊天室建立web ...
- 三种TCP协议聊天室实现
一 概述 使用Java的IO实现聊天室 使用Java的NIO实现聊天室 使用Netty实现聊天室 二 IO聊天室 1 服务器 public class IOServer { public static ...
- ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。
上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取) 上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容 ...
- [Java聊天室server]实战之二 监听类
前言 学习不论什么一个稍有难度的技术,要对其有充分理性的分析,之后果断做出决定---->也就是人们常说的"多谋善断":本系列尽管涉及的是socket相关的知识,但学习之前,更 ...
- Java Socket聊天室编程(二)之利用socket实现单聊聊天室
这篇文章主要介绍了Java Socket聊天室编程(二)之利用socket实现单聊聊天室的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 在上篇文章Java Socket聊天室编程(一)之 ...
- Netty入门(二)之PC聊天室
参看Netty入门(一):Netty入门(一)之webSocket聊天室 Netty4.X下载地址:http://netty.io/downloads.html 一:服务端 1.SimpleChatS ...
- Netty 仿QQ聊天室 (实战二)
Netty 聊天器(百万级流量实战二):仿QQ客户端 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之15 [博客园 总入口 ] 源码IDEA工程获取链接:Java 聊天室 实战 源码 写在 ...
随机推荐
- FreeRTOS基础篇教程目录汇总
以下教程(大部分章节)(尤其理论介绍部分)转载自安富莱电子,官网链接: http://forum.armfly.com/forum.php 然后根据安富莱的教程自己做了分析和测试,希望大家共同进步. ...
- python 调用函数 / 类型转换 / 切片/ 迭代
调用函数 / 类型转换 / 切片/ 迭代 1. 调用函数:abs(),max(),min() 2. 数据类型转换:int(),float(),str(),tool(),a=abs, 3. 定义函数, ...
- java资料——数据结构(转)
数据结构 (计算机存储.组织数据方式) 数据结构是 ...
- u-boot中网口处理--硬件部分
1. 网口硬件方案: AT91SAM9G10 + DM9000CEP: DM9000CEP为MAC+PHY解决方案,与MCU链接通过8位或16位数据总线. 内部SRAM为16Kbyte. 2. DM ...
- Unity3d修炼之路:GUIbutton简单使用,完毕对一个简单对象Cube的移动,旋转
#pragma strict private var m_pCubeObj : GameObject = null; private var m_pMeshFilter : MeshFilter = ...
- QML vs WEB
UI领域, 如果是桌面应用,QML可以更快速.如果是手机UI,H5绝对占优. 移动设备已经为各行业的HMI的响应性和用户友好性设定了标准.汽车,医疗设备,工业自动化系统和消费电子产品制造商现在希望为其 ...
- Mac中Java 配置maven及阿里云镜像
一:配置maven 1.下载maven,选择Binary tar.gz,解压拷贝到目录/usr/local/ 1 https://maven.apache.org/download.cgi 2.配置系 ...
- C语言 格式化输出--%m.n
格式字符:格式字符用以指定输出项的数据类型和输出格式. ①d格式:用来输出十进制整数(int).有以下几种用法: %d:按整型数据的实际长度输出. %m.nd:m为指定的输出字段的宽度,n定义为实际输 ...
- SEO之基于thinkphp的URL伪静态
最近基于thinkphp开发了个导购网站,现在有时间,将遇到的伪静态问题整理下,与大家分享.1.设置URL伪静态在config.ini.php中设置,如果只想前台URL伪静态,那么只在前台的confi ...
- 第二百八十四节,MySQL数据库-MySQL触发器
MySQL数据库-MySQL触发器 对某个表进行[增/删/改]操作的前后如果希望触发某个特定的行为时,可以使用触发器,触发器用于定制用户对表的行进行[增/删/改]前后的行为. 1.创建触发器基本语法 ...