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

过分执着 2024-07-15 11:03:01 阅读 70

一.界面展示

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:输入:图书信息,可以进行图书的增加

<code>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功能配置为路由文件

<code>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搭建.  通过监听各个组件与功能完成对接调试

代码如下

<code><!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<title>Bookstore App</title>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui/lib/theme-chalk/index.css">code>

<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.min.js"></script>code>

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>code>

<script src="https://cdn.jsdelivr.net/npm/element-ui/lib/index.js"></script>code>

</head>

<body>

<div id="app">code>

<el-card>

<el-button type="primary" @click="showAddBookForm">添加书籍</el-button>code>

<el-table :data="books" style="width: 100%; margin-top: 20px;">code>

<el-table-column prop="id" label="ID" width="50"></el-table-column>code>

<el-table-column prop="name" label="书名"></el-table-column>code>

<el-table-column prop="author" label="作者"></el-table-column>code>

<el-table-column prop="price" label="价格"></el-table-column>code>

<el-table-column prop="publisher" label="出版社"></el-table-column>code>

<el-table-column label="操作" width="150">code>

<template slot-scope="scope">code>

<el-button @click="showEditBookForm(scope.row)">编辑</el-button>code>

<el-button @click="deleteBook(scope.row.id)" type="danger">删除</el-button>code>

</template>

</el-table-column>

</el-table>

</el-card>

<!-- 添加书籍表单 -->

<el-dialog :visible.sync="addBookFormVisible" title="添加书籍" @close="resetAddBookForm">code>

<el-form :model="newBook" :rules="bookFormRules" ref="addBookForm">code>

<el-form-item label="书名" prop="name" label-width="100px">code>

<el-input v-model="newBook.name"></el-input>code>

</el-form-item>

<el-form-item label="作者" prop="author" label-width="100px">code>

<el-input v-model="newBook.author"></el-input>code>

</el-form-item>

<el-form-item label="价格" prop="price" label-width="100px">code>

<el-input v-model="newBook.price"></el-input>code>

</el-form-item>

<el-form-item label="出版社" prop="publisher" label-width="100px">code>

<el-input v-model="newBook.publisher"></el-input>code>

</el-form-item>

</el-form>

<span slot="footer" class="dialog-footer">code>

<el-button @click="addBookFormVisible = false">取消</el-button>code>

<el-button type="primary" @click="addBook">确定</el-button>code>

</span>

</el-dialog>

<!-- 编辑书籍表单 -->

<el-dialog :visible.sync="editBookFormVisible" title="编辑书籍" @close="resetEditBookForm">code>

<el-form :model="currentBook" :rules="bookFormRules" ref="editBookForm">code>

<!-- 使用v-bind绑定currentBook的数据到表单项 -->

<el-form-item label="书名" prop="name" label-width="100px">code>

<el-input v-model="currentBook.name"></el-input>code>

</el-form-item>

<!-- ...其他表单项与添加书籍相同... -->

</el-form>

<span slot="footer" class="dialog-footer">code>

<el-button @click="editBookFormVisible = false">取消</el-button>code>

<el-button type="primary" @click="updateBook">更新</el-button>code>

</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上开源.



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。