zoukankan      html  css  js  c++  java
  • webpack4+express+mongodb+vue 实现增删改查

    在讲解之前,我们先来看看效果如下所示:

    1)整个页面的效果如下:

    2) 新增数据效果如下:

    3) 新增成功如下:

    4) 编辑数据效果如下:

    5) 编辑成功效果如下:

    6) 删除数据效果如下:

    7) 删除成功效果如下:

    8) 查询效果如下:

    如上的效果,下面我们还是和之前一样,先看看我们整个项目的架构如下所示:

    ### 目录结构如下:
    demo1                                       # 工程名
    |   |--- dist                               # 打包后生成的目录文件             
    |   |--- node_modules                       # 所有的依赖包
    |   |----database                           # 数据库相关的文件目录
    |   | |---db.js                             # mongoose类库的数据库连接操作
    |   | |---user.js                           # Schema 创建模型
    |   | |---addAndDelete.js                   # 增删改查操作
    |   |--- app
    |   | |---index
    |   | | |-- views                           # 存放所有vue页面文件
    |   | | | |-- list.vue                      # 列表数据
    |   | | | |-- index.vue
    |   | | |-- components                      # 存放vue公用的组件
    |   | | |-- js                              # 存放js文件的
    |   | | |-- css                             # 存放css文件
    |   | | |-- store                           # store仓库
    |   | | | |--- actions.js
    |   | | | |--- mutations.js
    |   | | | |--- state.js
    |   | | | |--- mutations-types.js
    |   | | | |--- index.js
    |   | | | |
    |   | | |-- app.js                          # vue入口配置文件
    |   | | |-- router.js                       # 路由配置文件
    |   |--- views
    |   | |-- index.html                        # html文件
    |   |--- webpack.config.js                  # webpack配置文件 
    |   |--- .gitignore  
    |   |--- README.md
    |   |--- package.json
    |   |--- .babelrc                           # babel转码文件
    |   |--- app.js                             # express入口文件

    如上目录架构是我现在整个项目的架构图,其中database目录下存放 db.js ,该文件最主要是使用 mongoose 数据库连接操作,user.js 文件是创建一个Schema模型,也可以理解为表结构,addAndDelete.js 文件内部实现增删改查操作。

    如果对mongodb数据库相关的知识点不是很熟悉的话,可以先看下我之前写的一些关于mongodb文章(https://www.cnblogs.com/tugenhua0707/category/1240772.html), 先在本地把数据库搭建起来后,再慢慢学习哦,我这边文章实现 vue+mongodb 实现增删改查也是基于上面这些文章的基础之上来进行的,特别是居于这篇 使用Mongoose类库实现简单的增删改查
    (https://www.cnblogs.com/tugenhua0707/p/9256605.html) 来进行的,增删改查操作及使用Schema 创建模型 都是居于这篇文章的基础之上再进行使用vue来重构下的。本篇文章也是依赖于饿了么vue组件进行开发的。

    先来分别讲下代码结构吧:

    1)使用express创建服务器

    首先我们在项目的根目录新建app.js, 该app.js 主要实现的功能是 启动 3001端口的服务器,并且使用 bodyParser进行解析数据,如下代码:

    // 引入express模块
    const express = require('express');
    
    // 创建app对象
    const app = express();
    
    const addAndDelete = require('./database/addAndDelete');
    
    const bodyParser = require("body-parser")
    
    app.use(bodyParser.json());
    
    app.use(bodyParser.urlencoded({ extended: false }));
    
    // 使用
    app.use('/api', addAndDelete);
    
    // 定义服务器启动端口 
    app.listen(3001, () => {
      console.log('app listening on port 3001');
    });

    进入我们项目的根目录后,运行 node app.js 即可创建一个 http://127.0.0.1:3001 的服务器页面了。

    2)数据库连接
    在database/db.js 链接 mongodb://localhost:27017/dataDb 数据库。使用mongoose类库,如果不理解mongoose类库的话,可以返回来看我这篇文章(https://www.cnblogs.com/tugenhua0707/p/9256605.html)如下代码:

    var mongoose = require('mongoose');
    var DB_URL = 'mongodb://localhost:27017/dataDb';
    
    /* 链接 */
    mongoose.connect(DB_URL);
    
    /* 链接成功 */
    mongoose.connection.on('connected', function() {
      console.log('Mongoose connection open to ' + DB_URL);
    });
    
    // 链接异常
    mongoose.connection.on('error', function(err) {
      console.log('Mongoose connection error:' + err);
    });
    
    // 链接断开
    
    mongoose.connection.on('disconnected', function() {
      console.log('Mongoose connection disconnected');
    });
    module.exports = mongoose;

    3)创建数据模型
    在database/user.js 中使用 Schema创建一个模型,也就是说上面的 dataDb是数据库名称,这边使用schema创建的模型就是表结构的字段,有如下 name, age, sex 三个字段,代码如下所示:

    /*
     定义一个user的Schema
    */
    const mongoose = require('./db.js');
    const Schema = mongoose.Schema;
    
    // 创建一个模型
    const UserSchema = new Schema({
      name: { type: String }, // 属性name,类型为String
      age: { type: Number, default: 30 }, // 属性age,类型为Number,默认值为30
      sex: { type: String }
    });
    
    // 导出model模块
    const User = module.exports = mongoose.model('User', UserSchema);

    4)实现增删改查路由接口

    如下所有的增删改查的代码如下(如果代码看不懂的话,还是返回看这篇文章即可:https://www.cnblogs.com/tugenhua0707/p/9256605.html):

    // 引入express 模块 
    const express = require('express');
    
    const router = express.Router();
    
    // 引入user.js
    const User = require('./user');
    
    // 新增一条数据 接口为add
    router.post('/add', (req, res) => {
      const user = new User({
        name: req.body.name,
        age: req.body.age,
        sex: req.body.sex
      });
      user.save((err, docs) => {
        if (err) {
          res.send({ 'code': 1, 'errorMsg': '新增失败' });
        } else {
          res.send({ "code": 0, 'message': '新增成功' });
        }
      });
    });
    
    // 查询数据 
    router.post('/query', (req, res) => {
      const name = req.body.name,
        age = req.body.age,
        sex = req.body.sex;
      const obj = {};
      if (name !== '') {
        obj['name'] = name;
      }
      if (age !== '') {
        obj['age'] = age;
      }
      if (sex !== '') {
        obj['sex'] = sex;
      }
      User.find(obj, (err, docs) => {
        if (err) {
          res.send({ 'code': 1, 'errorMsg': '查询失败' });
        } else {
          res.send(docs);
        }
      });
    });
    
    // 根据 _id 删除数据
    router.post('/del', (req, res) => {
      const id = req.body.id;
      // 根据自动分配的 _id 进行删除
      const whereid = { '_id': id };
      User.remove(whereid, (err, docs) => {
        if (err) {
          res.send({ 'code': 1, 'errorMsg': '删除失败' });
        } else {
          res.send(docs);
        }
      })
    });
    
    // 更新数据
    router.post('/update', (req, res) => {
      console.log(req.body)
      // 需要更新的数据
      const id = req.body.id,
        name = req.body.name,
        age = req.body.age,
        sex = req.body.sex;
      const updateStr = {
        name: name,
        age: age,
        sex: sex
      };
      const ids = {
        _id: id
      };
      console.log(ids);
      User.findByIdAndUpdate(ids, updateStr, (err, docs) => {
        if (err) {
          res.send({ 'code': 1, 'errorMsg': '更新失败' });
        } else {
          res.send(docs);
        }
      });
    });
    module.exports = router;

    5)搭建vue页面,如何通过页面的接口请求?

    在app/index/views/list.vue 基本代码如下(所有的html代码是基于饿了么vue组件的,最主要一些form表单组件的用法及表格的插件及弹窗的插件),代码如下:

    <style lang="stylus">
      #list-container 
        width 100%
    </style>
    <template>
      <div id="list-container" style="margin:20px auto">
        <div style="100%;overflow:hidden;">
          <el-form ref="form" label-width="80px">
            <div style="float:left;20%">
              <el-form-item label="姓名">
                <el-input v-model="name"></el-input>
              </el-form-item>
            </div>
            <div style="float:left;20%">
              <el-form-item label="年龄">
                <el-input v-model="age"></el-input>
              </el-form-item>
            </div>
            <div style="float:left;20%">
              <el-form-item label="性别">
                <el-select v-model="sex">
                  <el-option
                    v-for="item in options2"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                  </el-option>
                </el-select>
              </el-form-item>
            </div>
            <el-button type="primary" style="margin-left:20px;" @click="query(true)">查 询</el-button>
            <el-button type="success" @click="newAdd">新 增</el-button>
          </el-form>
        </div>
        <div style="90%; margin: 0 auto; border: 1px solid #ebebeb; border-radius: 3px;overflow:hidden;">
          <el-table
            :data="tableData"
            style=" 100%">
            <el-table-column
              prop="name"
              label="姓名"
              width="180">
            </el-table-column>
            <el-table-column
              prop="age"
              label="年龄"
              width="180">
            </el-table-column>
            <el-table-column
              prop="sex"
              label="性别">
            </el-table-column>
            <el-table-column
              fixed="right"
              label="操作"
              width="100">
              <template slot-scope="scope">
                <el-button type="text" size="small" @click="editFunc(scope.row)">编辑</el-button>
                <el-button type="text" size="small" @click="delFunc(scope.row)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
        <el-dialog
          title="新增"
          :visible.sync="dialogVisible"
          width="30%">
          <el-form label-width="40px">
            <div style="float:left;100%">
              <el-form-item label="姓名">
                <el-input v-model="add.name"></el-input>
              </el-form-item>
            </div>
            <div style="float:left;100%">
              <el-form-item label="年龄">
                <el-input v-model="add.age"></el-input>
              </el-form-item>
            </div>
            <div style="float:left;100%">
              <el-form-item label="性别">
                <el-select v-model="add.sex">
                  <el-option
                    v-for="item in options2"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                  </el-option>
                </el-select>
              </el-form-item>
            </div>
          </el-form>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="addConfirm">确 定</el-button>
          </span>
        </el-dialog>
        <el-dialog
          title="编辑"
          :visible.sync="dialogVisible2"
          width="30%">
          <el-form label-width="40px">
            <div style="float:left;100%">
              <el-form-item label="姓名">
                <el-input v-model="update.name"></el-input>
              </el-form-item>
            </div>
            <div style="float:left;100%">
              <el-form-item label="年龄">
                <el-input v-model="update.age"></el-input>
              </el-form-item>
            </div>
            <div style="float:left;100%">
              <el-form-item label="性别">
                <el-select v-model="update.sex">
                  <el-option
                    v-for="item in options2"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                  </el-option>
                </el-select>
              </el-form-item>
            </div>
          </el-form>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="editConfirm">确 定</el-button>
          </span>
        </el-dialog>
        <el-dialog
          title="提示"
          :visible.sync="dialogVisible3"
          width="30%">
          <div>是否确认删除?</div>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible3 = false">取 消</el-button>
            <el-button type="primary" @click="delConfirm">确 定</el-button>
          </span>
        </el-dialog>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {  
            formLabelWidth: '120px',
            name: '',
            age: '',
            sex: '',
            options2: [
              {
                value: '1',
                label: '男'
              }, {
                value: '2',
                label: '女'
              }
            ],
            tableData: [],
            // 新增页面
            add: {
              name: '',
              age: '',
              sex: ''
            },
            // 修改页面
            update: {
              name: '',
              age: '',
              sex: ''
            },
            dialogVisible: false,
            dialogVisible2: false,
            dialogVisible3: false,
            row: null,
            _id: ''
          }
        },
        created() {
          this.query();
        },
        methods: {
          setData(datas) {
            if (datas.length > 0) {
              for (let i = 0; i < datas.length; i++) {
                if (datas[i].sex * 1 === 1) {
                  this.$set(datas[i], 'sex', '男');
                } else if (datas[i].sex * 1 === 2) {
                  this.$set(datas[i], 'sex', '女');
                }
              }
            }
            return datas;
          },
          // 查询数据
          query(isquery) {
            const obj = {
              name: this.name,
              age: this.age,
              sex: this.sex
            };
            this.$http.post('/api/query', obj).then((res) => {
              if (res.ok) {
                this.tableData = res.body ? this.setData(res.body) : [];
                if (isquery) {
                  this.$message({
                    message: '查询成功',
                    type: 'success'
                  });
                }
              } else {
                if (isquery) {
                  this.$message({
                    message: '查询失败',
                    type: 'warning'
                  });
                }
                this.tableData = [];
              }
            });
          },
          newAdd() {
            this.dialogVisible = true;
          },
          editFunc(row) {
            this.dialogVisible2 = true;
            this._id = row._id;
            this.$set(this.$data.update, 'name', row.name);
            this.$set(this.$data.update, 'age', row.age);
            this.$set(this.$data.update, 'sex', row.sex);
            this.row = row;
          },
          delFunc(row) {
            this.dialogVisible3 = true;
            console.log(row);
            this.row = row;
          },
          // 编辑页面提交
          editConfirm() {
            const id = this._id,
              name = this.update.name,
              age = this.update.age,
              sex = this.update.sex;
            const obj = {
              id: id,
              name: name,
              age: age,
              sex: sex
            };
            this.$http.post('/api/update', obj).then((res) => {
              if (res.ok) {
                // 删除成功
                this.$message({
                  message: '更新成功',
                  type: 'success'
                });
                // 重新请求下查询
                this.query(false);
              } else {
                // 删除成功
                this.$message({
                  message: '更新失败',
                  type: 'success'
                });
              }
              this.dialogVisible2 = false;
            });
          },
          // 删除提交
          delConfirm() {
            const obj = {
              'id': this.row._id
            };
            this.$http.post('/api/del', obj).then((res) => {
              console.log(res.body)
              if (res.body.ok) {
                // 删除成功
                this.$message({
                  message: '删除成功',
                  type: 'success'
                });
                // 成功后,触发重新查询下数据 
                this.query();
              } else {
                // 删除失败
                this.$message({
                  message: res.body.errorMsg,
                  type: 'warning'
                });
              }
              this.dialogVisible3 = false;
            });
          },
          // 新增提交
          addConfirm() {
            // 新增的时候,姓名,年龄,性别 不能为空,这里就不判断了。。。
            const obj = {
              name: this.add.name,
              age: this.add.age,
              sex: this.add.sex
            };
            this.$http.post('/api/add', obj).then((res) => {
              console.log(111);
              console.log(res);
              if (res.body.code === 0) {
                this.$message({
                  message: '新增成功',
                  type: 'success'
                });
                // 成功后,触发重新查询下数据 
                this.query();
              } else {
                this.$message({
                  message: res.body.errorMsg,
                  type: 'warning'
                });
              }
              this.dialogVisible = false;
            });
          }
        }
      }
    </script>

    6. 解决跨域问题,及接口如何访问的?

    首先我们是使用express启动的是 http://127.0.0.1:3001 服务器的,但是在我们的webpack中使用的是8081端口的,也就是说页面访问的是http://127.0.0.1:8081/ 这样访问的话,因此肯定会存在接口跨域问题的,因此我们需要在webpack中使用 devServer.proxy 配置项配置一下,如下代码配置:

    module.exports = {
      devServer: {
        port: 8081,
        // host: '0.0.0.0',
        headers: {
          'X-foo': '112233'
        },
        inline: true,
        overlay: true,
        stats: 'errors-only',
        proxy: {
          '/api': {
            target: 'http://127.0.0.1:3001',
            changeOrigin: true  // 是否跨域
          }
        }
      },
    }

    因为我list.vue页面所有的请求都是类似于这样请求的 this.$http.post('/api/query', obj); 因此当我使用 /api/query请求的话,它会被代理到 http://127.0.0.1:3001/api/query, 这样就可以解决跨域的问题了,同时我们在项目的根目录中的 将路由应用到 app.js 中,有如下这句代码:

    const addAndDelete = require('./database/addAndDelete');
    app.use('/api', addAndDelete);

    当请求http://127.0.0.1:3001/api/query的时候,会自动使用 addAndDelete.js 中的 /query的接口方法。

    查看github代码

  • 相关阅读:
    JavaScript高级:JavaScript面向对象,JavaScript内置对象,JavaScript BOM,JavaScript封装
    JavaScript基础:javaScript基本语法,javaScript DOM,javaScript事件,javaScript综合案例
    Mybatis基础:Mybatis映射配置文件,Mybatis核心配置文件,Mybatis传统方式开发
    【笔记】Bagging和Pasting以及oob(Out-of-Bag)
    【笔记】集成学习入门之soft voting classifier和hard voting classifier
    8.23(day22)ATM+购物车系统
    Configure Dynamics 365 for Operations Virtual Machine/Virtual Hard Disk (VHD)
    Capture pictures to Power Platform
    How to convert HTML file to PDF using Power Automate
    Add B2B SSO to a Power Apps Portal
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/9926725.html
Copyright © 2011-2022 走看看