前言

自己的这个博客从开始搭建上线已有两年多的时间了,博客主要采用Vue.js+MongoDB+Node.js的技术,由于自己开始也是从摸索中前行,一步一个坑踩过来的,才有了这个简单的博客系统。但是时间长了,难免会有些遗忘,所以趁当下肺炎疫情的非常时期,静下心来认真梳理一下整个开发的过程,一方面温故而知新,另一方面也为抗击肺炎做贡献。

项目目录结构

1.png

Config

2.png

使用vue-cli模板构建的vue项目都会有这些文件,属于webpack相关配置;

dev.env.js文件是开发环境的变量,npm run dev命令;在build文件下webpack.dev.conf可找到在什么地方引入了此变量;

prod.env.js文件是生产环境的变量,npm run build命令;在build文件下webpack.prod.conf可找到在什么地方引入了此变量;

index.js文件中可以配置代理地址,已解决跨域的问题,具体的配置如下:

3.png

举例:localhost:8080/api/xxx 代理到 http://localhost:9000/api/xxx,如果用pathRewrite重写则代理到http://localhost:9000/xxx
  将'/api'转为'/'
  proxyTable: {
      '/api': {// '/api':匹配项
        target: 'http://localhost:9000',// 接口的域名
        // secure: false,// 如果是https接口,需要配置这个参数
        changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
     // pathRewrite: {// 如果接口本身没有/api需要通过pathRewrite来重写了地址
     //   '^api': ''
        // }
      }
    }

models和schemas

  

models实体类,schemas对应MongoDB中的表结构,以article.js为例:

//schemas
var mongoose = require('../server/db.js')
var ArticleSchema = new mongoose.Schema({
  title:String,
  summary:String,
  content:String,
  imgUrl:String,
  isDel:{
    type:Boolean,
    default:false
  },
  createDate:{
    type:Date,
    default:Date.now()
  },
  updateDate:{
    type:Date,
    default:Date.now()
  },
  comments:{ // 评论次数
    type:Number,
    default:0
  },
  views:{ // 浏览次数
    type:Number,
    default:0
  },
  up:{ // 推荐次数
    type:Number,
    default:0
  },
  down:{ // 反对次数
    type:Number,
    default:0
  },
  categoryId:String // 所属类别 c1,c2,...
},{
  collection:'article'
})
module.exports = ArticleSchema
//models
var mongoose = require('../server/db')
var ArticleSchema = require('../schemas/article')
var Article = mongoose.model('Article',ArticleSchema)
module.exports = Article

server

5.png

db.js:使用node.js访问MongoDB的接口文件;

api.js:服务接口文件。

// db.js
const mongoose = require('mongoose');
// 连接数据库 如果不自己创建 默认MyBlog数据库会自动生成
// node.js访问MongoDB,需引入mongoose中间件
var db_url = 'mongodb://localhost:27017/Blog'
mongoose.connect(db_url);
module.exports = mongoose
/**
 * Created by dupeng on 2017/10/23.
 * 编写数据访问层接口
 */
var http = require("http");
var https = require("https");
var User = require('../models/user');
var Article = require('../models/article');
var Category = require('../models/category');
var Comment = require('../models/comments');
var ViewerInfo = require('../models/viewerinfo');
var express = require('express');
var multer=require('multer');
var router = express.Router();
var fs = require('fs');
var path = require('path');
var upload = multer();
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var responseData;
router.use(function (req, res, next) {
  responseData = {
    code:0,
    message:''
  };
  next()
});
// 上传文件
router.post('upload',upload.single('upfile'),function (req,res,next) {
  console.log(req.file);
  console.log(req.file[0]);
  var fix = req.file.originalname.substring(req.file.originalname.lastIndexOf('.'));
  var filename = new Date().getTime();
  var filepath = path.join(__dirname,'./static/fileroot/',filename + fix);
  console.log(filepath);
  fs.writeFile(filepath,req.file.buffer,function (err) {
    responseData.code = 200
    responseData.message = '上传成功'
    responseData.data = "fileroot/"+filename+fix
    res.json(responseData)
  })
});
// 条件查询文章列表
router.route('/findArticlesBy').get((req,res)=>{
  var _title = req.query.title;
  var query = {}
  if(_title){
    query['title'] = new RegExp(_title,'i') // NodeJs中,必须使用正则实现模糊查询
  }
  Article.find(query,function (err,docs) {
    if(err){
      res.send(err);
      return
    }
    responseData.code = 200;
    responseData.message = '根据标题查询文章列表'
    responseData.data = docs;
    res.json(responseData)
  }).where({isDel:false}).sort({'createDate':-1})
});
// 添加文章
router.route('/admin/saveArticle').post((req,res)=>{
  let info = req.body.articleInformation
  Article.find({_id:info._id},function (err, docs) {
    if(err){
      res.send(err)
      return
    }
    Article(info).save(function (err) {
      if(err){
        res.status(500).send()
        return
      }
      responseData.code = 200
      responseData.message = '添加成功'
      res.json(responseData)
    })
  })
});
// 删除文章
router.route('/admin/removeArticle').post((req,res)=>{
  var _id = req.query._id
  Article.update({_id:_id},{$set:{isDel:true}},function (err) {
    if(err){
      res.status(500).send()
      return
    }
    responseData.code = 200
    responseData.message = '删除成功'
    res.json(responseData)
  })
});
// 编辑文章信息
router.route('/admin/updateArticle').post((req,res)=>{
  var info = req.body.articleInformation
  var where = {_id:info._id}
  var updates = {
    title:info.title,
    summary:info.summary,
    content:info.content,
    imgUrl:info.imgUrl,
    updateDate:Date.now(),
    categoryId:info.categoryId
  }
  Article.update(where,updates,function (err) {
    if(err){
      res.status(500).send()
      return
    }
    responseData.code = 200
    responseData.message = '修改成功'
    res.json(responseData)
  })
});
// 按条件查询文章类别列表
router.route('/admin/findCategoryBy').get((req,res)=>{
  var _name = req.query.name
  var query = {}
  if(_name){
    query['categoryname'] = new RegExp(_name,'i')
  }
  Category.find(query,function (err, docs) {
    if(err){
      res.send(err)
      return
    }
    responseData.code = 200
    responseData.message = '查询文章类别列表'
    responseData.data = docs
    res.json(responseData)
  }).where({isDel:false})
});
/**
 *  定义分页数据对象
 * */
var pageData = {
  pageIndex:1,
  pageSize:20,
  total:0,
  pageCount:function () {
    return Math.ceil(this.total/this.pageSize)
  },
  data:[]
};
// 分页查询文章列表
router.route('/admin/getArticlePageList').post((req,res)=>{
  var pageModel = req.body.criteriaObj;
  pageData.pageIndex = pageModel.pageIndex || 1; //页码
  pageData.pageSize = pageModel.pageSize || pageData.pageSize; //每页显示多少条
  var skipCount = parseInt((pageData.pageIndex-1)*pageData.pageSize);
  var takeCount = parseInt(pageData.pageSize);
  var _title = pageModel.searchKey; //查询条件
  var _categoryId = pageModel.categoryId;
  var query = {};
  var where = {};
  if(_title){
    query['title'] = new RegExp(_title,'i') // NodeJs中,必须使用正则实现模糊查询
  }
  if(_categoryId){
    where = {categoryId:_categoryId,isDel:false}
  }else{
    where = {isDel:false}
  }
  Article.where(query).count(function (err,count) {
    if(err){
      res.send(err);
      return
    }
    pageData.total = count;
    Article.find(query,function (err, docs) {
      if(err){
        res.send(err);
        return
      }
      pageData.data = docs;
      res.json(pageData)
    }).where(where)
      .sort({'createDate':-1})
      .skip(skipCount)
      .limit(takeCount)
  }).where(where);
});
app.use("/static/",express.static(__dirname+"/static/"));
app.use('/api',router);
app.use('/index',function (req,res,next) {
  res.sendFile(__dirname+"/index.html");
});
app.use('/',function (req,res,next) {
  res.sendFile(__dirname+"/index.html");
});
var server = http.createServer(app);
// 后端服务启动的端口,与前端的端口不同,
// 这里需要在config/index.js中配置相应的代理
server.listen(9000);
// https.createServer(options,app).listen(443,function () {
//   console.log('https')
// })

src

7.png

assets:静态文件(css\image\js等);
components:vue.js自定义组件;
router:路由,与mvc中类似功能;
store:vuex为vue.js专门设计的集中式状态管理架构,后续再详细介绍;
utils:自定义的一些公共方法
views:视图文件;
App.vue:是我们的主组件,所有页面都是在App.vue下进行切换的。其实也可以理解为所有的路由也是App.vue的子组件
main.js:是我们的入口文件,主要作用是初始化vue实例,并引入所需要的插件;
index.html:项目运行得入口文件。

总结

最后借用网友的一张图来总结vue项目的结构

8.png

作者: 一蓑烟雨

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类: Vue.js
posted 阅读(18 ) 评论(0 )

评论内容: