vue2.0构建全栈项目(前后分离实践,后端NodeJS框架搭建)【4】

个人网站地址 www.wenghaoping.com

Vue + express + Mongodb构建 请大家多支持一下。

前言

因为也不是专业的后端,本项目也只是大致介绍一下流程,就不要吐槽什么写的不好啦,

本章节,将会把所有的请求全写为跨域请求。不知道为什么,很多人一用了框架就会不知所措。给大家一个忠告,享受框架带来的便利,别忘了时刻提醒自己学好基础知识。

还有帮助大家了解下整个流程啦


正文

我们的数据交互其实很简单,所以我在这选择使用大家最熟悉的ExpressMongodb。 (本章节不介绍Mongodb的使用,默认会安装Mongodb以及环境的搭建,可以看之前的文章,有很完整的介绍,包括配置文件等的设置) MongDB在windows和Linux上的安装与使用

首先,安装几个必要的包

安利下新的yarn的使用,可以看之前的文章,之前有介绍yarn的使用, yarn的安装与使用

yarn add formidable mongodb express morgan body-parser

morgan body-parser 这两个插件morgan是用于日志美化,body-parser是用于解析客户端请求的body中的内容

自己去百度下吧。度娘会告诉你到底用来干嘛的

新学的,用一下试试吧,代码就是要折腾嘛


Mongodb相关 首先本地启动数据库,为什么这样启动,看上面的文章。


在我们的根目录下,创建app.js初始化以下代码

// app.js
var express = require("express");
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
var morgan = require('morgan');

var router = require("./router");

app.use(morgan('dev')); // 打印到控制台
app.use(bodyParser.json()); // json化


app.post("/creat",router.creat);        // 创建计划

app.post("/getList",router.getList);    // 获取总列表

app.post("/deletePlan",router.deletePlan);   // 删除计划

http.listen(3000);
复制代码

在我们的根目录下,创建router文件夹,在文件夹下创建Index.js初始化路由

// router/index.js
var formidable = require("formidable");  // 
var db = require("../models/db.js");  // mongodb数据库请求封装
var path = require("path");
var fs = require("fs");

// 创建数据
exports.creat = function(req, res, next) {
// dosometing
}

// 获取列表
exports.getList = function(req, res, next) {
// dosometing
}

// 删除计划
exports.deletePlan = function(req, res, next) {
// dosometing
}
复制代码

在我们的根目录下,创建config.js文件,作为数据库的配置文件


// config.js
module.exports = {
    "dburl" : "mongodb://@localhost:27017/story"   //本地数据库地址(线上有账号密码,也在这里写)
}
复制代码

在我们的根目录下,创建models文件夹,在文件夹下创建db.js封装Mongodb的增删改查,(不介绍,可以自己看看,也可以不使用,可以直接连接数据库。但是直接连接的话,就自己百度吧。)


//这个模块里面封装了所有对数据库的常用操作
// models/db.js

var MongoClient = require('mongodb').MongoClient; // 创建数据库连接
var config = require("../config.js");  // 引入配置
//不管数据库什么操作,都是先连接数据库,所以我们可以把连接数据库
//封装成为内部函数
function _connectDB(callback) {
    var url = config.dburl;   //从config文件中,都数据库地址
    //连接数据库
    MongoClient.connect(url, function (err, db) {
        if (err) {
            callback(err, null);
            return;
        }
        callback(err, db);
    });
}

init();//只运行一次,创建索引
function init(){
    //对数据库进行一个初始化
    _connectDB(function(err, db){
        if (err) {
            console.log(err);
            return;
        }
// 创建索引,可以让数据库查找更快,这里连接plan数据表,没有没关系,会自己创建的   
        db.collection('plan').createIndex(  
            { "plan_id": 1},
            null,
            function(err, results) {
                if (err) {
                    console.log(err);
                    return;
                }
                console.log("索引建立成功");
            }
        );
    });
}

//插入数据
exports.insertOne = function (collectionName, json, callback) {
    _connectDB(function (err, db) {
        db.collection(collectionName).insertOne(json, function (err, result) {
            callback(err, result);
            db.close(); //关闭数据库
        })
    })
};

//查找数据,找到所有数据。args是个对象{"pageamount":10,"page":10}
exports.find = function (collectionName, json, C, D) {
    var result = [];    //结果数组
    if (arguments.length == 3) {
        //那么参数C就是callback,参数D没有传。
        var callback = C;
        var skipnumber = 0;
        //数目限制
        var limit = 0;
    } else if (arguments.length == 4) {
        var callback = D;
        var args = C;
        //应该省略的条数
        var skipnumber = args.pageamount * args.page || 0;
        console.log("===>"+skipnumber)
        //数目限制,每页显示条数
        var limit = args.pageamount || 0;
        //排序方式
        var sort = args.sort || {};
    } else {
        throw new Error("find函数的参数个数,必须是3个,或者4个。");
        return;
    }

    //连接数据库,连接之后查找所有
    _connectDB(function (err, db) {
        var cursor = db.collection(collectionName).find(json).skip(skipnumber).limit(limit).sort(sort);
        cursor.each(function (err, doc) {
            if (err) {
                callback(err, null);
                db.close(); //关闭数据库
                return;
            }
            if (doc != null) {
                result.push(doc);   //放入结果数组
            } else {
                //遍历结束,没有更多的文档了
                callback(null, result);
                db.close(); //关闭数据库
            }
        });
    });
}

//删除
exports.deleteMany = function (collectionName, json, callback) {
    _connectDB(function (err, db) {
        //删除
        db.collection(collectionName).deleteMany(
            json,
            function (err, results) {
                callback(err, results);
                db.close(); //关闭数据库
            }
        );
    });
}

//修改
exports.updateMany = function (collectionName, json1, json2, callback) {
    _connectDB(function (err, db) {
        db.collection(collectionName).updateMany(
            json1,
            json2,
            function (err, results) {
                callback(err, results);
                db.close();
            });
    })
}

//得到总数量
exports.getAllCount = function (collectionName,callback) {
    _connectDB(function (err, db) {
        db.collection(collectionName).count({}).then(function(count) {

            callback(count);
            db.close();
        });
    })
}
复制代码

以上Node的框架搭建完毕,我们先来试试请求,目前服务器不会返回任何东西,因为我们啥都没让返回,所以,先调通

我们修改一下前端代码

首先我们简单封装一下请求,并且在Main中引入


// src/utils/request.js

import axios from 'axios';
import qs from 'qs';

axios.defaults.timeout = 60000;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
axios.defaults.baseURL = 'http://192.168.9.19:3000'; // 本地node端口

// POST传参序列化 http request 拦截器
axios.interceptors.request.use((config) => {
  if (config.method === 'post') {
    config.data = qs.stringify(config.data);
  }
  return config;
}, (error) => {
  console.log('错误的传参');
  return Promise.reject(error);
});

// code状态码200判断http response 拦截器
axios.interceptors.response.use((res) => {
  if (res.status !== 200) {
    return Promise.reject(res);
  }
  return res;
}, (error) => {
  console.log(error);
  console.log('网络异常');
  return Promise.reject(error);
});

export default axios;

复制代码

main中引入

// main.js中加入
~~~
import axios from './utils/request';// axios请求配置
import URL_ from './api/url';// URL请求地址汇总
Vue.prototype.URL = URL_;
Vue.prototype.$http = axios;
~~~~~

复制代码

下面修改一下页面的js请求,包括新增,删除,以及列表展示三个请求,


// src/views/index/index.vue

<script type="text/ecmascript-6">
  import { mavonEditor } from 'mavon-editor';
  export default {
    props: [],
    data () {
      return {
        loading: false,
        plans: [],
        article: {}
      };
    },
    computed: {
      /* plans () {
        // 从store中取出数据
        return this.$store.state.list;
      } */
    },
    mounted () {},
    // 组件
    components: { mavonEditor },
    methods: {
        // 删除该事件
      deletePlan (plan, index) {
//        this.$store.dispatch('deletePlan', index);  // 现在不从store中删除,直接请求删除
        let id = plan._id;
        this.$http.post(this.URL.deletePlan, {_id: id})
          .then(res => {
            let data = res.data;
            if (data.code === -3) {
              alert(data.msg);
            } else {
              this.$notify({
                title: '成功',
                message: '删除成功',
                type: 'success'
              });
              this.getToList();
            }
          })
          .catch(err => {
            console.log(err);
          });
      },
      // 去创建页面,路由跳转
      creatPlan () {
          // 路由去创建页面
        this.$router.push({name: 'creatPlan', query: {}});
      },
      // 获取所有列表
      getToList () {
        this.$http.post(this.URL.getList)
          .then(res => {
            console.log(res);
            let data = res.data;
            if (data.code === -3) {
              alert(data.msg);
            } else {
              this.plans = data.result;
            }
          })
          .catch(err => {
            console.log(err);
          });
      }
    },
    // 当dom一创建时
    created () {
      this.getToList();   // 在这里调用
    },
    watch: {}
  };
</script>
复制代码

以上请求都写完了,我们打开页面,刷新,看能否成功

会发现报了个错。这其实就是最常见的跨域请求错误

但是我们明明写得是post请求为什么显示得是options呢?

这其实是跨域请求前会先发起的一个options请求,需要先问问服务端,我需要一些操作可以吗?如果服务端那里是允许的,才会继续让你发送post请求。

我不知道那些使用axios各种姿势也想满足跨域请求的人是怎么想的。你想上天吗?

所以我们需要服务端配置,而不是前端

//app.js
app.all("*", function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
  res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
  if (req.method == 'OPTIONS') {
    res.send(200);
  } else {
    next();
  }
});
复制代码

Access-Control-Allow-Origin是设置你的来源域名,写*是很危险的操作。所以我们可以直接写成我们所需的域名和端口,别人就没法请求了。

另外几行就不解释了,一看就懂。

不出意外,可以发现发送了options后,马上发送了post,然后就请求成功了

接着来让我们一口气写完剩下的三个请求。列表渲染,删除计划,创建计划的后台接口

var formidable = require("formidable");  // 接受请求参数用的
var db = require("../models/db.js");
var ObjectID = require('mongodb').ObjectID  // 获取唯一id
// 创建数据
exports.creat = function(req, res, next) {
    //得到表单之后做的事情
    var form = new formidable.IncomingForm();
    form.parse(req, function (err, fields, files){
        //得到表单之后做的事情
        var avatar = fields.avatar;
        var name = fields.name;
        var date = fields.date;
        console.log(fields);
        //如果我们需要的字段不存在,返回前端信息
        if(!avatar || !name || !introduce || !date) {
            res.send({code:-1,msg:"params missed"});
            return;
        }
        //插入plan表,没有这个表没关系,会自动创建
        db.insertOne("plan", {
            "avatar": avatar,
            "name": name,
            "introduce": introduce,
            "date": date,
        }, function (err, result) {
            if (err) {
                res.send({code:-3,msg:"服务器错误"}); //服务器错误
                return;
            }
            res.send({code:1,msg:"创建成功"}); 
        })
    });
}

// 获取列表
exports.getList = function(req, res, next) {
// 这里使用的是数据库组件的,自己封装的一个,还没用到被人的插件,应该会更好
    db.find("plan",{},{"sort":{_id:-1}},function(err,result){
        if (err) {
            res.send({code:-3,msg:"service err"}); //服务器错误
            return;
        }
        res.send({code:1, result: result});
    });
}

// 删除计划
exports.deletePlan = function(req, res, next) {
    var form = new formidable.IncomingForm();
    form.parse(req, function (err, fields, files) {
        //得到表单之后做的事情
        let id = new ObjectID(fields._id);// 得到id
        console.log(id);
        db.deleteMany("plan", {_id: id},function (err, results) {
            if (err) {
                res.send({result:-3,msg:"service err"}); //服务器错误
                return;
            }
            res.send({result:1}); //删除成功
        });
    });
}

复制代码

现在我们看一下是否连通成功.

我们可以看到,现在可以是POST请求,也有数据返回了

完结


到此,我们就将我们整个应用完成了。新增 创建 删除都可用了。

本系列让大家轻松的了解学习了 vue, vue-router, axios, express, mongodb 的运用。

还是那句话,享受框架带来便利的同时,别忘了加强基础的训练。基本功才是真正的王道啊。玩电竞的玩家一定深有体会。

比如我大星际的乐趣,哈哈哈哈哈

项目地址

::: hljs-center

来扫我啊

:::

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值