引言:为什么需要学习这个项目?
在当今数字化时代,掌握全栈开发能力 是成为优秀程序员的必经之路。今天,我将带领大家从零开始构建一个完整的停车场管理系统。这个项目不仅涵盖了C++核心编程 、MySQL数据库操作 、软件架构设计 等关键技术,更是一个绝佳的综合练习项目,适合有一定C++基础想提升实战能力的开发者。
一、项目概述与技术栈
1.1 项目功能亮点
-
🚗 智能车辆管理:入场登记、出场结算、停车查询
-
💰 灵活计费系统:支持小时计费、月卡会员、优惠折扣
-
📊 实时数据监控:车位状态、收入统计、使用率分析
-
🔐 多用户系统:管理员与操作员分级权限
1.2 技术栈详解
cpp
// 技术栈构成
- 核心语言: C++11/14 (现代C++特性)
- 数据库: MySQL 8.0 (关系型数据库)
- 连接驱动: MySQL Connector/C++ (官方库)
- 开发环境: VS2019 (Windows) / GCC (Linux)
- 设计模式: 单例模式、工厂模式、策略模式
二、环境配置:一步一图详细教程
2.1 Windows环境配置(VS2019)
步骤1:安装MySQL数据库
bash
# 1. 访问MySQL官网下载安装包
# 2. 选择MySQL Installer for Windows
# 3. 安装时记住设置的root密码(如:123456)
# 4. 确保MySQL服务已启动(在服务中查看)
步骤2:配置VS2019项目
打开VS2019,按以下步骤操作:
项目属性配置:
-
右键项目 → 属性 → VC++目录
-
包含目录 添加:
C:\Program Files\MySQL\MySQL Connector C++ 8.0\include -
库目录 添加:
C:\Program Files\MySQL\MySQL Connector C++ 8.0\lib64
链接器配置:
-
属性 → 链接器 → 输入
-
附加依赖项 添加:
mysqlcppconn.lib
重要: 将libmysql.dll复制到:
-
项目输出目录(Debug/Release文件夹)
-
或
C:\Windows\System32(64位系统)
2.2 Linux环境配置
cpp
# Ubuntu/Debian系统
sudo apt update
sudo apt install mysql-server mysql-client
sudo apt install libmysqlcppconn-dev build-essential cmake
# 启动MySQL服务
sudo systemctl start mysql
sudo systemctl enable mysql
# 验证安装
mysql --version
三、数据库设计:初学者必懂的核心概念
3.1 数据库创建与配置
cpp
-- 第一步:创建数据库
CREATE DATABASE IF NOT EXISTS parking_system
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE parking_system;
-- 第二步:创建核心表
-- 车辆信息表(核心表)
CREATE TABLE vehicles (
id INT PRIMARY KEY AUTO_INCREMENT,
plate_number VARCHAR(20) NOT NULL, -- 车牌号
vehicle_type ENUM('小型车','中型车','大型车') DEFAULT '小型车',
entry_time DATETIME NOT NULL, -- 入场时间
exit_time DATETIME, -- 出场时间
parking_space INT NOT NULL, -- 停车位
status ENUM('parking','exited') DEFAULT 'parking',
total_fee DECIMAL(10,2) DEFAULT 0.00, -- 总费用
paid_amount DECIMAL(10,2) DEFAULT 0.00 -- 已付金额
);
-- 收费记录表
CREATE TABLE payment_records (
id INT PRIMARY KEY AUTO_INCREMENT,
vehicle_id INT NOT NULL,
plate_number VARCHAR(20) NOT NULL,
payment_time DATETIME NOT NULL,
amount DECIMAL(10,2) NOT NULL,
FOREIGN KEY (vehicle_id) REFERENCES vehicles(id)
);
3.2 为什么要这样设计?
-
AUTO_INCREMENT:自动生成ID,避免重复
-
ENUM类型:限制字段取值范围,保证数据一致性
-
DATETIME:精确记录时间,便于计费计算
-
外键约束:保证数据完整性,防止无效记录
四、核心代码实现:分模块详解
4.1 数据库连接模块
cpp
// DatabaseHandler.h - 数据库连接核心类
#ifndef DATABASEHANDLER_H
#define DATABASEHANDLER_H
#include <mysql.h>
#include <string>
#include <iostream>
class DatabaseHandler {
private:
MYSQL* connection;
std::string host;
std::string user;
std::string password;
std::string database;
// 私有化构造函数(单例模式)
DatabaseHandler() {
host = "localhost";
user = "root";
password = "123456"; // 修改为你的密码
database = "parking_system";
connection = nullptr;
}
public:
// 获取单例实例
static DatabaseHandler& getInstance() {
static DatabaseHandler instance;
return instance;
}
// 禁止拷贝
DatabaseHandler(const DatabaseHandler&) = delete;
DatabaseHandler& operator=(const DatabaseHandler&) = delete;
// 连接数据库
bool connect() {
connection = mysql_init(nullptr);
if (!connection) {
std::cerr << "初始化MySQL连接失败" << std::endl;
return false;
}
// 建立连接
if (!mysql_real_connect(connection, host.c_str(), user.c_str(),
password.c_str(), database.c_str(),
3306, nullptr, 0)) {
std::cerr << "连接失败: " << mysql_error(connection) << std::endl;
return false;
}
// 设置字符集
mysql_set_character_set(connection, "utf8");
std::cout << "数据库连接成功!" << std::endl;
return true;
}
// 执行查询
MYSQL_RES* query(const std::string& sql) {
if (mysql_query(connection, sql.c_str()) != 0) {
std::cerr << "查询失败: " << mysql_error(connection) << std::endl;
return nullptr;
}
return mysql_store_result(connection);
}
// 执行更新(插入、更新、删除)
bool execute(const std::string& sql) {
return mysql_query(connection, sql.c_str()) == 0;
}
// 获取最后插入的ID
int getLastInsertId() {
return mysql_insert_id(connection);
}
~DatabaseHandler() {
if (connection) {
mysql_close(connection);
}
}
};
#endif // DATABASEHANDLER_H
4.2 车辆管理模块
cpp
// VehicleManager.cpp - 车辆业务逻辑
#include "DatabaseHandler.h"
#include <sstream>
#include <iomanip>
class VehicleManager {
private:
DatabaseHandler& db;
public:
VehicleManager() : db(DatabaseHandler::getInstance()) {}
// 车辆入场
bool vehicleEntry(const std::string& plate, int space) {
// 检查车辆是否已在场内
std::string checkSql = "SELECT COUNT(*) FROM vehicles WHERE "
"plate_number = '" + plate + "' AND status = 'parking'";
MYSQL_RES* result = db.query(checkSql);
if (result) {
MYSQL_ROW row = mysql_fetch_row(result);
if (row && std::stoi(row[0]) > 0) {
std::cout << "车辆已在场内!" << std::endl;
mysql_free_result(result);
return false;
}
mysql_free_result(result);
}
// 获取当前时间
time_t now = time(nullptr);
tm* ltm = localtime(&now);
std::stringstream ss;
ss << (1900 + ltm->tm_year) << "-"
<< std::setfill('0') << std::setw(2) << (1 + ltm->tm_mon) << "-"
<< std::setfill('0') << std::setw(2) << ltm->tm_mday << " "
<< std::setfill('0') << std::setw(2) << ltm->tm_hour << ":"
<< std::setfill('0') << std::setw(2) << ltm->tm_min << ":"
<< std::setfill('0') << std::setw(2) << ltm->tm_sec;
std::string entryTime = ss.str();
// 插入车辆记录
std::string insertSql = "INSERT INTO vehicles (plate_number, entry_time, "
"parking_space, status) VALUES ('" + plate + "', '"
+ entryTime + "', " + std::to_string(space) + ", 'parking')";
if (db.execute(insertSql)) {
std::cout << "车辆入场成功!" << std::endl;
std::cout << "车牌号: " << plate << std::endl;
std::cout << "停车位: " << space << std::endl;
std::cout << "入场时间: " << entryTime << std::endl;
return true;
}
return false;
}
// 车辆出场
bool vehicleExit(const std::string& plate, double hourlyRate = 5.0) {
// 获取车辆信息
std::string selectSql = "SELECT id, entry_time FROM vehicles WHERE "
"plate_number = '" + plate + "' AND status = 'parking'";
MYSQL_RES* result = db.query(selectSql);
if (!result) return false;
MYSQL_ROW row = mysql_fetch_row(result);
if (!row) {
std::cout << "未找到该车辆的停车记录!" << std::endl;
mysql_free_result(result);
return false;
}
int vehicleId = std::stoi(row[0]);
std::string entryTime = row[1];
mysql_free_result(result);
// 计算停车时长和费用
time_t now = time(nullptr);
tm entryTm = {}, nowTm = {};
strptime(entryTime.c_str(), "%Y-%m-%d %H:%M:%S", &entryTm);
localtime_r(&now, &nowTm);
double hours = difftime(now, mktime(&entryTm)) / 3600.0;
double fee = hours * hourlyRate;
// 获取当前时间作为出场时间
std::stringstream ss;
ss << (1900 + nowTm.tm_year) << "-"
<< std::setfill('0') << std::setw(2) << (1 + nowTm.tm_mon) << "-"
<< std::setfill('0') << std::setw(2) << nowTm.tm_mday << " "
<< std::setfill('0') << std::setw(2) << nowTm.tm_hour << ":"
<< std::setfill('0') << std::setw(2) << nowTm.tm_min << ":"
<< std::setfill('0') << std::setw(2) << nowTm.tm_sec;
std::string exitTime = ss.str();
// 更新车辆记录
std::string updateSql = "UPDATE vehicles SET exit_time = '" + exitTime +
"', total_fee = " + std::to_string(fee) +
", status = 'exited' WHERE id = " + std::to_string(vehicleId);
if (db.execute(updateSql)) {
// 添加收费记录
std::string paymentSql = "INSERT INTO payment_records (vehicle_id, plate_number, "
"payment_time, amount) VALUES (" + std::to_string(vehicleId) +
", '" + plate + "', '" + exitTime + "', " +
std::to_string(fee) + ")";
db.execute(paymentSql);
std::cout << "\n=== 收费详情 ===" << std::endl;
std::cout << "车牌号: " << plate << std::endl;
std::cout << "入场时间: " << entryTime << std::endl;
std::cout << "出场时间: " << exitTime << std::endl;
std::cout << "停车时长: " << std::fixed << std::setprecision(2)
<< hours << "小时" << std::endl;
std::cout << "停车费用: " << fee << "元" << std::endl;
return true;
}
return false;
}
// 查询停放中车辆
void showParkingVehicles() {
std::string sql = "SELECT plate_number, vehicle_type, entry_time, "
"parking_space FROM vehicles WHERE status = 'parking'";
MYSQL_RES* result = db.query(sql);
if (!result) return;
std::cout << "\n=== 停放中车辆列表 ===" << std::endl;
std::cout << std::left << std::setw(15) << "车牌号"
<< std::setw(10) << "车型"
<< std::setw(20) << "入场时间"
<< std::setw(10) << "停车位" << std::endl;
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))) {
std::cout << std::left << std::setw(15) << (row[0] ? row[0] : "")
<< std::setw(10) << (row[1] ? row[1] : "")
<< std::setw(20) << (row[2] ? row[2] : "")
<< std::setw(10) << (row[3] ? row[3] : "") << std::endl;
}
mysql_free_result(result);
}
};
4.3 用户界面模块
cpp
// ParkingSystem.cpp - 主程序
#include <iostream>
#include <string>
#include <limits>
class ParkingSystem {
private:
VehicleManager vehicleMgr;
void clearInputBuffer() {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
public:
void run() {
int choice;
do {
showMainMenu();
std::cout << "请选择操作: ";
std::cin >> choice;
clearInputBuffer();
switch (choice) {
case 1:
processVehicleEntry();
break;
case 2:
processVehicleExit();
break;
case 3:
vehicleMgr.showParkingVehicles();
break;
case 4:
showStatistics();
break;
case 0:
std::cout << "感谢使用,再见!" << std::endl;
break;
default:
std::cout << "无效选择,请重新输入!" << std::endl;
}
if (choice != 0) {
std::cout << "\n按Enter键继续...";
std::cin.get();
}
} while (choice != 0);
}
private:
void showMainMenu() {
system("cls"); // Windows清屏,Linux用"clear"
std::cout << "==================================" << std::endl;
std::cout << " 停车场管理系统 v1.0" << std::endl;
std::cout << "==================================" << std::endl;
std::cout << "1. 车辆入场登记" << std::endl;
std::cout << "2. 车辆出场结算" << std::endl;
std::cout << "3. 查看停放车辆" << std::endl;
std::cout << "4. 查看统计信息" << std::endl;
std::cout << "0. 退出系统" << std::endl;
std::cout << "==================================" << std::endl;
}
void processVehicleEntry() {
std::string plate;
int space;
std::cout << "\n=== 车辆入场登记 ===" << std::endl;
std::cout << "请输入车牌号: ";
std::getline(std::cin, plate);
std::cout << "请输入停车位号: ";
std::cin >> space;
clearInputBuffer();
vehicleMgr.vehicleEntry(plate, space);
}
void processVehicleExit() {
std::string plate;
std::cout << "\n=== 车辆出场结算 ===" << std::endl;
std::cout << "请输入车牌号: ";
std::getline(std::cin, plate);
vehicleMgr.vehicleExit(plate);
}
void showStatistics() {
DatabaseHandler& db = DatabaseHandler::getInstance();
// 统计总车辆数
std::string totalSql = "SELECT COUNT(*) FROM vehicles";
MYSQL_RES* result = db.query(totalSql);
if (result) {
MYSQL_ROW row = mysql_fetch_row(result);
std::cout << "\n总停车记录: " << (row[0] ? row[0] : "0") << "条" << std::endl;
mysql_free_result(result);
}
// 统计当前停放车辆
std::string parkingSql = "SELECT COUNT(*) FROM vehicles WHERE status = 'parking'";
result = db.query(parkingSql);
if (result) {
MYSQL_ROW row = mysql_fetch_row(result);
std::cout << "当前停放车辆: " << (row[0] ? row[0] : "0") << "辆" << std::endl;
mysql_free_result(result);
}
// 统计总收入
std::string revenueSql = "SELECT SUM(amount) FROM payment_records";
result = db.query(revenueSql);
if (result) {
MYSQL_ROW row = mysql_fetch_row(result);
std::cout << "总收入: " << (row[0] ? row[0] : "0") << "元" << std::endl;
mysql_free_result(result);
}
}
};
4.4 完整主程序
cpp
// main.cpp - 程序入口
#include "DatabaseHandler.h"
#include "ParkingSystem.cpp"
int main() {
// 设置控制台编码(Windows)
#ifdef _WIN32
system("chcp 65001 > nul");
system("title 停车场管理系统");
#endif
std::cout << "==================================" << std::endl;
std::cout << " 停车场管理系统启动中..." << std::endl;
std::cout << "==================================" << std::endl;
try {
// 初始化数据库连接
DatabaseHandler& db = DatabaseHandler::getInstance();
if (!db.connect()) {
std::cout << "数据库连接失败,程序退出!" << std::endl;
return 1;
}
// 运行主系统
ParkingSystem system;
system.run();
} catch (const std::exception& e) {
std::cerr << "系统错误: " << e.what() << std::endl;
std::cout << "按Enter键退出...";
std::cin.get();
return 1;
}
return 0;
}
五、常见问题与解决方案
5.1 编译错误解决
问题1:找不到mysql.h
错误:fatal error: mysql.h: No such file or directory
解决方案:
-
检查VS2019包含目录设置是否正确
-
确保MySQL Connector已正确安装
-
在项目属性中添加包含路径
问题2:链接错误
错误:LNK2019: 无法解析的外部符号
解决方案:
-
检查库目录设置
-
确认附加依赖项包含
mysqlcppconn.lib -
确保平台匹配(x64/x86)
5.2 运行时错误解决
问题1:连接数据库失败
解决方案:
-
检查MySQL服务是否启动
-
验证用户名和密码是否正确
-
检查防火墙设置
问题2:中文乱码
解决方案:
cpp
// 在连接后设置字符集
mysql_set_character_set(connection, "utf8mb4");
六、项目扩展建议
6.1 功能扩展方向
1. 月卡会员系统
cpp
class MonthlyMember {
private:
struct MemberInfo {
std::string member_id;
std::string plate_number;
std::string start_date;
std::string end_date;
double fee;
};
public:
bool addMember(const MemberInfo& member) {
// 实现月卡会员添加逻辑
}
bool isMember(const std::string& plate) {
// 检查是否为月卡会员
}
};
2. 图形界面开发
使用Qt或MFC开发图形界面,提升用户体验:
cpp
// Qt示例
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow() {
QPushButton* entryBtn = new QPushButton("车辆入场", this);
connect(entryBtn, &QPushButton::clicked,
this, &MainWindow::onEntryClicked);
}
private slots:
void onEntryClicked() {
// 处理入场逻辑
}
};
6.2 代码优化建议
1. 使用智能指针
cpp
#include <memory>
class DatabaseManager {
private:
std::unique_ptr<MYSQL, decltype(&mysql_close)> connection;
public:
DatabaseManager() : connection(nullptr, &mysql_close) {
connection.reset(mysql_init(nullptr));
}
// 自动管理资源,无需手动关闭
};
2. 添加日志系统
cpp
class Logger {
public:
enum LogLevel { INFO, WARNING, ERROR };
static void log(LogLevel level, const std::string& message) {
std::ofstream file("parking.log", std::ios::app);
file << getCurrentTime() << " [" << toString(level)
<< "] " << message << std::endl;
}
};
七、学习路线建议
7.1 初学者学习路径
-
第一阶段:运行现有代码,理解基本流程
-
第二阶段:修改计费规则,添加新功能
-
第三阶段:优化代码结构,实现设计模式
-
第四阶段:开发图形界面,部署到服务器
7.2 推荐的进阶学习
-
C++进阶:《Effective C++》、《C++ Primer》
-
数据库优化:《高性能MySQL》
-
软件设计:《设计模式:可复用面向对象软件的基础》
-
项目实战:参与开源项目,积累经验
八、总结
通过这个停车场管理系统的开发,你将掌握:
✅ 现代C++编程技巧
✅ MySQL数据库设计与操作
✅ 软件架构设计思想
✅ 实际项目开发流程
✅ 问题调试与解决能力
这个项目不仅是一个学习工具,更是一个可以展示你编程能力的作品集项目。
建议你在理解基础代码后,尝试添加自己的创新功能,比如:
-
添加预约停车功能
-
实现车牌识别接口
-
开发手机端管理应用
-
添加数据分析模块
记住:编程能力不是看会的,而是练会的。
动手实现这个项目,遇到问题解决问题,你的编程水平一定会有质的飞跃!