全栈(C + HTML/CSS/JS + MySQL)开发学生管理系统教程(三)

简介: 教程来源 https://www.wkmsa.cn/ 本项目基于C语言与CGI技术构建学生信息管理系统,含HTML前端页面(支持静态分离与AJAX)、MySQL数据库集成及Apache部署方案;提供完整Makefile、目录规划、编译部署指南与常见错误解决方案,兼顾实用性与教学价值。

第三部分:前端HTML页面

3.1 主页面导航
由于CGI程序动态生成HTML内容,前端样式已经在template.c中以内联CSS方式实现。为了更好的开发体验,可以使用独立的CSS文件。

3.2 静态页面(可选)
如果希望将前端与后端分离,可以创建独立的HTML文件并通过AJAX调用API。以下是前端页面的示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>学生管理系统</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: 'Microsoft YaHei', sans-serif; background: #f0f2f5; }
        .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; }
        .container { max-width: 1200px; margin: 20px auto; padding: 0 20px; }
        .card { background: white; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 20px; }
        .form-group { margin-bottom: 15px; }
        .form-group label { display: block; margin-bottom: 5px; font-weight: bold; }
        .form-group input, .form-group select { width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; }
        button { background: #667eea; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; }
        button:hover { background: #5a67d8; }
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; }
        th { background: #f5f5f5; }
        .btn-edit { background: #28a745; margin-right: 5px; }
        .btn-delete { background: #dc3545; }
        .btn-small { padding: 4px 10px; font-size: 12px; }
        .filter-bar { margin-bottom: 20px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
        .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); justify-content: center; align-items: center; z-index: 1000; }
        .modal-content { background: white; border-radius: 8px; padding: 20px; width: 500px; max-width: 90%; }
        .close { float: right; cursor: pointer; font-size: 24px; }
    </style>
</head>
<body>
    <div class="header">
        <div class="container">
            <h1>📚 学生管理系统</h1>
            <p>管理学生信息、成绩和班级</p>
        </div>
    </div>

    <div class="container" id="app">
        <div class="filter-bar">
            <select id="classFilter">
                <option value="">全部班级</option>
            </select>
            <button onclick="loadStudents()">筛选</button>
            <button onclick="showAddModal()" style="background:#28a745;">+ 添加学生</button>
        </div>

        <div class="card">
            <h2>学生列表</h2>
            <div id="studentTable"></div>
        </div>
    </div>

    <!-- 添加/编辑模态框 -->
    <div id="studentModal" class="modal">
        <div class="modal-content">
            <span class="close" onclick="closeModal()">&times;</span>
            <h2 id="modalTitle">添加学生</h2>
            <form id="studentForm">
                <input type="hidden" id="studentId" name="id">
                <div class="form-group">
                    <label>学号:</label>
                    <input type="text" id="studentNo" name="student_no" required>
                </div>
                <div class="form-group">
                    <label>姓名:</label>
                    <input type="text" id="studentName" name="name" required>
                </div>
                <div class="form-group">
                    <label>性别:</label>
                    <select id="studentGender" name="gender">
                        <option value="男">男</option>
                        <option value="女">女</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>出生日期:</label>
                    <input type="date" id="studentBirth" name="birth_date">
                </div>
                <div class="form-group">
                    <label>班级:</label>
                    <select id="studentClass" name="class_id"></select>
                </div>
                <div class="form-group">
                    <label>家长电话:</label>
                    <input type="text" id="studentPhone" name="phone">
                </div>
                <div class="form-group">
                    <label>家庭地址:</label>
                    <input type="text" id="studentAddress" name="address">
                </div>
                <button type="button" onclick="saveStudent()">保存</button>
                <button type="button" onclick="closeModal()">取消</button>
            </form>
        </div>
    </div>

    <script>
        // 加载班级列表
        function loadClasses() {
            fetch('/cgi-bin/class.cgi?action=list')
                .then(response => response.json())
                .then(data => {
                    const classSelect = document.getElementById('classFilter');
                    const classModal = document.getElementById('studentClass');

                    data.data.forEach(cls => {
                        const option = document.createElement('option');
                        option.value = cls.id;
                        option.textContent = cls.name;
                        classSelect.appendChild(option.cloneNode(true));
                        classModal.appendChild(option);
                    });
                });
        }

        // 加载学生列表
        function loadStudents() {
            const classId = document.getElementById('classFilter').value;
            let url = '/cgi-bin/student.cgi?action=list&format=json';
            if (classId) url += '&class_id=' + classId;

            fetch(url)
                .then(response => response.json())
                .then(data => {
                    renderStudentTable(data.data);
                });
        }

        // 渲染学生表格
        function renderStudentTable(students) {
            const container = document.getElementById('studentTable');
            if (!students || students.length === 0) {
                container.innerHTML = '<p style="text-align:center; padding:40px;">暂无数据</p>';
                return;
            }

            let html = '<table>';
            html += '<thead><tr><th>学号</th><th>姓名</th><th>性别</th><th>班级</th><th>电话</th><th>操作</th></tr></thead>';
            html += '<tbody>';

            students.forEach(s => {
                html += '<tr>';
                html += `<td>${s.student_no}</td>`;
                html += `<td>${s.name}</td>`;
                html += `<td>${s.gender}</td>`;
                html += `<td>${s.class_name}</td>`;
                html += `<td>${s.phone || ''}</td>`;
                html += `<td>
                            <button class="btn-small" onclick="viewStudent(${s.id})">查看</button>
                            <button class="btn-small btn-edit" onclick="editStudent(${s.id})">编辑</button>
                            <button class="btn-small btn-delete" onclick="deleteStudent(${s.id})">删除</button>
                        </td>`;
                html += '</tr>';
            });

            html += '</tbody></table>';
            container.innerHTML = html;
        }

        // 显示添加模态框
        function showAddModal() {
            document.getElementById('modalTitle').innerText = '添加学生';
            document.getElementById('studentForm').reset();
            document.getElementById('studentId').value = '';
            document.getElementById('studentModal').style.display = 'flex';
        }

        // 编辑学生
        function editStudent(id) {
            fetch(`/cgi-bin/student.cgi?action=detail&id=${id}&format=json`)
                .then(response => response.json())
                .then(data => {
                    const s = data.data;
                    document.getElementById('modalTitle').innerText = '编辑学生';
                    document.getElementById('studentId').value = s.id;
                    document.getElementById('studentNo').value = s.student_no;
                    document.getElementById('studentName').value = s.name;
                    document.getElementById('studentGender').value = s.gender;
                    document.getElementById('studentBirth').value = s.birth_date || '';
                    document.getElementById('studentClass').value = s.class_id;
                    document.getElementById('studentPhone').value = s.phone || '';
                    document.getElementById('studentAddress').value = s.address || '';
                    document.getElementById('studentModal').style.display = 'flex';
                });
        }

        // 保存学生
        function saveStudent() {
            const id = document.getElementById('studentId').value;
            const data = {
                student_no: document.getElementById('studentNo').value,
                name: document.getElementById('studentName').value,
                gender: document.getElementById('studentGender').value,
                birth_date: document.getElementById('studentBirth').value,
                class_id: document.getElementById('studentClass').value,
                phone: document.getElementById('studentPhone').value,
                address: document.getElementById('studentAddress').value
            };

            const url = id ? '/cgi-bin/student.cgi?action=edit' : '/cgi-bin/student.cgi?action=add';
            fetch(url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: new URLSearchParams(data)
            }).then(() => {
                closeModal();
                loadStudents();
                alert(id ? '修改成功' : '添加成功');
            });
        }

        // 删除学生
        function deleteStudent(id) {
            if (confirm('确定要删除该学生吗?')) {
                fetch(`/cgi-bin/student.cgi?action=delete&id=${id}`)
                    .then(() => {
                        loadStudents();
                        alert('删除成功');
                    });
            }
        }

        // 关闭模态框
        function closeModal() {
            document.getElementById('studentModal').style.display = 'none';
        }

        // 页面加载
        window.onload = () => {
            loadClasses();
            loadStudents();
        };
    </script>
</body>
</html>

第四部分:编译与部署

4.1 开发环境详解
4.1.1 Linux开发环境搭建(Ubuntu/Debian)
在开始编译之前,我们需要搭建完整的开发环境。以下是详细的安装步骤:

步骤1:安装GCC编译器套件

# 更新软件包列表
sudo apt update

# 安装build-essential包(包含gcc、g++、make等编译工具)
sudo apt install build-essential -y

# 验证GCC安装
gcc --version
# 预期输出:gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0

步骤2:安装MySQL开发库

MySQL开发库提供了C语言连接MySQL所需的头文件和库文件:

# 安装MySQL客户端开发库
sudo apt install libmysqlclient-dev -y

# 安装MySQL服务器(如果需要本地数据库)
sudo apt install mysql-server -y

# 验证MySQL头文件位置
ls /usr/include/mysql/
# 应该看到mysql.h、mysql_version.h等文件

步骤3:安装Apache Web服务器

# 安装Apache2
sudo apt install apache2 -y

# 启用CGI模块
sudo a2enmod cgi
sudo a2enmod rewrite

# 重启Apache服务
sudo systemctl restart apache2

# 检查Apache状态
sudo systemctl status apache2

4.1.2 项目目录结构规划
在开始编写代码之前,规划好项目目录结构:

student-management-system/
├── src/                    # 源代码目录
│   ├── common.h           # 公共头文件
│   ├── db.c               # 数据库操作函数
│   ├── utils.c            # 工具函数
│   ├── template.c         # HTML模板函数
│   └── student.c          # 主程序
├── include/               # 头文件目录(可选)
├── lib/                   # 编译生成的库文件(可选)
├── build/                 # 编译输出目录
├── cgi-bin/               # CGI程序部署目录
├── html/                  # 静态HTML文件目录
├── config/                # 配置文件目录
│   └── database.conf      # 数据库配置文件
├── logs/                  # 日志目录
├── Makefile               # 编译配置文件
└── README.md              # 项目说明文档

4.2 Makefile编写详解
Makefile是自动化编译的核心工具,它定义了编译规则和依赖关系。以下是完整的Makefile:

# ============================================================
# Makefile - 学生管理系统编译配置
# ============================================================

# 编译器设置
CC = gcc
CFLAGS = -Wall -g -O2 -I/usr/include/mysql
LDFLAGS = -lmysqlclient

# 目录设置
SRC_DIR = src
BUILD_DIR = build
CGI_DIR = /usr/lib/cgi-bin

# 源文件列表
SOURCES = $(SRC_DIR)/student.c \
          $(SRC_DIR)/db.c \
          $(SRC_DIR)/utils.c \
          $(SRC_DIR)/template.c

# 目标文件列表
OBJECTS = $(BUILD_DIR)/student.o \
          $(BUILD_DIR)/db.o \
          $(BUILD_DIR)/utils.o \
          $(BUILD_DIR)/template.o

# 最终生成的可执行文件
TARGET = $(BUILD_DIR)/student.cgi

# ============================================================
# 默认目标:编译主程序
# ============================================================
all: $(TARGET)

# 链接目标文件生成可执行文件
$(TARGET): $(OBJECTS)
    @mkdir -p $(BUILD_DIR)
    $(CC) $(OBJECTS) -o $(TARGET) $(LDFLAGS)
    @echo "✓ 编译完成: $(TARGET)"

# 编译student.c
$(BUILD_DIR)/student.o: $(SRC_DIR)/student.c $(SRC_DIR)/common.h
    @mkdir -p $(BUILD_DIR)
    $(CC) $(CFLAGS) -c $< -o $@

# 编译db.c
$(BUILD_DIR)/db.o: $(SRC_DIR)/db.c $(SRC_DIR)/common.h
    $(CC) $(CFLAGS) -c $< -o $@

# 编译utils.c
$(BUILD_DIR)/utils.o: $(SRC_DIR)/utils.c $(SRC_DIR)/common.h
    $(CC) $(CFLAGS) -c $< -o $@

# 编译template.c
$(BUILD_DIR)/template.o: $(SRC_DIR)/template.c $(SRC_DIR)/common.h
    $(CC) $(CFLAGS) -c $< -o $@

# ============================================================
# 安装:将编译好的程序部署到CGI目录
# ============================================================
install: $(TARGET)
    sudo cp $(TARGET) $(CGI_DIR)/
    sudo chmod 755 $(CGI_DIR)/student.cgi
    @echo "✓ 部署完成: $(CGI_DIR)/student.cgi"

# ============================================================
# 清理:删除编译产生的文件
# ============================================================
clean:
    rm -rf $(BUILD_DIR)/*.o $(TARGET)
    @echo "✓ 清理完成"

# ============================================================
# 完全清理并重新编译
# ============================================================
rebuild: clean all

# ============================================================
# 运行测试
# ============================================================
test:
    @echo "开始测试..."
    @echo "请访问: http://localhost/cgi-bin/student.cgi?action=list"

# ============================================================
# 帮助信息
# ============================================================
help:
    @echo "可用命令:"
    @echo "  make        - 编译项目"
    @echo "  make install- 部署到CGI目录"
    @echo "  make clean  - 清理编译文件"
    @echo "  make rebuild- 完全重新编译"
    @echo "  make test   - 显示测试信息"

4.3 编译过程详解
4.3.1 编译前的准备工作

# 1. 创建项目目录结构
mkdir -p student-management-system/{src,build,html,config,logs}
cd student-management-system

# 2. 将所有源代码放入src目录
# 将前文的所有.c和.h文件保存到src目录

# 3. 创建Makefile
# 将上面的Makefile内容保存到项目根目录

# 4. 确保MySQL服务正在运行
sudo systemctl start mysql
sudo systemctl status mysql

4.3.2 执行编译

# 执行编译
make

# 编译过程输出示例:
# mkdir -p build
# gcc -Wall -g -O2 -I/usr/include/mysql -c src/student.c -o build/student.o
# gcc -Wall -g -O2 -I/usr/include/mysql -c src/db.c -o build/db.o
# gcc -Wall -g -O2 -I/usr/include/mysql -c src/utils.c -o build/utils.o
# gcc -Wall -g -O2 -I/usr/include/mysql -c src/template.c -o build/template.o
# gcc build/student.o build/db.o build/utils.o build/template.o -o build/student.cgi -lmysqlclient
# ✓ 编译完成: build/student.cgi

4.3.3 解决常见编译错误
错误1:mysql.h: No such file or directory

# 原因:MySQL开发库未安装
# 解决方案:
sudo apt install libmysqlclient-dev

# 验证头文件位置
find /usr -name "mysql.h" 2>/dev/null

错误2:undefined reference to `mysql_init'

# 原因:链接器找不到MySQL库
# 解决方案:检查Makefile中的LDFLAGS是否包含-lmysqlclient
# 或者手动指定库路径
gcc -o student.cgi *.o -L/usr/lib/x86_64-linux-gnu -lmysqlclient

错误3:collect2: error: ld returned 1 exit status

# 原因:多个源文件中有重复的main函数定义
# 解决方案:确保只有student.c中有main函数
# 其他.c文件中不应包含main函数

错误4:权限被拒绝

# 原因:没有写入build目录的权限
# 解决方案:
mkdir -p build
chmod 755 build

4.4 部署配置详解
4.4.1 CGI目录配置
Apache的CGI程序需要放置在特定目录并具有执行权限:

# 1. 部署CGI程序
sudo make install
# 或手动复制
sudo cp build/student.cgi /usr/lib/cgi-bin/
sudo chmod 755 /usr/lib/cgi-bin/student.cgi

# 2. 验证文件已正确放置
ls -la /usr/lib/cgi-bin/student.cgi
# 输出示例:-rwxr-xr-x 1 root root 98765 May 1 10:30 student.cgi

4.4.2 Apache虚拟主机配置

# /etc/apache2/sites-available/student.conf
<VirtualHost *:80>
    ServerName student.local
    DocumentRoot /var/www/html

    # CGI配置
    ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
    <Directory "/usr/lib/cgi-bin">
        Options +ExecCGI
        AddHandler cgi-script .cgi
        Require all granted
    </Directory>

    # 静态文件目录
    Alias /static /var/www/student/static
    <Directory "/var/www/student/static">
        Options Indexes FollowSymLinks
        Require all granted
    </Directory>

    # 日志配置
    ErrorLog ${APACHE_LOG_DIR}/student_error.log
    CustomLog ${APACHE_LOG_DIR}/student_access.log combined
</VirtualHost>

4.4.3 启用站点配置

# 1. 启用虚拟主机
sudo a2ensite student.conf

# 2. 禁用默认站点(可选)
sudo a2dissite 000-default.conf

# 3. 检查配置语法
sudo apachectl configtest
# 预期输出:Syntax OK

# 4. 重启Apache
sudo systemctl restart apache2

4.4.4 数据库配置

# 1. 创建配置文件(避免硬编码密码)
cat > config/database.conf << 'EOF'
DB_HOST=localhost
DB_USER=root
DB_PASS=your_password
DB_NAME=student_db
EOF

# 2. 设置配置文件权限(仅所有者可读)
chmod 600 config/database.conf

# 3. 导入数据库表结构
mysql -u root -p < database.sql

来源:
https://wkmsa.cn/

相关文章
|
8天前
|
缓存 人工智能 自然语言处理
我对比了8个Claude API中转站,踩了不少坑,总结给你
本文是个人开发者耗时1周实测的8大Claude中转平台横向评测,聚焦Claude Code真实体验:以加权均价(¥/M token)、内部汇率、缓存支持、模型真实性及稳定性为核心指标。
3435 20
|
20天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
本文介绍了Claude Code终端AI助手的使用指南,主要内容包括:1)常用命令如版本查看、项目启动和更新;2)三种工作模式切换及界面说明;3)核心功能指令速查表,包含初始化、压缩对话、清除历史等操作;4)详细解析了/init、/help、/clear、/compact、/memory等关键命令的使用场景和语法。文章通过丰富的界面截图和场景示例,帮助开发者快速掌握如何通过命令行和交互界面高效使用Claude Code进行项目开发,特别强调了CLAUDE.md文件作为项目知识库的核心作用。
17984 60
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
|
1天前
|
SQL 人工智能 弹性计算
阿里云发布 Agentic NDR,威胁检测与响应进入智能体时代
欢迎前往阿里云云防火墙控制台体验!
1158 2
|
4天前
|
人工智能 JSON BI
DeepSeek V4 来了!超越 Claude Sonnet 4.5,赶紧对接 Claude Code 体验一把
JeecgBoot AI专题研究 把 Claude Code 接入 DeepSeek V4Pro 的真实体验与避坑记录 本文记录我将 Claude Code 对接 DeepSeek 最新模型(V4Pro)后的真实体验,测试了 Skills 自动化查询和积木报表 AI 建表两个场景——有惊喜,也踩
1857 8
|
15天前
|
人工智能 JavaScript Ubuntu
低成本搭建AIP自动化写作系统:Hermes保姆级使用教程,长文和逐步实操贴图
我带着怀疑的态度,深度使用了几天,聚焦微信公众号AIP自动化写作场景,写出来的几篇文章,几乎没有什么修改,至少合乎我本人的意愿,而且排版风格,也越来越完善,同样是起码过得了我自己这一关。 这个其实OpenClaw早可以实现了,但是目前我觉得最大的区别是,Hermes会自主总结提炼,并更新你的写作技能。 相信就冲这一点,就值得一试。 这篇帖子主要就Hermes部署使用,作一个非常详细的介绍,几乎一步一贴图。 关于Hermes,无论你赞成哪种声音,我希望都是你自己动手行动过,发自内心的选择!
3172 29
|
3天前
|
人工智能 缓存 BI
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
JeecgBoot AI专题研究 把 Claude Code 接入 DeepSeek V4Pro,跑完 Skills —— OA 审批、大屏、报表、部署 5 大实战场景后的真实体验 ![](https://oscimg.oschina.net/oscnet/up608d34aeb6bafc47f
1479 3
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
|
4天前
|
机器学习/深度学习 缓存 测试技术
DeepSeek-V4开源:百万上下文,Agent能力比肩顶级闭源模型
DeepSeek-V4正式开源!含V4-Pro(1.6T参数)与V4-Flash(284B参数)双版本,均支持百万token上下文。首创混合注意力架构,Agent能力、世界知识与推理性能全面领先开源模型,数学/代码评测比肩顶级闭源模型。
1737 6
|
5天前
|
人工智能 测试技术 API
阿里Qwen3.6-27B正式开源:网友直呼“太牛了”!
阿里云千问3.6系列重磅开源Qwen3.6-27B稠密大模型!官网:https://t.aliyun.com/U/JbblVp 仅270亿参数,编程能力媲美千亿模型,在SWE-bench等权威基准中表现卓越。支持多模态理解、本地部署及OpenClaw等智能体集成,已开放Hugging Face与ModelScope下载。