NodeJS简易博客系统(八)功能需求描述及用户模块实现

一、功能需求描述

用一张导图来说明:

二、页面设计

页面设计如下:

三、梳理下整个系统的业务流程

对这个小项目进行业务流程的梳理,流程图大致如下:

四、用户模块实现

1、数据库设计及代码

(1)用户表(users)

(2)博文分类表(categories)

(3)博文评论列表(contents)

从title往下依次是博文标题,分类,浏览次数,所属用户id,评论列表(评论内容,评论所属用户id),发表时间,文章描述,文章详情,数据库版本。

2、用户模块

由上述流程图得用户模块有登录、注册、博文列表、阅读原文及评论功能。

(1)页面代码

首页的界面使用的是bootstrap+jquery框架设计,首页总共有三个div块,一个是header,content-details,login-register。下面是页面的代码:

main_template.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>简单博客系统</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <link rel="stylesheet" type="text/css" href="/public/css/bootstrap.css">
    <link rel="stylesheet" type="text/css" href="/public/css/index.css">
    <script type="text/javascript" src="/public/js/jquery.js"></script>
    <script type="text/javascript" src="/public/js/bootstrap.js"></script>
    <script type="text/javascript" src="/public/js/index.js"></script>
</head>
<body>
<header>
    <div class="container-fluid header1">
        <span>NodeJS简单博客系统</span>
    </div>
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
            </div>
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    {%if category == ''%}
                    <li><a href="/" class="focus">首页</a></li>
                    {%else%}
                    <li><a href="/">首页</a></li>
                    {%endif%}
                    {%for cate in categories%}
                    {%if category == cate.id%}
                    <li><a href="/?category={{cate.id}}" class="focus">{{cate.name}}</a></li>
                    {%else%}
                    <li><a href="/?category={{cate.id}}">{{cate.name}}</a></li>
                    {%endif%}
                    {%endfor%}
                </ul>

            </div>

        </div>
    </nav>
</header>
<section>
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-md-8 moveup" id="content">
                <!--文章列表block-->
                {% block content %}
                {% endblock %}
            </div>
            <div class="col-lg-4 col-md-4" >
                {% if userInfo._id %}
                <div class="userinfo spindown" id="userinfo" >
                    <h2>用户信息</h2>
                    <h3 class="account">用户名:{{userInfo.username}}</h3>
                    {% if userInfo.isadmin %}
                    <p>您好,管理员! <a href="/admin/"> 点击这里</a>进入管理页面</p>
                    {% else %}
                    <p>你好,欢迎光临我的博客!</p>
                    {% endif %}
                    <p><a href="javascript:;" class="logout">退出</a></p>
                </div>
                {% else %}
                <div class="register spindown" id="register"  style="display: none">
                    <h2>注册</h2>
                    <div class="line">
                        <span>用户名:</span>
                        <input type="text" name="username" title="username">
                    </div>
                    <div class="line">
                        <span>密码:</span>
                        <input type="password" name="password" title="password">
                    </div>
                    <div class="line">
                        <span>确认:</span>
                        <input type="password" name="repassword" title="repassword">
                    </div>
                    <div class="line">
                        <input type="submit" name="submit" value="注册" >
                    </div>
                    <p class="warning"></p>
                    <p>已有账号? <a href="javascript:;">点击登录</a></p>
                </div>

                <div class="login spindown" id="login" >
                    <h2>登录</h2>
                    <div class="line">
                        <span>用户名:</span>
                        <input type="text" name="username" title="username">
                    </div>
                    <div class="line">
                        <span>密码:</span>
                        <input type="password" name="password" title="password">
                    </div>
                    <div class="line">
                        <input type="submit" name="submit" value="登录" >
                    </div>
                    <h2 class="warning"></h2>
                    <p>还没注册? <a href="javascript:;">点击注册</a></p>
                </div>
                {% endif %}
            </div>
        </div>
    </div>
</section>
<footer>
    <p>Copyright © 小马实验室 | 京ICP备11951015号 | 京公网安备11011105210084</p>
    <a href="#"><span class="glyphicon glyphicon-arrow-up"></span></a>
</footer>
</body>
</html>

文章详情article_detail.html

{% extends "main_template.html" %}
{% block content %}
<div class="papers">
    <h2>{{contents.title}}</h2>
    <p class="paperabout">
        作者:<span class="paperinfo">{{contents.user.username}}</span>-
        时间:<span class="paperinfo">{{contents.addtime|date('Y-m-d  H:i:s', -8*60)}}</span>-
        阅读:<span class="paperinfo">{{contents.num}}</span>-
        分类于:<span class="paperinfo">{{contents.category.name}}</span>-
        评论:<span class="paperinfo">{{contents.comment.length}}</span>
    </p>
    <dfn><p>{{contents.composition}}</p></dfn>
    <div class="readmore"><a href="javascript:window.history.back()">返回</a></div>
</div>
<div id="comment">
    <h3 ><strong>评论 </strong> <span class="much"> 共 <em id="commentCount">0</em> 条评论</span></h3>
    <div style="font-size: 22px;">
        <div>
            <textarea  name="name" id="commentarea" placeholder="请填写评论"
            style="height: 150px;width: 100%;"></textarea>
            <input  type="hidden" id="contentid" name="contentid" value="{{contents.id}}">
        </div>
        <button type="submit" id="addcomment" class="btn btn-primary btn-lg">发表评论</button>
    </div>
    {% if userInfo._id %}
    {% else %}
    <h4 class="loginfo" >你还没有登录,请先登录!</h4>
    {% endif %}
    {% if contents.comment.length == 0 %}
    <h4 class="loginfo" >暂无评论,赶紧来评论吧!</h4>
    {% endif %}
    <div id="commentlist">
    </div>
    <div class="pages">
        <a id="prevpage" style="float: left;"><span>上一页</span></a>
        <span id="currentpage"></span> / <span id="totalpage"></span>
        <a id="nextpage" style="float: right;"><span>下一页</span></a>
    </div>
</div>
{% endblock %}

首页index.html

<!--首页-->
{% extends "main_template.html" %}
{% block content %}
 {% for content in contents %}
 <div class="papers">
     <h2>{{content.title}}</h2>
     <p class="paperabout">
         作者:<span class="paperinfo">{{content.user.username}}</span>-
         时间:<span class="paperinfo">{{content.addtime|date('Y-m-d  H:i:s', -8*60)}}</span>-
         阅读:<span class="paperinfo">{{content.num}}</span>-
         分类于:<span class="paperinfo">{{content.category.name}}</span>-
         评论:<span class="paperinfo">{{content.comment.length}}</span>
     </p>
     <dfn><p>description:{{content.description}}</p></dfn>
     <div class="readmore"><a href="/article?contentid={{content.id}}">阅读全文</a></div>
 </div>
 {% endfor %}
<div class="pages">
    <a href="/?category={{category}}&page={{page-1}}" style="float: left;"><span>上一页</span></a>
    <span>{{page}}</span> / <span>{{pages}}</span>
    <a href="/?category={{category}}&page={{page+1}}" style="float: right;"><span>下一页</span></a>
</div>
{% endblock %}

(2)页面对应的js、css代码

index.js

$(function(){
    var loginbox = $("#login");
    var registerbox = $("#register");
    var userinfobox = $("#userinfo");
    loginbox.find("a").on("click",function(){
        loginbox.hide();
        registerbox.show();
    });
    registerbox.find("a").on("click",function(){
        loginbox.show();
        registerbox.hide();
    });    registerbox.find("input[name='submit']").on("click",function(){
        $.ajax({
            type: "post",
            url: "/api/user/register",
            dataType: "json",
            data: {
                username: registerbox.find('input[name="username"]').val(),
                password: registerbox.find('input[name="password"]').val(),
                repassword: registerbox.find('input[name="repassword"]').val()},
            success :function(result){
                console.log(result);                registerbox.find(".warning").html(result.message);
                setTimeout(function(){
                    registerbox.find(".warning").html("");
                },1500);
                if(!result.code){
                    setTimeout(function(){
                        loginbox.show();
                        registerbox.hide();                        registerbox.find('input[name="username"]').val("");
                        registerbox.find('input[name="password"]').val("");
                        registerbox.find('input[name="repassword"]').val("");
                    },1500);
                }
            }

        });

    });
loginbox.find("input[name='submit']").on("click",function(){
        $.ajax({
            type: "post",
            url: "/api/user/login",
            dataType: "json",
            data: {
                username: loginbox.find('input[name="username"]').val(),
                password: loginbox.find('input[name="password"]').val()
                },
            success :function(result){
                console.log(result);
                loginbox.find(".warning").html(result.message);
                setTimeout(function(){
                    loginbox.find(".warning").html("");
                },1500);
                if(!result.code){
                    setTimeout(function(){
                        window.location.reload();
                    },1500);
                }
            }

        });

    });
    userinfobox.find(".logout").on("click",function(){

        $.ajax({
            url:"/api/user/logout",
            success:function(result){
                console.log(result);
                if(!result.code){
                    window.location.reload();
                }
            }
        })

    });


//在页面加载时获取评论
    $.ajax({
        url: '/api/pinglun',
        type:"get",
        dataType:"json",
        data: {
            contentid: $('#contentid').val()
        },
        success: function(result) {
            //console.log(111111);
            render(result.postdata);
            quanju=result.postdata;
        }
    });

//提交评论
    $("#addcomment").on("click",function(){
        $.ajax({
            type:"post",
            url:"/api/comment",
            dataType:"json",
            data:{
                comment: $("#comment").find("textarea").val(),
                contentid: $("#contentid").val()
            },
            success:function(result){
                //console.log(result);
                $("#commentarea").val("");
                render(result.postdata);
                quanju=result.postdata;
            }
        })
    });
    var quanju=null;
    var page=1;
    var limit=3;
    var pagecount=0;
    $("#prevpage").on("click",function(){
       page--;
        render(quanju);
    });
    $("#nextpage").on("click",function(){
        page++;
        render(quanju);
    });
    function render(data) {
        var str = "";
        var start=(page-1)*limit;
        var end = start+limit;
        var comments=data.comment.reverse();
        var showcomments=comments.slice(start,end);
        pagecount = Math.ceil(data.comment.length/limit);
        page = Math.min(pagecount,page);
        page = Math.max(1,page);
        $("#totalpage").html(pagecount);
        $("#currentpage").html(page);
        $("#commentCount").html(comments.length);
        for (var i = 0; i < showcomments.length; i++) {
            str += `<div>
                <span class="commenter">${showcomments[i].user}</span>
                <span class="commenttime">${formatDate(showcomments[i].time)}</span>
                </div>
                <p class="contents">${showcomments[i].comment}</p>`;
        }
        $("#commentlist").html(str);
    }
    function formatDate(d) {
        var date1 = new Date(d);
        return date1.getFullYear() + '-' + (date1.getMonth()+1) + '-' + date1.getDate() + '- ' + date1.getHours() + ':' + date1.getMinutes() + ':' + date1.getSeconds();
    }
});

index.css

body{
    background:#ebebeb;
    min-width: 650px;
}
body h2, body h3 {
    padding: 0;
    margin: 0;
}
a{
    text-decoration: none !important;
    color: #fc6423;
}
.container .row .container-fluid {
    padding: 0;
}
.header1{
    height: 200px !important;
    background:url(/public/img/backimg.jpg);
    background-size:cover;

}
.header1 span{
    margin-left: 40px;
    line-height: 200px;
    font-size: 30px;
    color: #fc6423;
    opacity: 0.7;
    filter: alpha(opacity=70);
}
div[class*="col"]{
    padding: 0;
    color:#000;
}
#content .papers{
    height: 500px;
    margin-bottom: 20px;
    background:#fff;
    text-align: center;
    position: relative;
}
#content .papers h2{
    /*height: 80px;*/
    line-height: 50px;
    font-size: 25px;
}
#content .paperabout{
    font-size: 18px;
}
#content .paperinfo{
    color: #fc6423;
}
#content dfn p{
    height: 300px;
    font-size: 25px;
    padding: 20px;
    background: #ddd;
}
#content .readmore{
    width: 150px;
    height: 40px;
    line-height: 36px;
    font-size: 25px;
    background:#fff;
    border:2px solid #fc6423;
    position: absolute;
    bottom: 30px;
    left: 50px;
}
#content .readmore a{
    display: inline-block;
    width: 150px;
    height: 40px;
}
#content .readmore:hover{
    background:#fc6423;
    border:2px solid #fff;
}
#content .pages{
    font-size: 18px;
    height: 40px;
    line-height: 40px;
    text-align: center;
    margin-bottom:20px;
}
#content .pages a{
    color: #fc6423;
    display: block;
    height: 40px;
    line-height: 40px;
    width: 80px;
    border:1px solid #fc6423;
}
#content .pages a:hover{
    color: #fff;
    background-color: #fc6423;

}
#content .pages>span{
    color: #fc6423;
}
#register{
    background:#fff;
    margin-left: 30px;
    padding-bottom: 20px;
    margin-bottom: 20px;
    transition: 0.5s ease-out;
}
#register h2{
    height: 50px;
    margin-left: 30px;
    line-height: 50px;
    font-size: 24px;
    color: #fc6423;
}
#register .line{
    height: 50px;
    text-align: center;
    line-height: 50px;
    font-size: 18px;
}
#register .line input{
    height: 60%;
    outline: none;
    border-color: #fc6423;
}
#register .line input[type="submit"]{
    width: 200px;
    border:none;
    padding: 0;
    background-color: #fc6423;
    line-height: 100%;
}
#register .warning{
    height: 50px;
    text-align: center;
    line-height: 50px;
    font-size: 20px;
    color: #fc6423;
}
#register>p{
    margin-left: 30px;
}
#login{
    background:#fff;
    padding-bottom: 20px;
    margin-left: 30px;
    margin-bottom: 20px;
    transition: 0.5s ease-out;
}
#login h2{
    height: 50px;
    margin-left: 30px;
    line-height: 50px;
    font-size: 24px;
    color: #fc6423;
}
#login .line{
    height: 50px;
    text-align: center;
    line-height: 50px;
    font-size: 18px;
}
#login .line input{
    height: 60%;
    outline: none;
    border-color: #fc6423;
}
#login .line input[type="submit"]{
    width: 200px;
    border:none;
    padding: 0;
    background-color: #fc6423;
    line-height: 100%;
}
#login .warning{
    height: 50px;
    text-align: center;
    line-height: 50px;
    font-size: 20px;
    color: #fc6423;
}
#login>p{
    margin-left: 30px;
}
#userinfo, #community{
    background:#fff;
    margin-left: 30px;
    margin-bottom: 20px;
    padding-bottom: 20px;
}
#userinfo h2, #community h2{
    height: 50px;
    margin-left: 30px;
    line-height: 50px;
    font-size: 24px;
    color: #fc6423;
}
#userinfo h3, #community h3{
    height: 35px;
    margin-left: 30px;
    line-height: 35px;
    font-size: 16px;
}
#userinfo>p{
    text-align: center;
    font-size: 15px;
}
footer{
    height: 60px;
    background:#333;
    position: relative;
}
footer p{
    text-align: center;
    line-height: 60px;
    color: #fff;
    opacity: 0.7;
}
footer a{
    display: block;
    width: 60px;
    height: 60px;
    position: absolute;
    top: -70px;
    right: 10px;
    background-color: #fc6423;
    border-radius: 30px;
    text-align: center;
    line-height:100%;
}
footer a span{
    font-size: 30px;
    color: #fff;
    margin-top: 10px;
}
#bs-example-navbar-collapse-1 ul{
    width: 100%;
    padding-left: 15%;
    text-align: center;
}
#bs-example-navbar-collapse-1 li{
    height: 60px;
}
#bs-example-navbar-collapse-1 ul a{
    margin: 0;
    padding: 0;
    color: #fc6423;
    width: 150px;
    height: 60px;
    line-height: 60px;
    font-size: 20px;
}
#bs-example-navbar-collapse-1 ul a:hover{
    background: #fc6423;
    color:#fff;
    -webkit-transform: scale(1.1);
    transform: scale(1.1);
    transition: 0.5s ease-out;
}

#comment{
    padding: 30px;
    background: #fff;

}
#comment h3{
    text-align: left;
    height: 60px;
    line-height: 100%;
    color: #fc6423;
}
#comment h3 .much{
    float: right;
    color: #888;
    font-size: 18px;
}
#comment h4{
    color: red;
    text-align: center;
}
#commentlist{

    margin-bottom: 30px;
}
#commentlist>p{
    background: #eee;
    height: 80px;
    text-indent: 2em;
    padding:5px 20px;
    font-size: 18px;
    color: #555;
    margin-bottom: 10px;
}
#commentlist>div{
    line-height: 40px;
    padding: 5px;
    height: 40px;
}
#commentlist>div .commenter{
    float: left;
    margin-left: 20px;
    color: #fc6423;
}
#commentlist .commenttime{
    float: right;
    margin-right: 20px;
}
@keyframes moveup {
    0%{
        -webkit-transform: translateY(100px);
        transform: translateY(100px);
        opacity: 0;
        filter: alpha(opacity=0);
    }
    50%{
        -webkit-transform: translateY(30px);
        transform: translateY(30px);
        opacity: 0.25;
        filter: alpha(opacity=25);
    }
    75%{
         -webkit-transform: translateY(13px);
         transform: translateY(13px);
         opacity: 0.5;
         filter: alpha(opacity=50);
     }
    100%{
          -webkit-transform: translateY(0);
          transform: translateY(0);
          opacity: 1;
          filter: alpha(opacity=100);
      }

}
@keyframes turndown {
    0%{
        opacity: 0;
        filter: alpha(opacity=0);
    }
    100%{
        opacity: 1;
        filter: alpha(opacity=100);
    }
}
.moveup{
    -webkit-animation: moveup 0.7s ease-in;
    animation: moveup 0.7s ease-in;
    -webkit-animation-fill-mode: forwards;
}
.spindown{
    -webkit-animation: turndown 0.7s  ease-in;
    animation: turndown 0.7s  ease-in;
    -webkit-animation-fill-mode: forwards;
}

3、后台代码

(1)项目配置

package.json

{
  "name": "myblog",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.2",
    "cookies": "^0.7.1",
    "express": "^4.16.2",
    "mongoose": "^4.12.4",
    "promise": "^8.0.1",
    "swig": "^1.4.2"
  }
}

app.js

//加载express模块
var express = require("express");
//加载swig模块
var swig = require("swig");
var User = require("./models/user");
//加载mongoose数据库,这个中间件是nodejs与mongoDB数据库的桥梁
var mongoose = require("mongoose");
var Cookies = require('cookies');
//创建一个新的服务器,相当于httpcreateServer
var app = express();

//静态文件资源托管的,js css img等
app.use("/public",express.static( __dirname+"/public"));

//定义应用使用的模板引擎,第一个参数:所要渲染模板文件的后缀,也是模板引擎的名称,第二个参数:渲染的方法
app.engine("html",swig.renderFile);
//定义模板文件存放的路径,第一个参数必须是views,这是模块内指定的解析字段,第二个参数为路径:./表示根目录
app.set("views","./views");
//注册使用模板引擎;第一个参数不能变,第二个参数和上面的html一致
app.set("view engine","html");
//设置完就可以直接在res中渲染html文件了:res.render("index.html",{要渲染的变量})第一个参数是相对于views文件夹

//在开发过程中要取消模板缓存,便于调试
swig.setDefaults({cache : false});

//加载bodyparser模块,用来解析前端提交过来的数据
var bodyparser = require("body-parser");
app.use(bodyparser.urlencoded({extended:true}));

app.use( function(req, res, next) {
    req.cookies = new Cookies(req, res);
    req.userInfo = {};
    if(req.cookies.get('userInfo')){
        var str1 = req.cookies.get('userInfo');
        req.userInfo=JSON.parse(str1);
        User.findById(req.userInfo._id).then(function(userInfodata){
            req.userInfo.isadmin = Boolean(userInfodata.isadmin);
        });
    }
    next();

} );
//浏览器地址映射
app.use("/admin" ,require("./routers/admin"));
app.use("/" ,require("./routers/main"));
app.use("/api" ,require("./routers/api"));
// 连接数据库
mongoose.connect("mongodb://localhost:27017/myBlog",{useMongoClient:true},function (err) {
    if(err){
        console.log("数据库连接失败!");
    }else{
        console.log("数据库连接成功!");
        app.listen(3000);
    }
});

(2)schemas

users.js

var mongoose = require("mongoose");
module.exports = new mongoose.Schema({
    username: String,
    password: String,
    isadmin:{
        type:Boolean,
        default:false
    }
});

categories.js

var mongoose = require("mongoose");
module.exports = new mongoose.Schema({
    name: String
});

contents.js

var mongoose = require("mongoose");
module.exports = new mongoose.Schema({
    title: String,
    category : {
        type:mongoose.Schema.Types.ObjectId,
        ref : "Category"
    },
    composition:{
        type: String,
        default : ""
    },
    description :{
        type: String,
        default : ""
    },
    user:{
        type:mongoose.Schema.Types.ObjectId,
        ref : "User"
    },
    num:{
        type:Number,
        dafault:0
    },
    addtime:{
        type:Date,
        default: new Date()
    },
    comment:{
        type:Array,
        default:[]
    }
});

(3)models

user.js

var mongoose = require("mongoose");
var userschama = require("../schemas/users");
module.exports = mongoose.model("User",userschama);

category.js

var mongoose = require("mongoose");
var userschama = require("../schemas/users");
module.exports = mongoose.model("User",userschama);

contents.js

var mongoose = require("mongoose");
var contentschama = require("../schemas/contents");
module.exports = mongoose.model("Content",contentschama);

(4)路由(routers)

api.js

var express = require("express");
var User = require("../models/user");
var Content = require("../models/content");
var router= express.Router();

//统一返回给前端的数据格式
var resdata;
router.use(function(req,res,next){
    resdata = {
        code:0,
        message:""
    };
    next();
});
router.post("/user/register",function(req ,res ){
    var username = req.body.username;
    var password = req.body.password;
    var repassword = req.body.repassword;
    if(username == ""){
        resdata.code=1;
        resdata.message="用户名不能为空!";
        res.json(resdata);
        return;
    }
    if(password == ""){
        resdata.code=2;
        resdata.message="密码不能为空!";
        res.json(resdata);
        return;
    }
    if(password != repassword){
        resdata.code=3;
        resdata.message="两次输入的密码不一致!";
        res.json(resdata);
        return;
    }
    User.findOne({
        username:username
    },function(err,userinfo){
        if(err){
            console.log(err);
        }
        if(userinfo){
            resdata.code = 4;
            resdata.message = "该用户已被注册!";
            res.json(resdata);
            return false;
        }else{
            var newuser = new User({
                username: username,
                password: password
            });
            newuser.save();
            resdata.message = "注册成功!";
            res.json(resdata);
        }
    });
});
router.post("/user/login",function(req ,res ){
    var username = req.body.username;
    var password = req.body.password;
    if(username == ""||password==""){
        resdata.code=1;
        resdata.message="用户名和密码不能为空!";
        res.json(resdata);
        return;
    }
    User.findOne({
        username:username,
        password:password
    },function(err,userinfo){
        if(err){
            console.log(err);
        }
        if(!userinfo){
            resdata.code = 2;
            resdata.message = "用户名或密码错误!";
            res.json(resdata);
            return false;
        }
        resdata.message = "登录成功!";
        resdata.userinfo={
            id:userinfo._id ,
            username:userinfo.username,
            isadmin:userinfo.isadmin
        };
        req.cookies.set('userInfo', JSON.stringify({
            "_id": userinfo._id,
            "username": userinfo.username,
            "isadmin":userinfo.isadmin
        }));

        res.json(resdata);

    })

});
router.get("/user/logout",function(req ,res ){
    req.cookies.set('userInfo', null);
    res.message="退出成功!";
    res.json(resdata);
});
router.get('/pinglun', function(req, res) {
    var contentid = req.query.contentid || '';
    Content.findOne({
        _id: contentid
    }).then(function(content) {
        //content.comment.reverse();
        resdata.postdata = content;
        //resdata.data.comments.reverse();
        res.json(resdata);
    })
});
router.post("/comment",function(req,res){
    var id = req.body.contentid;
    var commentdata={
        comment:req.body.comment||"",
        user:req.userInfo.username,
        time: new Date()
    };
    Content.findOne({_id:id}).then(function(thiscon){
        if(commentdata.comment!=""){
            thiscon.comment.push(commentdata);
        }
        //thiscon.comment.reverse();
        thiscon.save().then(function(newcon){
            resdata.postdata = newcon;
            resdata.message="评论成功!";
            res.json(resdata);
            //console.log(newcon);
        });

    });

});

module.exports=router;

main.js

var express = require("express");
var router= express.Router();
var Category = require("../models/category");
var Content = require("../models/content");

var data;

//处理通用的数据,首页,分类页,每篇文章详情页均需要的变量
router.use(function (req, res, next) {
    data = {
        userInfo: req.userInfo,
        categories: []
    };
    Category.find().then(function(categories) {
        data.categories = categories;
        next();
    });
});

//渲染首页
router.get("/", function(req, res) {
    data.category = req.query.category ||"";
    data.count = 0;
    data.page = Number(req.query.page || 1);
    // 默认两条数据
    data.limit = 2;
    data.pages = 0;
    var where = {};
    if (data.category) {
        where.category = data.category
    }
    Content.where(where).count().then(function(count) {
        data.count = count;
        //计算总页数
        data.pages = Math.ceil(data.count / data.limit);
        //取值不能超过pages
        data.page = Math.min( data.page, data.pages );
        //取值不能小于1
        data.page = Math.max( data.page, 1 );
        var skip = (data.page - 1) * data.limit;
        return Content.where(where).find().limit(data.limit).skip(skip).populate(['category', 'user']).sort({
            addtime:-1
        });
    }).then(function(contents) {
        data.contents = contents;
        //console.log(data);
        res.render('main/index', data);
    })
});
//进入详细阅读部分
router.get("/article",function(req,res){
    var id = req.query.contentid||"";
    Content.findOne({_id:id}).populate(["category","user"]).then(function(content){
        data.contents = content;
        content.num++;
        content.save();
        //console.log(data);
        res.render("main/article_detail",data);
    });
});

module.exports = router;

(五)运行效果

(1)首页

(2)博文详情页面

下篇博文将说明后台管理的设计与实现。

©️2020 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值