diff --git a/cache/cache.go b/cache/cache.go index 968a8932..a0e6fed4 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -3,24 +3,56 @@ package cache import ( "github.com/astaxie/beego/cache" "time" + "encoding/gob" + "fmt" + "bytes" + "errors" + "github.com/astaxie/beego" ) var bm cache.Cache -func Get(key string) interface{} { +func Get(key string,e interface{}) error { - return bm.Get(key) + val := bm.Get(key) + + if val == nil { + return errors.New("cache does not exist") + } + if b,ok := val.([]byte); ok { + buf := bytes.NewBuffer(b) + + decoder := gob.NewDecoder(buf) + + err := decoder.Decode(e) + + if err != nil { + fmt.Println("反序列化对象失败 ->", err) + } + return err + } + return errors.New("value is not []byte") } 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) + var buf bytes.Buffer + + encoder := gob.NewEncoder(&buf) + + err := encoder.Encode(val) + if err != nil { + beego.Error("序列化对象失败 ->",err) + return err + } + + return bm.Put(key, buf.String(), timeout) } + func Delete(key string) error { return bm.Delete(key) } diff --git a/commands/command.go b/commands/command.go index fb699997..c5d67a29 100644 --- a/commands/command.go +++ b/commands/command.go @@ -24,6 +24,7 @@ import ( "github.com/lifei6671/mindoc/conf" "github.com/lifei6671/mindoc/models" "github.com/lifei6671/mindoc/utils/filetil" + "github.com/astaxie/beego/cache/redis" ) // RegisterDataBase 注册数据库 @@ -91,6 +92,8 @@ func RegisterModel() { new(models.Label), new(models.Blog), ) + gob.Register(models.Blog{}) + gob.Register(models.Document{}) //migrate.RegisterMigration() } @@ -100,28 +103,69 @@ func RegisterLogger(log string) { logs.SetLogFuncCall(true) logs.SetLogger("console") logs.EnableFuncCallDepth(true) - logs.Async() + + if beego.AppConfig.DefaultBool("log_is_async", true) { + logs.Async(1e3) + } + if log == "" { + log = conf.WorkingDir("runtime","logs") + } logPath := filepath.Join(log, "log.log") - if _, err := os.Stat(logPath); os.IsNotExist(err) { - + if _, err := os.Stat(log); os.IsNotExist(err) { os.MkdirAll(log, 0777) - - if f, err := os.Create(logPath); err == nil { - f.Close() - config := make(map[string]interface{}, 1) - - config["filename"] = logPath - - b, _ := json.Marshal(config) - - beego.SetLogger("file", string(b)) - } } + config := make(map[string]interface{}, 1) + + config["filename"] = logPath + config["perm"] = "0755" + config["rotate"] = true + + if maxLines := beego.AppConfig.DefaultInt("log_maxlines", 1000000); maxLines > 0 { + config["maxLines"] = maxLines + } + if maxSize := beego.AppConfig.DefaultInt("log_maxsize", 1<<28); maxSize > 0 { + config["maxsize"] = maxSize + } + if !beego.AppConfig.DefaultBool("log_daily", true) { + config["daily"] = false + } + if maxDays := beego.AppConfig.DefaultInt("log_maxdays", 7); maxDays > 0 { + config["maxdays"] = maxDays + } + if level := beego.AppConfig.DefaultString("log_level", "Trace"); level != "" { + switch level { + case "Emergency": + config["level"] = beego.LevelEmergency;break + case "Alert": + config["level"] = beego.LevelAlert;break + case "Critical": + config["level"] = beego.LevelCritical;break + case "Error": + config["level"] = beego.LevelError; break + case "Warning": + config["level"] = beego.LevelWarning; break + case "Notice": + config["level"] = beego.LevelNotice; break + case "Informational": + config["level"] = beego.LevelInformational;break + case "Debug": + config["level"] = beego.LevelDebug;break + } + } + b, err := json.Marshal(config); + if err != nil { + beego.Error("初始化文件日志时出错 ->",err) + beego.SetLogger("file", `{"filename":"`+ logPath + `"}`) + }else{ + beego.SetLogger(logs.AdapterFile, string(b)) + } + + + beego.SetLogFuncCall(true) - beego.BeeLogger.Async() } // RunCommand 注册orm命令行工具 @@ -270,6 +314,10 @@ func RegisterCache() { beegoCache.DefaultEvery = cacheInterval cache.Init(memory) } else if cacheProvider == "redis" { + //设置Redis前缀 + if key := beego.AppConfig.DefaultString("cache_redis_prefix",""); key != "" { + redis.DefaultKey = key + } var redisConfig struct { Conn string `json:"conn"` Password string `json:"password"` @@ -320,7 +368,7 @@ func RegisterCache() { } else { cache.Init(&cache.NullCache{}) - beego.Warn("不支持的缓存管道,缓存将禁用.") + beego.Warn("不支持的缓存管道,缓存将禁用 ->" ,cacheProvider) return } beego.Info("缓存初始化完成.") diff --git a/conf/app.conf.example b/conf/app.conf.example index 1113b0ff..6a16b7db 100644 --- a/conf/app.conf.example +++ b/conf/app.conf.example @@ -26,6 +26,8 @@ sessionproviderconfig=./runtime/session #时区设置 timezone = Asia/Shanghai + + ####################MySQL 数据库配置########################### #支持MySQL和sqlite3两种数据库,如果是sqlite3 则 db_database 标识数据库的物理目录 db_adapter=mysql @@ -87,12 +89,6 @@ export_queue_limit_num=100 #导出项目的缓存目录配置 export_output_path=./runtime/cache -###############配置CDN加速################## -cdn= -cdnjs= -cdncss= -cdnimg= - ################百度地图密钥################# baidumapkey= @@ -116,35 +112,73 @@ ldap_user_role=2 #ldap搜索filter规则,AD服务器: objectClass=User, openldap服务器: objectClass=posixAccount ,也可以定义为其他属性,如: title=mindoc ldap_filter=objectClass=posixAccount +###############配置CDN加速################## +cdn= +cdnjs= +cdncss= +cdnimg= ######################缓存配置############################### + #是否开启缓存,true 开启/false 不开启 cache=false + #缓存方式:memory/memcache/redis/file cache_provider=memory + #当配置缓存方式为memory时,内存回收时间,单位是秒 cache_memory_interval=120 + #当缓存方式配置为file时,缓存的储存目录 cache_file_path=./runtime/cache/ + #缓存文件后缀 cache_file_suffix=.bin + #文件缓存目录层级 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= - - - - +#缓存键的前缀 +cache_redis_prefix=mindoc::cache + + +#########日志储存配置############## + +#日志保存路径,在linux上,自动创建的日志文件请不要删除,否则将无法写入日志 +log_path=./runtime/logs + +#每个文件保存的最大行数,默认值 1000000 +log_maxlines=1000000 + +# 每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB +log_maxsize= + +# 是否按照每天 logrotate,默认是 true +log_daily=true + +# 文件最多保存多少天,默认保存 7 天 +log_maxdays=30 + +# 日志保存的时候的级别,默认是 Trace 级别,可选值: Emergency/Alert/Critical/Error/Warning/Notice/Informational/Debug/Trace +log_level=Trace + +# 是否异步生成日志,默认是 true +log_is_async=true diff --git a/controllers/BlogController.go b/controllers/BlogController.go index 1a01ed2f..5b3cb7b7 100644 --- a/controllers/BlogController.go +++ b/controllers/BlogController.go @@ -15,6 +15,7 @@ import ( "github.com/astaxie/beego/orm" "html/template" "encoding/json" + "github.com/lifei6671/mindoc/utils" ) type BlogController struct{ @@ -58,6 +59,13 @@ func (c *BlogController) Index() { c.Data["Model"] = blog c.Data["Content"] = template.HTML(blog.BlogRelease) + if blog.BlogExcerpt == "" { + c.Data["Description"] = utils.AutoSummary(blog.BlogRelease,120) + }else{ + c.Data["Description"] = blog.BlogExcerpt + } + + if nextBlog,err := models.NewBlog().QueryNext(blogId);err == nil { c.Data["Next"] = nextBlog } @@ -86,6 +94,10 @@ func (c *BlogController) List() { pager := pagination.NewPagination(c.Ctx.Request, totalCount, conf.PageSize, c.BaseUrl()) c.Data["PageHtml"] = pager.HtmlPages() for _,blog := range blogList { + //如果没有添加文章摘要,则自动提取 + if blog.BlogExcerpt == "" { + blog.BlogExcerpt = utils.AutoSummary(blog.BlogRelease,120) + } blog.Link() } } else { diff --git a/controllers/DocumentController.go b/controllers/DocumentController.go index 3e40dd01..2ca3b637 100644 --- a/controllers/DocumentController.go +++ b/controllers/DocumentController.go @@ -70,6 +70,7 @@ func (c *DocumentController) Index() { c.Data["Title"] = doc.DocumentName c.Data["Content"] = template.HTML(doc.Release) + c.Data["Description"] = utils.AutoSummary(doc.Release,120) } }else { c.Data["Title"] = "概要" @@ -208,6 +209,10 @@ func (c *DocumentController) Read() { c.Abort("500") } + + c.Data["Description"] = utils.AutoSummary(doc.Release,120) + + c.Data["Model"] = bookResult c.Data["Result"] = template.HTML(tree) c.Data["Title"] = doc.DocumentName diff --git a/converter/converter.go b/converter/converter.go index 65299521..b4d32dc4 100644 --- a/converter/converter.go +++ b/converter/converter.go @@ -510,8 +510,6 @@ func (this *Converter) convertToMobi() (err error) { args := []string{ filepath.Join(this.OutputPath, "content.epub"), filepath.Join(this.OutputPath, output, "book.mobi"), - "--debug-pipeline", - "--verbose", } cmd := exec.Command(ebookConvert, args...) if this.Debug { @@ -526,8 +524,6 @@ func (this *Converter) convertToPdf() (err error) { args := []string{ filepath.Join(this.OutputPath, "content.epub"), filepath.Join(this.OutputPath, output, "book.pdf"), - "--debug-pipeline", - "--verbose", } //页面大小 if len(this.Config.PaperSize) > 0 { @@ -579,8 +575,6 @@ func (this *Converter) convertToDocx() (err error) { args := []string{ filepath.Join(this.OutputPath , "content.epub"), filepath.Join(this.OutputPath , output , "book.docx"), - "--debug-pipeline", - "--verbose", } args = append(args, "--docx-no-toc") diff --git a/models/Blog.go b/models/Blog.go index 3b9fbf5e..93f3ff10 100644 --- a/models/Blog.go +++ b/models/Blog.go @@ -103,18 +103,18 @@ func (b *Blog) Find(blogId int) (*Blog,error) { //从缓存中读取文章 func (b *Blog) FindFromCache(blogId int) (blog *Blog,err error) { key := fmt.Sprintf("blog-id-%d",blogId); - obj := cache.Get(key) - - if b,ok := obj.(Blog); ok { - blog = &b - blog.Link() + var temp Blog + if err := cache.Get(key,&temp); err == nil { + b = &temp + b.Link() beego.Info("从缓存读取文章成功 ->", key) - return + return b,nil } + blog,err = b.Find(blogId) if err == nil { //默认一个小时 - if err := cache.Put(key,*blog,time.Hour * 1); err != nil { + if err := cache.Put(key,blog,time.Hour * 1); err != nil { beego.Error("将文章存入缓存失败 ->",err) } } @@ -219,7 +219,7 @@ func (b *Blog) Save(cols ...string) error { if b.BlogId > 0 { b.Modified = time.Now() _,err = o.Update(b,cols...) - key := fmt.Sprintf("blog-id-%d",b.BlogId); + key := fmt.Sprintf("blog-id-%d", b.BlogId ) cache.Delete(key) }else{ @@ -320,7 +320,7 @@ func (b *Blog) QueryNext(blogId int) (*Blog,error) { err := o.QueryTable(b.TableNameWithPrefix()).Filter("order_index__gte",blog.OrderIndex).Filter("blog_id__gt",blogId).OrderBy("-order_index","-blog_id").One(blog) - if err != nil { + if err != nil && err != orm.ErrNoRows{ beego.Error("查询文章时出错 ->",err) } return blog,err @@ -338,7 +338,7 @@ func (b *Blog) QueryPrevious(blogId int) (*Blog,error) { err := o.QueryTable(b.TableNameWithPrefix()).Filter("order_index__lte",blog.OrderIndex).Filter("blog_id__lt",blogId).OrderBy("-order_index","-blog_id").One(blog) - if err != nil { + if err != nil && err != orm.ErrNoRows{ beego.Error("查询文章时出错 ->",err) } return blog,err @@ -353,13 +353,13 @@ func (b *Blog) LinkAttach() (err error) { //当不是关联文章时,用文章ID去查询附件 if b.BlogType != 1 || b.DocumentId <= 0 { _, err = o.QueryTable(NewAttachment().TableNameWithPrefix()).Filter("document_id", b.BlogId).Filter("book_id",0).All(&attachList) - if err != nil { + if err != nil && err != orm.ErrNoRows{ beego.Error("查询文章附件时出错 ->", err) } }else { _, err = o.QueryTable(NewAttachment().TableNameWithPrefix()).Filter("document_id", b.DocumentId).Filter("book_id", b.BookId).All(&attachList) - if err != nil { + if err != nil && err != orm.ErrNoRows{ beego.Error("查询文章附件时出错 ->", err) } } diff --git a/models/DocumentModel.go b/models/DocumentModel.go index ecaa4b12..6a952c2f 100644 --- a/models/DocumentModel.go +++ b/models/DocumentModel.go @@ -3,7 +3,6 @@ package models import ( "time" - "encoding/json" "fmt" "strconv" @@ -151,18 +150,18 @@ func (m *Document) RecursiveDocument(docId int) error { //将文档写入缓存 func (m *Document) PutToCache() { go func(m Document) { - 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 { + if err := cache.Put("Document.Id."+strconv.Itoa(m.DocumentId), m, time.Second*3600); err != nil { beego.Info("文档缓存失败:", m.DocumentId) } } else { - if err := cache.Put(fmt.Sprintf("Document.BookId.%d.Identify.%s", m.BookId, m.Identify), v, time.Second*3600); err != nil { + if err := cache.Put(fmt.Sprintf("Document.BookId.%d.Identify.%s", m.BookId, m.Identify), m, time.Second*3600); err != nil { beego.Info("文档缓存失败:", m.DocumentId) } } - } + }(*m) } @@ -179,31 +178,35 @@ func (m *Document) RemoveCache() { //从缓存获取 func (m *Document) FromCacheById(id int) (*Document, error) { - b := cache.Get("Document.Id." + strconv.Itoa(id)) - if v, ok := b.([]byte); ok { - if err := json.Unmarshal(v, m); err == nil { - beego.Info("从缓存中获取文档信息成功", m.DocumentId) - return m, nil - } + var doc Document + if err := cache.Get("Document.Id."+strconv.Itoa(id), &m); err == nil { + m = &doc + beego.Info("从缓存中获取文档信息成功", m.DocumentId) + return m, nil } - defer func() { - if m.DocumentId > 0 { - m.PutToCache() - } - }() - return m.Find(id) + + if m.DocumentId > 0 { + m.PutToCache() + } + m,err := m.Find(id) + + if err == nil { + m.PutToCache() + } + return m,err } //根据文档标识从缓存中查询文档 func (m *Document) FromCacheByIdentify(identify string, bookId int) (*Document, error) { - b := cache.Get(fmt.Sprintf("Document.BookId.%d.Identify.%s", bookId, identify)) - if v, ok := b.([]byte); ok { - if err := json.Unmarshal(v, m); err == nil { - beego.Info("从缓存中获取文档信息成功", m.DocumentId, identify) - return m, nil - } + + key := fmt.Sprintf("Document.BookId.%d.Identify.%s", bookId, identify) + + if err := cache.Get(key,m); err == nil { + beego.Info("从缓存中获取文档信息成功", key) + return m, nil } + defer func() { if m.DocumentId > 0 { m.PutToCache() diff --git a/utils/html.go b/utils/html.go index 1b49d54e..c9719a92 100644 --- a/utils/html.go +++ b/utils/html.go @@ -29,3 +29,28 @@ func StripTags(s string) string { return src } +//自动提取文章摘要 +func AutoSummary(body string,l int) string { + + //匹配图片,如果图片语法是在代码块中,这里同样会处理 + re := regexp.MustCompile(`

(.*?)

`) + + contents := re.FindAllString(body, -1) + + if len(contents) <= 0 { + return "" + } + content := "" + for _,s := range contents { + b := strings.Replace(StripTags(s),"\n","", -1) + + if l <= 0 { + break + } + l = l - len([]rune(b)) + + content += b + + } + return content +} diff --git a/views/blog/index.tpl b/views/blog/index.tpl index 1ad46c9d..20a776dc 100644 --- a/views/blog/index.tpl +++ b/views/blog/index.tpl @@ -8,7 +8,7 @@ - + {{.Model.BlogTitle}} - Powered by MinDoc diff --git a/views/document/default_read.tpl b/views/document/default_read.tpl index 7abebd37..655c5e43 100644 --- a/views/document/default_read.tpl +++ b/views/document/default_read.tpl @@ -11,7 +11,7 @@ - +