图书馆管理系统完整开发文档(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

相关推荐
笨鸟先飞,勤能补拙17 分钟前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
长和信泰光伏储能1 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂2 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study2 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境3 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境3 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1233 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy12393102164 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb004 小时前
一个项目带你入门AI应用开发01
python
0566464 小时前
Python康复训练——常用标准库
开发语言·python·学习