后端技术入门:用PyCharm、Python、MySQL和宝塔面板打造健康养老数据API

在这4个学时中,你将学习后端开发,使用 PythonFlaskMySQL,通过 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。

  • 本地环境设置

    1. 安装 PyCharm 和 Python 3.8+(python.org)。

    2. 安装 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;

    3. 创建 PyCharm 项目:

      • “File > New Project”,选“Python”,命名(如“HealthAPI”)。

      • 配置虚拟环境(“File > Settings > Project > Python Interpreter”)。

      • 安装依赖:

        pip install flask flask-cors mysql-connector-python

    4. 项目结构:

      • app.py(主程序)。

      • config.py(数据库配置)。

    5. 测试工具: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.pyindex.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 本地调试步骤

  1. 配置MySQL

    • Start MySQL service (Windows: Services; Mac: brew services start mysql; Linux: sudo service mysql start).

    • 登录:mysql -u root -p,输入密码。

    • 创建数据库:CREATE DATABASE health_db;

  2. 创建PyCharm项目

    • “File > New Project”,选“Python”,命名“HealthAPI”。

    • 创建 config.pyapp.py,复制代码。

    • 更新 config.pypassword

    • 安装依赖(PyCharm终端):

      pip install flask flask-cors mysql-connector-python

  3. 运行后端

    • 右键 app.py,选“Run”。

    • Chrome访问 http://localhost:5000/api/health,应返回 []

  4. 测试前端

    • 更新 index.html(确保API地址为 http://localhost:5000)。

    • 右键 index.html,选“Open in Browser”(Live Server)。

    • 输入数据(姓名“张三”、血压“120/80”、心率“70”、血糖“5.5”、体重“70.5”、步数“10000”),点击“添加”。

    • 点击“清空表格”,验证清空。

  5. 调试

    • 后端:PyCharm终端检查MySQL连接错误。

    • 前端:Chrome F12,“Network”查看API状态(200为成功)。

    • MySQLmysql -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 准备工作

  1. 本地环境

    • 打开PyCharm,加载“HealthAPI”项目。

    • 确保MySQL运行,依赖已安装。

    • 前端 index.html 已配置。

  2. 阿里云宝塔面板

    • 登录:http://<公网IP>:8888,使用学生凭据。

    • 确认已安装:MySQL、Nginx、Python项目管理器。

  3. 起点

    • 复制 app.pymy_app.pyconfig.pymy_config.py

    • 更新 index.html(若端口变化)。

3.3 任务分解

任务1:添加数据验证

  • 目标:验证血糖(0-20)、体重(30-200)、步数(0-50000)。

  • 操作

    • my_app.pyadd_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.pyget_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和前端,公网访问。

  • 操作

    1. 宝塔面板配置

      • 登录:http://<公网IP>:8888

      • MySQL

        • 导航到“数据库”,点击“添加数据库”。

        • 名称:health_db,用户名:health_user,密码:Health123!,权限:全部。

        • 记录用户名和密码。

      • 安全

        • 导航到“安全”,开放端口5000(API)、80(前端)。

      • Python项目管理器

        • 导航到“软件管理”,安装“Python项目管理器”。

        • 确保Python 3.8+已安装(宝塔“软件管理” > “Python版本”)。

      • 文件

        • 导航到“文件”,进入 /www/wwwroot

        • 创建目录 health_api

    2. 上传代码

      • 在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'
        }

    3. 部署API

      • 在宝塔“Python项目管理器”,点击“添加Python项目”。

      • 配置:

        • 路径:/www/wwwroot/health_api

        • 启动文件:my_app.py

        • 端口:5000。

        • 依赖:点击“安装依赖”,自动安装 requirements.txt

      • 启动项目,状态显示“运行中”。

    4. 部署前端

      • 在宝塔“网站”,点击“添加站点”。

      • 域名:留空,根目录:/www/wwwroot/health_api,默认首页:index.html

      • 提交后,宝塔配置Nginx,端口80。

      • 更新 index.html,将 http://localhost:5000 替换为 http://<公网IP>:5000

    5. 测试

      • 访问 http://<公网IP>,测试前端。

      • 添加数据、查询、清空,验证功能。

      • 访问 http://<公网IP>:5000/api/health,检查API。

    6. 确保运行

      • 宝塔“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-04-18 07:32
最后编辑:信息技术教研室  更新时间:2025-08-13 10:53