45、无依赖信息查询系统(C语言+SQLite3+HTML)

无依赖信息查询系统(C语言+SQLite3+HTML)

一、项目核心信息

1. 项目定位

  • 适用场景:简易商品信息查询、嵌入式Web学习、轻量级部署场景(无服务器依赖)
  • 核心目标:实现「登录验证→商品搜索→详情查看」三大核心功能
  • 项目优势:无第三方框架依赖、编译后单文件运行、SQLite3文件数据库(无需额外部署)、支持中文关键词搜索

2. 核心技术栈

  • 后端:C语言(实现HTTP服务器、socket编程、数据库操作)
  • 数据库:SQLite3(轻量级文件数据库,存储用户和商品数据)
  • 前端:HTML(静态交互界面,登录表单、搜索表单)
  • 关键技术:URL编解码(中文传输兼容)、SQL预处理(防注入)、二进制文件传输(商品图片)

3. 数据库设计

项目依赖123.db文件数据库,包含两张核心表,结构如下:

(1)用户表 users(登录验证用)
字段名 数据类型 约束 说明
user_id INTEGER 自增主键 用户唯一标识
user_name TEXT 非空、唯一 登录用户名(如zhangsan)
password TEXT 非空 登录密码(如123456)
email TEXT 可选 预留字段(用户邮箱)
(2)商品表 goods(商品数据存储)
字段名 数据类型 约束 说明
goods_id INTEGER 自增主键 商品唯一标识
goods_name TEXT 非空 商品名称(如"联通100元充值卡")
shop_price REAL 非空 商品售价(如95.0)
keywords TEXT 可选 商品关键词(如"联通 充值")
goods_desc TEXT 可选 商品详细介绍
goods_thumb TEXT 可选 缩略图路径(如"images/xxx.jpg")
goods_img TEXT 可选 商品大图路径
original_img TEXT 可选 商品原图路径(支持放大查看)
goods_number INTEGER 非空 库存数量(如100)

二、核心功能实现流程

1. 整体流程闭环

复制代码
浏览器访问 → 登录页面(login.html)→ 输入账号密码 → 登录验证(查询users表)→ 搜索页面(search.html)→ 输入关键词 → 商品搜索(模糊查询goods表)→ 商品列表(动态HTML)→ 点击商品 → 详情页面(动态拼接商品信息)

2. 三大核心功能详解

(1)用户登录验证
  • 触发条件:浏览器访问http://127.0.0.1:8080,提交登录表单
  • 核心逻辑:
    1. 解析URL中的userpass参数,通过urldecode处理中文/特殊字符;
    2. 调用check_login函数,通过SQL预处理语句查询users表,避免SQL注入;
    3. 验证通过则返回search.html,失败则返回错误提示页面。
(2)商品搜索查询
  • 触发条件:登录后输入关键词(如"三星""联通"),提交搜索请求
  • 核心逻辑:
    1. 解析并解码搜索关键词,非空校验后调用handle_search函数;
    2. 执行SQL模糊查询(LIKE '%' || ? || '%'),匹配goods_name字段;
    3. 遍历结果集,动态拼接HTML片段(包含商品名称、价格、缩略图、详情链接);
    4. 无匹配商品时显示"共找到0个相关商品",支持重新搜索。
(3)商品详情查看
  • 触发条件:点击商品列表中的商品名称,发起/detail?id=xxx请求
  • 核心逻辑:
    1. 解析URL中的商品ID,查询goods表的完整字段;
    2. 动态拼接详情页HTML,包含价格、库存、详细介绍、缩略图+原图(支持点击放大);
    3. 商品不存在时返回404页面,字段缺失时显示默认值(如"暂无详细介绍")。

三、核心代码解析

1. HTTP服务器初始化(C语言socket编程)

服务器的核心是基于TCP socket实现HTTP请求监听与响应,关键代码如下:

c 复制代码
int main() {
    // 1. 创建TCP套接字
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    // 2. 配置服务器地址(监听8080端口,所有网卡可访问)
    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(PORT),  // PORT=8080
        .sin_addr.s_addr = INADDR_ANY
    };
    // 3. 绑定端口+监听连接
    bind(sfd, (struct sockaddr*)&addr, sizeof(addr));
    listen(sfd, 5);  // 最大排队连接数5
    printf("HTTP server running at http://127.0.0.1:%d\n", PORT);

    // 4. 循环接收客户端连接
    while (1) {
        int cfd = accept(sfd, NULL, NULL);  // 阻塞等待连接
        char buf[BUF_SIZE] = {0};
        recv(cfd, buf, BUF_SIZE - 1, 0);  // 接收HTTP请求
        printf("request:\n%s\n", buf);

        // 5. 路由分发(根据请求路径调用对应模块)
        if (strncmp(buf, "GET /login?", 11) == 0) {
            handle_login(cfd, buf);  // 登录请求
        } else if (strncmp(buf, "GET /search?", 12) == 0) {
            handle_search_request(cfd, buf);  // 搜索请求
        } else if (strncmp(buf, "GET /detail?", 12) == 0) {
            handle_detail_request(cfd, buf);  // 详情请求
        } else if (strncmp(buf, "GET /images/", 12) == 0) {
            send_image(cfd, buf);  // 图片请求
        } else {
            send_file(cfd, "login.html");  // 默认返回登录页
        }

        close(cfd);  // 关闭当前连接
    }
    close(sfd);
    return 0;
}
  • 关键亮点:通过strncmp解析请求路径,实现简单路由;单线程模型,适合轻量场景;无额外依赖,编译后直接运行。

2. 登录验证模块(SQL预处理防注入)

登录验证的核心是安全查询数据库,使用SQL预处理语句避免注入攻击:

c 复制代码
int check_login(const char *user, const char *pass) {
    sqlite3 *db = NULL;
    sqlite3_stmt *stmt = NULL;
    int ret = 0;

    // 打开数据库
    if (sqlite3_open("123.db", &db) != SQLITE_OK) {
        fprintf(stderr, "打开数据库失败:%s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 0;
    }

    // SQL预处理语句(?为参数占位符)
    const char *sql = "SELECT 1 FROM users WHERE user_name = ? AND password = ?;";
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
        fprintf(stderr, "SQL预处理失败:%s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 0;
    }

    // 绑定参数(避免SQL注入)
    sqlite3_bind_text(stmt, 1, user, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, pass, -1, SQLITE_TRANSIENT);

    // 执行查询(存在匹配用户则返回1)
    if (sqlite3_step(stmt) == SQLITE_ROW) {
        ret = 1;
    }

    // 释放资源
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return ret;
}
  • 关键亮点:使用sqlite3_prepare_v2预处理SQL,sqlite3_bind_text绑定参数,彻底杜绝SQL注入;查询结果仅判断是否存在,提高效率。

3. 商品搜索模块(动态HTML拼接)

搜索模块需要将数据库结果动态转为HTML,核心代码如下:

c 复制代码
void handle_search(int cfd, const char *key) {
    sqlite3 *db = NULL;
    sqlite3_stmt *stmt = NULL;

    // 打开数据库+预处理查询
    sqlite3_open("123.db", &db);
    const char *sql = "SELECT goods_id, goods_name, shop_price, keywords, goods_thumb FROM goods WHERE goods_name LIKE '%' || ? || '%';";
    sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, key, -1, SQLITE_TRANSIENT);

    // 发送HTTP响应头(指定UTF-8编码,避免中文乱码)
    const char *header = "HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=UTF-8\r\n\r\n";
    send(cfd, header, strlen(header), 0);
    send(cfd, "<h2>商品搜索结果</h2>", strlen("<h2>商品搜索结果</h2>"), 0);

    // 遍历结果集,动态拼接HTML
    int count = 0;
    char buf[2048];
    while (sqlite3_step(stmt) == SQLITE_ROW) {
        count++;
        int goods_id = sqlite3_column_int(stmt, 0);
        const char *name = sqlite3_column_text(stmt, 1);
        double price = sqlite3_column_double(stmt, 2);
        const char *keywords = sqlite3_column_text(stmt, 3);
        const char *img = sqlite3_column_text(stmt, 4);

        // 字段默认值处理
        name = name ? name : "未知商品";
        keywords = keywords ? keywords : "暂无简介";
        img = img ? img : "images/default.jpg";

        // 拼接商品卡片HTML
        snprintf(buf, sizeof(buf), 
            "<div style='margin:15px 0;padding:10px;border:1px solid #ccc;'>"
            "<h3><a href=\"/detail?id=%d\">%s</a></h3>"
            "<p>价格:¥%.2f</p>"
            "<p>关键词:%s</p>"
            "<img src=\"%s\" width=\"120\" height=\"100\">"
            "</div><hr>",
            goods_id, name, price, keywords, img);
        send(cfd, buf, strlen(buf), 0);
    }

    // 发送商品总数
    snprintf(buf, sizeof(buf), "<p>共找到 %d 个相关商品</p>", count);
    send(cfd, buf, strlen(buf), 0);

    sqlite3_finalize(stmt);
    sqlite3_close(db);
}
  • 关键亮点:动态拼接HTML,无需静态列表页;字段默认值处理,避免空指针异常;支持中文关键词,UTF-8编码兼容。

4. 图片传输模块(二进制文件发送)

商品图片需要以二进制模式读取并发送,核心代码如下:

c 复制代码
void send_binary_file(int cfd, const char *filename) {
    FILE *fp = fopen(filename, "rb");  // 二进制模式打开图片
    if (!fp) {
        const char *err = "HTTP/1.1 404 Not Found\r\n\r\n";
        send(cfd, err, strlen(err), 0);
        return;
    }

    // 发送图片响应头(指定Content-Type为image/jpeg)
    const char *header = "HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\n\r\n";
    send(cfd, header, strlen(header), 0);

    // 循环读取并发送二进制数据
    char buf[4096];
    size_t n;
    while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
        send(cfd, buf, n, 0);
    }

    fclose(fp);
}
  • 关键亮点:二进制模式rb读取图片,避免文件损坏;分块发送大文件,适配不同大小图片;支持JPEG格式,可扩展PNG/ICO。

四、项目部署与测试

1. 环境准备(Ubuntu/Debian)

bash 复制代码
# 安装SQLite3开发库(编译依赖)
sudo apt-get update && sudo apt-get install libsqlite3-dev -y

# 安装GCC编译器(若未安装)
sudo apt-get install gcc -y

2. 项目文件结构

复制代码
mall_project/
├── login_server.c  # 核心服务器代码
├── login.html      # 登录表单页面
├── search.html     # 搜索表单页面
├── 123.db          # SQLite3数据库文件
└── images/         # 商品图片目录
    ├── default.jpg  # 默认图片
    └── 200905/      # 商品图片子目录

3. 编译与运行

bash 复制代码
# 编译代码(链接SQLite3库)
gcc login_server.c -o login_server -lsqlite3

# 运行服务器(监听8080端口)
./login_server
  • 运行成功提示:HTTP server running at http://127.0.0.1:8080

4. 功能测试

  1. 登录测试 :浏览器访问http://127.0.0.1:8080,输入用户名zhangsan、密码123456,登录成功跳转至搜索页;
  2. 搜索测试:输入关键词"联通",点击搜索,显示2个充值卡商品(ID27、28);
  3. 详情测试:点击商品名称,进入详情页,查看价格、库存、图片和详细介绍;
  4. 异常测试:输入错误账号密码,返回登录失败提示;搜索无结果时显示"共找到0个相关商品"。

五、项目优势与局限

1. 核心优势

  • 轻量级部署:无需服务器(如Nginx、Tomcat),无需数据库服务(如MySQL),单文件+数据库+静态资源即可运行;
  • 安全可靠:SQL预处理防注入,URL编解码兼容中文,输入参数校验避免异常;
  • 易扩展:模块化设计,新增功能(如购物车、订单)可直接添加模块;
  • 学习价值高:覆盖C语言socket编程、SQLite3操作、HTTP协议、HTML交互,适合嵌入式Web学习。

2. 局限与优化方向

  • 单线程模型:同一时间仅支持一个客户端连接,可优化为多线程/进程模型;
  • GET请求传输:登录和搜索参数暴露在URL中,可新增POST请求支持;
  • 无状态管理:关闭浏览器后需重新登录,可添加Cookie/Session支持;
  • 密码明文存储:可新增MD5加密存储,提升安全性;
  • 并发性能:适合小规模使用,高并发场景需优化网络模型。
相关推荐
Rabbit_QL1 天前
【水印添加工具】从零设计一个工程级 Python 图片水印工具:WaterMask 架构与实现
开发语言·python
天“码”行空1 天前
简化Lambda——方法引用
java·开发语言
z20348315201 天前
C++对象布局
开发语言·c++
戌中横1 天前
JavaScript——Web APIs DOM
前端·javascript·html
Beginner x_u1 天前
如何解释JavaScript 中 this 的值?
开发语言·前端·javascript·this 指针
List<String> error_P1 天前
STM32窗口看门狗WWDG详解
stm32·单片机·嵌入式硬件·定时器
java1234_小锋1 天前
Java线程之间是如何通信的?
java·开发语言
张张努力变强1 天前
C++ Date日期类的设计与实现全解析
java·开发语言·c++·算法
feifeigo1231 天前
基于EM算法的混合Copula MATLAB实现
开发语言·算法·matlab
鑫—萍1 天前
嵌入式开发学习——STM32单片机入门教程
c语言·驱动开发·stm32·单片机·嵌入式硬件·学习·硬件工程