图书馆管理系统完整开发文档(Flask + Vue3 + Element Plus + MySQL )

前言

  • 本项目为前后端分离标准项目,结构清晰、注释完整,适合新手学习。
  • 可直接作为课程设计、毕业设计、求职项目演示。
  • 可扩展功能:用户管理、分类管理、借阅记录、上传封面、分页等。

一、文档信息

  • 系统名称:图书馆管理系统
  • 开发技术栈
    • 后端: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(后端运行环境)

  1. 下载地址:https://www.python.org/
  2. 版本选择:3.8 ~ 3.11 均可
  3. 安装注意:必须勾选 Add Python to PATH
  4. 验证安装
bash 复制代码
python --version
pip --version

2.2 安装 Node.js(前端运行环境)

  1. 下载地址:https://nodejs.org/ 选择 LTS 版本
  2. 一路默认安装即可
  3. 验证安装
bash 复制代码
node -v
npm -v

2.3 安装 MySQL 数据库

  1. 下载 MySQL 5.7 或 8.0
  2. 安装过程中记住以下信息:
    • 主机:localhost
    • 端口:3306
    • 用户名:root
    • 密码:自定义(示例:123456)
  3. 数据库管理工具推荐: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 后端部署

  1. backend 上传至服务器 /var/www/library
  2. 创建虚拟环境并安装依赖
bash 复制代码
cd /var/www/library
python3 -m venv venv
source venv/bin/activate
pip install flask flask-cors flask-mysqldb python-dotenv gunicorn
  1. 修改 .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
  1. 后台启动后端服务
bash 复制代码
nohup gunicorn -w 4 -b 0.0.0.0:5000 app:app &

7.3 前端部署

  1. 本地打包前端
bash 复制代码
npm run build
  1. dist 目录上传至 /var/www/library/frontend/dist

  2. 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;
    }
}
  1. 重启 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

八、常见问题及解决方案

  1. 前端跨域报错

    已在后端使用 CORS(app) 解决,无需额外配置。

  2. MySQL 连接失败

    • 检查 MySQL 服务是否启动
    • 检查 .env 中用户名、密码、库名是否正确
  3. 接口返回 404

    • 检查前端 baseURL 是否正确
    • 检查后端路由是否书写错误
  4. Vue 页面刷新 404

    已在 Nginx 配置 try_files 解决。

  5. 服务器无法访问

    • 检查安全组是否开放 80、5000 端口
    • 检查防火墙是否放行端口

Flask的学习链接
https://www.runoob.com/flask/flask-tutorial.html

MySql的学习链接 https://blog.csdn.net/jason_renyu/article/details/159172753

服务器部署的学习文档 https://blog.csdn.net/jason_renyu/article/details/133927034

相关推荐
费弗里1 小时前
新版本Dash完美支持原生FastAPI后端
python·fastapi·dash
Ulyanov2 小时前
《玩转QT Designer Studio:从设计到实战》 QT Designer Studio环境搭建与核心工作区详解
开发语言·python·qt·系统仿真·雷达电子战系统仿真
2301_816660212 小时前
c++ openimageio工具 c++如何使用oiiotool进行图像批量处理
jvm·数据库·python
m0_377618232 小时前
SQL性能调优:为何尽量使用窗口函数而非关联子查询
jvm·数据库·python
2301_796588502 小时前
如何监控MongoDB索引碎片的产生_compact命令与碎片整理
jvm·数据库·python
qq_432703662 小时前
HTML函数运行吃CPU吗_HTML函数对处理器性能影响评估【教程】
jvm·数据库·python
databook2 小时前
如何灵活设置公式中各个部分的颜色?
python·数学·动效
hhb_6182 小时前
Python 工程化开发与性能优化实践
开发语言·python·性能优化
NiKick2 小时前
Python 爬虫实战案例 - 获取社交平台事件热度并进行影响分析
开发语言·爬虫·python