基于Python實(shí)現(xiàn)從頭搭建一個(gè)在線聊天室框架
今天從頭開(kāi)始做一個(gè)在線聊天網(wǎng)站,網(wǎng)上各種各樣的聊天工具已經(jīng)很多了,為啥還要做這么一個(gè)聊天工具呢,無(wú)他,興趣耳!
今天先完成第一部分,搭建起聊天網(wǎng)站的整體框架。
整體技術(shù)棧
- flask 框架
- flask_login 的使用
- jquery 簡(jiǎn)單應(yīng)用
搭建權(quán)限框架
還是使用 Flask 來(lái)搭建后臺(tái)應(yīng)用,使用 flask-login 擴(kuò)展來(lái)處理用戶登陸鑒權(quán)邏輯。
首先定義登陸表單
class?LoginForm(FlaskForm): ????username?=?StringField('Username',?validators=[DataRequired(),?]) ????password?=?PasswordField('Password',?validators=[DataRequired()]) ????remember_me?=?BooleanField('Keep?me?logged?in') ????submit?=?SubmitField('Log?in')
一個(gè)簡(jiǎn)單的登陸表單,不做過(guò)多解釋
接下來(lái)定義數(shù)據(jù)庫(kù)結(jié)構(gòu)
class?User(UserMixin,?db.Model): ????__tablename__?=?'users' ????id?=?db.Column(db.Integer,?primary_key=True) ????username?=?db.Column(db.String(64),?unique=True,?index=True) ????password?=?db.Column(db.String(64))
當(dāng)前,我們只需要一個(gè) user 用戶表,只包含三個(gè)字段的簡(jiǎn)單表。用戶密碼也只是簡(jiǎn)單的保存了明文,后面再處理用戶密碼的 hash 問(wèn)題。
下面就可以定義用戶登陸表單
from?flask_login?import?LoginManager login_manager?=?LoginManager() login_manager.session_protection?=?'strong' login_manager.login_view?=?'login' app?=?Flask(__name__) login_manager.init_app(app) app.config['SECRET_KEY']?=?'hardtohard' @login_manager.user_loader def?load_user(user_id): ????return?User.query.get(int(user_id)) @app.route('/login',?methods=['GET',?'POST']) def?login(): ????form?=?LoginForm() ????if?form.validate_on_submit(): ????????user?=?User.query.filter_by(username=form.username.data).first() ????????if?user: ????????????login_user(user) ????????????return?redirect(url_for('chat')) ????return?render_template('login.html',?form=form)
這里定義了,只檢查用戶名是否存在,如果存在,就執(zhí)行 login_user() 函數(shù),登陸。用戶密碼的使用,也留到后面再做處理。
其中 load_user,是回調(diào)函數(shù),將獲取到的 user 對(duì)象存儲(chǔ)到瀏覽器的 session 中,然后在調(diào)用 login_user 函數(shù)時(shí),就會(huì)調(diào)用 load_user 來(lái)把真正需要登陸的用戶設(shè)置到 session 中。當(dāng)?shù)顷懗晒?,就?huì)跳轉(zhuǎn)到 chat 函數(shù)所對(duì)應(yīng)的頁(yè)面。
chat 函數(shù)比較簡(jiǎn)單,只是展示一個(gè)網(wǎng)頁(yè)
@app.route('/chat',?methods=['GET',?'POST']) @login_required def?chat(): ????return?render_template('chat.html')
使用 login_required 裝飾器,保證該函數(shù)只允許登陸的用戶訪問(wèn)。
增加些初始化函數(shù)
@app.route('/adddb',?methods=['GET',?'POST']) def?addbd(): ????db.create_all() ????return?"OK" @app.route('/deldb',?methods=['GET',?'POST']) def?delbd(): ????db.drop_all() ????return?"OK" @app.route('/adduser/<user>',?methods=['GET',?'POST']) def?adduser(user): ????user?=?User(username=user,?password='admin') ????db.session.add(user) ????db.session.commit() ????return?"OK"
增加了初始化數(shù)據(jù)庫(kù)和新增用戶的函數(shù)。
構(gòu)建前端頁(yè)面
首先處理登陸頁(yè)面,在 login.html 中添加
{%?extends?"bootstrap/base.html"?%} {%?import?"bootstrap/wtf.html"?as?wtf?%} {%?block?title?%}Flasky{%?endblock?%} {%?block?navbar?%} <div?class="navbar?navbar-inverse"?role="navigation"> ????<div?class="container"> ????????<div?class="navbar-header"> ????????????<button?type="button"?class="navbar-toggle"?data-toggle="collapse"?data-target=".navbar-collapse"> ????????????????<span?class="sr-only">Toggle?navigation</span> ????????????????<span?class="icon-bar"></span> ????????????????<span?class="icon-bar"></span> ????????????????<span?class="icon-bar"></span> ????????????</button> ????????????<a?class="navbar-brand"?href="/" rel="external nofollow" rel="external nofollow" >Flasky</a> ????????</div> ????????<div?class="navbar-collapse?collapse"> ????????????<ul?class="nav?navbar-nav"> ????????????????<li><a?href="/" rel="external nofollow" rel="external nofollow" >Home</a></li> ????????????</ul> ????????????<ul?class="nav?navbar-nav?navbar-right"> ????????????????{%?if?current_user.is_authenticated?%} ????????????????<li><a?href="{{?url_for('logout')?}}" rel="external nofollow" rel="external nofollow" >Logout</a></li> ????????????????{%?else?%} ????????????????<li><a?href="{{?url_for('login')?}}" rel="external nofollow" rel="external nofollow" >Login</a></li> ????????????????{%?endif?%} ????????????</ul> ????????</div> ????</div> </div>?{%?endblock?%} {%?block?content?%} <div?class="container"> ????<div?class="page-header"> ????????<h1>Hello,?Welcome!</h1> ????</div> ????{{?wtf.quick_form(form)?}} </div> {%?endblock?%}
使用擴(kuò)展庫(kù) flask_bootstrap 來(lái)快速構(gòu)建頁(yè)面。
下面重點(diǎn)來(lái)看看 chat 頁(yè)面,主要使用了 Ajax 來(lái)處理文字交互。
首先來(lái)看看主體頁(yè)面,在 chat.html 中填入代碼
{%?extends?'bootstrap/base.html'?%} {%?import?"bootstrap/wtf.html"?as?wtf?%} {%?block?title?%}Kung?Fu?Realm{%endblock?%} {%?block?head?%} <head> <meta?charset="utf-8"> <title>Hi?Hi?聊天室</title> <link?rel="shortcut?icon"?href="{{?url_for('static',filename='chat/images/hihi.jpg')}}" rel="external nofollow" rel="external nofollow" > <link?rel="icon"?href="{{?url_for('static',filename='chat/images/hihi.jpg')}}" rel="external nofollow" rel="external nofollow" ?type="image/x-icon"> <link?type="text/css"?rel="stylesheet"?href="/static/chat/css/style.css" rel="external nofollow" > <script?type="text/javascript"?src="{{?url_for('static',?filename='chat/js/jquery.min.js')?}}"></script> </head> {%?endblock?%} {%?block?content?%} <body> <div?class="chatbox"> ??<div?class="chat_top?fn-clear"> ??????<div?class="uinfo?fn-clear"??style="float:?left;"><div?class="uface"><h1?style="color:?#7777">ROOM:?聊天室123哈哈哈</h1></div></div> ????<div?class="uinfo?fn-clear"> ????{%?if?current_user.is_authenticated?%} ??????<div?class="uface"><img?src="{{?url_for('static',?filename='chat/images/hi.jpg')?}}"?width="40"?height="40"??alt=""/></div> ????{%?else?%} ??????<div?class="uface"><img?src="{{?url_for('static',?filename='chat/images/hi.jpg')}}"?width="40"?height="40"??alt=""/></div> ????{%?endif?%} ??????<div?class="uname"> ????????小HI<i?class="fontico?down"></i> ????????<ul?class="managerbox"> ????????????{%?if?current_user.is_authenticated?%} ??????????<li><a?href="{{?url_for('login')?}}" rel="external nofollow" rel="external nofollow" ><i?class="fontico?lock"></i>退出登陸</a></li> ????????????{%?else?%} ??????????<li><a?href="{{?url_for('logout')?}}" rel="external nofollow" rel="external nofollow" ><i?class="fontico?logout"></i>登錄</a></li> ????????????{%?endif?%} ????????</ul> ??????</div> ????</div> ??</div> ??<div?class="chat_message?fn-clear"> ????<div?class="chat_left"> ??????<div?class="message_box"?id="message_box"> ????????<div?class="msg_item?fn-clear"> ??????????<div?class="uface"><img?src="{{?url_for('static',?filename='chat/images/duck.jpg')}}"?width="40"?height="40"??alt=""/></div> ??????????<div?class="item_right"> ????????????<div?class="msg?own"><img?src="{{?url_for('static',?filename='chat/images/hihi.jpg')}}"?width="400"?height="400"??alt=""/></div> ????????????<div?class="name_time">小黃鴨?</div> ??????????</div> ????????</div> ??????????{%?if?current_user.is_authenticated?%} ????????<div?class="msg_item?fn-clear"> ??????????<div?class="uface"><img?src="{{?url_for('static',?filename='chat/images/duck.jpg')}}"?width="40"?height="40"??alt=""/></div> ??????????<div?class="item_right"> ????????????<div?class="msg">Welcome to Hihi Chat Room. 歡迎來(lái)到 Hihi 聊天室。?</div> ????????????<div?class="name_time">小黃鴨?</div> ??????????</div> ????????</div> ??????????{%?else?%} ??????????<div?class="msg_item?fn-clear"> ??????????<div?class="uface"><img?src="{{?url_for('static',?filename='chat/images/duck.jpg')}}"?width="40"?height="40"??alt=""/></div> ??????????<div?class="item_right"> ????????????<div?class="msg">您還沒(méi)有登陸,先和小黃鴨聊聊吧。?</div> ????????????<div?class="name_time">小黃鴨?</div> ??????????</div> ????????</div> ??????????{%?endif?%} ??????</div> ??????<div?class="write_box"> ??????{%?if?current_user.is_authenticated?%} ????????<textarea?id="message"?name="message"?class="write_area"?placeholder="說(shuō)點(diǎn)啥吧..."></textarea> ??????{%?else?%} ??????<textarea?id="message_not"?name="message"?class="write_area"?placeholder="說(shuō)點(diǎn)啥吧..."></textarea> ??????{%?endif?%} ????????<input?type="hidden"?name="fromname"?id="fromname"?value="你"?/> ????????<input?type="hidden"?name="to_uid"?id="to_uid"?value="0"> ????????<div?class="facebox?fn-clear"> ??????????<div?class="expression"></div> ??????????<div?class="chat_type"?id="chat_type">群聊</div> ????????????{%?if?current_user.is_authenticated?%} ??????????<button?name="login"?class="sub_but"?id="sub_but_login">提?交</button> ????????????{%?else?%} ??????????<button?name="logout"?class="sub_but"?id="sub_but">提?交</button> ????????????{%?endif?%} ????????</div> ??????</div> ????</div> ??</div> </div>
整體效果如下,是不是挺少女系的。
當(dāng)用戶在點(diǎn)擊“提交”按鈕后,調(diào)用 JS 函數(shù)
????/*用戶登陸的用戶點(diǎn)擊提交按鈕發(fā)送消息按鈕*/ ????$('#sub_but_login').click(function(event){ ????????sendMessageLogin(event,?fromname,?to_uid,?to_uname); ????});
為了后面便于擴(kuò)展,將未登錄的用戶特別區(qū)分開(kāi)來(lái),后面也許同樣允許未登陸用戶訪問(wèn)該頁(yè)面,但是只能同機(jī)器人小黃鴨聊天
????/*用戶未登陸的用戶點(diǎn)擊提交按鈕發(fā)送消息按鈕*/ ????$('#sub_but').click(function(event){ ????????sendMessage(event,?fromname,?to_uid,?to_uname); ????});
再來(lái)看函數(shù) sendMessageLogin
function?sendMessageLogin(event,?from_name,?to_uid,?to_uname){ ????var?msg?=?$("#message").val(); ????var?myDate?=?new?Date(); ????var?myTime?=?myDate.toLocaleTimeString(); ????var?itTime?=?myDate.toLocaleString(); ????//var?iTime?=?myDate.toDateString(); ????var?htmlData?=???'<div?class="msg_item?fn-clear">' ???????????????????+?'???<div?class="uface">{%?if?current_user.is_authenticated?%}<img?src="{{?url_for('static',?filename='chat/images/hi.jpg')?}}"?width="40"?height="40"??alt=""/>{%?endif?%}</div>' ???????????????????+?'???<div?class="item_right">' ???????????????????+?'?????<div?class="msg?own">'?+?msg?+?'</div>' ???????????????????+?'?????<div?class="name_time">'?+?from_name?+?'?·?'?+?itTime?+'</div>' ???????????????????+?'???</div>' ???????????????????+?'</div>'; ????$("#message_box").append(htmlData); ????$('#message_box').scrollTop($("#message_box")[0].scrollHeight?+?20); ????$("#message").val(''); ????setTimeout(function(){sendToServer(from_name,?msg)},?1000);?//延時(shí)調(diào)用 }
接收幾個(gè)參數(shù),然后將當(dāng)前會(huì)話消息追加到 HTML 頁(yè)面中,并且調(diào)用真正的后臺(tái) API 函數(shù) sendToServer
function?sendToServer(name,?msg){ ????var?xmlhttp?=?new?XMLHttpRequest(); ????var?myDate?=?new?Date(); ????//var?myTime?=?myDate.toLocaleTimeString(); ????var?myTime?=?myDate.toLocaleString(); ????xmlhttp.onreadystatechange=function()?{ ????????if?(xmlhttp.readyState?==?4?&&?xmlhttp.status?==?200)?{ ????????????myObj?=?xmlhttp.responseText; ????????????var?htmlData2?=???'<div?class="msg_item?fn-clear">' ???????????????????+?'???<div?class="uface"><img?src="{{?url_for('static',?filename='chat/images/duck.jpg')}}"?width="40"?height="40"??alt=""/></div>' ???????????????????+?'???<div?class="item_right">' ???????????????????+?'?????<div?class="msg">'?+?myObj?+?'</div>' ???????????????????+?'?????<div?class="name_time">'?+?'小黃鴨'?+?'?·?'?+?myTime?+'</div>' ???????????????????+?'???</div>' ???????????????????+?'</div>'; ????????????$("#message_box").append(htmlData2); ????????????$('#message_box').scrollTop($("#message_box")[0].scrollHeight?+?20); ????????} ????} ????xmlhttp.open("GET",?"/api/sendchat/"?+?msg,?true); ????xmlhttp.send(); };
sendToServer 函數(shù)調(diào)用后臺(tái) API,并把接收到的消息回寫(xiě)到 HTML 頁(yè)面中。
而目前的后臺(tái) API 也比較簡(jiǎn)單,直接返回用戶輸入的消息
@app.route('/api/sendchat/<info>',?methods=['GET',?'POST']) @login_required def?send_chat(info): ????return?info
這樣,一個(gè)整體的聊天室架子就搭建好了,后面我們?cè)俳尤?redis 和自己訓(xùn)練的聊天機(jī)器人,來(lái)實(shí)現(xiàn)真正的在線聊天室。
到此這篇關(guān)于基于Python實(shí)現(xiàn)從頭搭建一個(gè)在線聊天室的文章就介紹到這了,更多相關(guān)Python在線聊天室內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡(jiǎn)單了解Python3 bytes和str類(lèi)型的區(qū)別和聯(lián)系
這篇文章主要介紹了簡(jiǎn)單了解Python3 bytes和str類(lèi)型的區(qū)別和聯(lián)系,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12YOLOv5改進(jìn)系列之增加小目標(biāo)檢測(cè)層
yolov5出來(lái)已經(jīng)很長(zhǎng)時(shí)間了,所以有關(guān)yolov5的一些詳細(xì)介紹在這里就不一一介紹了,下面這篇文章主要給大家介紹了關(guān)于YOLOv5改進(jìn)系列之增加小目標(biāo)檢測(cè)層的相關(guān)資料,需要的朋友可以參考下2022-09-09python 請(qǐng)求服務(wù)器的實(shí)現(xiàn)代碼(http請(qǐng)求和https請(qǐng)求)
本篇文章主要介紹了python 請(qǐng)求服務(wù)器的實(shí)現(xiàn)代碼(http請(qǐng)求和https請(qǐng)求),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05淺談在django中使用redirect重定向數(shù)據(jù)傳輸?shù)膯?wèn)題
這篇文章主要介紹了淺談在django中使用redirect重定向數(shù)據(jù)傳輸?shù)膯?wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Python爬蟲(chóng)之pandas基本安裝與使用方法示例
這篇文章主要介紹了Python爬蟲(chóng)之pandas基本安裝與使用方法,結(jié)合實(shí)例形式分析了Python爬蟲(chóng)操作中pandas的pip命令安裝與HTML、Excel等格式文件保存相關(guān)操作技巧,需要的朋友可以參考下2018-08-08Python并發(fā)爬蟲(chóng)常用實(shí)現(xiàn)方法解析
這篇文章主要介紹了Python并發(fā)爬蟲(chóng)常用實(shí)現(xiàn)方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11