Browse Source

1、完善日志配置
2、文章自动生成摘要
3、修正文档名称问题
4、修复Redis无法读取缓存的BUG

lifei6671 7 năm trước cách đây
mục cha
commit
1cbdd4baca

+ 36 - 4
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)
 }

+ 60 - 12
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()
 
-	logPath := filepath.Join(log, "log.log")
+	if beego.AppConfig.DefaultBool("log_is_async", true) {
+		logs.Async(1e3)
+	}
+	if log == "" {
+		log = conf.WorkingDir("runtime","logs")
+	}
 
-	if _, err := os.Stat(logPath); os.IsNotExist(err) {
+	logPath := filepath.Join(log, "log.log")
 
+	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
+	config := make(map[string]interface{}, 1)
 
-			b, _ := json.Marshal(config)
+	config["filename"] = logPath
+	config["perm"] = "0755"
+	config["rotate"] = true
 
-			beego.SetLogger("file", string(b))
+	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("缓存初始化完成.")

+ 40 - 6
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
 
 
 

+ 12 - 0
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 {

+ 5 - 0
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

+ 0 - 6
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")
 

+ 12 - 12
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)
 		}
 	}

+ 26 - 23
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()

+ 25 - 0
utils/html.go

@@ -29,3 +29,28 @@ func StripTags(s string) string  {
 
 	return src
 }
+//自动提取文章摘要
+func AutoSummary(body string,l int) string {
+
+	//匹配图片,如果图片语法是在代码块中,这里同样会处理
+	re := regexp.MustCompile(`<p>(.*?)</p>`)
+
+	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
+}

+ 1 - 1
views/blog/index.tpl

@@ -8,7 +8,7 @@
     <meta name="author" content="Minho" />
     <meta name="site" content="https://www.iminho.me" />
     <meta name="keywords" content="{{.Model.BlogTitle}}">
-    <meta name="description" content="{{.Model.BlogTitle}}-{{.Model.BlogExcerpt}}">
+    <meta name="description" content="{{.Model.BlogTitle}}-{{.Description}}">
     <title>{{.Model.BlogTitle}} - Powered by MinDoc</title>
 
     <!-- Bootstrap -->

+ 1 - 1
views/document/default_read.tpl

@@ -11,7 +11,7 @@
     <meta name="author" content="Minho" />
     <meta name="site" content="https://www.iminho.me" />
     <meta name="keywords" content="{{.Model.BookName}},{{.Title}}">
-    <meta name="description" content="{{.Title}}-{{.Model.Description}}">
+    <meta name="description" content="{{.Title}}-{{if .Description}}{{.Description}}{{else}}{{.Model.Description}}{{end}}">
 
     <!-- Bootstrap -->
     <link href="{{cdncss "/static/bootstrap/css/bootstrap.min.css"}}" rel="stylesheet">