分享自己如何从小白了解node,感谢nswbmw大神github上https://github.com/nswbmw/N-blog这一项目让小白可以搭建数据库跑起一个简单项目。直接进入本人学习心得,自己学了大神github项目后大概整理了一个快速学习版,希望能帮助到跟我一样node不知道如何入手的,整个node搭建流程如下
(ps:期间对express的封装突然疑惑了下,疑问express的封装原理等,具体疑问跟解答链接为下,有兴趣可以点击看下https://www.jianshu.com/p/797a4e38fe77,https://cnodejs.org/topic/5396cd60c3ee0b5820f00e2a,https://nodejs.org/dist/latest-v8.x/docs/api/http.html,https://www.cnblogs.com/dabinglian/p/6874290.html)
一、MongoDB安装和启动
1、mongoDB的安装https://www.mongodb.com/download-center#community
2、启动mongoDB(本人安装在了d盘下的MongDB目录,启动前需要在mongodb下新建一个data目录)
window+R启动命令窗口,执行下列命令
二、上面两个步骤启动MongoDB数据库后就是项目搭建,我们搭建一个express框架,接下来的流程均为参考nswbmw大神进行浓缩。
1、新建项目
(1)安装淘宝镜像
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
(2)新建目录e-own,用gitbash直接进入目录,执行
新建好后,手动添加到目录结构如下
models
: 存放操作数据库的文件public
: 存放静态文件,如样式、图片等routes
: 存放路由文件views
: 存放模板文件index.js
: 程序主文件package.json
: 存储项目名、描述、作者、依赖等等信息(3)安装依赖模块
npm i config-lite connect-flash connect-mongo ejs express express-session marked moment mongolass objectid-to-timestamp sha1 winston express-winston --save
npm i https://github.com:utatti/express-formidable.git --save # 从 GitHub 安装 express-formidable 最新版,v1.0.0 有 bug
express
: web 框架express-session
: session 中间件connect-mongo
: 将 session 存储于 mongodb,结合 express-session 使用connect-flash
: 页面通知的中间件,基于 session 实现ejs
: 模板express-formidable
: 接收表单及文件上传的中间件config-lite
: 读取配置文件marked
: markdown 解析moment
: 时间格式化mongolass
: mongodb 驱动objectid-to-timestamp
: 根据 ObjectId 生成时间戳sha1
: sha1 加密,用于密码加密winston
: 日志express-winston
: express 的 winston 日志中间件(4)config/default.js
module.exports = {
port:3001,
session:{
secret:'own',
key:'own',
maxAge:2592000000
},
mongodb:'mongodb://localhost:27017/own'
}
port
: 程序启动要监听的端口号session
: express-session 的配置信息,后面介绍mongodb
: mongodb 的地址,以 mongodb://
协议开头,myblog
为 db 名(5)路由(routes/index.js)
module.exports = function(app){
app.get('/',function(req,res){
res.send('hello,this is a simple test');
})
}
(6)项目启动文件index.js(该文件设置了session存储位置,路由,模版引擎)
const path = require('path')
const express = require("express")
const session = require('express-session')
//connect-mongo用于将session持久化到mongodb数据库
const MongoStore = require('connect-mongo')(session)
//flash报错框(flash 中间件应该放到 session 中间件之后加载,因为 flash 是基于 session 实现的。)
const flash = require('connect-flash')
const config = require('config-lite')(__dirname)//读取config下default.js配置项
const routes = require('./routes')
const pkg = require('./package')
const app = express()
//设置模板目录
app.set('views',path.join(__dirname,'views'))
//设置模板引擎为ejs
app.set('view engine','ejs')
//设置静态文件目录
app.use(express.static(path.join(__dirname,'public')))
//session中间件
app.use(session({
name:config.session.key,//设置cookie中保存session id 的字段名字
secret:config.session.secret,//通过设置secret来计算hash值并放在cookie中,使产生的signedCookie防篡改
resave:true,//强制更新
saveUninitialized:false,//设置为false,强制创建一个session,即使用户未登录
cookie:{
maxAge:config.session.maxAge//过期时间,过期后cookie中的sessionid删除
},
store:new MongoStore({
url:config.mongodb
})
}))
//flash中间件
app.use(flash())
//路由
routes(app)
// 监听端口,启动程序
app.listen(config.port, function () {
console.log(`${pkg.name} listening on port ${config.port}`)
})
上面几个配置好后,确保已经开启Mongodb的同时在进入e-own目录下下面命令启动项目
在浏览器中输入网址localhost:3001,查看到界面如下,则可继续进行下一步,否则请确保程序正确运行后再继续下面的操作。
三、上面的简单的三步骤只是简单的进行页面跳转,接着我们以实现登录注册为例子,通过连接数据库跟操作数据跟界面的搭建基本的了解整个流程
checkLogin
: 当用户信息(req.session.user
)不存在,即认为用户没有登录,则跳转到登录页,同时显示 未登录
的通知,用于需要用户登录才能操作的页面checkNotLogin
: 当用户信息(req.session.user
)存在,即认为用户已经登录,则跳转到之前的页面,同时显示 已登录
的通知,如已登录用户就禁止访问登录、注册页面(1)路由设置routes/index.js(打开页面后直接进入登录页)
module.exports = function(app){
app.get('/',function(req,res){
res.redirect('/signin')
})
app.use('/signin',require('./signin'))
}
routes/signin.js
const express = require('express');
const router = express.Router()
//get/signin登录页
router.get('/',checkNotLogin,function(req,res,next){
res.render('signin')
})
module.exports = router;
signin.js中res.render('signin')用户渲染界面,index.js下通过app.set("views",path.join(__dirname,'views'))。app.set('view engine','ejs')设置了模板引擎为ejs,模板目录,app.use(express.static(path.join(__dirname,'public')))指定了静态文件目录,直接上本人的signin.ejs代码,个人比较想通过nodejs制作一个移动端项目,因此引入rem.js跟reset.css
(views/header.ejs)
<%= blog.title %>
(views/footer.ejs)
(views/signin.ejs)
<%- include('header') %>
HAPPY 一起
<%- include('footer') %>
public/css/custom.css
/*登录页面样式*/
.login-content{
/*背景渐变*/
background:#d4a112;
background: -webkit-gradient(linear, left top,left bottom, color-stop(0, rgb(231, 194, 194)),
color-stop(1, #d4a112));
background: -ms-linear-gradient(right, #F5DA91, #d4a112);
background: -o-linear-gradient( #F5DA91, #d4a112);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F5DA91', endColorstr
='#d4a112', GradientType=0);
box-shadow: none;
text-align:center;
position: absolute;
top:0;right:0;bottom:0;left:0;
padding:0 10%;
}
.logo-content{
text-align:center;
padding:7rem 0;
}
.login-title{
color:#fff;
font-size:3rem;
}
.input-content{
line-height:7rem;
text-align: center;
}
.input-radius{
width:100%;
height:4rem;
padding:0.3rem;
font-size:1.5rem;
margin:0 auto;
border-radius:10px;
border:1px solid #fff;
}
.btn-login{
width:100%;
height:5rem;
margin-top:5rem;
text-align:center;
font-size:2rem;
color:#fff;
border-radius:10px;
outline:none;
background-color:#DF7614;
border:none;
}
public/css/reset.css
@charset 'utf-8';
html{color:#000;background:#FFF;font-family:'Microsoft YaHei',sans-serif,Arial;}
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td,strong{padding:0;margin:0;font-family:'Microsoft YaHei',sans-serif,Arial;}
table{border-collapse:collapse;border-spacing:0;}img{border:0;}a{text-decoration:none; color:#000; outline:none;}a:hover{text-decoration:underline;}
var,em,strong{font-style:normal;}
em,strong,th,var{font-style:inherit;font-weight:inherit;}
li{list-style:none;}
caption,th{text-align:left;}
h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}
input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style: inherit;font-weight:inherit;}
input,button,textarea,select{*font-size:100%;}
.clearfix {*zoom:1}
.clearfix:after {content:'\200B';clear:both;display:block;height:0px}
public/js/rem.js
(function (doc, win) {
console.log("dpr:" + win.devicePixelRatio);
var docEle = doc.documentElement,
isIos = navigator.userAgent.match(/iphone|ipod|ipad/gi),
dpr = Math.min(win.devicePixelRatio, 3);
scale = 1 / dpr,
resizeEvent = 'orientationchange' in window ? 'orientationchange' : 'resize';
docEle.dataset.dpr = dpr;
var metaEle = doc.createElement('meta');
metaEle.name = 'viewport';
metaEle.content = 'user-scalable=no,initial-scale=' + scale + ',maximum-scale=' + scale;
docEle.firstElementChild.appendChild(metaEle);
var recalCulate = function () {
var width = docEle.clientWidth;
if (width / dpr > 640) {
width = 640 * dpr;
}
docEle.style.fontSize = 20 * width / 750 + 'px';
};
recalCulate();
if (!doc.addEventListener) return;
win.addEventListener(resizeEvent, recalCulate, false);
})(document, window);
上面文件确保正确后,确保mongodb开启的同时进入文件目录执行node index即可得到下图登录页
点击登录,需验证账号密码是否已填,填写后需请求数据库是否存在该用户,若存在这进入主页,若不存在则进入注册页面,该逻辑在sigin.js里路由进行处理
routes/signin.js
const sha1 = require('sha1')
const express = require('express')
const router = express.Router()
const UserModel = require('../models/users')
const checkNotLogin = require('../middlewares/check').checkNotLogin
// GET /signin 登录页
router.get('/', checkNotLogin, function (req, res, next) {
res.render('signin')
})
// POST /signin 用户登录
router.post('/', checkNotLogin, function (req, res, next) {
const name = req.fields.name
const password = req.fields.password
// 校验参数
try {
if (!name.length) {
throw new Error('请填写用户名')
}
if (!password.length) {
throw new Error('请填写密码')
}
} catch (e) {
req.flash('error', e.message)
return res.redirect('back')
}
UserModel.getUserByName(name)
.then(function (user) {
if (!user) {
req.flash('error', '用户不存在')
return res.redirect('back')
}
// 检查密码是否匹配
if (sha1(password) !== user.password) {
req.flash('error', '用户名或密码错误')
return res.redirect('back')
}
req.flash('success', '登录成功')
// 用户信息写入 session
delete user.password
req.session.user = user
// 跳转到主页
res.redirect('/posts')
})
.catch(next)
})
module.exports = router
上面通过mongodb查询数据库,接着便进入数据库的相关操作,lib/mongo.js链接数据库并建立User集合
lib/mongo.js
const config = require('config-lite')(__dirname)
const Mongolass = require("mongolass")
const mongolass = new Mongolass()
const moment = require('moment')
const objectIdToTimestamp = require("objectid-to-timestamp")
//根据id生成创建时间created_at
mongolass.plugin("addCreatedAt",{
afterFind:function(results){
results.forEach(function(item){
item.created_at = moment(objectIdToTimestamp(item._id)).format("YYYY-MM-DD HH:mm")
})
return result
},
afterFindOne:function(result){
if(result){
result.created_at = moment(objectIdToTimestamp(item._id)).format("YYYY-MM-DD HH:mm")
}
return result
}
})
mongolass.connect(config.mongodb)
exports.User = mongolass.model('User', {
name: { type: 'string', required: true },
password: { type: 'string', required: true },
avatar: { type: 'string', required: true },
gender: { type: 'string', enum: ['m', 'f', 'x'], default: 'x' },
bio: { type: 'string', required: true }
})
exports.User.index({ name: 1 }, { unique: true }).exec()// 根据用户名找到用户,用户名全局唯一
对数据库的创建查询方法在models文件夹下处理
models/users.js
const User = require('../lib/mongo').User
module.exports = {
// 注册一个用户
create: function create (user) {
return User.create(user).exec()
},
// 通过用户名获取用户信息
getUserByName: function getUserByName (name) {
return User
.findOne({ name: name })
.addCreatedAt()
.exec()
}
}
至此,我们已经实现了登录后进入主页的流程,其他流程类比一下登录页,创建数据库相关集合在lib/mongo.js,数据库处理逻辑,增删改查均在models文件夹下创建对应的文件进行处理,界面均为views下的ejs文件,且通过res.render引入。
解决:确保此处正确书写
router.post("/",checkNotLogin,function(req,res,next){
const name = req.fields.name
const password = req.fields.password
console.log("name passwprd",name,password);
})
由于时间关系,可能有些地方不够详细,有错之处请指出。接下来自己将这个移动端项目完善再写该博客后续,再次感谢大神们对知识的分享,让小白有了更多的学习资源来研究新的技术