1

记个人博客工程从设计到落地(二)

链接:github/meteor
开发期:04/01-04/09

前文简述

前文主要叙述了项目启动的原因与分析过程,以及一些初期的设计和前端功能的落地。

二期内容

二期主要的开发内容是博客管理后台及数据库的环境搭建和逻辑服务,以及前后端的一些联调工作。

需求确认

  • 博客可视化管理
  • 博客展示带类目、标签
  • 提供书签收集功能
  • 提供记录(追剧/书进度、车票记录...)功能

数据库设计

20200410133818.jpg

整体梳理

工程梳理.png

前端路由说明

路由.png

技术选型

在一期的基础上,第二期开发时做了些修改调整,对于技术选型更加明确。

  • 前端 vue+element+front-matter(vue-cli4.2)
  • 后端 node+express/koa
  • 数据库 MongoDB
  • 自动化 python
  • 网络 内网穿透
技术方案
- 前端脚手架 vue-cli4.2
- 前端 vue(vuex/router)+element-ui
- 前端请求 axios
- 前端第三方api跨域 vue-jsonp
- 前端样式预处理语言 less
- 前端markdown编辑器 mavon-editor
- 后端 node+express
- 后端swagger swagger-ui-express+swagger-jsdoc
- 后端日志 express-winston
- 后端跨域 cors
- 后端数据库事务 mongoose
- 数据库 MongoDB
- 图床 PicGo+github
- 网络 内网穿透

项目结构

后端目录

后端目录
- service
    - config    //  配置
    - lib   //  工具
    - logs  //  日志
        - logs.log  //  开发日志
        - error.log //  错误日志
        - success.log   //  成功日志
    - middlewares   //  中间件
        -   checkUser //    检测用户session(未使用)
    - models    //  数据模型
    - public    //  静态资源(未使用)
    - routes    //  路由层 controller
    - swagger   //  swagge插件配置
    - views     //  视图页面(未使用)
    - app.js    //  服务入口

前端目录

前端目录
- src
    - api    //  请求封装
    - assets   //  资源
    - components  //  组件
    - config   //  配置
    - plugin    //  插件
    - router    //  路由
    - store   //  vuex
    - util     //  工具
    - views    //  页面
    - App.vue    //  主视图
    - main.js    //  服务入口
    - registerServiceWorker.js    //  pwa(暂未开发)

入口文件

后端入口

//  引入依赖
var express = require('express');
var path = require('path');
var createError = require('http-errors');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var ejs = require('ejs');
var cors = require('cors');
var http = require('http');
var mongoose = require('mongoose');
var winston = require('winston');
var expressWinston = require('express-winston');

//  引入路由接口
var routers = require('./routes');
//  引入配置文件
const config_default = require('./config/default.js');
//  连接数据库
var db = mongoose.connection;
//  监听是否有异常
db.on('error', function callback() {console.log("**** Connection error")});
//  连接成功
db.on("connected",function () {console.log(`**** 数据库表[${config_default.dbName}]连接成功`)});
//  连接数据库
// mongoose.connect('mongodb://数据库登录用户名:数据库登录密码@数据库连接地址')
mongoose.connect(config_default.mongodb, {
    "useNewUrlParser": true ,   //  地址处理
    "useUnifiedTopology": true  //  解除警告
});
//  定义express应用
var app = express();
//  设置 host&port
app.set('host', config_default.host);
app.set('port', config_default.port);
// 配置模板引擎
app.set('views', path.join(__dirname, 'views'));
app.engine('.html',ejs.__express); //引用ejs引擎
app.set('view engine', 'html');
app.use(logger('dev'));
//  调用中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
//  设置公用资源地址
// app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.resolve(__dirname, './../dist')));
//  支持跨域
app.use(cors());
// 正常请求的日志
app.use(expressWinston.logger({
    transports: [
        new (winston.transports.Console)({
            json: true,
            colorize: true
        }),
        new winston.transports.File({
            filename: path.join(__dirname, './logs/success.log')
        })
    ]
}));
//  装填路由
routers(app);
// 引入swagger
var setSwagger = require ('./swagger');
setSwagger(app);
// 错误请求的日志
app.use(expressWinston.errorLogger({
    transports: [
        new winston.transports.Console({
            json: true,
            colorize: true
        }),
        new winston.transports.File({
            filename: path.join(__dirname, './logs/error.log')
        })
    ]
}));
// catch 404 and forward to error handler
app.use(function(req, res, next) {
    next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
    // set locals, only providing error in development
    res.locals.message = err.message;
    console.log(err.message);
    res.locals.error = req.app.get('env') === 'development' ? err : {};

    // render the error page
    res.status(err.status || 500);
    res.render('error');
});
// Create HTTP server
var server = http.createServer(app);
//  Listen on provided port, on all network interfaces.
server.listen(config_default.port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Event listener for HTTP server "error" event.
 */
function onError(error) {
    if (error.syscall !== 'listen') {
        throw error;
    }

    var bind = typeof port === 'string'
        ? 'Pipe ' + port
        : 'Port ' + port;

    // handle specific listen errors with friendly messages
    switch (error.code) {
        case 'EACCES':
            console.error(bind + ' requires elevated privileges');
            process.exit(1);
            break;
        case 'EADDRINUSE':
            console.error(bind + ' is already in use');
            process.exit(1);
            break;
        default:
            throw error;
    }
}

/**
 * Event listener for HTTP server "listening" event.
 */
function onListening() {
    const hello = require('./config/hello');
    var addr = server.address();
    var bind = typeof addr === 'string'
        ? 'pipe ' + addr
        : 'port ' + addr.port;
    console.log([
        `${hello.ctx}`,
        `${hello.line}`,
        `${config_default.name} | Listening on ${bind}`,
        `${hello.line}`,
    ].join('\n'));

}

前端入口

import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
//  全局引入element-ui
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI)
//  markdown编辑器,样式需单独引入
import mavonEditor from 'mavon-editor'
Vue.use(mavonEditor)
//  markdown md-str转html工具类
Vue.prototype.$markDown = mavonEditor.markdownIt
//  初始化浏览器样式
import "./assets/style/reset.less"
//  全局基本样式
import "./assets/style/common.less"
// 布局组件相关样式
import "./assets/style/layout.less"
import "mavon-editor/dist/css/index.css";
//  跨域请求
import VueJsonp from 'vue-jsonp'
Vue.use(VueJsonp)
//  util工具
import util from './util'
Vue.prototype.$util = util
//  api接口
import api from './api'
Vue.prototype.$api = api
//  配置信息
import conf from './config'
Vue.prototype.$conf = conf


Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#meteor')

整体进度

- 前端
    - 开始页 √
    - 404页
    - Empty组件
    - 博客站点
        - 页首 √
            - 页首搜索功能
        - 页脚 √
            - 协议版权 √
            - 应用信息 √
            - 开发者信息 √
        - 首页 √
            - 悬浮翻转对联 √
            - 动漫-死神-背景 √
            - 像素打印动画 √
        - 博客页 √
            - 博客类目树 √
            - blog查看窗口开发 √
            - blog分享页开发
            - 浏览数 √
            - 无限滚动列表 √
            - 点赞文章
            - 分享链接
            - 快照截图
            - 评论功能
        - 书签页 √
            - 三类书签数据导入 √
            - 首字母快速检索
        - 记录页
            - log-开发日志 √
            - 多媒体(书籍、动漫、影视剧)进度记录 开发
            - 票据(车票)使用记录 开发
        - 个人信息页
        - 加载态
    - 管理平台 √
        - 页首 √
            - 每日一诗 √
        - 页脚 √
            - 音乐播放器
        - 博客管理
            - 标签词云
            - 博客备份文件默认命名(日期_文件名) √
        - 用户管理 √
            - 密码强度检测
            - 随机生成头像
        - 标签管理 √
        - 书签管理 √
        - 类目管理 √
            - 拖拽顶点
            - 排序
        - 导入
        - 导出
    - 其他
        - 多屏端适配(@media)
        - 浏览器兼容(主要适配safari)
        - 引入 element-scroll 滚动条 √
        - 侧边进度条
        - 回到顶部 √
        - 背景粒子动画particles √
        - 地理位置获取 √
        - 当地日出日落时间获取 √
        - 天气获取
    - ...
- 后端
    - user-CRUD √
    - cats-CRUD √
    - tag-CRUD √
    - blog-CRUD √
        - 更新文章同时本地备份md文件 √
        - 根据blog/tags标签生成词云
    - bookmark-CRUD √
    - record/media-CRUD
    - record/ticket-CRUD
    - record/log √
    - 成功/异常日志输出 √
    - 增删改接口session请求校验
- 数据库
    - conf_user √
    - conf_tag √
    - conf_cats √
    - conf_blog √
    - conf_bookmark √
    - conf_ticket
    - conf_media
    - conf_session

截图

swagger
20200410125945.jpg
登录
20200409210017.jpg
开发日志
20200409210146.jpg
管理平台
20200409210220.jpg
博客管理
20200409210708.jpg
博客编辑
20200409210404.jpg

下期计划

  • 接口session认证
  • 内网穿透
  • ...

参考链接


Mulander
527 声望17 粉丝

人生不过一场空,我不灿烂谁灿烂