react+express+mongodb实践
写了一小段时间的react和antd了,突然想把遇到的问题以及面试题都整理一下,然后就想到了react和express,何不做一个小网站把他们规整起来呢?小网站使用react+react-router+antd+express+mongodb+redux,说是一个全家桶一点都不过分。简洁的记录一下此次行动。
一、搭建react环境,这个就不多说了,然后将react-router、antd都添加进来(这个要是不会,回炉重造吧)
二、该写的组件,该配的router都搞好,坐等接数据
三、将express添加到项目中来。首先在根目录(和src同级)新增一个server文件夹,新建package.json:
{
"name": "server",
"version": "1.0.0",
"description": "server config",
"main": "server.js",
"author": "luffy",
"license": "MIT",
"dependencies": {
"babel-cli": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"body-parser": "^1.18.2",
"express": "^4.16.3",
"mongoose": "^5.0.16"
},
"scripts": {
"start": "nodemon ./server.js",
"build": "babel ./server.js --out-file server-compiled.js",
"serve": "node server-compiled.js"
}
}
PS:这里为了让后台的代码变化后也会自动更新,需要全局安装nodemon,npm install nodemon -g
四、在server文件夹下新建server.js:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
// 给app配置bodyParser中间件
// 通过如下配置再路由种处理request时,可以直接获得post请求的body部分
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// 注册路由
const router = express.Router();
// 路由中间件
router.use((req, res, next) => {
// 任何路由信息都会执行这里面的语句
console.log('this is a api request!');
// 把它交给下一个中间件,注意中间件的注册顺序是按序执行
next();
})
// 获取用户列表信息的路由
router.get('/user/list', (req, res) => {
const userList = [
{
name: 'luffy',
age: 24,
gender: '男'
},{
name: 'lfy',
age: 23,
gender: '女'
}
];
res.json(userList);
});
// 所有的路由会加上“/interview”前缀
app.use('/interview', router); //添加router中间件
// express 自动帮我们创建一个server,封装的node底层http
app.listen(3003, () => {
console.log('node server is listening 3003');
});
PS:这个文件就是我们监听后台端口,撰写接口的地方,通过express中的 router监听(即访问的接口),来触发不同的方法(即接口),然后返回数据
五、来测试一下前后端是不是通了
cd server
npm start
//后端express的运行
npm start
//前端运行
浏览器访问http://localhost:3003/api/user/list,页面上打印出刚刚server.js中的userList数组。前后端通了。
但是每次启动都得分两次分别启动前后端,很烦的。
修改package.json的scripts部分,首先安装一个concurrently的玩意儿,
npm install concurrently
"scripts": {
"start-react": "react-scripts start",
"build-react": "react-scripts build",
+ "start": "concurrently \"react-scripts start\" \"cd server && npm start\"",
+ "bulid": "concurrently \"react-app-rewired build\" \"cd server && npm build\"",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
npm start就可以前后端同时启动了
六、完事具备,只欠数据~库。安装mongodb,官方教程。然后项目安装mongodb。npm install mongoose。(mongodb有很多可视化工具,本次使用的是studio 3T)
在根目录下新建db文件夹,文件夹目录如下
关于mongodb的基本概念
// 下面是关于mongoose的几个概念:
Schema: 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力
Model: 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对象
Entity: 由Model创建的实体,它的操作也会影响数据库
Schema、Model、Entity的关系请牢记,Schema生成Model,Model创造Entity。
Model和Entity都可对数据库操作造成影响,但Model比Entity更具操作性。
1、config.js:
module.exports = {
mongodb:'mongodb://127.0.0.1:27017/interview'
}
//127.0.0.1:27017其实就是我们的localhost,interview就是数据库名字,没设置用户名密码就不用写了
2、mongoose.js:
const mongoose = require('mongoose');
const config = require('./config');
module.exports = ()=>{
mongoose.connect(config.mongodb);//链接数据库
var db = mongoose.connection;
db.on('error',console.log.bind('console','mongodb数据库连接错误!'));
db.on('open',(callback)=>{
console.log('mongodb数据库连接成功!');
})
//监听数据库连接和错误,使用回调抛出错误
return db;
}
3、schemase.js
const mongoose = require('mongoose');
const schema = mongoose.Schema;
const Interview = new schema({
question:String,
code:String,
word:String,
type:String,
time:Date
})
//此处映射一个数据库表结构,就是所谓的骨架
module.exports = Interview;
4、models.js
const mongoose = require('mongoose');
const Interview = require('../schemas/schemase');
//此处需要注意的是表明,所以mongoose.model()方法的第一个参数就是映射一个表名
//和数据库表要一致(需要少个s)mongodb会自己在映射的时候给表名添加一个s
//一个schema对应一个model对应一个数据库表
const Interviews = mongoose.model('interview',Interview);
module.exports = Interviews;
七、嘿嘿,真万事俱备,只欠接口
在server.js中的router.use()方法中写一个接口
router.get('/searchInterview', (req, res) => {
let path = req.query.type;
let Type = {'type':''};
switch (path) {
case 'cssinterview':Type.type = 'css';break;
case 'jsinterview':Type.type = 'js';break;
case 'vueinterview':Type.type = 'vue';break;
case 'reactinterview':Type.type = 'react';break;
case 'httpinterview':Type.type = 'http';break;
}
Interviews.find(Type,(err,data)=>{
if(err){
next(err);
res.json(data);
}else{
res.json(data);
}
})
});//按条件查询列表
前端随便找个地方写一个get方法
Get(
'/interview/searchInterview',{type:pathName},
(data)=>{
console.log(data);
this.setState({
tableData:data
})
},
(err)=>{
console.log(err)
}
)
哦吼,data即我们从数据库中查到的数据。
搞定,告辞~!
八、遇到的问题:
1、链接数据库之后查询,数据组为空,确认条件正确,schema正确,数据库连接正常,问题所在:model映射表时候表名错误,多写一个s,切记此处mongodb的坑,s、s、s。重要的事情说三遍
2、对于post、get请求参数获取方式,在server.js中有两行代码
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
这就是用来处理post,get所带参数的。
在接口router.get()或者router.post()的回调中有一个req的参数,这里面包括了好多东西(没参悟透)。req.body即post请求的参数,req.qurey即get请求的参数
九、关于express中的app.use()中间件
当一个请求发送到后台之后,后台会先接受到请求request,然后做出各种处理,然后在响应response,在接受到请求到响应这中间就可以做各种事情。中间件app.use()就是搞这个的,所谓的中间件就是一系列的函数,这一系列函数就可以对HTTP请求做一些列的处理。其中有next参数,next参数其实就是一个函数,表示下一个中间件函数,这样就可以依次去执行函数。express中维护一个中间件数组,这个数据就是一些列的中间件函数,当一个app.use(fun)使用过后,这个fun又会被扔回这个数据中,如果有执行next()则找这个函数的下一个函数,如果没有就终止了。
var express = require('express');
var app = express();
app.listen(3000, function () {
console.log('listen 3000...');
});
function middlewareA(req, res, next) {
console.log('middlewareA before next()');
next();
console.log('middlewareA after next()');
}
function middlewareB(req, res, next) {
console.log('middlewareB before next()');
next();
console.log('middlewareB after next()');
}
function middlewareC(req, res, next) {
console.log('middlewareC before next()');
next();
console.log('middlewareC after next()');
}
app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);
输出:middlewareA before next()
middlewareB before next()
middlewareC before next()
middlewareA after next()
middlewareB after next()
middlewareC after next()
写的不错哦~~
这是我见过最生动的分享整理了,读起来很生动!!!