0


web图书管理全栈开发实战vue+elementui+node.js+mysql

一.界面展示

1.主界面

2.添加书籍

3.删除书籍

4.编辑书籍信息

二.技术栈与框架设计

项目设计

  1. 数据库设计

    设计了books表,包含字段:id, name, author, price, publisher。

  2. Node.js + Express后端设计

    初始化Express应用。

    创建了基础路由和服务器监听。

    配置了数据库连接。

    实现了图书模型(BookModel),提供了对图书增删改查的功能。

  3. 前端页面设计(Element UI)

    使用Vue.js和Element UI创建了图书管理界面。

    设计了图书列表展示、添加、编辑和删除的交互界面。

技术栈

后端(Node.js + Express)

实现了RESTful API,包括获取所有图书、根据作者查询图书、删除指定ID的图书、更新指定ID的图书信息、增加新图书。

前端(Vue.js + Element UI)

使用Element UI组件创建了图书列表和表单。

使用axios实现了与后端API的交互,包括获取图书列表、添加新图书、编辑和删除图书。

测试

提供了测试脚本,用于验证图书模型的各种功能。

部署

后端部署在

http://localhost:3000,前端页面通过Vue.js渲染并与后端API交互

项目目录

后端项目配置的很详细,也很工程化.
前端因为时间仓促设置简单了点

三.详细项目设计流程

数据库设计

mysql建立图书数据库 建立books表,包含信息:

主键id、name,author,price,publisher

测试数据输入:

后端配置

a.配置node.js+express 环境

b.链接数据库

编写链接配置文件

创建sql链接并且导出

c.编写bookModel功能模型,为路由配置做准备

功能1:显示所有书籍数据,不需要输入

功能2:输入:指定作者的书,可以进行查询

功能3:输入:指定id的书,可以进行删除

功能4:输入:指定id的书,可以进行信息修改

功能5:输入:图书信息,可以进行图书的增加
const db = require('database'); // 确保此路径正确指向您的数据库连接文件

class BookModel {
    // 获取所有图书
    static async getAllBooks() {
        return new Promise((resolve, reject) => {
            db.query('SELECT * FROM books', (err, results) => {
                if (err) return reject(err);
                resolve(results);
            });
        });
    }

    // 根据作者查询图书
    static async getBooksByAuthor(author) {
        return new Promise((resolve, reject) => {
            db.query('SELECT * FROM books WHERE author = ?', [author], (err, results) => {
                if (err) return reject(err);
                resolve(results);
            });
        });
    }

    // 根据ID删除图书
    static async deleteBookById(bookId) {
        return new Promise((resolve, reject) => {
            db.query('DELETE FROM books WHERE id = ?', [bookId], (err, results) => {
                if (err) return reject(err);
                resolve(results);
            });
        });
    }

    // 根据ID更新图书信息
    static async updateBookById(bookId, bookData) {
        return new Promise((resolve, reject) => {
            const { name, author, price, publisher } = bookData;
            db.query(
                'UPDATE books SET name = ?, author = ?, price = ?, publisher = ? WHERE id = ?',
                [name, author, price, publisher, bookId],
                (err, results) => {
                    if (err) return reject(err);
                    resolve(results);
                }
            );
        });
    }

    // 增加新图书
    static async addBook(newBook) {
        return new Promise((resolve, reject) => {
            const { name, author, price, publisher } = newBook;
            db.query(
                'INSERT INTO books (name, author, price, publisher) VALUES (?, ?, ?, ?)',
                [name, author, price, publisher],
                (err, results) => {
                    if (err) return reject(err);
                    resolve(results);
                }
            );
        });
    }
}

module.exports = BookModel;

完成功能后,使用配置测试文件testmodel.js 使用样例测试各个功能

d.将boolModel功能配置为路由文件

const express = require('express');
const router = express.Router();
const BookModel = require('bookModel'); // 确保此路径正确指向您的模型文件GET http://localhost:3000/api/books

// 功能1:显示所有书籍数据
router.get('/books', async (req, res) => {
    try {
        const books = await BookModel.getAllBooks();
        res.json(books);
    } catch (err) {
        res.status(500).json({ message: 'Error retrieving books', error: err.message });
    }
});

// 功能2:输入指定作者,查询书籍
router.get('/books', async (req, res) => {
    try {
        const author = req.query.author; // 从查询参数中获取作者
        const booksByAuthor = await BookModel.getBooksByAuthor(author);
        res.json(booksByAuthor);
    } catch (err) {
        res.status(500).json({ message: 'Error retrieving books by author', error: err.message });
    }
});

// 功能3:输入指定id,删除书籍
router.delete('/books/:id', async (req, res) => {
    try {
        const bookId = req.params.id;
        await BookModel.deleteBookById(bookId);
        res.status(204).end();
    } catch (err) {
        res.status(500).json({ message: 'Error deleting book', error: err.message });
    }
});

// 功能4:输入指定id,修改书籍信息
router.put('/books/:id', async (req, res) => {
    try {
        const bookId = req.params.id;
        const updateData = req.body; // 获取请求体中的书籍信息
        await BookModel.updateBookById(bookId, updateData);
        res.status(200).json({ message: 'Book updated successfully' });
    } catch (err) {
        res.status(500).json({ message: 'Error updating book', error: err.message });
    }
});

// 功能5:输入图书信息,增加图书
router.post('/books', async (req, res) => {
    try {
        const newBook = req.body; // 获取请求体中的书籍信息
        await BookModel.addBook(newBook);
        res.status(201).json({ message: 'Book added successfully' });
    } catch (err) {
        res.status(500).json({ message: 'Error adding book', error: err.message });
    }
});

module.exports = router;
/*mysql> CREATE TABLE books (
->     id INT AUTO_INCREMENT PRIMARY KEY,
->     name VARCHAR(255) NOT NULL,
->     author VARCHAR(255) NOT NULL,
->     price DECIMAL(10, 2) NOT NULL,
->     publisher VARCHAR(255) NOT NULL
    -> );*/

e.使用express搭建后端服务

因为需要进行跨域链接,安装了cors模块i保证服务器允许链接

const express = require('express');
const app = express();
const port = 3000;
const cors = require('cors');
// 引入上面编写的路由
const bookRouter = require('routes'); // 确保此路径正确指向您的路由文件
app.use(cors());
// 使用中间件来解析请求体
app.use(express.json());

// 挂载路由
app.use('/api', bookRouter); // 将路由挂载到'/api'路径下

// 启动服务器
app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});

f.http测试

后端搭建完毕
浏览器测试http get请求,其他接口测试需要用到postman API测试工具

搭建前端项目:

前端项目搭建思路:
通过axios向后端发送http(get等)请求,后端返回json数据,交给vue组件进行渲染,渲染完成后加载页面.组件模版采用elementui搭建. 通过监听各个组件与功能完成对接调试
代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Bookstore App</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui/lib/theme-chalk/index.css">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/element-ui/lib/index.js"></script>
</head>
<body>
<div id="app">
    <el-card>
        <el-button type="primary" @click="showAddBookForm">添加书籍</el-button>
        <el-table :data="books" style="width: 100%; margin-top: 20px;">
            <el-table-column prop="id" label="ID" width="50"></el-table-column>
            <el-table-column prop="name" label="书名"></el-table-column>
            <el-table-column prop="author" label="作者"></el-table-column>
            <el-table-column prop="price" label="价格"></el-table-column>
            <el-table-column prop="publisher" label="出版社"></el-table-column>
            <el-table-column label="操作" width="150">
                <template slot-scope="scope">
                    <el-button @click="showEditBookForm(scope.row)">编辑</el-button>
                    <el-button @click="deleteBook(scope.row.id)" type="danger">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
    </el-card>
    
    <!-- 添加书籍表单 -->
    <el-dialog :visible.sync="addBookFormVisible" title="添加书籍" @close="resetAddBookForm">
        <el-form :model="newBook" :rules="bookFormRules" ref="addBookForm">
            <el-form-item label="书名" prop="name" label-width="100px">
                <el-input v-model="newBook.name"></el-input>
            </el-form-item>
            <el-form-item label="作者" prop="author" label-width="100px">
                <el-input v-model="newBook.author"></el-input>
            </el-form-item>
            <el-form-item label="价格" prop="price" label-width="100px">
                <el-input v-model="newBook.price"></el-input>
            </el-form-item>
            <el-form-item label="出版社" prop="publisher" label-width="100px">
                <el-input v-model="newBook.publisher"></el-input>
            </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
            <el-button @click="addBookFormVisible = false">取消</el-button>
            <el-button type="primary" @click="addBook">确定</el-button>
        </span>
    </el-dialog>
    
    <!-- 编辑书籍表单 -->
    <el-dialog :visible.sync="editBookFormVisible" title="编辑书籍" @close="resetEditBookForm">
        <el-form :model="currentBook" :rules="bookFormRules" ref="editBookForm">
            <!-- 使用v-bind绑定currentBook的数据到表单项 -->
            <el-form-item label="书名" prop="name" label-width="100px">
                <el-input v-model="currentBook.name"></el-input>
            </el-form-item>
            <!-- ...其他表单项与添加书籍相同... -->
        </el-form>
        <span slot="footer" class="dialog-footer">
            <el-button @click="editBookFormVisible = false">取消</el-button>
            <el-button type="primary" @click="updateBook">更新</el-button>
        </span>
    </el-dialog>
</div>

<script>
const app = new Vue({
    el: '#app',
    data() {
        return {
            books: [],
            newBook: {
                id: null,
                name: '',
                author: '',
                price: '',
                publisher: ''
            },
            currentBook: {},
            addBookFormVisible: false,
            editBookFormVisible: false,
            bookFormRules: {
                name: [
                    { required: true, message: '请输入书名', trigger: 'blur' },
                    { min: 3, max: 50, message: '长度为 3 到 50 个字符', trigger: 'blur' }
                ],
                author: [
                    { required: true, message: '请输入作者名', trigger: 'blur' }
                ],
                price: [
                    { required: true, message: '请输入价格', trigger: 'blur' }
                ],
                publisher: [
                    { required: true, message: '请输入出版社', trigger: 'blur' }
                ]
            }
        };
    },
    methods: {
        async fetchBooks() {
            try {
                const response = await axios.get('http://localhost:3000/api/books');
                this.books = response.data;
            } catch (error) {
                console.error('Error fetching books:', error);
                this.$message.error('无法获取书籍列表');
            }
        },
        showAddBookForm() {
            this.newBook = { id: null, name: '', author: '', price: '', publisher: '' };
            this.addBookFormVisible = true;
        },
        resetAddBookForm() {
            this.$refs.addBookForm.resetFields();
        },
        async addBook() {
            this.$refs.addBookForm.validate(async (valid) => {
                if (valid) {
                    try {
                        const response = await axios.post('http://localhost:3000/api/books', this.newBook);
                        this.addBookFormVisible = false;
                        this.fetchBooks(); // 刷新书籍列表
                        this.$message.success('书籍添加成功');
                    } catch (error) {
                        console.error('Error adding book:', error);
                        this.$message.error('添加书籍失败');
                    }
                }
            });
        },
        showEditBookForm(book) {
            this.currentBook = Object.assign({}, book);
            this.editBookFormVisible = true;
        },
        resetEditBookForm() {
            this.$refs.editBookForm.resetFields();
        },
        async updateBook() {
            this.$refs.editBookForm.validate(async (valid) => {
                if (valid) {
                    try {
                        const response = await axios.put(`http://localhost:3000/api/books/${this.currentBook.id}`, this.currentBook);
                        this.editBookFormVisible = false;
                        await this.fetchBooks(); // 刷新书籍列表
                        this.$message.success('书籍更新成功');
                    } catch (error) {
                        console.error('Error updating book:', error);
                        this.$message.error('更新书籍失败');
                    }
                }
            });
        },
        async deleteBook(bookId) {
            try {
                await axios.delete(`http://localhost:3000/api/books/${bookId}`);
                await this.fetchBooks(); // 刷新书籍列表
                this.$message.success('书籍删除成功');
            } catch (error) {
                console.error('Error deleting book:', error);
                this.$message.error('删除书籍失败');
            }
        }
    },
    mounted() {
        this.fetchBooks();
    }
});
</script>
</body>
</html>

至此项目结束,完成了一个简易的图书馆管理系统的全栈开发,和测试. 项目源码随后会在git上开源.

标签: 前端 vue.js elementui

本文转载自: https://blog.csdn.net/weixin_51143649/article/details/139497675
版权归原作者 过分执着 所有, 如有侵权,请联系我们删除。

“web图书管理全栈开发实战vue+elementui+node.js+mysql”的评论:

还没有评论