今天闲来无聊,想做个小项目练练手,顺便复习一下Flask框架,于是就做了个带有简单的注册和登录功能的聊天网页。
界面展示



以上界面没啥解释的,就是几个简单的界面。
接下来展示简单的聊天页面。

现在我们还没有输入聊天内容,试试。

点了发送后就会发送到上面去。

另开一个浏览器(开谷歌浏览器),注册一个账号,用户名叫qi,然后进入聊天页面。
图中省略注册和登录,直接登录。
然后输入聊天内容。

这就是简简单单的聊天网页。由于Flask框架的简洁性,实现这个功能也很简单。
关键代码
后端代码只需要一个app.py便可实现所有功能。
导入必要的包。
python 代码:import json
from flask import Flask, render_template, request, session, url_for, redirect, flash, jsonify
from redis import StrictRedis
实例化Flask应用对象、实例化Redis连接对象,配置密钥(因为用到了消息闪现和session存储用户名)。
python 代码:redis = StrictRedis(host='192.168.204.129', decode_responses=True)
app = Flask(__name__)
app.config['SECRET_KEY'] = 'qi'
首页路由,直接渲染模板即可。
python 代码:@app.route('/')
def index():
return render_template('html/index.html')
聊天界面路由,判断Session中是否存储了用户登录的信息,若没有则301到登录页面。
python 代码:@app.route('/chat')
def chat():
if session.get('username') is None:
return redirect(url_for('login'))
else:
return render_template('html/chat.html')
登录路由。若用户已登录则301到聊天页面。
python 代码:@app.route('/login', methods=['GET', 'POST'])
def login():
if session.get('username') is not None:
return redirect(url_for('chat'))
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
password_r = redis.hget('user', username)
if password_r == password:
session['username'] = username
return redirect(url_for('index'))
else:
flash('error', '请输入正确的用户名和密码')
return render_template('html/login.html')
注册路由。若页面为POST请求则接收参数,加以验证,然后存到数据库里。
python 代码:@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if redis.hexists('user', username):
flash('error', '用户名已存在')
else:
redis.hset('user', username, password)
flash('success', '<a href="/login">注册成功!点此跳转到登录页面</a>')
return render_template('html/register.html')
获取聊天记录的路由。前端使用Ajax获取请求,因此这里返回消息的列表。
python 代码:@app.route('/recv', methods=['POST'])
def recv():
messages = redis.lrange('messages', 0, -1)
messages = [json.loads(m) for m in messages]
return jsonify(messages)
发送消息的路由。也是使用异步发送,所以只提交到数据库即可。
python 代码:@app.route('/send', methods=['POST'])
def send():
message = {
'username': request.json['username'],
'content': request.json['content']
}
redis.rpush('messages', json.dumps(message))
return jsonify({'status': 'success'})
最后运行应用对象即可。
python 代码:if __name__ == '__main__':
app.run()
前端页面的话首先创建了一个基模板base.html,用block定义了标题区和内容区,将每个页面公共的页面都放到基模板中:
html 代码:<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
<title>{% block title %}{% endblock %}</title>
<style>
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100%;
}
.error {
color: red;
}
.success {
color: green;
}
.chat-container {
max-height: 500px;
overflow-y: scroll;
}
.left-message {
background-color: #f8f9fa;
}
.right-message {
background-color: #d4edda;
align-self: flex-end;
}
::-webkit-scrollbar {
width: 0.5em;
background-color: #F5F5F5;
}
::-webkit-scrollbar-thumb {
background-color: #000000;
}
</style>
</head>
<body>
{% block content %}
{% endblock %}
<script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
</body>
</html>
随后使每个子模板继承自该模板即可,如登录页面,代码如下:
html 代码:{% extends 'html/base.html' %}
{% block title %}
登录 - 聊天程序
{% endblock %}
{% block content %}
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h2 class="card-title">登录</h2>
</div>
<div class="card-body">
<form action="/login" method="post">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" name="username" id="username"
placeholder="请输入用户名">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" name="password" id="password"
placeholder="请输入密码">
</div>
{% with messages = get_flashed_messages(with_categories=True) %}
{% if get_flashed_messages %}
<div class="form-group">
<ul>
{% if messages %}
{% for message, category in messages %}
<li class={{ category }}>{{ message }}</li>
{% endfor %}
{% endif %}
</ul>
</div>
{% endif %}
{% endwith %}
<button type="submit" class="btn btn-primary">登录</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
聊天页面则使用了Ajax向后端发送请求,在接收数据后删除原有节点并添加新节点以实现更新聊天记录的功能;在表单提交后使用Ajax向后端发送请求以更新数据库而不用刷新页面。代码:
html 代码:{% extends 'html/base.html' %}
{% block title %}聊天页面 - 聊天程序{% endblock %}
{% block content %}
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="panel panel-default" style="height: 500px !important; overflow: scroll">
<div class="panel-heading">
<div class="d-flex justify-content-between align-items-center"
style="display: flex; align-items: center; justify-content: space-between">
<h3 class="panel-title flex-grow-1" style="display: inline">聊天界面</h3>
<button type="button" class="btn btn-danger">退出登录</button>
</div>
</div>
<div id="messages-container">
</div>
</div>
<div class="panel-footer">
<div class="input-group">
<input type="hidden" id="username" value="{{ session['username'] }}">
<input type="text" id="content" class="form-control" placeholder="请输入消息">
<span class="input-group-btn">
<button onclick="sendMessage()" class="btn btn-primary" type="button">发送</button>
</span>
</div>
</div>
</div>
</div>
</div>
<script>
// 每五秒获取一次聊天记录
setInterval(getMessages, 100);
function getMessages() {
$.ajax({
url: '/recv',
type: 'POST',
success: function (response) {
// 更新聊天页面内容
var messagesContainer = document.getElementById('messages-container');
messagesContainer.innerHTML = '';
response.forEach(function (message) {
var messageDiv = '<div class="message left-message mb-2"><div class="message-content">' + message.username + ':' + message.content + '</div></div>';
messagesContainer.innerHTML += messageDiv;
});
}
});
}
function sendMessage() {
// 获取用户名和消息内容
var username = document.getElementById('username').value;
var content = document.getElementById('content').value;
// 发送消息到后端
$.ajax({
url: '/send',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({'username': username, 'content': content}),
success: function (response) {
// 清空输入框
document.getElementById('content').value = '';
}
});
}
</script>
{% endblock %}