上节课内容我们实现了项目主页的文章列表功能和分页功能。本节课继续进行开发实现,当点击文章的时候,应该显示文章的详细内容。
一、Controller
首先先设置路由:
func init() {
...
//写文章
beego.Router("/article/add", &controllers.AddArticleController{})
//显示文章内容
beego.Router("/article/:id", &controllers.ShowArticleController{})
}
然后再controllers目录下创建一个go文件,show_article_controller.go:
type ShowArticleController struct {
//beego.Controller
BaseController
}
func (this *ShowArticleController) Get() {
idStr := this.Ctx.Input.Param(":id")
id, _ := strconv.Atoi(idStr)
fmt.Println("id:", id)
//获取id所对应的文章信息
art := models.QueryArticleWithId(id)
this.Data["Title"] = art.Title
this.Data["Content"] = art.Content
//this.Data["Content"] = utils.SwitchMarkdownToHtml(art.Content)
this.TplName="show_article.html"
}
二、Model
接下来在article_model.go文件中,添加方法,根据id查询文章:
//----------查询文章-------------
func QueryArticleWithId(id int) Article {
row := utils.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:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{.Title}}</title>
<link href="../static/css/blogsheet.css" rel="stylesheet">
</head>
<body>
{{template "block/nav.html" .}}
<div id="main">
<h1>{{.Title}}</h1>
<div>{{.Content}}</div>
</div>
</body>
</html>
四、运行
接下来我们重启项目,并刷新页面:
点击一篇文章:
五、Markdown
虽然页面能够显示文章内容,但是看着很不舒服,一锅粥一样,我们通过markdown语法格式显示。
我们先了解一下,在进行项目开发前先熟悉下我们需要用到的库。包括:
- 转换Markdown语法:russross/blackfriday
- 查找Document的内容:PuerkitoBio/goquery
- 语法高亮:sourcegraph/syntaxhighlight
- 插入模块:html/template
- 执行外部命令:os/exec
- 文件操作:path/filepath
- 创建Web服务器:SimpleHTTPServer
- 解析.yml配置文件:http://gopkg.in/yaml.v2
首先需要安装markdown的安装包:
打开终端输入以下命令:
go get github.com/russross/blackfriday
go get github.com/PuerkitoBio/goquery
go get github.com/sourcegraph/syntaxhighlight
安装之后也可以到src目录下查看:
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:
## 一、russross/blackfriday包
示例代码:
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 文档的一部分。
type Document struct {
*Selection
Url *url.URL
rootNode *html.Node // 文档的根节点
}
因为 Document 中内嵌了一个 Selection 类型,因此,Document 可以直接使用 Selection 类型的方法。提供有五种方法获取一个 Document 实例。
2. Selection
Selection 代表符合特定条件的节点集合。
type Selection struct {
Nodes []*html.Node
document *Document
prevSel *Selection
}
一般地,得到了 Document 实例后,通过 Dcoument.Find 方法获取一个 Selection 实例,然后像 jQuery 一样使用链式语法和方法操作它。
Selection 类型提供的方法可以分为如下几大类
- 类似函数的位置操作
- 扩大 Selection 集合(增加选择的节点)
- 过滤方法,减少节点集合
- 循环遍历选择的节点
- 修改文档
- 检测或获取节点属性值
- 查询或显示一个节点的身份
- 在文档树之间来回跳转(常用的查找节点方法)
3. 基本用法:
1、创建文档
1. d,e := goquery.NewDocumentFromReader(reader io.Reader)
2. d,e := goquery.NewDocument(url string)
2、查找内容
1. ele.Find("#title") //根据id查找
2. ele.Find(".title") //根据class查找
3. ele.Find("h2").Find("a") //链式调用
3、获取内容
1. ele.Html()
2. ele.Text()
4、获取属性
1. ele.Attr(“href”)
2. ele.AttrOr(“href”, “”)
5、遍历
1. ele.Find(“.item”).Each(func(index int, ele *goquery.Selection){
2.
3. })
示例:
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 。如:
语法表述#firstname选择 id="firstname" 的所有元素。*选择所有元素。p选择所有 <p> 元素。div,p选择所有 <div> 元素和所有 <p> 元素。div p选择 <div> 元素内部的所有 <p> 元素。div>p选择父元素为 <div> 元素的所有 <p> 元素。div+p选择紧接在 <div> 元素之后的所有 <p> 元素。[target]选择带有 target 属性所有元素。[target=_blank]选择 target="_blank" 的所有元素。a[src*=”abc”]选择其 src 属性中包含 “abc” 子串的每个 <a> 元素。a[src$=”.pdf”]选择其 src 属性以 “.pdf” 结尾的所有 <a> 元素。
5.1.3 sourcegraph/syntaxhighlight包
syntaxhighlight包提供代码的语法高亮显示。 它目前使用独立于语言的词法分析器, 并在JavaScript,Java,Ruby,Python,Go和C上表现出色。
主要的AsHTML(src []byte) ([]byte, error)函数,输出就是HTML 与google-code-prettify相同的CSS类,因此任何样式表也应该适用于此包。
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>
通过如下规则就行的转换
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页面上导入样式包:
<!DOCTYPE html>
<html lang="en">
<head>
...
<link href="../static/css/lib/highlight.css" rel="stylesheet">
</head>
接下来在utils目录下,myUtils.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()方法:
func (this *ShowArticleController) Get() {
...
this.Data["Title"] = art.Title
//this.Data["Content"] = art.Content
this.Data["Content"] = utils.SwitchMarkdownToHtml(art.Content)
this.TplName="show_article.html"
}
5.3 运行结果
重启项目后,然后刷新页面:
可以看到,效果就比较好看了,这就实现了我们对页面的美化效果。