前言
- 本项目为前后端分离标准项目,结构清晰、注释完整,适合新手学习。
- 可直接作为课程设计、毕业设计、求职项目演示。
- 可扩展功能:用户管理、分类管理、借阅记录、上传封面、分页等。
一、文档信息
- 系统名称:图书馆管理系统
- 开发技术栈
- 后端:Python 3.8+、Flask、flask-cors、flask-mysqldb
- 前端:Vue3、Vite、Element Plus、Axios、Vue Router
- 数据库:MySQL 5.7 / 8.0
- 功能模块
- 管理员登录
- 系统首页
- 书籍列表查询 + 模糊搜索
- 书籍新增、编辑、删除
- 适用人群:编程新手、毕业设计、课程设计、全栈入门练习
- 运行环境:Windows / Linux 均可
二、开发环境准备
2.1 安装 Python(后端运行环境)
- 下载地址:https://www.python.org/
- 版本选择:3.8 ~ 3.11 均可
- 安装注意:必须勾选 Add Python to PATH
- 验证安装
bash
python --version
pip --version
2.2 安装 Node.js(前端运行环境)
- 下载地址:https://nodejs.org/ 选择 LTS 版本
- 一路默认安装即可
- 验证安装
bash
node -v
npm -v
2.3 安装 MySQL 数据库
- 下载 MySQL 5.7 或 8.0
- 安装过程中记住以下信息:
- 主机:localhost
- 端口:3306
- 用户名:root
- 密码:自定义(示例:123456)
- 数据库管理工具推荐:Navicat Premium / SQLyog
三、MySQL 数据库创建与初始化
打开 MySQL 客户端,执行以下 SQL 语句:
sql
-- 创建数据库
CREATE DATABASE library CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE library;
-- 用户表(用于登录)
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL
);
-- 书籍信息表
CREATE TABLE book (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL COMMENT '书名',
author VARCHAR(50) COMMENT '作者',
press VARCHAR(100) COMMENT '出版社'
);
-- 插入默认管理员账号
INSERT INTO user (username, password) VALUES ('admin', '123456');
四、后端项目开发(Flask)
4.1 项目结构
backend/
├─ .env # 项目配置文件(数据库、端口等)
└─ app.py # Flask 主程序(接口+数据库操作)
4.2 安装后端依赖包
新建文件夹 backend,打开终端进入目录执行:
bash
pip install flask flask-cors flask-mysqldb python-dotenv
4.3 配置文件 .env(详细注释)
ini
# ===================== Flask 服务配置 =====================
# 本机访问用 127.0.0.1,服务器部署用 0.0.0.0
FLASK_HOST=127.0.0.1
# 后端服务端口
FLASK_PORT=5000
# ===================== MySQL 数据库配置 =====================
# 数据库地址
MYSQL_HOST=localhost
# 数据库用户名
MYSQL_USER=root
# 数据库密码(必须改为自己的 MySQL 密码)
MYSQL_PASSWORD=123456
# 数据库名称
MYSQL_DB=library
# 数据库编码(固定 utf8mb4,支持特殊字符)
MYSQL_CHARSET=utf8mb4
4.4 后端主程序 app.py(完整代码+逐行注释)
python
# 导入 Flask 核心类
from flask import Flask, jsonify, request
# 解决跨域问题,允许前端访问后端
from flask_cors import CORS
# MySQL 数据库驱动
from flask_mysqldb import MySQL
# 读取 .env 配置文件
from dotenv import load_dotenv
import os
# 加载环境变量配置
load_dotenv()
# 初始化 Flask 应用
app = Flask(__name__)
# 允许所有域名跨域(前后端分离必备)
CORS(app)
# ======================== 数据库配置 ========================
app.config['MYSQL_HOST'] = os.getenv("MYSQL_HOST")
app.config['MYSQL_USER'] = os.getenv("MYSQL_USER")
app.config['MYSQL_PASSWORD'] = os.getenv("MYSQL_PASSWORD")
app.config['MYSQL_DB'] = os.getenv("MYSQL_DB")
app.config['MYSQL_CHARSET'] = os.getenv("MYSQL_CHARSET")
# 初始化 MySQL 连接
mysql = MySQL(app)
# ======================== 通用 SQL 执行函数 ========================
def execute_sql(sql, args=(), is_query=True):
"""
统一封装数据库操作,减少重复代码
:param sql: 要执行的 SQL 语句
:param args: SQL 语句中的参数
:param is_query: 是否为查询操作(查为True,增删改为False)
:return: 查询结果 / 操作成功
"""
cursor = mysql.connection.cursor()
cursor.execute(sql, args)
if is_query:
result = cursor.fetchall()
cursor.close()
return result
# 增删改操作需要提交事务
mysql.connection.commit()
cursor.close()
return True
# ======================== 1. 登录接口 ========================
@app.route("/api/login", methods=["POST"])
def login():
# 获取前端传递的 JSON 数据
data = request.get_json()
username = data.get("username")
password = data.get("password")
# 查询用户是否存在
sql = "SELECT * FROM user WHERE username=%s AND password=%s"
user = execute_sql(sql, (username, password))
if user:
return jsonify({"code": 200, "msg": "登录成功"})
else:
return jsonify({"code": 400, "msg": "账号或密码错误"})
# ======================== 2. 书籍列表 + 模糊搜索 ========================
@app.route("/api/book/list", methods=["GET"])
def book_list():
# 获取搜索关键词
keyword = request.args.get("keyword", "")
if keyword:
sql = "SELECT * FROM book WHERE name LIKE %s"
books = execute_sql(sql, (f"%{keyword}%",))
else:
sql = "SELECT * FROM book"
books = execute_sql(sql)
return jsonify({
"code": 200,
"data": books
})
# ======================== 3. 新增书籍接口 ========================
@app.route("/api/book/add", methods=["POST"])
def book_add():
data = request.get_json()
name = data.get("name")
author = data.get("author")
press = data.get("press")
sql = "INSERT INTO book(name, author, press) VALUES(%s, %s, %s)"
execute_sql(sql, (name, author, press), is_query=False)
return jsonify({"code": 200, "msg": "添加成功"})
# ======================== 4. 修改书籍接口 ========================
@app.route("/api/book/update", methods=["POST"])
def book_update():
data = request.get_json()
id = data.get("id")
name = data.get("name")
author = data.get("author")
press = data.get("press")
sql = "UPDATE book SET name=%s, author=%s, press=%s WHERE id=%s"
execute_sql(sql, (name, author, press, id), is_query=False)
return jsonify({"code": 200, "msg": "修改成功"})
# ======================== 5. 删除书籍接口 ========================
@app.route("/api/book/delete", methods=["POST"])
def book_delete():
id = request.get_json().get("id")
sql = "DELETE FROM book WHERE id=%s"
execute_sql(sql, (id,), is_query=False)
return jsonify({"code": 200, "msg": "删除成功"})
# ======================== 启动服务 ========================
if __name__ == "__main__":
app.run(
host=os.getenv("FLASK_HOST"),
port=int(os.getenv("FLASK_PORT")),
debug=True
)
五、前端项目开发(Vue3 + Element Plus)
5.1 项目结构
frontend/
├─ src/
│ ├─ request.js # Axios 请求封装
│ ├─ router/
│ │ └─ index.js # 路由配置
│ ├─ views/
│ │ ├─ Login.vue # 登录页面
│ │ ├─ Home.vue # 系统首页
│ │ └─ Book.vue # 书籍管理(增删改查)
│ ├─ App.vue
│ └─ main.js
5.2 创建 Vue 项目并安装依赖
bash
npm create vite@latest frontend -- --template vue
cd frontend
npm install
npm install element-plus axios vue-router
5.3 Axios 封装 src/request.js
js
import axios from 'axios'
// 创建 axios 实例,统一配置后端接口地址
const request = axios.create({
baseURL: 'http://127.0.0.1:5000/api'
})
export default request
5.4 路由配置 src/router/index.js
js
import { createRouter, createWebHistory } from 'vue-router'
import Login from '../views/Login.vue'
import Home from '../views/Home.vue'
import Book from '../views/Book.vue'
const routes = [
{ path: '/', component: Login },
{ path: '/home', component: Home },
{ path: '/book', component: Book }
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
5.5 登录页面 src/views/Login.vue
javascript
<template>
<div class="login-box">
<el-card style="width: 400px; margin: 100px auto">
<h2 style="text-align:center">图书馆管理系统</h2>
<el-input v-model="username" placeholder="账号" style="margin: 10px 0" />
<el-input v-model="password" placeholder="密码" type="password" style="margin: 10px 0" />
<el-button type="primary" @click="login" style="width: 100%">登录</el-button>
</el-card>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import request from '../request.js'
import { useRouter } from 'vue-router'
const router = useRouter()
const username = ref('')
const password = ref('')
// 登录请求
const login = async () => {
const res = await request.post('/login', {
username: username.value,
password: password.value
})
if (res.data.code === 200) {
ElMessage.success('登录成功')
router.push('/home')
} else {
ElMessage.error('账号或密码错误')
}
}
</script>
5.6 首页 src/views/Home.vue
javascript
<template>
<div style="padding: 20px">
<h2>欢迎使用图书馆管理系统</h2>
<el-button type="primary" @click="$router.push('/book')">
进入书籍管理
</el-button>
</div>
</template>
5.7 书籍管理(增删改查)src/views/Book.vue
javascript
<template>
<div style="padding: 20px">
<h3>书籍管理</h3>
<div style="margin-bottom:10px">
<el-input v-model="keyword" placeholder="搜索书名" @input="getList" style="width:300px" />
<el-button type="primary" @click="openAdd" style="margin-left:10px">新增书籍</el-button>
</div>
<!-- 书籍列表表格 -->
<el-table :data="books" border style="width:100%">
<el-table-column label="ID" prop="id" />
<el-table-column label="书名" prop="name" />
<el-table-column label="作者" prop="author" />
<el-table-column label="出版社" prop="press" />
<el-table-column label="操作">
<template #default="scope">
<el-button @click="openEdit(scope.row)">编辑</el-button>
<el-button type="danger" @click="delBook(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新增/编辑弹窗 -->
<el-dialog v-model="dialogVisible" title="书籍信息">
<el-input v-model="form.name" placeholder="书名" style="margin-bottom:10px" />
<el-input v-model="form.author" placeholder="作者" style="margin-bottom:10px" />
<el-input v-model="form.press" placeholder="出版社" style="margin-bottom:10px" />
<el-button type="primary" @click="saveBook">保存</el-button>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '../request.js'
const books = ref([])
const keyword = ref('')
const dialogVisible = ref(false)
const form = ref({ id: '', name: '', author: '', press: '' })
// 获取书籍列表
const getList = async () => {
const res = await request.get('/book/list', {
params: { keyword: keyword.value }
})
books.value = res.data.data
}
// 打开新增弹窗
const openAdd = () => {
form.value = { id: '', name: '', author: '', press: '' }
dialogVisible.value = true
}
// 打开编辑弹窗
const openEdit = (row) => {
form.value = { ...row }
dialogVisible.value = true
}
// 保存书籍(新增+修改)
const saveBook = async () => {
if (form.value.id) {
await request.post('/book/update', form.value)
} else {
await request.post('/book/add', form.value)
}
ElMessage.success('保存成功')
dialogVisible.value = false
getList()
}
// 删除书籍
const delBook = async (id) => {
await request.post('/book/delete', { id })
ElMessage.success('删除成功')
getList()
}
// 页面加载时自动获取列表
onMounted(() => {
getList()
})
</script>
5.8 入口文件 src/main.js
js
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import router from './router'
const app = createApp(App)
app.use(ElementPlus)
app.use(router)
app.mount('#app')
5.9 根组件 App.vue
vue
<template>
<router-view />
</template>
六、本地运行项目
6.1 启动后端服务
进入 backend 目录:
bash
python app.py
后端运行地址:http://127.0.0.1:5000
6.2 启动前端服务
进入 frontend 目录:
bash
npm run dev
前端访问地址:http://localhost:5173
6.3 测试登录
- 账号:admin
- 密码:123456
登录成功后可进入首页、书籍管理,完成增删改查操作。
七、Linux 服务器部署(上线完整版)
7.1 服务器环境安装
bash
yum install -y python3 python3-devel mysql-devel gcc nginx
7.2 后端部署
- 将
backend上传至服务器/var/www/library - 创建虚拟环境并安装依赖
bash
cd /var/www/library
python3 -m venv venv
source venv/bin/activate
pip install flask flask-cors flask-mysqldb python-dotenv gunicorn
- 修改
.env
ini
FLASK_HOST=0.0.0.0
FLASK_PORT=5000
MYSQL_HOST=localhost
MYSQL_USER=root
MYSQL_PASSWORD=你的数据库密码
MYSQL_DB=library
MYSQL_CHARSET=utf8mb4
- 后台启动后端服务
bash
nohup gunicorn -w 4 -b 0.0.0.0:5000 app:app &
7.3 前端部署
- 本地打包前端
bash
npm run build
-
将
dist目录上传至/var/www/library/frontend/dist -
Nginx 配置文件
/etc/nginx/conf.d/library.conf
nginx
server {
listen 80;
server_name 你的服务器公网IP;
root /var/www/library/frontend/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://127.0.0.1:5000/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
- 重启 Nginx
bash
nginx -t
systemctl restart nginx
7.4 防火墙开放端口
bash
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=5000/tcp
firewall-cmd --reload
八、常见问题及解决方案
-
前端跨域报错
已在后端使用
CORS(app)解决,无需额外配置。 -
MySQL 连接失败
- 检查 MySQL 服务是否启动
- 检查
.env中用户名、密码、库名是否正确
-
接口返回 404
- 检查前端
baseURL是否正确 - 检查后端路由是否书写错误
- 检查前端
-
Vue 页面刷新 404
已在 Nginx 配置
try_files解决。 -
服务器无法访问
- 检查安全组是否开放 80、5000 端口
- 检查防火墙是否放行端口
Flask的学习链接
https://www.runoob.com/flask/flask-tutorial.htmlMySql的学习链接 https://blog.csdn.net/jason_renyu/article/details/159172753
服务器部署的学习文档 https://blog.csdn.net/jason_renyu/article/details/133927034