个人网站地址 www.wenghaoping.com
Vue + express + Mongodb构建 请大家多支持一下。
前言
因为也不是专业的后端,本项目也只是大致介绍一下流程,就不要吐槽什么写的不好啦,
本章节,将会把所有的请求全写为跨域请求。不知道为什么,很多人一用了框架就会不知所措。给大家一个忠告,享受框架带来的便利,别忘了时刻提醒自己学好基础知识。
还有帮助大家了解下整个流程啦
正文
我们的数据交互其实很简单,所以我在这选择使用大家最熟悉的Express
和Mongodb
。 (本章节不介绍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
来扫我啊
:::