数据库实验五
Author:心猿意马
实验要求
自学掌握在3层或4层架构中访问数据库,通过Web页面的操作插入、修改和查询数据,并将操作结果和数据以Web页面的形式展示出来的技术。自主学习内容范围包括:
Web服务器、应用服务器和数据库服务器的概念
Web服务器安装使用和Web服务器部署
Java(首选)、Python等数据库编程、前端网页脚本语言及编程
第八章中的过程化SQL、存储过程、游标等基本概念
多层架构中各层之间的接口编程技术
实验内容及提交要求:
结合自己所选的应用案例,至少完成一个简单案例,Web页面的操作应包括增、删、改、查,查询结果以表格或表单形式展现。
整个系统架构至少应包括前端、Web服务器、应用服务器、数据库服务器。Web服务器和应用服务器可以合在一起,也可以根据硬件资源情况分开。
要求提交系统代码、程序与实验报告,届时将逐个检查。
flask框架版
基础配置信息讲解
首先进入虚拟环境,这里我们使用的是anaconda prompt
我们进入我们自己创造的虚拟环境 pytorch
conda activate pytorch
输入下面的代码,用来安装必要的库
pip install flask mysql-connector-python
可能会有点慢,接下来在下载的同时,我介绍一下创建项目的注意事项
编译器使用的是jetbrain公司的pycharm,如果你是学生可以免费使用(得向jetbran公司提交一些学信网的材料)
在pycharm左上角的新建项目里面选择flask项目,将所需的虚拟环境添加到解释器即可
然后在创建好的文件夹下的templates文件夹放入这些html文件(文件代码放在本章末尾)
mainpage.html
SignUp.html
Revice.html
Revoke.html
Inquiry.html
Dynamic_express.html
我的数据库补充说明:
我的数据库是放在学校的虚拟机上面的,登录校园网才能访问。
其次,本次实验操作的表是我的数据库"zhihu_db"中的usr表,该表的建库SQL语句如下
create table usr
(
usr_id int not null
primary key,
ip_address varchar(45) not null,
user_brief_intro varchar(140) null,
user_name varchar(10) not null
)
collate = utf8mb3_unicode_ci;
项目结构示意图
flask_db5/
├── app.py ->这只是个py文件示意,不是链接,不要点
├── templates/
│ ├── mainpage.html
│ ├── SignUp.html
│ ├── Revice.html
│ ├── Revoke.html
│ ├── Inquiry.html
│ └── Dynamic_express.html
└── static/
这里只要注意这五个html和app.py的相对位置就行了
如何验证已经连接并登录上了数据库?
验证用代码
from flask import Flask, render_template_string
import mysql.connector
app = Flask(__name__)
# 数据库连接信息
db_config = {
'user': 'root',
'password': '123456',
'host': '172.24.65.160',
'database': 'zhihu_db',
'port': 3306
}
# 数据库连接
def get_db_connection():
conn = mysql.connector.connect(**db_config)
return conn
@app.route('/')
def index():
try:
conn = get_db_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute('SELECT * FROM usr')
users = cursor.fetchall()
cursor.close()
conn.close()
# 渲染用户信息的简单HTML模板
template = """
<!doctype html>
<title>User List</title>
<h1>User List</h1>
<table border="1">
<tr>
<th>usr_id</th>
<th>ip_address</th>
<th>user_brief_intro</th>
<th>user_name</th>
</tr>
{% for user in users %}
<tr>
<td>{{ user.usr_id }}</td>
<td>{{ user.ip_address }}</td>
<td>{{ user.user_brief_intro }}</td>
<td>{{ user.user_name }}</td>
</tr>
{% endfor %}
</table>
"""
return render_template_string(template, users=users)
except Exception as e:
return f"An error occurred: {e}"
if __name__ == '__main__':
app.run(debug=True)
代码讲解
其他的都没有什么讲的,如果你需要使用,只需要更改下面的内容
# 数据库连接信息
db_config = {
'user': 'root',
'password': '123456',
'host': '172.24.65.160',
'database': 'zhihu_db',
'port': 3306
}
host是你的数据库的地址,有的是localhost,有的则是登录ip地址
database是你的数据库的名字
port是端口,这个一般不变
user和password是你的这个数据库登录时候使用的用户和密码
这里的代码是简单地提取我的usr表中的内容,让我们尝试运行一下
运行与验证结果
这里的Runnig on http…………
告诉我们要到这个网址找,那么我们打开我们的浏览器输入相应的IP地址看看吧。
那么果不其然我们成功验证了能够链接上数据库,接下来我们直接开始吧
三重架构实现增删改查flask版
设计运行展示
先注册
我们在后台查看是否注册成功?
确实注册成功了,那么我们接下来进行查询、注销等一系列操作吧
架构设计讲解&代码讲解
在Flask应用中,三层架构通常由表示层(Presentation Layer)、业务逻辑层(Business Logic Layer)和数据访问层(Data Access Layer)组成。这种架构设计有助于分离关注点,使代码更加模块化、易于维护和扩展。
表示层(Presentation Layer)
功能: 负责与用户交互,处理用户输入并将输出结果展示给用户。表示层主要包含视图函数和模板。
在Flask中的实现:
- 视图函数: 处理HTTP请求,调用业务逻辑,并返回HTTP响应。视图函数通常使用装饰器
@app.route
来定义。 - 模板: 使用Jinja2模板引擎将数据渲染为HTML页面,以提供给用户。模板文件通常存放在
templates
文件夹中。
业务逻辑层(Business Logic Layer)
功能: 负责处理应用的业务逻辑。包括数据验证、数据处理以及与数据访问层的交互。业务逻辑层通常包含在视图函数中,但也可以抽象到单独的服务或模块中。
在Flask中的实现:
- 视图函数中的业务逻辑: 处理用户输入数据,调用数据访问层,执行业务操作,并返回结果。
- 独立模块或服务: 可以将复杂的业务逻辑提取到单独的模块或服务中,以便于复用和测试。
数据访问层(Data Access Layer)
功能: 负责与数据库或其他持久化存储进行交互,执行CRUD操作。数据访问层通常封装在单独的函数或类中,以便于复用和维护。
在Flask中的实现:
-
数据库连接: 管理与数据库的连接,执行SQL查询,并返回结果。
-
数据访问函数: 封装具体的数据库操作,如插入、查询、更新和删除等。
-
表示层(Presentation Layer): 包含视图函数和模板,负责处理HTTP请求和响应,渲染HTML页面。
-
业务逻辑层(Business Logic Layer): 包含应用的业务逻辑,处理用户输入和数据处理。
-
数据访问层(Data Access Layer): 负责与数据库交互,执行CRUD操作。
代码展示
app.py
from flask import Flask, render_template, request, redirect, url_for
import mysql.connector
app = Flask(__name__)
# 数据库连接信息
db_config = {
'user': 'root',
'password': '123456',
'host': '172.24.65.160',
'database': 'zhihu_db',
'port': 3306
}
# 数据库连接
def get_db_connection():
conn = mysql.connector.connect(**db_config)
return conn
# 首页 - 用户中心
@app.route('/')
def main_page():
return render_template('mainpage.html')
# 用户注册
@app.route('/signup', methods=['GET', 'POST'])
def sign_up():
if request.method == 'POST':
usr_id = request.form['usr_id']
ip_address = request.form['ip_address']
user_brief_intro = request.form['user_brief_intro']
user_name = request.form['user_name']
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(
'INSERT INTO usr (usr_id, ip_address, user_brief_intro, user_name) VALUES (%s, %s, %s, %s)',
(usr_id, ip_address, user_brief_intro, user_name)
)
conn.commit()
cursor.close()
conn.close()
return redirect(url_for('main_page'))
return render_template('SignUp.html')
# 用户信息修改
@app.route('/revice', methods=['GET', 'POST'])
def revice():
if request.method == 'POST':
usr_id = request.form['usr_id']
user_name = request.form['user_name']
user_brief_intro = request.form['user_brief_intro']
ip_address = request.form['ip_address']
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(
'UPDATE usr SET user_name = %s, user_brief_intro = %s, ip_address = %s WHERE usr_id = %s',
(user_name, user_brief_intro, ip_address, usr_id)
)
conn.commit()
cursor.close()
conn.close()
return redirect(url_for('main_page'))
return render_template('Revice.html')
# 用户注销
@app.route('/revoke', methods=['GET', 'POST'])
def revoke():
if request.method == 'POST':
usr_id = request.form['usr_id']
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('DELETE FROM usr WHERE usr_id = %s', (usr_id,))
conn.commit()
cursor.close()
conn.close()
return redirect(url_for('main_page'))
return render_template('Revoke.html')
# 用户查询
@app.route('/inquiry', methods=['GET', 'POST'])
def inquiry():
user_data = None
if request.method == 'POST':
usr_id = request.form['usr_id']
conn = get_db_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute('SELECT * FROM usr WHERE usr_id = %s', (usr_id,))
user_data = cursor.fetchone()
cursor.close()
conn.close()
return render_template('Inquiry.html', user_data=user_data)
# 用户列表
@app.route('/dynamic_express')
def dynamic_express():
conn = get_db_connection()
cursor = conn.cursor(dictionary=True)
cursor.execute('SELECT * FROM usr')
users = cursor.fetchall()
cursor.close()
conn.close()
return render_template('Dynamic_express.html', users=users)
if __name__ == '__main__':
app.run(debug=True)
主页mainpage.html
<!DOCTYPE html>
<html>
<head>
<title>用户中心</title>
<style>
body {
background-color: #e0f2f1; /* 温和的绿色背景 */
font-family: '微软雅黑'; /* 统一字体设置为微软雅黑 */
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置视口高度,使内容垂直居中 */
}
.container {
width: 50%; /* 设置容器宽度 */
background-color: #ffffff; /* 容器背景色 */
padding: 20px;
border-radius: 10px; /* 圆角边框 */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* 阴影效果 */
text-align: center; /* 文字居中 */
}
button {
font-family: '微软雅黑';
width: 80%; /* 按钮宽度 */
padding: 15px; /* 按钮内边距 */
margin-top: 10px; /* 按钮顶部边距 */
margin-bottom: 10px; /* 按钮底部边距 */
cursor: pointer; /* 鼠标悬停显示指针 */
border: none;
background-color: #4CAF50; /* 按钮背景色 */
color: white; /* 文字颜色 */
border-radius: 5px; /* 按钮圆角 */
}
button:hover {
background-color: #45a049; /* 按钮悬停时的背景色变化 */
}
</style>
</head>
<body>
<div class="container">
<p style="font-size: 40px;">用户中心</p>
<button onclick="window.location.href='{{ url_for('sign_up') }}'">用户注册</button>
<button onclick="window.location.href='{{ url_for('revice') }}'">用户信息修改</button>
<button onclick="window.location.href='{{ url_for('revoke') }}'">用户注销</button>
<button onclick="window.location.href='{{ url_for('inquiry') }}'">用户查询</button>
<button onclick="window.location.href='{{ url_for('dynamic_express') }}'">用户列表</button>
</div>
</body>
</html>
注册页SignUp.html
<!DOCTYPE html>
<html>
<head>
<title>Sign Up</title>
<style>
body {
background-color: #e0f2f1; /* 更温和的绿色背景 */
font-family: '微软雅黑'; /* 统一字体设置为微软雅黑 */
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置视口高度,使内容垂直居中 */
}
.container {
width: 50%; /* 设置容器宽度 */
background-color: #ffffff; /* 容器背景色 */
padding: 20px;
border-radius: 10px; /* 圆角边框 */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* 阴影效果 */
}
input, button {
font-family: '微软雅黑';
width: 95%; /* 输入框宽度 */
padding: 10px; /* 输入框内边距 */
margin-top: 5px; /* 顶部边距 */
margin-bottom: 15px; /* 底部边距 */
}
form {
display: flex;
flex-direction: column;
align-items: center;
}
</style>
</head>
<body>
<div class="container">
<p align="center" style="font-size: 40px;">Sign Up</p>
<form method="post" action="{{ url_for('sign_up') }}">
Enter usr_id(输入用户ID):<br>
<input type="number" name="usr_id" placeholder="usr_id">
<br>
Enter ip_address(输入用户IP地址):<br>
<input type="text" name="ip_address" placeholder="ip_address">
<br>
Enter user_brief_intro(输入个人简介):<br>
<input type="text" name="user_brief_intro" placeholder="user_brief_intro">
<br>
Enter user_name(输入用户昵称):<br>
<input type="text" name="user_name" placeholder="user_name">
<br>
<input type="submit" value="Submit">
</form>
<form method="post" action="{{ url_for('main_page') }}">
<input type="submit" value="返回">
</form>
</div>
</body>
</html>
修改页Revice.html
<!DOCTYPE html>
<html>
<head>
<title>修改用户信息</title>
<style>
body {
background-color: #e0f2f1; /* 更温和的绿色背景 */
font-family: '微软雅黑'; /* 统一字体设置为微软雅黑 */
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置视口高度,使内容垂直居中 */
}
.container {
width: 50%; /* 设置容器宽度 */
background-color: #ffffff; /* 容器背景色 */
padding: 20px;
border-radius: 10px; /* 圆角边框 */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* 阴影效果 */
}
input, button {
font-family: '微软雅黑';
width: 95%; /* 输入框宽度 */
padding: 10px; /* 输入框内边距 */
margin-top: 5px; /* 顶部边距 */
margin-bottom: 15px; /* 底部边距 */
}
form {
display: flex;
flex-direction: column;
align-items: center;
}
</style>
</head>
<body>
<div class="container">
<p align="center" style="font-size: 40px;">修改用户信息</p>
<form method="post" action="{{ url_for('revice') }}">
Enter usr_id(输入用户ID):<br>
<input type="number" name="usr_id" placeholder="usr_id">
<br>
Enter new user_name(输入新的用户昵称):<br>
<input type="text" name="user_name" placeholder="user_name">
<br>
Enter new user_brief_intro(输入新的个人简介):<br>
<input type="text" name="user_brief_intro" placeholder="user_brief_intro">
<br>
Enter new ip_address(输入新的IP地址):<br>
<input type="text" name="ip_address" placeholder="ip_address">
<br>
<input type="submit" value="Submit">
</form>
<form method="post" action="{{ url_for('main_page') }}">
<input type="submit" value="返回">
</form>
</div>
</body>
</html>
注销页revoke.html
<!DOCTYPE html>
<html>
<head>
<title>注销用户</title>
<style>
body {
background-color: #e0f2f1; /* 更温和的绿色背景 */
font-family: '微软雅黑'; /* 统一字体设置为微软雅黑 */
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置视口高度,使内容垂直居中 */
}
.container {
width: 50%; /* 设置容器宽度 */
background-color: #ffffff; /* 容器背景色 */
padding: 20px;
border-radius: 10px; /* 圆角边框 */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* 阴影效果 */
}
input, button {
font-family: '微软雅黑';
width: 95%; /* 输入框宽度 */
padding: 10px; /* 输入框内边距 */
margin-top: 5px; /* 顶部边距 */
margin-bottom: 15px; /* 底部边距 */
}
form {
display: flex;
flex-direction: column;
align-items: center;
}
.warning {
color: red;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<p align="center" style="font-size: 40px;">注销用户</p>
<form method="post" action="{{ url_for('revoke') }}">
Enter usr_id(输入用户ID):<br>
<input type="number" name="usr_id" placeholder="usr_id">
<br>
<input type="submit" value="Submit">
</form>
<form method="post" action="{{ url_for('main_page') }}">
<input type="submit" value="返回">
</form>
<p class="warning">注意:注销账户不可恢复!</p>
</div>
</body>
</html>
查询页Inquiry.html
<!DOCTYPE html>
<html>
<head>
<title>查询用户信息</title>
<style>
body {
background-color: #e0f2f1; /* 更温和的绿色背景 */
font-family: '微软雅黑'; /* 统一字体设置为微软雅黑 */
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置视口高度,使内容垂直居中 */
}
.container {
width: 50%; /* 设置容器宽度 */
background-color: #ffffff; /* 容器背景色 */
padding: 20px;
border-radius: 10px; /* 圆角边框 */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* 阴影效果 */
}
input, button {
font-family: '微软雅黑';
width: 95%; /* 输入框宽度 */
padding: 10px; /* 输入框内边距 */
margin-top: 5px; /* 顶部边距 */
margin-bottom: 15px; /* 底部边距 */
}
form {
display: flex;
flex-direction: column;
align-items: center;
}
.result {
margin-top: 20px;
font-size: 20px;
}
</style>
</head>
<body>
<div class="container">
<p align="center" style="font-size: 40px;">查询用户信息</p>
<form method="post" action="{{ url_for('inquiry') }}">
Enter usr_id(输入用户ID):<br>
<input type="number" name="usr_id" placeholder="usr_id">
<br>
<input type="submit" value="Submit">
</form>
<form method="post" action="{{ url_for('main_page') }}">
<input type="submit" value="返回">
</form>
{% if user_data %}
<div class="result">
<p>用户ID: {{ user_data.usr_id }}</p>
<p>IP地址: {{ user_data.ip_address }}</p>
<p>个人简介: {{ user_data.user_brief_intro }}</p>
<p>用户名: {{ user_data.user_name }}</p>
</div>
{% endif %}
</div>
</body>
</html>
动态显示页Dynamic_express.html
<!DOCTYPE html>
<html>
<head>
<title>用户列表</title>
<style>
body {
background-color: #e0f2f1; /* 更温和的绿色背景 */
font-family: '微软雅黑'; /* 统一字体设置为微软雅黑 */
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置视口高度,使内容垂直居中 */
}
.container {
width: 80%; /* 设置容器宽度 */
background-color: #ffffff; /* 容器背景色 */
padding: 20px;
border-radius: 10px; /* 圆角边框 */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* 阴影效果 */
text-align: center; /* 文字居中 */
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<div class="container">
<p align="center" style="font-size: 40px;">用户列表</p>
<table>
<tr>
<th>用户ID</th>
<th>IP地址</th>
<th>个人简介</th>
<th>用户名</th>
</tr>
{% for user in users %}
<tr>
<td>{{ user.usr_id }}</td>
<td>{{ user.ip_address }}</td>
<td>{{ user.user_brief_intro }}</td>
<td>{{ user.user_name }}</td>
</tr>
{% endfor %}
</table>
<form method="post" action="{{ url_for('main_page') }}">
<input type="submit" value="返回">
</form>
</div>
</body>
</html>