node博客项目开辟手记

NodeJs开辟个人博客项目

预览地点:http://baijiawei.top

GitHub地点:https://github.com/bjw1234/blog

须要装置的模块

  • body-parser 剖析post要求
  • cookies 读写cookie
  • express 搭建效劳器
  • markdown Markdown语法剖析天生器
  • mongoose 操纵Mongodb数据库
  • swig 模板剖析引擎

目次构造

  • db 数据库存储目次
  • models 数据库模子文件目次
  • public 大众文件目次(css,js,img)
  • routers 路由文件目次
  • schemas 数据库构造文件
  • views 模板视图文件目次
  • app.js 启动文件
  • package.json

app.js 文件

1.建立运用、监听端口

const app = express();

app.get('/',(req,res,next) => {
    res.send("Hello World !");
});
app.listen(3000,(req,res,next) => {
    console.log("app is running at port 3000");
});

2.设置运用模板

  • 定义运用的模板引擎 app.engine(‘html’,swig.renderFile) 参数1:模板引擎的称号,同时也是模板文件的后缀 参数2:示意用于剖析处置惩罚模板内容的要领
  • 设置模板文件寄存的目次 app.set(‘views’,’./views’)
  • 注册所运用的模板引擎 app.set(‘view engine’,’html’)

3.用模板引擎去剖析文件

/**
 * 读取views目次下的指定文件,剖析并返回给客户端 
 * 参数1:模板文件
 * 参数2:给模板通报的参数 
 */
 
res.render('index',{
    title:'首页 ',
    content: 'hello swig'
});

4.开辟过程当中须要作废模板缓存的限定

swig.setDefaults({
  cache: false
});

app.set('view cache', false);

5.设置静态文件托管

 // 当用户接见的是/public途径下的文件,那末直接返回
app.use('/public',express.static(__dirname + '/public'));

分别模块

  • 前台模块
  • 背景模块
  • API模块
// 依据差别的功用分别模块
app.use('/',require('./routers/main'));
app.use('/admin',require('./routers/admin'));
app.use('/api',require('./routers/api'));

关于治理员模块 admin.js

var express = require('express');
var router = express.Router();

// 比方接见 /admin/user
router.get('/user',function(req,res,next) {
    res.send('User');
});

module.exports = router;

前台路由 + 模板

  • main 模块
    / 首页
    /view 内容页
  • api模块
    / 首页
    /register 用户注册
    /login 用户登录
    /comment 批评猎取
    /comment/post 批评提交

背景(admin)路由+模板

  • 首页
    / 背景首页
  • 用户治理
    /user 用户列表
  • 分类治理
    /category 分类列表
    /category/add 分类增加
    /category/edit 分类修正
    /caterory/delete 分类删除
  • 文章内容治理
    /article nei内容列表
    /article/add 内容增加
    /article/edit 内容修正
    /article/delete 内容删除
  • 批评内容治理
    /comment 批评列表
    /comment/delete 批评删除

功用开辟递次

功用模块开辟递次

  • 用户
  • 栏目
  • 内容
  • 批评

编码递次

  • 经由过程Schema定义设想数据存储构造
  • 功用逻辑
  • 页面展现

衔接数据库(mongoDB)

启动MongoDB效劳端:
mongod –dbpath=G:\data\db –port=27017
启动效劳设置数据库的存储地点以及端口

var mongoose = require('mongoose');
// 数据库链接
mongoose.connect("mongodb://localhost:27017/blog",(err) => {
    if(err){
        console.log("数据库衔接失利");
    }else{
        console.log("数据库衔接胜利");
      // 启动效劳器,监听端口  
      app.listen(3000,(req,res,next) => {
            console.log("app is running at port 3000");
        });
    }
});

定义数据表构造和模子

关于用户数据表(users.js)在schema文件夹下:

var mongoose = require('mongoose');
module.exports = new mongoose.Schema({
    // 用户名
   username:String,
   // 暗码
   password:String
});

在models目次下建立user.js模子类

var mongoose = require('mongoose');
var userSchema = require('../schemas/users');

module.exports = mongoose.model('User',userSchema);

处置惩罚用户注册

  • 前端经由过程ajax提交用户名和暗码

url: /api/register

  • 后端对前端提交(POST)的数据剖析
var bodyParser = require('body-parser');
// bodyParser 设置
// 经由过程运用这一要领,可以为req对象增加一个body属性
app.use( bodyParser.urlencoded({extended:true}));

// 在api模块中:
// 1.能够定义一个中间件,来一致返回花样
var responseData;
router.use( function(req,res,next){ // path默以为'/',当接见该目次时这个中间件被挪用
    responseData = {
         code:0,
       message:''
    };
    next();
});

router.post('/register',(req,res,next) => {
    console.log(req.body);
   // 去推断用户名、暗码是不是正当
   // 推断是不是用户名已被注册
   // 经由过程 res.json(responseData) 给客户端返回json数据
   
   // 查询数据库
   User.findOne({    // 返回一个promise对象
           username: username
   }).then(function( userInfo ) {
           if( userInfo ){ // 数据库中有该条纪录
            ...
          res.json(responseData);
          return;
       }
       // 给数据库中增加该条信息
       var user = new User({ username:username,password:password });
       return user.save(); // 返回promise对象
   }).then(function( newUserInfo ){
            console.log(newUserInfo);
       res.json(responseData);  // 数据保留胜利  
   });
});

cookies 模块的运用

  • 全局(app.js)注册运用
// 设置cookie
// 只需客户端发送要求就会经由过程这个中间件
app.use((req, res, next) => {
    req.cookies = new cookies(req, res);

    /**
     * 剖析用户的cookies信息
     * 查询数据库推断是不是为治理员 isAdmin
     * 注重:查询数据库是异步操纵,next应当放在回调里边
     */
    req.userInfo = {};
    if (req.cookies.get("userInfo")) {
        try {
            req.userInfo = JSON.parse(req.cookies.get("userInfo"));
            // 查询数据库推断是不是为治理员
            User.findById(req.userInfo._id).then(function (result) {
                req.userInfo.isAdmin = Boolean(result.isAdmin);
                next();
            });
        } catch (e) {
            next();
        }
    } else {
        next();
    }
});

// 当用户登录或注册胜利以后,可以为其设置cookies
req.cookies.set("userInfo",JSON.stringify({
     _id:result._id,
    username:result.username 
}));

swig模板引擎

1.变量
{{ name }}

2.属性
{{ student.name }}

3.if推断
{ % if name === ‘郭靖’ % }
hello 靖哥哥
{ % endif % }

4.for轮回
// arr = [1, 2, 3]
{ % for key, val in arr % }
<p>{ { key } } — { { val } }</p>
{ % endfor % }

5.set敕令
用来设置一个变量,在当前高低文中复用

{% set foo = [0, 1, 2, 3, 4, 5] %}

  • {% extends ‘layout.html’ %} // 继续某一个HTML模板
  • {% include ‘page.html’ %} // 包括一个模板到当前位置
  • {% block main %} xxx {% endblock %} //重写某一区块

6.autoescape 自动编码
当想在某个div中显现后端天生的HTML代码,模板衬着时会自动编码,
以字符串的情势显现。经由过程以下体式格局,能够防止这个状况:

 <div id="article-content" class="content">
    {% autoescape false %}
    {{ data.article_content_html }}
    {% endautoescape %}
</div>

用户治理和分页

  • CRUD用户数据
const User = require('../models/user');

// 查询一切的用户数据
User.find().then(function(users){

});

// 依据某一字段查询数据
User.findOne({
    username:username
}).then(function(result){

});

// 依据用户ID查询数据
User.findById(id).then(function(user){

});

// 依据ID删除数据
User.remove({
    _id: id
}).then(function(){

});

// 修正数据
User.update({
    _id: id
},{
    username: name
}).then(function(){
    
});

  • 数据分页治理

两个主要要领
limit(Number): 限定猎取的数据条数
skip(Number): 疏忽数据的条数 前number条

疏忽条数:(当前页 – 1) * 每页显现的条数


// 吸收传过来的page
let query_page = Number(req.query.page) || 1;
query_page = Math.max(query_page, 1);  // 限定最小为1
query_page = Math.min(Math.ceil(count / limit), query_page); // 限定最大值 count/limit向上取整


var cur_page = query_page;  // 当前页
var limit = 10; // 每页显现的条数
var skip = (cur_page - 1) * limit; //疏忽的条数

User.find().limit(limit).skip(skip).then(function(users){
    ...
  // 将当前页 page 传给页面
  // 将最大页码 maxPage 传给页面
});

文章的表构造

// 关于content.js
var mongoose = require('mongoose');
var contentSch = require('../schemas/contentSch');

module.exports = mongoose.model('Content',contentSch);


// contentSch.js
module.exports = new mongoose.Schema({
    
   // 关联字段 - 分类的id
   category:{
        // 范例
        type:mongoose.Schema.Types.ObjectId,
        // 援用
        ref:'Category'  
    },
    
    // 内容题目
    title: String,
    
    // 简介
    description:{
        type: String,
        default: ''  
    },
    
    // 内容
    content:{
        type:String,
        default:''
    }
});

// 文章查询时关联category字段
Content.find().populate('category').then(contents => {
    // 那末经由过程如许的体式格局,我们就能够找到Content表中的
   // 关联信息     content.category.category_name 
});

MarkDown语法高亮

  • 在HTML中直接运用
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>

<script src="https://cdn.bootcss.com/marked/0.3.17/marked.min.js"></script>

// marked相干设置
marked.setOptions({
    renderer: new marked.Renderer(),
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: true,
    smartLists: true,
    smartypants: false,
    highlight: function (code) {
        return hljs.highlightAuto(code).value;
    }
});

// MarkDown语法剖析内容预览
$('#bjw-content').on('keyup blur', function () {
    $('#bjw-previous').html(marked($('#bjw-content').val()));
});
  • node环境中运用
// 在模板页面引入默许款式
<!--语法高亮-->
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">

const marked = require('marked');
const hljs = require('highlight.js');

// marked相干设置
marked.setOptions({
    renderer: new marked.Renderer(),
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: true,
    smartLists: true,
    smartypants: false,
    highlight: function (code) {
        return hljs.highlightAuto(code).value;
    }
});

// 对内容举行markdown语法转换
data.article_content_html = marked(article.content);

使文本域支撑Tab缩进

$('#bjw-content').on('keydown',function(e){
    if(e.keyCode === 9){ // Tab键
         var position = this.selectionStart + 2; // Tab === 俩空格
       this.value = this.value.substr(0,this.selectionStart) + "  " + this.value.substr(this.selectionStart);
       this.selectionStart = position;
       this.selectionEnd = position;
       this.focus();
       e.preventDefault();
    }
});

layer 弹框

// 显现弹框
function showDialog(text, icon, callback) {
    layer.open({
        time: 1500,
        anim: 4,
        offset: 't',
        icon: icon,
        content: text,
        btn: false,
        title: false,
        closeBtn: 0,
        end: function () {
            callback && callback();
        }
    });
});

随机用户头像天生


// 引入对应的库
const crypto = require('crypto');
const identicon = require('identicon.js');

// 当用户注册时,依据用户的用户名天生随机头像
let hash = crypto.createHash('md5');
hash.update(username);
let imgData = new identicon(hash.digest('hex').toString());
let imgUrl = 'data:/image/png;base64,'+imgData;

form表单提交的小题目

当运用form表单提交一些代码的时刻,会涌现浏览器阻拦的征象,原因是:浏览器误以为客户举行xss进击。所以呢处理这个题目也很简单,就是对提交的内容举行base64或许其他情势的编码,在效劳器端举行解码,即可处理。

项目地点:https://github.com/bjw1234/blog

结束 撒花 ^_^ ~

    原文作者:五月花开
    原文地址: https://segmentfault.com/a/1190000013738908
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞