首页 > 开发 > JS > 正文

node.js博客项目开发手记

2024-05-06 16:43:09
字体:
来源:转载
供稿:网友

需要安装的模块

  • 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/userrouter.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();  }});// 当用户登录或注册成功之后,可以为其设置cookiesreq.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) * 每页显示的条数

// 接收传过来的pagelet query_page = Number(req.query.page) || 1;query_page = Math.max(query_page, 1); // 限制最小为1query_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.jsvar mongoose = require('mongoose');var contentSch = require('../schemas/contentSch');module.exports = mongoose.model('Content',contentSch);// contentSch.jsmodule.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或者其他形式的编码,在服务器端进行解码,即可解决。

源码地址:https://github.com/bjw1234/blog


注:相关教程知识阅读请移步到JavaScript/Ajax教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表