上节内容已经实现了客户端使用长轮询的方式获取消息的功能.
但是还没有展现到前端.本节内容将实现
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聊天室二的更多相关文章

  1. python2.0_day21_web聊天室一

    bbs系统项目中我们用到的ajax不多,但是在聊天室里用到的全是ajax,所以本项目的主要内容就是:前端使用ajax传输json格式的数据是本节的重点以及 前端函数的的使用.http协议的特点是:短链 ...

  2. python2.0_s12_day21_web聊天室一

    本节内容: 项目实战:开发一个WEB聊天室 功能需求: 用户可以与好友一对一聊天 可以搜索.添加某人为好友 用户可以搜索和添加群 每个群有管理员可以审批用户的加群请求,群管理员可以用多个,群管理员可以 ...

  3. python tornado websocket 多聊天室(返回消息给部分连接者)

    python tornado 构建多个聊天室, 多个聊天室之间相互独立, 实现服务器端将消息返回给相应的部分客户端! chatHome.py // 服务器端, 渲染主页 --> 聊天室建立web ...

  4. 三种TCP协议聊天室实现

    一 概述 使用Java的IO实现聊天室 使用Java的NIO实现聊天室 使用Netty实现聊天室 二 IO聊天室 1 服务器 public class IOServer { public static ...

  5. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。

    上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取) 上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容 ...

  6. [Java聊天室server]实战之二 监听类

    前言 学习不论什么一个稍有难度的技术,要对其有充分理性的分析,之后果断做出决定---->也就是人们常说的"多谋善断":本系列尽管涉及的是socket相关的知识,但学习之前,更 ...

  7. Java Socket聊天室编程(二)之利用socket实现单聊聊天室

    这篇文章主要介绍了Java Socket聊天室编程(二)之利用socket实现单聊聊天室的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 在上篇文章Java Socket聊天室编程(一)之 ...

  8. Netty入门(二)之PC聊天室

    参看Netty入门(一):Netty入门(一)之webSocket聊天室 Netty4.X下载地址:http://netty.io/downloads.html 一:服务端 1.SimpleChatS ...

  9. Netty 仿QQ聊天室 (实战二)

    Netty 聊天器(百万级流量实战二):仿QQ客户端 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之15 [博客园 总入口 ] 源码IDEA工程获取链接:Java 聊天室 实战 源码 写在 ...

随机推荐

  1. CTreeCtrl 控件实现多选并取得选中项

    刚开始以为实现起来很难,所以就在网上寻找实现的扩展控件,到最后才发现只要把CTreeCtrl 控件的Check Boxes 属性设为真就可以了,会在每个树形节点前添加一个CheckBox. 多选已经实 ...

  2. highcharts 动态生成x轴和折线图

    highchart 动态生成x轴和折线图 <!DOCTYPE HTML> <html> <head> <meta charset="utf-8&qu ...

  3. C语言 · 整除问题

    算法训练 整除问题   时间限制:1.0s   内存限制:512.0MB      问题描述 编写一个程序,输入三个正整数min.max和factor,然后对于min到max之间的每一个整数(包括mi ...

  4. [4G]Linux平台上实现4G通信

    转自:http://blog.sina.com.cn/s/blog_7880d3350102wb92.html 在ARM平台上实现4G模块的PPP拨号上网,参考网上的资料和自己的理解,从一无所知到开发 ...

  5. C#操作word类文件

    最近频繁操作Word文档,写了很多word的操作代码及方法,虽然已经有很多关于word的操作类了,自己还是进行了一下整合: 1.通过模板创建新文件 2.在书签处插入值 3.插入表格 4.合并单元格 5 ...

  6. CentOS ext4 磁盘分区 格式化 挂载

    [root@appserver ~]# df -h /*查看现有分区情况*/文件系统 容量 已用 可用 已用%% 挂载点/dev/vda1 9.9G 8.2G 1.2G 88% /tmpfs 3.9G ...

  7. Install Homebrew

    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/instal ...

  8. ansible 的user模块

    user模块与group模块 user模块是请求的是useradd, userdel, usermod三个指令,goup模块请求的是groupadd, groupdel, groupmod 三个指令. ...

  9. windows server 2003中用系统自带工具调整磁盘分区大小

    先在需要扩展的右边留出未分配的磁盘空间,可以通过 我的电脑 右键 管理 磁盘管理来操作 首先 进入cmd界面 然后输入Diskpart 这个时候进入DISKPART> 界面 然后你 先选择磁盘一 ...

  10. Ubuntu-Python2.7安装 scipy,numpy,matplotlib 和pip

    一. scipy,numpy,matplotlib sudo apt-get install python-scipy sudo apt-get install python-numpy sudo a ...