背景
个人开发者普遍拥有属于自己的个人博客站点。常见的框架无论是Hexo、Gitbook,亦或是Docsify,这些框架本身并不支持文章阅读量或者站点访问量的功能,需要各种对应的插件支持 目前市面上这些插件基本上是基于busuanzi,LeanCloud实现的,而MemFireDB Cloud[1]旨在提供数据库服务,若后续提供sdk功能,能够实现对应框架的插件供个人开发者使用,并提供相关文章,也能吸引很多个人开发者(因为我本身也是基于使用插件的需要,才在LeanCloud上注册了账户。)
概述
基本上述背景,尝试着基于memfire去实现一个统计gitbook文章访问量的插件
实现
建库建表
登录MemFireDB Cloud
需要在MemFireDB Cloud[2]上注册账户,并创建自己的数据库
进入在线编辑器
点击SQL查询进入在线编辑器
建表
CREATE TABLE counter (
id serial NOT NULL,
url varchar(500),
time int,
title varchar(200),
PRIMARY KEY (id)
)复制
数据库连接
因为目前MemFireDB Cloud[3]还不提供sdk等功能,所以先自己简单写一个中间服务,便于插件访问。
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
_ "github.com/lib/pq"
)
const (
host = "<db ip>"
port = <db port>
user = "<your db user>"
password = "<your db password>"
dbname = "<your db name>"
)
func main() {
r := gin.Default()
r.Use(Cors()) //开启中间件 允许使用跨域请求
r.GET("/counter", GetCount) // 获取文章访问量
r.POST("/counter", AddCount) // 创建文章访问量
r.PUT("/counter", UpdateCount) // 更新文章访问量
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin") //请求头部
if origin != "" {
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
c.Header("Access-Control-Max-Age", "172800")
c.Header("Access-Control-Allow-Credentials", "true")
}
//允许类型校验
if method == "OPTIONS" {
c.JSON(http.StatusOK, "ok!")
}
defer func() {
if err := recover(); err != nil {
log.Printf("Panic info is: %v", err)
}
}()
c.Next()
}
}
func GetCount(c *gin.Context) {
url := c.Query("url")
if url == "" {
url = "#"
}
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
rows, err := db.Query("SELECT time FROM counter WHERE url = $1", url)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var time int
for rows.Next() {
err := rows.Scan(&time)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Row[%d]\n", time)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
defer db.Close()
c.JSON(200, gin.H{
"time":time,
})
return
}
func AddCount(c *gin.Context) {
url := c.PostForm("url")
if url == "" {
url = "#"
}
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
insert := "INSERT INTO counter(url, time) VALUES ("
insert += "'" + url + "', 1)"
fmt.Println("insert statement: ", insert)
if _, err := db.Exec(insert); err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted data: %s\n", insert)
defer db.Close()
return
}
func UpdateCount(c *gin.Context) {
url := c.PostForm("url")
if url == "" {
url = "#"
}
time := c.PostForm("time")
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
update := "UPDATE counter SET time=" + time + " Where url= '" + url + "'"
if _, err := db.Exec(update); err != nil {
log.Fatal(err)
}
fmt.Printf("update data: %s\n", update)
defer db.Close()
return
}复制
构建gitbook插件
仿造其他插件,建立代码仓库
修改book下plugin.js
var gitbook = window.gitbook;
/*
<!-- Start of CuterCounter Code -->
<a href="http://www.cutercounter.com/" target="_blank"><img src="http://www.cutercounter.com/hit.php?id=gmvufxqck&nd=1&style=116" border="0" alt="visitor counter"></a>
<!-- End of CuterCounter Code -->
*/
var iconSVg = '<svg t="1543310294340" \
class="icon" style="" viewBox="0 0 1024 1024" version="1.1" \
xmlns="http://www.w3.org/2000/svg" p-id="1104" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14"><defs><style type="text/css"></style></defs>\
<path d="M512 416a96 96 0 1 0 0 192 96 96 0 0 0 0-192z m511.952 102.064c-0.016-0.448-0.064-0.864-0.096-1.296a8.16 8.16 0 0 0-0.08-0.656c0-0.32-0.064-0.624-0.128-0.928-0.032-0.368-0.064-0.736-0.128-1.088-0.032-0.048-0.032-0.096-0.032-0.144a39.488 39.488 0 0 0-10.704-21.536c-32.672-39.616-71.536-74.88-111.04-107.072-85.088-69.392-182.432-127.424-289.856-150.8-62.112-13.504-124.576-14.064-187.008-2.64-56.784 10.384-111.504 32-162.72 58.784-80.176 41.92-153.392 99.696-217.184 164.48-11.808 11.984-23.552 24.224-34.288 37.248-14.288 17.328-14.288 37.872 0 55.216 32.672 39.616 71.52 74.848 111.04 107.056 85.12 69.392 182.448 127.408 289.888 150.784 62.096 13.504 124.608 14.096 187.008 2.656 56.768-10.4 111.488-32 162.736-58.768 80.176-41.936 153.376-99.696 217.184-164.48 11.792-12 23.536-24.224 34.288-37.248 5.712-5.872 9.456-13.44 10.704-21.568l0.032-0.128a12.592 12.592 0 0 0 0.128-1.088c0.064-0.304 0.096-0.624 0.128-0.928l0.08-0.656 0.096-1.28c0.032-0.656 0.048-1.296 0.048-1.952l-0.096-1.968zM512 704c-106.032 0-192-85.952-192-192s85.952-192 192-192 192 85.968 192 192c0 106.048-85.968 192-192 192z"\
fill="#CCC" p-id="1105"></path></svg>'
require(["gitbook", "jQuery"], function (gitbook, $) {
gitbook.events.bind("page.change", function() {
var bookHeader = $('.book-header')
var lastChild = bookHeader.children().last()
var renderWrapper = $('<div class="page-view-wrapper dropdown pull-left">\
<span class="btn toggle-dropdown">'+ iconSVg + '</span>\
<span class="page-view-counter" title="阅读数">-</span>\
</div>')
if(lastChild.length){
renderWrapper.insertBefore(lastChild)
}else{
bookHeader.append(renderWrapper)
}
var Counter = function (method, url, data) {
return $.ajax({
method: method,
url : `http://127.0.0.1:8080${url}`,
data: data,
});
};
var url = location.href.replace(/^http:\/\/[^/]+/, "").trim();
url = decodeURI(url);
var s = url.split("/").pop();
var title = s.replace(".html", "");
var time = 0;
Counter('get', '/counter', { url: url }).done(function (results ) {
console.log(results)
if (results.time > 0) {
time = results.time+1;
Counter('put', `/counter`, {url: url, time: time }).done(function () {
console.log(time);
renderWrapper.find('.page-view-counter').html(time)
})
} else {
Counter('post', '/counter', { title: title, url: url, time: 1}).done(function ({ results }) {
renderWrapper.find('.page-view-counter').html(1)
})
}
});
})
});复制
仓库地址:https://github.com/TiannV/gitbook-plugin-mf-pageview npm publish发布到npm市场
使用
添加插件
在自己的gitbook仓库的book.json文件添加插件
执行gitbook install即可将应用市场上的插件下载到gitbook项目中 gitboolk build 执行编译
运行数据库连接服务
go run mf.go
启动gitbook
gitbook serve
查看界面:
成功~
代码仓库
TiannV/gitbook-plugin-mf-pageview
References
[1]
MemFireDB Cloud: https://memfiredb.com/
文章转载自奥思立方,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
数据库国产化替代深化:DBA的机遇与挑战
代晓磊
1338次阅读
2025-04-27 16:53:22
2025年4月国产数据库中标情况一览:4个千万元级项目,GaussDB与OceanBase大放异彩!
通讯员
820次阅读
2025-04-30 15:24:06
【活动】分享你的压箱底干货文档,三篇解锁进阶奖励!
墨天轮编辑部
545次阅读
2025-04-17 17:02:24
一页概览:Oracle GoldenGate
甲骨文云技术
512次阅读
2025-04-30 12:17:56
GoldenDB数据库v7.2焕新发布,助力全行业数据库平滑替代
GoldenDB分布式数据库
486次阅读
2025-04-30 12:17:50
优炫数据库成功入围新疆维吾尔自治区行政事业单位数据库2025年框架协议采购!
优炫软件
370次阅读
2025-04-18 10:01:22
给准备学习国产数据库的朋友几点建议
白鳝的洞穴
363次阅读
2025-05-07 10:06:14
XCOPS广州站:从开源自研之争到AI驱动的下一代数据库架构探索
韩锋频道
320次阅读
2025-04-29 10:35:54
MySQL 30 周年庆!MySQL 8.4 认证免费考!这次是认真的。。。
数据库运维之道
309次阅读
2025-04-28 11:01:25
国产数据库图谱又上新|82篇精选内容全览达梦数据库
墨天轮编辑部
293次阅读
2025-04-23 12:04:21