45-46学时:编程实践 后端技术
后端技术入门:用PyCharm、Python、MySQL和宝塔面板打造健康养老数据API
在这4个学时中,你将学习后端开发,使用 Python、Flask 和 MySQL,通过 PyCharm Community Edition 构建一个健康养老数据的 RESTful API,支持前端网页(HTML+CSS+JavaScript)。你将先在本地调试通过,然后利用 宝塔面板 部署到阿里云免费ECS服务器。课程适合初学者,逐步讲解:
用Flask创建API端点。
用MySQL存储健康数据(姓名、血压、心率、血糖、体重、步数、时间)。
前端与后端交互。
通过宝塔面板部署API和前端。
课程安排
学时1:理论课 - 了解后端、API、MySQL和宝塔面板。
学时2:演示课 - 老师带你用Flask和MySQL写API,在本地测试。
学时3-4:实践课 - 修改API代码,添加功能,部署到阿里云。
开发环境
IDE:PyCharm Community Edition(下载)。
浏览器:Chrome,调试API。
本地环境设置:
安装 PyCharm 和 Python 3.8+(python.org)。
安装 MySQL:
Windows:下载 MySQL Community Server (mysql.com),设置 root 密码。
Mac:
brew install mysql。Linux:
sudo apt install mysql-server。启动 MySQL:
mysql -u root -p,输入密码。创建数据库:
CREATE DATABASE health_db;
创建 PyCharm 项目:
“File > New Project”,选“Python”,命名(如“HealthAPI”)。
配置虚拟环境(“File > Settings > Project > Python Interpreter”)。
安装依赖:
pip install flask flask-cors mysql-connector-python
项目结构:
app.py(主程序)。config.py(数据库配置)。
测试工具:Postman(getpostman.com)或Chrome。
阿里云环境(宝塔面板):
学生已申请阿里云ECS(Ubuntu 20.04)并安装宝塔面板。
宝塔面板管理MySQL、Nginx、文件上传、Python环境。
登录宝塔:
http://<公网IP>:8888,使用学生自己的用户名/密码。
学时1:理论课 - 认识后端、MySQL和宝塔面板
1.1 什么是后端?
后端负责数据存储、处理和API,与前端交互:
存储:健康数据(如血压、心率)保存到MySQL。
API:提供接口(如
/api/health)供前端调用。逻辑:验证数据(如心率50-120)。
例子:前端显示健康数据表格,后端从MySQL查询数据,返回JSON。
1.2 RESTful API
API使用HTTP请求:
GET /api/health:获取所有健康数据。
POST /api/health:添加新数据。
DELETE /api/health:清空数据。
JSON:数据格式,如:
{"name": "张三", "blood_pressure": "120/80", "heart_rate": 70}
1.3 Flask
Flask是轻量级Python框架:
定义端点:
@app.route('/api/health', methods=['GET'])。处理请求:返回JSON或错误码。
连接MySQL:使用
mysql-connector-python。
1.4 MySQL
MySQL是关系型数据库:
表:存储健康数据(id、name、blood_pressure等)。
SQL:
创建表:
CREATE TABLE health_data (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), ...)插入:
INSERT INTO health_data (name, blood_pressure) VALUES ('张三', '120/80')查询:
SELECT * FROM health_data删除:
DELETE FROM health_data
管理:本地用MySQL客户端,阿里云用宝塔面板。
1.5 宝塔面板
宝塔面板(BT Panel)是服务器管理工具,简化阿里云ECS配置:
数据库:创建MySQL数据库和用户。
文件:上传
app.py和index.html。网站:配置Nginx托管前端。
Python:管理Flask项目,运行API。
端口:开放5000(API)、80(前端)。
1.6 目标API功能
GET /api/health:返回所有健康数据。
POST /api/health:添加数据。
DELETE /api/health:清空数据。
学时2:演示课 - 搭建并本地测试API
2.1 目标
老师用PyCharm创建Flask API,连接MySQL,在本地测试:
查询、添加、清空健康数据。
前端通过API交互。
2.2 完整代码
config.py
# 本地MySQL配置
MYSQL_CONFIG = {
'host': 'localhost',
'user': 'root',
'password': 'your_mysql_password', # 替换为你的MySQL root密码
'database': 'health_db'
}
app.py
from flask import Flask, jsonify, request
from flask_cors import CORS
import mysql.connector
from mysql.connector import Error
from datetime import datetime
import config
app = Flask(__name__)
CORS(app)
# 连接MySQL
def get_db_connection():
try:
conn = mysql.connector.connect(**config.MYSQL_CONFIG)
return conn
except Error as e:
print(f"数据库连接错误: {e}")
return None
# 初始化数据库
def init_db():
conn = get_db_connection()
if conn:
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS health_data (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
blood_pressure VARCHAR(20),
heart_rate INT,
blood_sugar FLOAT,
weight FLOAT,
steps INT,
timestamp VARCHAR(20)
)''')
conn.commit()
cursor.close()
conn.close()
# 获取所有健康数据
@app.route('/api/health', methods=['GET'])
def get_health_data():
conn = get_db_connection()
if not conn:
return jsonify({'error': '数据库连接失败'}), 500
cursor = conn.cursor(dictionary=True)
cursor.execute('SELECT * FROM health_data')
rows = cursor.fetchall()
cursor.close()
conn.close()
return jsonify(rows)
# 添加新健康数据
@app.route('/api/health', methods=['POST'])
def add_health_data():
data = request.get_json()
name = data.get('name')
blood_pressure = data.get('blood_pressure')
heart_rate = data.get('heart_rate')
blood_sugar = data.get('blood_sugar')
weight = data.get('weight')
steps = data.get('steps')
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
if not all([name, blood_pressure, heart_rate, blood_sugar, weight, steps]):
return jsonify({'error': '所有字段必须填写'}), 400
try:
heart_rate = int(heart_rate)
blood_sugar = float(blood_sugar)
weight = float(weight)
steps = int(steps)
if not (50 <= heart_rate <= 120):
return jsonify({'error': '心率必须在50-120之间'}), 400
except ValueError:
return jsonify({'error': '心率、血糖、体重、步数必须是有效数字'}), 400
conn = get_db_connection()
if not conn:
return jsonify({'error': '数据库连接失败'}), 500
cursor = conn.cursor()
cursor.execute('''INSERT INTO health_data (name, blood_pressure, heart_rate, blood_sugar, weight, steps, timestamp)
VALUES (%s, %s, %s, %s, %s, %s, %s)''',
(name, blood_pressure, heart_rate, blood_sugar, weight, steps, timestamp))
conn.commit()
cursor.close()
conn.close()
return jsonify({'message': '数据添加成功'}), 201
# 清空健康数据
@app.route('/api/health', methods=['DELETE'])
def clear_health_data():
conn = get_db_connection()
if not conn:
return jsonify({'error': '数据库连接失败'}), 500
cursor = conn.cursor()
cursor.execute('DELETE FROM health_data')
conn.commit()
cursor.close()
conn.close()
return jsonify({'message': '数据已清空'}), 200
if __name__ == '__main__':
init_db()
app.run(debug=True)
index.html (Frontend)
Same as previous, included for completeness:
<!DOCTYPE html>
<html>
<head>
<title>健康养老数据管理</title>
<style>
body { font-family: Arial; margin: 20px; }
table { border-collapse: collapse; width: 60%; }
th, td { border: 1px solid black; padding: 8px; text-align: center; }
input, button { margin: 10px; padding: 5px; font-size: 18px; }
button { background-color: #28a745; color: white; border: none; }
h1 { color: #28a745; }
</style>
</head>
<body>
<h1>健康养老数据管理</h1>
<table id="healthTable">
<tr>
<th>姓名</th>
<th>血压</th>
<th>心率</th>
<th>血糖</th>
<th>体重</th>
<th>步数</th>
<th>时间</th>
</tr>
</table>
<h2>添加新数据</h2>
<input type="text" id="nameInput" placeholder="姓名">
<input type="text" id="bpInput" placeholder="血压 (如120/80)">
<input type="text" id="hrInput" placeholder="心率">
<input type="text" id="bsInput" placeholder="血糖 (如5.5)">
<input type="text" id="weightInput" placeholder="体重 (如70.5)">
<input type="text" id="stepsInput" placeholder="步数 (如10000)">
<button onclick="addData()">添加</button>
<button onclick="clearTable()">清空表格</button>
<script>
function loadData() {
fetch('http://localhost:5000/api/health')
.then(response => response.json())
.then(data => {
let table = document.getElementById('healthTable');
while (table.rows.length > 1) table.deleteRow(1);
data.forEach(row => {
let newRow = table.insertRow();
newRow.insertCell(0).innerHTML = row.name;
newRow.insertCell(1).innerHTML = row.blood_pressure;
newRow.insertCell(2).innerHTML = row.heart_rate;
newRow.insertCell(3).innerHTML = row.blood_sugar;
newRow.insertCell(4).innerHTML = row.weight;
newRow.insertCell(5).innerHTML = row.steps;
newRow.insertCell(6).innerHTML = row.timestamp;
});
})
.catch(error => console.error('加载数据失败:', error));
}
function addData() {
let name = document.getElementById('nameInput').value;
let bp = document.getElementById('bpInput').value;
let hr = document.getElementById('hrInput').value;
let bs = document.getElementById('bsInput').value;
let weight = document.getElementById('weightInput').value;
let steps = document.getElementById('stepsInput').value;
if (!name || !bp || !hr || !bs || !weight || !steps) {
alert('请填写所有字段!');
return;
}
fetch('http://localhost:5000/api/health', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name, blood_pressure: bp, heart_rate: hr,
blood_sugar: bs, weight, steps
})
})
.then(response => {
if (!response.ok) throw new Error('添加失败');
return response.json();
})
.then(() => {
document.getElementById('nameInput').value = '';
document.getElementById('bpInput').value = '';
document.getElementById('hrInput').value = '';
document.getElementById('bsInput').value = '';
document.getElementById('weightInput').value = '';
document.getElementById('stepsInput').value = '';
loadData();
})
.catch(error => alert('添加失败: ' + error.message));
}
function clearTable() {
fetch('http://localhost:5000/api/health', { method: 'DELETE' })
.then(response => {
if (!response.ok) throw new Error('清空失败');
return response.json();
})
.then(() => loadData())
.catch(error => alert('清空失败: ' + error.message));
}
window.onload = loadData;
</script>
</body>
</html>
2.3 本地调试步骤
配置MySQL:
Start MySQL service (Windows: Services; Mac:
brew services start mysql; Linux:sudo service mysql start).登录:
mysql -u root -p,输入密码。创建数据库:
CREATE DATABASE health_db;
创建PyCharm项目:
“File > New Project”,选“Python”,命名“HealthAPI”。
创建
config.py和app.py,复制代码。更新
config.py的password。安装依赖(PyCharm终端):
pip install flask flask-cors mysql-connector-python
运行后端:
右键
app.py,选“Run”。Chrome访问
http://localhost:5000/api/health,应返回[]。
测试前端:
更新
index.html(确保API地址为http://localhost:5000)。右键
index.html,选“Open in Browser”(Live Server)。输入数据(姓名“张三”、血压“120/80”、心率“70”、血糖“5.5”、体重“70.5”、步数“10000”),点击“添加”。
点击“清空表格”,验证清空。
调试:
后端:PyCharm终端检查MySQL连接错误。
前端:Chrome F12,“Network”查看API状态(200为成功)。
MySQL:
mysql -u root -p,运行SELECT * FROM health_db.health_data;。
调试提示:
MySQL连接失败:检查
config.py密码,MySQL服务状态。API无响应:确认
app.py运行,端口5000空闲。前端错误:Chrome“Console”检查JS错误。
学时3-4:实践课 - 完善API并部署到阿里云
3.1 目标
修改API,添加功能(数据验证、按姓名查询)。
本地测试通过。
用宝塔面板部署到阿里云ECS,验证公网访问。
3.2 准备工作
本地环境:
打开PyCharm,加载“HealthAPI”项目。
确保MySQL运行,依赖已安装。
前端
index.html已配置。
阿里云宝塔面板:
登录:
http://<公网IP>:8888,使用学生凭据。确认已安装:MySQL、Nginx、Python项目管理器。
起点:
复制
app.py为my_app.py,config.py为my_config.py。更新
index.html(若端口变化)。
3.3 任务分解
任务1:添加数据验证
目标:验证血糖(0-20)、体重(30-200)、步数(0-50000)。
操作:
在
my_app.py,add_health_data()的try块后添加:if not (0 <= blood_sugar <= 20): return jsonify({'error': '血糖必须在0-20之间'}), 400 if not (30 <= weight <= 200): return jsonify({'error': '体重必须在30-200之间'}), 400 if not (0 <= steps <= 50000): return jsonify({'error': '步数必须在0-50000之间'}), 400保存,运行,测试无效数据(血糖“25”)。
任务2:按姓名查询
目标:支持
/api/health?name=xxx。操作:
修改
my_app.py的get_health_data():@app.route('/api/health', methods=['GET']) def get_health_data(): conn = get_db_connection() if not conn: return jsonify({'error': '数据库连接失败'}), 500 cursor = conn.cursor(dictionary=True) name = request.args.get('name') if name: cursor.execute('SELECT * FROM health_data WHERE name = %s', (name,)) else: cursor.execute('SELECT * FROM health_data') rows = cursor.fetchall() cursor.close() conn.close() return jsonify(rows)更新
index.html,在<h2>添加新数据</h2>前添加:<h2>按姓名查询</h2> <input type="text" id="searchName" placeholder="输入姓名"> <button onclick="searchByName()">查询</button>在
<script>,clearTable()后添加:function searchByName() { let name = document.getElementById('searchName').value; fetch(`http://localhost:5000/api/health?name=${encodeURIComponent(name)}`) .then(response => response.json()) .then(data => { let table = document.getElementById('healthTable'); while (table.rows.length > 1) table.deleteRow(1); data.forEach(row => { let newRow = table.insertRow(); newRow.insertCell(0).innerHTML = row.name; newRow.insertCell(1).innerHTML = row.blood_pressure; newRow.insertCell(2).innerHTML = row.heart_rate; newRow.insertCell(3).innerHTML = row.blood_sugar; newRow.insertCell(4).innerHTML = row.weight; newRow.insertCell(5).innerHTML = row.steps; newRow.insertCell(6).innerHTML = row.timestamp; }); }) .catch(error => console.error('查询失败:', error)); }保存,运行,测试姓名查询。
任务3:部署到阿里云(宝塔面板)
目标:部署API和前端,公网访问。
操作:
宝塔面板配置:
登录:
http://<公网IP>:8888。MySQL:
导航到“数据库”,点击“添加数据库”。
名称:
health_db,用户名:health_user,密码:Health123!,权限:全部。记录用户名和密码。
安全:
导航到“安全”,开放端口5000(API)、80(前端)。
Python项目管理器:
导航到“软件管理”,安装“Python项目管理器”。
确保Python 3.8+已安装(宝塔“软件管理” > “Python版本”)。
文件:
导航到“文件”,进入
/www/wwwroot。创建目录
health_api。
上传代码:
在PyCharm,“Tools > Deployment > Configuration”,配置SFTP(宝塔提供的主机IP、用户名、密码)。
创建
requirements.txt:flask flask-cors mysql-connector-python上传
my_app.py,my_config.py,requirements.txt,index.html到/www/wwwroot/health_api。更新
my_config.py:MYSQL_CONFIG = { 'host': 'localhost', 'user': 'health_user', 'password': 'Health123!', 'database': 'health_db' }
部署API:
在宝塔“Python项目管理器”,点击“添加Python项目”。
配置:
路径:
/www/wwwroot/health_api。启动文件:
my_app.py。端口:5000。
依赖:点击“安装依赖”,自动安装
requirements.txt。
启动项目,状态显示“运行中”。
部署前端:
在宝塔“网站”,点击“添加站点”。
域名:留空,根目录:
/www/wwwroot/health_api,默认首页:index.html。提交后,宝塔配置Nginx,端口80。
更新
index.html,将http://localhost:5000替换为http://<公网IP>:5000。
测试:
访问
http://<公网IP>,测试前端。添加数据、查询、清空,验证功能。
访问
http://<公网IP>:5000/api/health,检查API。
确保运行:
宝塔“Python项目管理器”自动后台运行。
若停止,点击“启动”。
调试提示:
MySQL错误:宝塔“数据库”检查用户/密码,测试连接。
API失败:宝塔“Python项目管理器”查看日志。
前端404:宝塔“网站”检查根目录和Nginx状态。
3.4 完整代码(参考)
my_config.py
MYSQL_CONFIG = {
'host': 'localhost',
'user': 'health_user',
'password': 'Health123!',
'database': 'health_db'
}
my_app.py
from flask import Flask, jsonify, request
from flask_cors import CORS
import mysql.connector
from mysql.connector import Error
from datetime import datetime
import config
app = Flask(__name__)
CORS(app)
def get_db_connection():
try:
conn = mysql.connector.connect(**config.MYSQL_CONFIG)
return conn
except Error as e:
print(f"数据库连接错误: {e}")
return None
def init_db():
conn = get_db_connection()
if conn:
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS health_data (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
blood_pressure VARCHAR(20),
heart_rate INT,
blood_sugar FLOAT,
weight FLOAT,
steps INT,
timestamp VARCHAR(20)
)''')
conn.commit()
cursor.close()
conn.close()
@app.route('/api/health', methods=['GET'])
def get_health_data():
conn = get_db_connection()
if not conn:
return jsonify({'error': '数据库连接失败'}), 500
cursor = conn.cursor(dictionary=True)
name = request.args.get('name')
if name:
cursor.execute('SELECT * FROM health_data WHERE name = %s', (name,))
else:
cursor.execute('SELECT * FROM health_data')
rows = cursor.fetchall()
cursor.close()
conn.close()
return jsonify(rows)
@app.route('/api/health', methods=['POST'])
def add_health_data():
data = request.get_json()
name = data.get('name')
blood_pressure = data.get('blood_pressure')
heart_rate = data.get('heart_rate')
blood_sugar = data.get('blood_sugar')
weight = data.get('weight')
steps = data.get('steps')
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
if not all([name, blood_pressure, heart_rate, blood_sugar, weight, steps]):
return jsonify({'error': '所有字段必须填写'}), 400
try:
heart_rate = int(heart_rate)
blood_sugar = float(blood_sugar)
weight = float(weight)
steps = int(steps)
if not (50 <= heart_rate <= 120):
return jsonify({'error': '心率必须在50-120之间'}), 400
if not (0 <= blood_sugar <= 20):
return jsonify({'error': '血糖必须在0-20之间'}), 400
if not (30 <= weight <= 200):
return jsonify({'error': '体重必须在30-200之间'}), 400
if not (0 <= steps <= 50000):
return jsonify({'error': '步数必须在0-50000之间'}), 400
except ValueError:
return jsonify({'error': '心率、血糖、体重、步数必须是有效数字'}), 400
conn = get_db_connection()
if not conn:
return jsonify({'error': '数据库连接失败'}), 500
cursor = conn.cursor()
cursor.execute('''INSERT INTO health_data (name, blood_pressure, heart_rate, blood_sugar, weight, steps, timestamp)
VALUES (%s, %s, %s, %s, %s, %s, %s)''',
(name, blood_pressure, heart_rate, blood_sugar, weight, steps, timestamp))
conn.commit()
cursor.close()
conn.close()
return jsonify({'message': '数据添加成功'}), 201
@app.route('/api/health', methods=['DELETE'])
def clear_health_data():
conn = get_db_connection()
if not conn:
return jsonify({'error': '数据库连接失败'}), 500
cursor = conn.cursor()
cursor.execute('DELETE FROM health_data')
conn.commit()
cursor.close()
conn.close()
return jsonify({'message': '数据已清空'}), 200
if __name__ == '__main__':
init_db()
app.run(debug=True)
3.5 提交要求
保存
my_app.py,my_config.py,index.html,上传到宝塔/www/wwwroot/health_api。提供公网IP,访问
http://<公网IP>验证前端,http://<公网IP>:5000/api/health验证API。个性化:
API添加
/api/stats返回记录数。前端添加CSS加载动画。
调试:宝塔日志(Python项目管理器),Chrome F12“Network”。
3.6 时间安排
学时3(1小时):
30分钟:任务1(数据验证),本地测试。
30分钟:任务2(姓名查询),调试。
学时4(1小时):
30分钟:完成任务2,优化API。
30分钟:宝塔部署,测试公网访问。
小贴士
本地调试:
MySQL连接失败:检查
my_config.py,测试mysql -u root -p。API错误:PyCharm终端查看Flask日志。
前端问题:Chrome F12“Console”/“Network”。
宝塔部署:
端口未开放:宝塔“安全”添加5000、80。
API失败:宝塔“Python项目管理器”检查状态/日志。
前端404:宝塔“网站”确认根目录。
创意:
API添加
/api/health/<id>删除单条记录。前端显示血糖警告(血糖 > 10)。
PyCharm:
代码补全:输入
cursor.execute,提示SQL。调试器:设置断点,检查MySQL连接。
SFTP:直接上传到宝塔。
最后编辑:信息技术教研室 更新时间:2025-08-13 10:53