基於Node與express完成圖書管理系統項目

基於express實現圖書信息的增刪改查

該項目一共包含三個版本,前兩個版本是存儲方式不同,第三個版本是渲染方式不同。

實現該項目可以用到兩種存儲方法,一種是使用靜態的json文件存儲圖書信息,通過對文件內容的修改實現增刪改查的功能,對應版本0;另外一個版本是結合mysql包,通過mysql數據庫存儲圖書信息,實現相同的功能,對應版本1。

以上兩種存儲方式都是基於後端渲染模板實現數據更新,還有一種就是基於ajax通過前端渲染實現數據更新,對應版本2。

開發準備

  • node環境安裝,這裏用的版本是v12.10.0
  • npm安裝,這裏使用的版本是6.10.0
  • 創建空項目文件夾libearyManage,在文件夾下新建入口文件index.js,然後初始化項目npm init -y
  • 在本地安裝依賴的包 npm install express art-template body-parser --save
  • 爲使express兼容art-template還需要安裝包 npm install express-art-template --save
  • node操作數據庫依賴的mysql包 npm install mysqljs/mysql --save
  • mysql環境:Server version: 5.7.24 MySQL Community Server (GPL)
  • 使用到的開發文檔: expressart-templateexpress-art-templatebody-parsermysql
  • 數據庫管理設計工具:navicat

入口文件index.js

const express = require('express');
const router = require('./router.js')
const path = require('path');
const template = require('art-template');
const bodyParser = require('body-parser');
const app = express();

//啓動靜態資源服務,設置虛擬路徑www(用於)
app.use('/www', express.static(path.join(__dirname, './public')));

//模板引擎配置
app.set('views', path.join(__dirname, './views'));
app.set('view engine', 'art');
app.engine('art', require('express-art-template'));

//body-parser使用設置
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());

app.use(router);  //路由文件
app.listen(3000, () => {
  console.log('running···')
})

靜態資源

  • 在目錄下新建public目錄用於存放靜態資源,例如頁面引入的css文件、靜態頁面html文件、圖片

頁面模板文件

  • 在目錄下新建data.json模擬後臺數據(基於mysql版本則不需要該文件)
[
  {
    "id": "1",
    "name": "三國演義",
    "author": "羅貫中",
    "category": "文學",
    "desc": "一個殺伐紛爭的年代"
  },
  {
    "id": "2",
    "name": "水滸傳",
    "author": "施耐庵",
    "category": "文學",
    "desc": "108條好漢的故事"
  },
  {
    "id": "3",
    "name": "西遊記",
    "author": "吳承恩",
    "category": "文學",
    "desc": "佛教與道教的鬥爭"
  },
  {
    "id": "4",
    "name": "紅樓夢",
    "author": "曹雪芹",
    "category": "文學",
    "desc": "一個封建王朝的縮影"
  },
  {
    "name": "天龍八部",
    "author": "金庸",
    "category": "文學",
    "desc": "武俠小說",
    "id": 5
  }
]
  • 在項目目錄下新建views文件夾,並在文件夾下新建index.art、addBook.art、editBook.art (可以先編寫.html靜態文件,之後再改寫爲模板文件),文件具體內容鏈接
    • index.art用於顯示圖書信息,以及提供跳轉入口
    • addBook.art 是一個表單,用於添加圖書信息
    • editBook.art 與addBook.art類似,但是需要渲染數據,用於修改圖書信息

業務處理模塊

  • 創建service.js文件,在該文件內處理業務
    • 基於靜態json文件的實現鏈接
    • 基於mysql數據庫存儲的實現鏈接

路由模塊

  • 創建router.js文件,在該文件內處理路由
    • 基於靜態json文件的實現鏈接

數據庫準備

  • 啓動數據庫:net start mysql(對應關閉數據庫的命令爲net stop mysql
  • 用navicat創建數據庫:命名爲library、字符集爲utf8 – UTF-8 Unicode、排序規則爲utf8_bin
  • 在數據庫library中新建表book,包含字段id、name、author、category、description
  • 創建connectDB.js文件用於存放數據庫操作通用api
//mysql通用通用操作封裝
const mysql = require('mysql');

exports.base = (sql, data, callback) => {
  const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'rootpass',
    database: 'library'
  });

  connection.connect();

  connection.query(sql, data, function (error, results, fields) {
    if (error) throw error;
    callback(results);  //數據庫操作是異步的,所以通過回調函數返回操作結果
  })
  connection.end();
}

在項目目錄下創建文件夾test,用於專門存放測試腳本

  • initsql.js 用於將json文件轉成insert語句,初始化數據,生成data.sql文件,在navicat中運行sql語句插入數據
/* 把data.json中的數據拼接成sql語句之後存儲到data.sql文件中 */
const path = require('path');
const fs = require('fs');

fs.readFile(path.join(__dirname, '../', 'data.json'), 'utf8', (err, content) => {
  if (err) return;
  let data = JSON.parse(content);
  let arrData = [];
  data.forEach((item) => {
    let sql = `insert into book (name,author,category,description) values ('${item.name}','${item.author}','${item.category}','${item.desc}');`;
    arrData.push(sql);
  })

  //寫入文件
  fs.writeFile(path.join(__dirname, './data.sql'), arrData.join(''), 'utf8', (err) => {
    if (err) {
      console.log('write erro');
      return;
    }
    console.log('data init finished!')
  })
})

版本2

前後端分離,通過ajax請求在前端完成頁面的渲染。開發環境與上述兩個版本一致,但因爲不需要後端渲染,所以依賴的包有所不同

開發準備

  • 創建項目resfulLibrary,在項目下創建入口文件index.js,初始化項目 npm init -y
  • 安裝express npm install express body-parser --save
  • 安裝node操作數據庫依賴的mysql包 npm install mysqljs/mysql --save
  • 數據庫常用操作封裝connectDB.js,文件內容鏈接
  • index.js作爲入口文件
/* nodejs實現圖書管理系統後臺resful接口 */
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const router = require('./router.js');
const app = express();

//設置靜態資源的虛擬目錄爲/www
app.use('/www', express.static(path.join(__dirname, './public')));

//body-parser使用設置
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use(router);
app.listen(3000, () => {
  console.log('running···');
})

路由管理router.js(採用resful接口)

const express = require('express');
const service = require('./service.js');
const router = express.Router();

//查詢所有圖書信息
router.get('/books', service.allBooks);

//添加圖書信息
router.post('/books/book', service.addBook);

//根據id查詢編輯圖書的信息
router.get('/books/book/:id', service.getBookById);

//提交編輯後的信息
router.put('/books/book', service.editBook);

//根據id刪除圖書信息
router.delete('/books/book/:id', service.deleteBook);

module.exports = router;

業務處理service.js(採用resful接口)

  • 主要包括圖書的增刪改查
const db = require('./connectDB.js');

exports.allBooks = (req, res) => {
  let sql = 'select * from book';
  db.base(sql, null, (result) => {
    res.json(result);
  })
}

exports.addBook = (req, res) => {
  let info = req.body;
  let sql = 'insert into book set ?';
  db.base(sql, info, (result) => {
    if (result.affectedRows == 1) {
      res.json({ flag: 1 });
    } else {
      res.json({ flag: 2 });
    }
  })
}

exports.getBookById = (req, res) => {
  let id = req.params.id;
  let sql = 'select * from book where id=?';
  let data = [id];
  db.base(sql, data, (result) => {
    res.json(result[0]);
  })
}

exports.editBook = (req, res) => {
  let info = req.body;
  let sql = 'update book set name=?,author=?,category=?,description=? where id=?';
  let data = [info.name, info.author, info.category, info.description, info.id];
  db.base(sql, data, (result) => {
    if (result.affectedRows == 1) {
      res.json({ flag: 1 });
    } else {
      res.json({ flag: 2 });
    }
  })
}

exports.deleteBook = (req, res) => {
  let id = req.params.id;
  let sql = 'delete from book where id=?';
  let data = [id];

  db.base(sql, data, (result) => {
    if (result.affectedRows == 1) {
      res.json({ flag: 1 });
    } else {
      res.json({ flag: 2 });
    }
  })
}

創建靜態資源目錄public存放靜態文件,在目錄下創建js、css文件夾、html文件

前端頁面渲染

//事件處理,通過ajax請求獲取數據渲染前端頁面
$(function () {
  //127.0.0.1:3000/books  渲染首頁
  initIndexlist();

  //添加圖書按鈕事件
  function addBook() {
    $('#toaddbook-btn').click(function () {
      var form = $('#book-form');

      //實例化彈窗,MarkBox操作的是原生的dom,所以需要將jquery對象轉爲原生的dom
      var dialog = new MarkBox(600, 400, "添加圖書", form.get(0));
      dialog.init();

      //綁定了添加圖書和修改圖書信息的按鈕事件,所以綁定事件之前需要解綁事件
      form.find('input[type=button]').unbind('click').click(function () {
        //提交添加圖書表單
        $.ajax({
          type: "post",
          url: "/books/book",
          dataType: "json",
          data: form.serialize(),  //格式化表單數據
          success: function (data) {
            if (data.flag == 1) {
              initIndexlist();  //圖書添加成功刷新列表數據
              dialog.close();
            }
          }
        })
      })
    })
  }


  //初始化列表
  function initIndexlist() {
    $.ajax({
      type: 'get',
      url: '/books',
      dataType: 'json',
      success: function (data) {
        //第一個參數爲模板id(帶引號),第二個參數爲渲染數據
        var html = template('indexTpl', { list: data });

        //渲染數據列表
        $('#book-list').html(html);

        //必須在渲染數據完成後纔可以對列表進行修改和刪除操作
        $('#book-list').find("tr").each(function (index, ele) {
          //ele是原生對象,要用$轉成jquery對象
          var td = $(ele).find('td:eq(5)');  //第6列是操作按鈕
          var id = $(ele).find('td:eq(0)').text();  //第1列存放的是id
          //編輯圖書信息按鈕
          td.find('a:eq(0)').click(function () {
            editBook(id);
          })

          //刪除圖書信息操作
          td.find('a:eq(1)').click(function () {
            deleteBook(id);
          })

          //綁定添加圖書信息的按鈕事件
          addBook();

          //與修改表單信息同一個form,所以需要清空表單
          var form = $('#book-form');
          form.get(0).reset();  //該方法不能清空隱藏元素的內容
          form.find('input[type=hidden]').val('');
        })
      }
    })
  }

  //編輯圖書信息
  function editBook(id) {
    var form = $('#book-form');
    var dialog = new MarkBox(600, 400, "修改圖書信息", form.get(0));
    $.ajax({
      type: 'get',
      url: '/books/book/' + id,
      dataType: 'json',
      success: function (data) {
        form.find('input[name=id]').val(data.id);
        form.find('input[name=name]').val(data.name);
        form.find('input[name=author]').val(data.author);
        form.find('input[name=category]').val(data.category);
        form.find('input[name=description]').val(data.description);
        dialog.init();
        form.find('input[type=button]').unbind('click').click(function () {
          //提交修改後的表單信息
          $.ajax({
            type: 'put',
            url: '/books/book',
            data: form.serialize(),
            dataType: 'json',
            success: function (data) {
              if (data.flag == '1') {
                initIndexlist();
                dialog.close();
              }
            }
          })
        })
      }
    })
  }

  //刪除圖書信息
  function deleteBook(id) {
    $.ajax({
      type: 'delete',
      url: '/books/book/' + id,
      dataType: 'json',
      success: function (data) {
        if (data.flag == '1') {
          initIndexlist();
        }
      }
    })
  }
})

項目地址,通過在每個版本的項目目錄下運行命令npm install安裝依賴的包,啓動服務index.js,訪問本地本地ip[127.0.0.1:3000]進行測試

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章