问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

Node.js开发实战详解的作者简介

发布网友 发布时间:2022-04-29 08:13

我来回答

2个回答

懂视网 时间:2022-05-15 04:31

本篇文章给大家总结了node.js博客项目开发的相关步骤以及知识点分享,有兴趣的朋友参考下。

需要安装的模块

  • 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:datadb --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 自动编码

    当想在某个p中显示后端生成的HTML代码,模板渲染时会自动编码,
    以字符串的形式显示。通过以下方式,可以避免这个情况:

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

    用户管理和分页

    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;

    orm表单提交的小问题

    当使用form表单提交一些代码的时候,会出现浏览器拦截的现象,原因是:浏览器误以为客户进行xss攻击。所以呢解决这个问题也很简单,就是对提交的内容进行base64或者其他形式的编码,在服务器端进行解码,即可解决。

    上面是我整理给大家的,希望今后会对大家有帮助。

    相关文章:

    javascript实现文件拖拽事件

    vue文件树组件使用详解

    vue全局组件与局部组件使用方法详解

    热心网友 时间:2022-05-15 01:39

    黄丹华,Web前端工程师。专注于PHP与Node.js的开发与应用。较早时间就开始关注Node.js的发展,并系统地学习和研究了国内外大量的Node.js学习资料。独创Mywebl.0的Node.js框架,正在开发Myweb2.0的Node.js框架。自营chinaNode.js微信公众账号,通过公众账号给国内外Node.js爱好者提供一个学习交流的平台。个人技术博客中提供的Node.js入门、资源分享和Nde.js异常分析等优秀文章,被众多的Node.js爱好者所认可。

    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    孩子依赖性太强,妈妈怎么办?目录 孩子对妈妈依赖性太强怎么办 介绍权利的游戏里龙之母全名是什么? 澳洲血橙胶原蛋白是玻璃瓶的吗? 梦见母亲侄子妹妹舅妈电话破屋的预兆 梦见坐别人的车什么意思 有多少人去拜过“龙母”,又有几人知道“龙母”是真的存在过 龙母庙地址在哪里? 龙母像地址在哪里? 龙姥姥是龙母娘娘吗 求Node.js开发指南-郭家宝书籍电子版百度云资源 《Node.js开发指南》epub下载在线阅读,求百度网盘云资源 Node.js开发实战详解的内容体系 如何使用node.js开发个人博客 歌手王筝曝丈夫出轨长达4年,为何网友说不值得同情? 谁告诉我歌手王筝嫁人了没?如果嫁人了他老公是谁叫什么有图最好、在这先谢谢各位了。 adobedreamweavercs6怎么安装 陕西女明星都有谁? 王筝曾为了老公退隐,如今老公出轨了,她该怎么办? 王筝深夜爆料老公出轨,你觉得对方出轨该不该高调宣扬? adobe dreamweaver cs6 破解教程 关于歌手王筝曝丈夫出轨四年一事,你觉得后续会是什么? 请问王筝的《对你说》是写给谁的? 歌手王筝曝丈夫出轨长达4年? 歌手王筝:不相信小姑娘会爱上跟爸爸同岁的男人,你相信吗? 女人梦见爬陡峭的坡爬不上去叫人拉了我一把才上去了是啥意思? 知名歌手曝丈夫出轨4年:二人大尺度画面,后来怎样了? 王筝结婚十五年曝老公出轨,她会选择离婚吗? 女歌手王筝自曝老公出轨,为何她说老公和出轨对象是真爱? 歌手王筝深夜发文,曝丈夫出轨,为什么王筝能接受丈夫出轨4年? Node.js开发实战详解的主体介绍 node.js开发实战详解怎么样 Node.js开发指南的图书简介 Node.js开发实战详解的图书目录 NodeJs的优势和适合开发的程序 现在还能用软件激活win7吗? 小白重装系统win7旗舰版是否激活 现在win7自动激活了吗 盗版windows7系统是否可以激活 win7怎么激活啊,之前重装系统,现在要激活,怎么办啊??? 网上下载win7系统怎么激活 现在装win7是不是激活不了了?那我前段时间用没联网的电脑激活了,等以后联网了还算激活了吗? 大神求教啊,现在win7系统怎样激活 曲阜师范大学一本专业有哪些 山东曲阜师范大学是几本 2019曲阜师范大学理科报考需要多少分? 曲阜师范大学学费收费标准 2021山东航空服务艺术与管理录取人数 曲阜师范大学日照校区的录取分数 曲阜师范大学是一本还是二本?