🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### GoWeb开发实战Gin框架】微博项目实战-显示文章详情 # 文章详情 当点击文章的时候,应该显示文章的详细内容。 ## 一、Controller 首先先设置路由: ~~~go //显示文章内容 router.GET("/show/:id", controllers.ShowArticleGet) ~~~ 然后再controllers目录下创建一个go文件,show\_article\_controller.go: ~~~go package controllers import ( "strconv" "fmt" "github.com/gin-gonic/gin" "net/http" "blogweb_gin/models" ) // 显示文章 func ShowArticleGet(c *gin.Context) { //获取session islogin := GetSession(c) idStr := c.Param("id") id, _ := strconv.Atoi(idStr) fmt.Println("id:", id) //获取id所对应的文章信息 art := models.QueryArticleWithId(id) //渲染HTML c.HTML(http.StatusOK, "show_article.html", gin.H{"IsLogin": islogin,"Title":art.Title,"Content":art.Content}) } ~~~ ## 二、Model 接下来在article\_model.go文件中,添加方法,根据id查询文章: ~~~go //----------查询文章------------- func QueryArticleWithId(id int) Article { row := database.QueryRowDB("select id,title,tags,short,content,author,createtime from article where id=" + strconv.Itoa(id)) title := "" tags := "" short := "" content := "" author := "" var createtime int64 createtime = 0 row.Scan(&id, &title, &tags, &short, &content, &author, &createtime) art := Article{id, title, tags, short, content, author, createtime} return art } ~~~ ## 三、View 接下来我们创建view,在views目录下,新建html页面文件,show\_article.html: ~~~html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{.Title}}</title> <link href="../static/css/blogsheet.css" rel="stylesheet"> </head> <body> {{template "nav.html" .}} <div id="main"> <h1>{{.Title}}</h1> <div>{{.Content}}</div> </div> </body> </html> ~~~ ## 四、运行 接下来我们重启项目,并刷新页面: ![gin_yunxing58](http://image.chaindesk.cn/gin_yunxing58.png/mark) 点击一篇文章: ![gin_yunxing59](http://image.chaindesk.cn/gin_yunxing59.png/mark) ## 五、Markdown 虽然页面能够显示文章内容,但是看着很不舒服,一锅粥一样,太丑了。我们可以通过markdown语法格式显示。 我们先了解一下,在进行项目开发前先熟悉下我们需要用到的库。包括: * 转换Markdown语法:russross/blackfriday * 查找Document的内容:PuerkitoBio/goquery * 语法高亮:sourcegraph/syntaxhighlight * 插入模块:html/template * 执行外部命令:os/exec * 文件操作:path/filepath * 创建Web服务器:SimpleHTTPServer * 解析.yml配置文件:gopkg.in/yaml.v2 首先需要安装markdown的安装包: 打开终端输入以下命令: ~~~shell go get github.com/russross/blackfriday go get github.com/PuerkitoBio/goquery go get github.com/sourcegraph/syntaxhighlight ~~~ ![package11](http://image.chaindesk.cn/package11.png/mark) 安装之后也可以到src目录下查看: ![package12](http://image.chaindesk.cn/package12.png/mark) ### 5.1 语法简介 #### 5.1.1 russross/blackfriday包 第三方库russross/blackfriday用于在golang中使用markdown语法。 **markdown**: 是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。 Markdown具有一系列衍生版本,用于扩展Markdown的功能(如表格、脚注、内嵌HTML等等),这些功能原初的Markdown尚不具备,它们能让Markdown转换成更多的格式,例如LaTeX,Docbook。Markdown增强版中比较有名的有Markdown Extra、MultiMarkdown、 Maruku等。这些衍生版本要么基于工具,如Pandoc;要么基于网站,如GitHub和Wikipedia,在语法上基本兼容,但在一些语法和渲染效果上有改动。 test.md: ~~~markdown ## 一、russross/blackfriday包 ~~~ 示例代码: ~~~go func main() { fileread, _ := ioutil.ReadFile("extra/blackfriday转换markdown/test.md") //转换Markdown语法,如将"#"转换为"<h1></h1>" subHtml := blackfriday.MarkdownCommon(fileread) subHtmlStr := string(subHtml) fmt.Println(subHtmlStr) } ~~~ 输出: ~~~ <h2>一、russross/blackfriday包</h2> ~~~ #### 5.1.2 PuerkitoBio/goquery包 做过 Web 开发的,应该都用过或听过 jQuery,它提供了方便的操作 DOM 的 API。使用 Go 语言做服务器端开发,有时候需要解析 HTML 文件,比如抓取网站内容、写一个爬虫等。这时候如果有一个类似 jQuery 的库可以使用,操作 DOM 会很方便,而且,上手也会很快。`PuerkitoBio/goquery`这个库就实现了类似 jQuery 的功能,让你能方便的使用 Go 语言操作 HTML 文档。 该库提供的类型很少,但方法却很多,我们不可能一个个方法讲解。这里通过模拟几个使用场景来讲解该库的使用。 ##### 1\. Document Document 代表一个将要被操作的 HTML 文档,不过,和 jQuery 不同,它装载的是 DOM 文档的一部分。 ~~~go type Document struct { *Selection Url *url.URL rootNode *html.Node // 文档的根节点 } ~~~ 因为 Document 中内嵌了一个 Selection 类型,因此,Document 可以直接使用 Selection 类型的方法。提供有五种方法获取一个 Document 实例。 ##### 2\. Selection Selection 代表符合特定条件的节点集合。 ~~~go type Selection struct { Nodes []*html.Node document *Document prevSel *Selection } ~~~ 一般地,得到了 Document 实例后,通过 Dcoument.Find 方法获取一个 Selection 实例,然后像 jQuery 一样使用链式语法和方法操作它。 Selection 类型提供的方法可以分为如下几大类 * 类似函数的位置操作 * 扩大 Selection 集合(增加选择的节点) * 过滤方法,减少节点集合 * 循环遍历选择的节点 * 修改文档 * 检测或获取节点属性值 * 查询或显示一个节点的身份 * 在文档树之间来回跳转(常用的查找节点方法) ##### 3\. 基本用法: 1、创建文档 ~~~go 1. d,e := goquery.NewDocumentFromReader(reader io.Reader) 2. d,e := goquery.NewDocument(url string) ~~~ 2、查找内容 ~~~go 1. ele.Find("#title") //根据id查找 2. ele.Find(".title") //根据class查找 3. ele.Find("h2").Find("a") //链式调用 ~~~ 3、获取内容 ~~~go 1. ele.Html() 2. ele.Text() ~~~ 4、获取属性 ~~~go 1. ele.Attr(“href”) 2. ele.AttrOr(“href”, “”) ~~~ 5、遍历 ~~~go 1. ele.Find(“.item”).Each(func(index int, ele *goquery.Selection){ 2. 3. }) ~~~ 示例: ~~~go func main() { doc, err := goquery.NewDocument("http://studygolang.com/topics") if err != nil { log.Fatal(err) } doc.Find(".topic").Each(func(i int, contentSelection *goquery.Selection) { title := contentSelection.Find(".title a").Text() //Find(".title a")与Find(".title").Find("a")一样 fmt.Println("第", i+1, "个帖子的标题:", title) //ret,_ := contentSelection.Html() //fmt.Printf("\n\n\n%v", ret) //fmt.Println(contentSelection.Text()) }) //最终输出为 html 文档: //new, err := doc.Html() } ~~~ 其中Find中的输入字符串是CSS selector,其语法风格参照[http://www.w3school.com.cn/cssref/css\_selectors.asp](http://www.w3school.com.cn/cssref/css_selectors.asp)。如: | 语法 | 表述 | | --- | --- | | #firstname | 选择 id="firstname" 的所有元素。 | | \* | 选择所有元素。 | | p | 选择所有 元素。 | | div,p | 选择所有 元素和所有 元素。 | | div p | 选择 元素内部的所有 元素。 | | div>p | 选择父元素为 元素的所有 元素。 | | div+p | 选择紧接在 元素之后的所有 元素。 | | \[target\] | 选择带有 target 属性所有元素。 | | \[target=\_blank\] | 选择 target="\_blank" 的所有元素。 | | a\[src\*=”abc”\] | 选择其 src 属性中包含 “abc” 子串的每个元素。 | | a\[src$=”.pdf”\] | 选择其 src 属性以 “.pdf” 结尾的所有元素。 | #### 5.1.3 sourcegraph/syntaxhighlight包 syntaxhighlight包提供代码的语法高亮显示。 它目前使用独立于语言的词法分析器, 并在JavaScript,Java,Ruby,Python,Go和C上表现出色。 主要的AsHTML(src \[\]byte) (\[\]byte, error)函数,输出就是HTML 与google-code-prettify相同的CSS类,因此任何样式表也应该适用于此包。 ~~~go func main() { src := []byte(` /* hello, world! */ var a = 3; // b is a cool function function b() { return 7; }`) highlighted, err := syntaxhighlight.AsHTML(src) if err != nil { fmt.Println(err) os.Exit(1) } fmt.Println(string(highlighted)) } ~~~ 输出 ~~~ <span class="com">/* hello, world! */</span> <span class="kwd">var</span> <span class="pln">a</span> <span class="pun">=</span> <span class="dec">3</span><span class="pun">;</span> <span class="com">// b is a cool function</span> <span class="kwd">function</span> <span class="pln">b</span><span class="pun">(</span><span class="pun">)</span> <span class="pun">{</span> <span class="kwd">return</span> <span class="dec">7</span><span class="pun">;</span> <span class="pun">}</span> ~~~ 通过如下规则就行的转换 ~~~go var DefaultHTMLConfig = HTMLConfig{ String: "str", Keyword: "kwd", Comment: "com", Type: "typ", Literal: "lit", Punctuation: "pun", Plaintext: "pln", Tag: "tag", HTMLTag: "htm", HTMLAttrName: "atn", HTMLAttrValue: "atv", Decimal: "dec", Whitespace: "", } ~~~ ### 5.2 修改项目代码 首先在show\_article.html页面上导入样式包: ~~~html <!DOCTYPE html> <html lang="en"> <head> ... <link href="../static/css/lib/highlight.css" rel="stylesheet"> </head> ~~~ 接下来在utils目录下,myUtils.go文件中添加方法: ~~~go func SwitchMarkdownToHtml(content string) template.HTML { markdown := blackfriday.MarkdownCommon([]byte(content)) //获取到html文档 doc, _ := goquery.NewDocumentFromReader(bytes.NewReader(markdown)) /** 对document进程查询,选择器和css的语法一样 第一个参数:i是查询到的第几个元素 第二个参数:selection就是查询到的元素 */ doc.Find("code").Each(func(i int, selection *goquery.Selection) { light, _ := syntaxhighlight.AsHTML([]byte(selection.Text())) selection.SetHtml(string(light)) fmt.Println(selection.Html()) fmt.Println("light:", string(light)) fmt.Println("\n\n\n") }) htmlString, _ := doc.Html() return template.HTML(htmlString) } ~~~ 最后修改controller中的Get()方法: ~~~go // 显示文章 func ShowArticleGet(c *gin.Context) { ... //渲染HTML //c.HTML(http.StatusOK, "show_article.html", gin.H{"IsLogin": islogin,"Title":art.Title,"Content":art.Content}) c.HTML(http.StatusOK, "show_article.html", gin.H{"IsLogin": islogin,"Title":art.Title,"Content":utils.SwitchMarkdownToHtml(art.Content)}) } } ~~~ ### 5.3 运行结果 重启项目后,然后刷新页面: ![gin_yunxing60](http://image.chaindesk.cn/gin_yunxing60.png/mark) 嗯嗯,比之前的好看多了。。