前言
关于个人博客这个项目,从我大学刚毕业的第一份工作开始开始就在筹划了,因为很酷,现在工作也有一段时间了,虽然还是个小菜鸟,但是可以尝试通过博客项目去进行学习,本来是打算从数据库到编辑器后端再到前端都一并完成,但是评估了一下觉得自己实力暂时不够,打算积累一下在制作,恰好某一天突发奇想想到可以借助某个平台的编辑器,然后通过api调用,这样就可以快速搭建,于是找到了语雀。
目标简单分解
1、创建数据库-blog
表user: 存放用户数据-本人数据
表article:存放文章数据
表articlelist: 存放各知识库文章列表数据
表knowledgecatalog: 存放知识库
表comment:存放文章评论数据
2、创建定时任务与手动更新:读取语雀的文章数据,读取blog数据,判断有的更新,没有的新增
3、创建api,前端页面制作
4、上线http://www.xfhhjy.top/#/
起步
通过npm安装egg.jsnpm init egg --type=simplenpm i
egg.js框架目录约定规范
- app/router.js 用于配置URL路由规则
- app/controller/** 用于解析用户输入,处理后返回相应结果
- app/service/** 用于编写业务逻辑层
- app/middleware/** 用于编写中间件
- app/public/** 用于放置静态资源
- app/extend/** 用于框架的扩展
- config/config.{env}.js 用于编写配置文件
- config/plugin.js 用于配置需要加载的插件
- test/ **用于单元测试
- app.js和agent.js用于自定义启动时的初始化工作
- app/schedule/ **用于定时任务
- app/view/ **用于放置模板文件
- app/model/** 用于放置领域模型
- 官方说明>>
创建完成egg.js以后,引入egg-mysql
npm i egg-mysql --save
config/plugin.js 安装插件
config/config.default.js 设置参数const plugin = {mysql : {enable: true,package: 'egg-mysql'}}module.exports = plugin
egg-mysql使用说明-点击跳转>>exports.mysql = {// database configurationclient: {// hosthost: '地址',// portport: '端口',// usernameuser: '',// passwordpassword: '',// databasedatabase: '数据库名称',},// load into app, default is openapp: true,// load into agent, default is closeagent: false,};
app/service 创建yuque.js
```javascript const Service = require(‘egg’).Service;
//存放所有语雀api返回 let knowledgeArr = [] //存放语雀返回的知识库原始数据 let articleListArr = [] //存放经过特殊处理的语雀返回的所有知识库下的次级文章数据 class Yuque extends Service {
async user() {const { app,yqApi } = thisconst data = await yqApi(`/user`)const result = await app.mysql.update('user',{id : 1,name : data.name,login : data.login,avatar_url : data.avatar_url})return `user数据更新成功!`}async knowledgeCatalog(){//更新知识库目录const { app,yqApi } = this/** 1、获取语雀api数据* 2、根据知识库id查询blog数据库表knowledgecatalog数据* 3、如果查询到了,则直接更新,否则执行添加*/const data = await yqApi( `/users/${app.config.yuque.namespaceId}/repos`)for(let item of data){if(item.name.indexOf('博客') !== -1 ){knowledgeArr.push(item)let row = {yuque_library_id : item.id,type : item.type,slug : item.slug,name : item.name,namespace : item.namespace,description : item.description}const query = await app.mysql.get('knowledgecatalog',{ yuque_library_id:item.id })if(!query){//数据新增const add = await app.mysql.insert('knowledgecatalog',row)}else{//数据覆盖更新row.id = query.idconst up = await app.mysql.update('knowledgecatalog',row)}}}return `knowledgeCatalog知识库数据更新成功!`}async articleList(){//先读取知识库,然后根据知识库id去读取知识库下面的文章列表页,并存入数据库const { app,yqApi } = thisconst Arr = []for(let list of knowledgeArr){const data = await yqApi(`/repos/${list.id}/docs`)data.forEach((item) => {Arr.push(item)})}articleListArr = Arrfor(let list of Arr){//循环所有次级文章列表,查询数据库是否有对应数据,如果无,则增加,有则覆盖最新数据let { id,slug,title,description,book_id,custom_description,created_at,updated_at } = listlet row = {yuque_id:id,slug,title,description,book_id,custom_description,created_at,updated_at}const query = await app.mysql.get('articlelist',{ yuque_id:id })if(!query){const add = await app.mysql.insert('articlelist',row)}else{row.id = query.idconst up = await app.mysql.update('articlelist',row)}}return `articleList文章列表数据更新成功!`}async article(){//通过知识库knowledgeArr的namespace与articleListArr的slug获取所有文档const { app,yqApi } = thisconst Arr = []let namespace = (book_id)=>{for(let item of knowledgeArr){if(item.id === book_id){return item.namespace}}}for(let list of articleListArr){const data = await yqApi(`/repos/${namespace(list.book_id)}/docs/${list.slug}`)Arr.push(data)}for(let list of Arr){//循环所有次级文章列表,查询数据库是否有对应数据,如果无,则增加,有则覆盖最新数据let { id,slug,title,book_id,format,body,body_draft,body_html,body_lake,created_at,updated_at } = listlet row = {yuque_id:id,slug,title,book_id,format,body,body_draft,body_html,body_lake,created_at,updated_at}const query = await app.mysql.get('article',{ yuque_id:id })if(!query){const add = await app.mysql.insert('article',row)}else{row.id = query.idconst up = await app.mysql.update('article',row)}}return `文章数据更新成功!`}yqApi = async (url) =>{const { ctx,app,jsonConvert } = thisconst c = await ctx.curl(`${app.config.yuque.baseUrl}${url}`,{headers:app.config.yuque.headers})const data = await jsonConvert(c.data)return data}async jsonConvert(data){//转换buffer数据为json并返回const result = JSON.parse(data.toString())return result.data}
}
module.exports = Yuque
<a name="JP8R4"></a>### app/controller 创建yuqueUpData.js```javascriptconst Controller = require('egg').Controller;class upData extends Controller {async index() {const { ctx } = this;const user = await ctx.service.yuque.user() //更新用户数据const knowledgeCatalog = await ctx.service.yuque.knowledgeCatalog() //更新知识库数据const articleList = await ctx.service.yuque.articleList() //更新文章列表数据const article = await ctx.service.yuque.article() //更新文章列表数据ctx.body = [user,knowledgeCatalog,articleList,article].join(' ');}}module.exports = upData;
app/schedule/UpBlogs.js 创建定时任务
//定时更新语雀数据到blog数据库const Subscription = require('egg').Subscriptionclass UpBlogs extends Subscription {static get schedule(){return {interval : '60m', //60分钟执行一次type: 'all' //指定所有的worker都需要执行}}async subscribe(){const { ctx } = this;const user = await ctx.service.yuque.user() //更新用户数据const knowledgeCatalog = await ctx.service.yuque.knowledgeCatalog() //更新知识库数据const articleList = await ctx.service.yuque.articleList() //更新文章列表数据const article = await ctx.service.yuque.article() //更新文章列表数据console.log([user,knowledgeCatalog,articleList,article].join(' '));}}module.exports = UpBlogs
app/router.js 创建路由手动更新链接
module.exports = app => {const { router, controller } = app;router.get('/yuque_up_data',controller.yuqueUpData.index)};
