mirror of https://github.com/mindoc-org/mindoc.git
实现文档缓存
parent
405a9c309f
commit
849058ff8a
|
@ -0,0 +1,46 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/cache"
|
||||
"time"
|
||||
)
|
||||
|
||||
var bm cache.Cache
|
||||
|
||||
func Get(key string) interface{} {
|
||||
|
||||
return bm.Get(key)
|
||||
}
|
||||
|
||||
func GetMulti(keys []string) []interface{} {
|
||||
|
||||
return bm.GetMulti(keys)
|
||||
}
|
||||
|
||||
func Put(key string, val interface{}, timeout time.Duration) error {
|
||||
|
||||
return bm.Put(key, val, timeout)
|
||||
}
|
||||
func Delete(key string) error {
|
||||
return bm.Delete(key)
|
||||
}
|
||||
func Incr(key string) error {
|
||||
return bm.Incr(key)
|
||||
}
|
||||
func Decr(key string) error {
|
||||
return bm.Decr(key)
|
||||
}
|
||||
func IsExist(key string) bool {
|
||||
return bm.IsExist(key)
|
||||
}
|
||||
func ClearAll() error{
|
||||
return bm.ClearAll()
|
||||
}
|
||||
|
||||
func StartAndGC(config string) error {
|
||||
return bm.StartAndGC(config)
|
||||
}
|
||||
//初始化缓存
|
||||
func Init(c cache.Cache) {
|
||||
bm = c
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package cache
|
||||
|
||||
import "time"
|
||||
|
||||
type NullCache struct {
|
||||
|
||||
}
|
||||
|
||||
|
||||
func (bm *NullCache)Get(key string) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bm *NullCache)GetMulti(keys []string) []interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bm *NullCache)Put(key string, val interface{}, timeout time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
func (bm *NullCache)Delete(key string) error {
|
||||
return nil
|
||||
}
|
||||
func (bm *NullCache)Incr(key string) error {
|
||||
return nil
|
||||
}
|
||||
func (bm *NullCache)Decr(key string) error {
|
||||
return nil
|
||||
}
|
||||
func (bm *NullCache)IsExist(key string) bool {
|
||||
return false
|
||||
}
|
||||
func (bm *NullCache)ClearAll() error{
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bm *NullCache)StartAndGC(config string) error {
|
||||
return nil
|
||||
}
|
|
@ -20,10 +20,15 @@ import (
|
|||
"github.com/lifei6671/mindoc/conf"
|
||||
"github.com/lifei6671/mindoc/models"
|
||||
"github.com/lifei6671/mindoc/utils"
|
||||
"github.com/lifei6671/mindoc/cache"
|
||||
beegoCache "github.com/astaxie/beego/cache"
|
||||
_ "github.com/astaxie/beego/cache/memcache"
|
||||
_ "github.com/astaxie/beego/cache/redis"
|
||||
)
|
||||
|
||||
// RegisterDataBase 注册数据库
|
||||
func RegisterDataBase() {
|
||||
beego.Info("正在初始化数据库配置.")
|
||||
adapter := beego.AppConfig.String("db_adapter")
|
||||
|
||||
if adapter == "mysql" {
|
||||
|
@ -37,13 +42,18 @@ func RegisterDataBase() {
|
|||
|
||||
dataSource := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true&loc=%s", username, password, host, port, database, url.QueryEscape(timezone))
|
||||
|
||||
orm.RegisterDataBase("default", "mysql", dataSource)
|
||||
err := orm.RegisterDataBase("default", "mysql", dataSource)
|
||||
if err != nil {
|
||||
beego.Error("注册默认数据库失败:",err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
location, err := time.LoadLocation(timezone)
|
||||
if err == nil {
|
||||
orm.DefaultTimeLoc = location
|
||||
} else {
|
||||
log.Fatalln(err)
|
||||
beego.Error("加载时区配置信息失败,请检查是否存在ZONEINFO环境变量:",err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if adapter == "sqlite3" {
|
||||
database := beego.AppConfig.String("db_database")
|
||||
|
@ -54,8 +64,17 @@ func RegisterDataBase() {
|
|||
dbPath := filepath.Dir(database)
|
||||
os.MkdirAll(dbPath, 0777)
|
||||
|
||||
orm.RegisterDataBase("default", "sqlite3", database)
|
||||
err := orm.RegisterDataBase("default", "sqlite3", database)
|
||||
|
||||
if err != nil {
|
||||
beego.Error("注册默认数据库失败:",err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}else{
|
||||
beego.Error("不支持的数据库类型.")
|
||||
os.Exit(1)
|
||||
}
|
||||
beego.Info("数据库初始化完成.")
|
||||
}
|
||||
|
||||
// RegisterModel 注册Model
|
||||
|
@ -120,7 +139,7 @@ func RegisterCommand() {
|
|||
migrate.RunMigration()
|
||||
}
|
||||
}
|
||||
|
||||
//注册模板函数
|
||||
func RegisterFunction() {
|
||||
beego.AddFuncMap("config", models.GetOptionValue)
|
||||
|
||||
|
@ -179,6 +198,7 @@ func RegisterFunction() {
|
|||
})
|
||||
}
|
||||
|
||||
//解析命令
|
||||
func ResolveCommand(args []string) {
|
||||
flagSet := flag.NewFlagSet("MinDoc command: ", flag.ExitOnError)
|
||||
flagSet.StringVar(&conf.ConfigurationFile, "config", "", "MinDoc configuration file.")
|
||||
|
@ -226,10 +246,95 @@ func ResolveCommand(args []string) {
|
|||
gocaptcha.ReadFonts(filepath.Join(conf.WorkingDirectory, "static", "fonts"), ".ttf")
|
||||
|
||||
RegisterDataBase()
|
||||
RegisterCache()
|
||||
RegisterModel()
|
||||
RegisterLogger(conf.LogFile)
|
||||
}
|
||||
|
||||
//注册缓存管道
|
||||
func RegisterCache() {
|
||||
isOpenCache := beego.AppConfig.DefaultBool("cache",false)
|
||||
if !isOpenCache {
|
||||
cache.Init(&cache.NullCache{})
|
||||
}
|
||||
beego.Info("正常初始化缓存配置.")
|
||||
cacheProvider := beego.AppConfig.String("cache_provider")
|
||||
if cacheProvider == "file" {
|
||||
cacheFilePath := beego.AppConfig.DefaultString("cache_file_path","./runtime/")
|
||||
if strings.HasPrefix(cacheFilePath, "./") {
|
||||
cacheFilePath = filepath.Join(conf.WorkingDirectory, string(cacheFilePath[1:]))
|
||||
}
|
||||
fileCache := beegoCache.NewFileCache()
|
||||
beegoCache.FileCachePath = cacheFilePath
|
||||
beegoCache.FileCacheDirectoryLevel = beego.AppConfig.DefaultInt("cache_file_dir_level",2)
|
||||
beegoCache.FileCacheEmbedExpiry = time.Duration(beego.AppConfig.DefaultInt64("cache_file_expiry",120))
|
||||
beegoCache.FileCacheFileSuffix = beego.AppConfig.DefaultString("cache_file_suffix",".bin")
|
||||
fileCache.StartAndGC("")
|
||||
|
||||
cache.Init(fileCache)
|
||||
}else if cacheProvider == "memory" {
|
||||
cacheInterval := beego.AppConfig.DefaultInt("cache_memory_interval",60)
|
||||
memory := beegoCache.NewMemoryCache()
|
||||
beegoCache.DefaultEvery = cacheInterval
|
||||
cache.Init(memory)
|
||||
}else if cacheProvider == "redis"{
|
||||
var redisConfig struct{
|
||||
Conn string `json:"conn"`
|
||||
Password string `json:"password"`
|
||||
DbNum int `json:"dbNum"`
|
||||
}
|
||||
redisConfig.DbNum = 0
|
||||
redisConfig.Conn = beego.AppConfig.DefaultString("cache_redis_host","")
|
||||
if pwd := beego.AppConfig.DefaultString("cache_redis_password","");pwd != "" {
|
||||
redisConfig.Password = pwd
|
||||
}
|
||||
if dbNum := beego.AppConfig.DefaultInt("cache_redis_db",0); dbNum > 0 {
|
||||
redisConfig.DbNum = dbNum
|
||||
}
|
||||
|
||||
bc,err := json.Marshal(&redisConfig)
|
||||
if err != nil {
|
||||
beego.Error("初始化Redis缓存失败:",err)
|
||||
os.Exit(1)
|
||||
}
|
||||
beego.Info(string(bc))
|
||||
redisCache,err := beegoCache.NewCache("redis",string(bc))
|
||||
|
||||
if err != nil {
|
||||
beego.Error("初始化Redis缓存失败:",err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cache.Init(redisCache)
|
||||
}else if cacheProvider == "memcache" {
|
||||
|
||||
var memcacheConfig struct{
|
||||
Conn string `json:"conn"`
|
||||
}
|
||||
memcacheConfig.Conn = beego.AppConfig.DefaultString("cache_memcache_host","")
|
||||
|
||||
bc,err := json.Marshal(&memcacheConfig)
|
||||
if err != nil {
|
||||
beego.Error("初始化Redis缓存失败:",err)
|
||||
os.Exit(1)
|
||||
}
|
||||
memcache,err := beegoCache.NewCache("memcache",string(bc))
|
||||
|
||||
if err != nil {
|
||||
beego.Error("初始化Memcache缓存失败:",err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cache.Init(memcache)
|
||||
|
||||
}else {
|
||||
cache.Init(&cache.NullCache{})
|
||||
beego.Warn("不支持的缓存管道,缓存将禁用.")
|
||||
return
|
||||
}
|
||||
beego.Info("缓存初始化完成.")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
if configPath ,err := filepath.Abs(conf.ConfigurationFile); err == nil {
|
||||
|
|
|
@ -105,7 +105,29 @@ ldap_user_role=2
|
|||
ldap_filter=objectClass=posixAccount
|
||||
|
||||
|
||||
|
||||
######################缓存配置###############################
|
||||
#是否开启缓存,true 开启/false 不开启
|
||||
cache=false
|
||||
#缓存方式:memory/memcache/redis/file
|
||||
cache_provider=memory
|
||||
#当配置缓存方式为memory时,内存回收时间,单位是秒
|
||||
cache_memory_interval=120
|
||||
#当缓存方式配置为file时,缓存的储存目录
|
||||
cache_file_path=./runtime/
|
||||
#缓存文件后缀
|
||||
cache_file_suffix=
|
||||
#文件缓存目录层级
|
||||
cache_file_dir_level=2
|
||||
#文件缓存的默认过期时间
|
||||
cache_file_expiry=3600
|
||||
#memcache缓存服务器地址
|
||||
cache_memcache_host=127.0.0.1:11211
|
||||
#redis服务器地址
|
||||
cache_redis_host=127.0.0.1:6379
|
||||
#redis数据库索引
|
||||
cache_redis_db=0
|
||||
#redis服务器密码
|
||||
cache_redis_password=
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -834,23 +834,23 @@ func (c *DocumentController) Content() {
|
|||
|
||||
c.JsonResult(0, "ok", doc)
|
||||
}
|
||||
|
||||
func (c *DocumentController) GetDocumentById(id string) (doc *models.Document, err error) {
|
||||
doc = models.NewDocument()
|
||||
if doc_id, err := strconv.Atoi(id); err == nil {
|
||||
doc, err = doc.Find(doc_id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
doc, err = doc.FindByFieldFirst("identify", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return doc, nil
|
||||
}
|
||||
//
|
||||
//func (c *DocumentController) GetDocumentById(id string) (doc *models.Document, err error) {
|
||||
// doc = models.NewDocument()
|
||||
// if doc_id, err := strconv.Atoi(id); err == nil {
|
||||
// doc, err = doc.Find(doc_id)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// } else {
|
||||
// doc, err = doc.FindByFieldFirst("identify", id)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return doc, nil
|
||||
//}
|
||||
|
||||
// 导出
|
||||
func (c *DocumentController) Export() {
|
||||
|
|
|
@ -2,7 +2,6 @@ package models
|
|||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/astaxie/beego"
|
||||
|
@ -13,6 +12,9 @@ import (
|
|||
"path/filepath"
|
||||
"strconv"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/lifei6671/mindoc/cache"
|
||||
"encoding/json"
|
||||
"qiniupkg.com/x/errors.v7"
|
||||
)
|
||||
|
||||
// Document struct.
|
||||
|
@ -63,6 +65,9 @@ func (m *Document) Find(id int) (*Document, error) {
|
|||
if id <= 0 {
|
||||
return m, ErrInvalidParameter
|
||||
}
|
||||
if m,err := m.FromCacheById(id); err == nil {
|
||||
return m,nil
|
||||
}
|
||||
o := orm.NewOrm()
|
||||
|
||||
err := o.QueryTable(m.TableNameWithPrefix()).Filter("document_id", id).One(m)
|
||||
|
@ -70,55 +75,85 @@ func (m *Document) Find(id int) (*Document, error) {
|
|||
if err == orm.ErrNoRows {
|
||||
return m, ErrDataNotExist
|
||||
}
|
||||
m.PutToCache()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
//插入和更新文档.
|
||||
func (m *Document) InsertOrUpdate(cols ...string) error {
|
||||
o := orm.NewOrm()
|
||||
|
||||
var err error
|
||||
if m.DocumentId > 0 {
|
||||
_, err := o.Update(m)
|
||||
return err
|
||||
_, err = o.Update(m)
|
||||
} else {
|
||||
_, err := o.Insert(m)
|
||||
_, err = o.Insert(m)
|
||||
NewBook().ResetDocumentNumber(m.BookId)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.PutToCache()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//根据指定字段查询一条文档.
|
||||
func (m *Document) FindByFieldFirst(field string, v interface{}) (*Document, error) {
|
||||
|
||||
if field == "identify" {
|
||||
if identify,ok := v.(string);ok {
|
||||
if m,err := m.FromCacheByIdentify(identify);err == nil{
|
||||
return m,nil
|
||||
}
|
||||
}
|
||||
}else if field == "document_id" {
|
||||
if id,ok := v.(int); ok && id > 0 {
|
||||
if m,err := m.FromCacheById(id);err == nil{
|
||||
return m,nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
o := orm.NewOrm()
|
||||
|
||||
err := o.QueryTable(m.TableNameWithPrefix()).Filter(field, v).One(m)
|
||||
|
||||
if err == nil {
|
||||
m.PutToCache()
|
||||
}
|
||||
|
||||
return m, err
|
||||
}
|
||||
|
||||
//递归删除一个文档.
|
||||
func (m *Document) RecursiveDocument(doc_id int) error {
|
||||
func (m *Document) RecursiveDocument(docId int) error {
|
||||
|
||||
o := orm.NewOrm()
|
||||
|
||||
if doc, err := m.Find(doc_id); err == nil {
|
||||
if doc, err := m.Find(docId); err == nil {
|
||||
o.Delete(doc)
|
||||
NewDocumentHistory().Clear(doc.DocumentId)
|
||||
}
|
||||
//
|
||||
//var docs []*Document
|
||||
//
|
||||
//_, err := o.QueryTable(m.TableNameWithPrefix()).Filter("parent_id", doc_id).All(&docs)
|
||||
|
||||
var docs []*Document
|
||||
|
||||
_, err := o.QueryTable(m.TableNameWithPrefix()).Filter("parent_id", doc_id).All(&docs)
|
||||
var maps []orm.Params
|
||||
|
||||
_, err := o.Raw("SELECT document_id FROM " + m.TableNameWithPrefix() + " WHERE parent_id=" + strconv.Itoa(docId)).Values(&maps)
|
||||
if err != nil {
|
||||
beego.Error("RecursiveDocument => ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, item := range docs {
|
||||
doc_id := item.DocumentId
|
||||
o.QueryTable(m.TableNameWithPrefix()).Filter("document_id", doc_id).Delete()
|
||||
m.RecursiveDocument(doc_id)
|
||||
for _, item := range maps {
|
||||
if docId,ok := item["document_id"].(string); ok{
|
||||
id,_ := strconv.Atoi(docId)
|
||||
o.QueryTable(m.TableNameWithPrefix()).Filter("document_id", id).Delete()
|
||||
m.RecursiveDocument(id)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -178,16 +213,54 @@ func (m *Document) ReleaseContent(bookId int) {
|
|||
if err != nil {
|
||||
beego.Error(fmt.Sprintf("发布失败 => %+v", item), err)
|
||||
}else {
|
||||
//当文档发布后,需要清除已缓存的转换文档和文档缓存
|
||||
item.PutToCache()
|
||||
os.RemoveAll(filepath.Join(conf.WorkingDirectory,"uploads","books",strconv.Itoa(bookId)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//将文档写入缓存
|
||||
func (m *Document) PutToCache(){
|
||||
if v,err := json.Marshal(m);err == nil {
|
||||
if m.Identify == "" {
|
||||
if err := cache.Put("Document.Id."+strconv.Itoa(m.DocumentId), v, time.Second*3600); err != nil {
|
||||
beego.Info("文档缓存失败:", m)
|
||||
}
|
||||
}else{
|
||||
if err := cache.Put("Document.Identify."+ m.Identify, v, time.Second*3600); err != nil {
|
||||
beego.Info("文档缓存失败:", m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//从缓存获取
|
||||
func (m *Document) FromCacheById(id int) (*Document,error) {
|
||||
b := cache.Get("Document.Id." + strconv.Itoa(id))
|
||||
if v,ok := b.([]byte); ok {
|
||||
beego.Info("从缓存中获取文档信息成功")
|
||||
if err := json.Unmarshal(v,m);err == nil{
|
||||
return m,nil
|
||||
}
|
||||
}
|
||||
return nil,errors.New("Cache not exists")
|
||||
}
|
||||
func (m *Document) FromCacheByIdentify(identify string) (*Document,error) {
|
||||
b := cache.Get("Document.Identify." + identify)
|
||||
if v,ok := b.([]byte); ok {
|
||||
beego.Info("从缓存中获取文档信息成功")
|
||||
if err := json.Unmarshal(v,m);err == nil{
|
||||
return m,nil
|
||||
}
|
||||
}
|
||||
return nil,errors.New("Cache not exists")
|
||||
}
|
||||
|
||||
//根据项目ID查询文档列表.
|
||||
func (m *Document) FindListByBookId(book_id int) (docs []*Document, err error) {
|
||||
func (m *Document) FindListByBookId(bookId int) (docs []*Document, err error) {
|
||||
o := orm.NewOrm()
|
||||
|
||||
_, err = o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).OrderBy("order_sort").All(&docs)
|
||||
_, err = o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", bookId).OrderBy("order_sort").All(&docs)
|
||||
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue