精通 Grails 文件上传和 Atom 联合(3)
- UID
- 1066743
|
精通 Grails 文件上传和 Atom 联合(3)
显示上传的文件如果不将上传的文件在某个地方显示出来,那有何意义呢?打开 grails-app/views/entry/_entry.gsp,添加清单 11 中的代码:
清单 11. 用于显示上传的图像的 GSP 代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <div class="entry">
<span class="entry-date">
<g:longDate>${entryInstance.lastUpdated}</g:longDate> : ${entryInstance.author}
</span>
<h2><g:link action="show" id="${entryInstance.id}">${entryInstance.title}</g:link></h2>
<p>${entryInstance.summary}</p>
<g:if test="${entryInstance.filename}">
<p>
<img src="${createLinkTo(dir:'payload/'+entryInstance.author.login,
file:''+entryInstance.filename)}"
alt="${entryInstance.filename}"
title="${entryInstance.filename}" />
</p>
</g:if>
</div>
|
由于上传文件是可选的,我将输出包含在一个 <g:if> 块中。如果 entryInstance.filename 字段被填充,则在一个 <img> 标记中显示结果。
图 2 显示新的列表,同时还在显眼的地方显示上传的 Grails 徽标:
图 2. 显示上传的图像但是,如果用户上传其他东西,而不是图像呢?这时就不是将更多的逻辑放入到 GSP 中了,最好的地方是一个定制的 TagLib。
创建 TagLibBlogito 在 grails-app/taglib 中已经有两个 TagLib:DateTagLib.groovy 和 LoginTagLib.groovy。在一个 TagLib 中可以定义任意数量的定制标记,但是这一次我建议创建一个新的 TagLib,以便按语义将标记分组。在命令提示符下输入 grails create-tag-lib Entry,并添加清单 12 中的代码:
清单 12. 创建 displayFile 标记1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| class EntryTagLib {
def displayFile = {attrs, body->
def user = attrs["user"]
def filename = attrs["filename"]
if(filename){
def extension = filename.split("\\.")[-1]
def userDir = "payload/${user}"
switch(extension.toUpperCase()){
case ["JPG", "PNG", "GIF"]:
def html = """
<p>
<img src="${createLinkTo(dir:''+userDir,
file:''+filename)}"
alt="${filename}"
title="${filename}" />
</p>
"""
out << html
break
case "HTML":
out << "p>html</p>"
break
default:
out << "<p>file</p>"
break
}
}else{
out << "<!-- no file -->"
}
}
}
|
不久后可以看到,该代码创建一个 <g:displayFile> 标记,该标记需要两个属性:user 和 filename。如果 filename 属性被填充,则取得文件扩展名,并将其转换为大写形式。
Groovy 中的 Switch 语句比 Java 中的对等物的灵活性要大得多。首先,可以在 String 上进行切换(而 Java 语言只能在 int 上进行切换)。更令人惊奇的是,case 既可以指定一个条件列表 List,也可以指定单个的条件。
有了这个 TagLib 后,可以大大简化 _entry.gsp 局部模板,如清单 13 所示:
清单 13. 简化的局部模板1
2
3
4
5
6
7
8
9
10
11
| <div class="entry">
<span class="entry-date">
<g:longDate>${entryInstance.lastUpdated}</g:longDate> : ${entryInstance.author}
</span>
<h2><g:link action="show" id="${entryInstance.id}">${entryInstance.title}</g:link></h2>
<p>${entryInstance.summary}</p>
<g:displayFile filename="${entryInstance.filename}"
user="${entryInstance.author.login}" />
</div>
|
重新启动 Grails,并再次上传 Grails 徽标。在添加对其他文件类型的支持之前,应该确保 TagLib 重构没有破坏已有的功能。
现在,可以确信仍可以上传图像。接下来就是添加对其他文件类型的支持,这只需在 switch 块中实现适当的 case。清单 14 演示如何处理上传的 HTML 文件,以及为默认的 case 创建一个链接来下载该文件:
清单 14. 完整的 switch/case 块1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| class EntryTagLib {
def displayFile = {attrs, body->
def user = attrs["user"]
def filename = attrs["filename"]
if(filename){
def extension = filename.split("\\.")[-1]
def userDir = "payload/${user}"
switch(extension.toUpperCase()){
case ["JPG", "PNG", "GIF"]:
//SNIP
break
case "HTML":
def webRootDir = servletContext.getRealPath("/")
out << new File(webRootDir+"/"+userDir, filename).text
break
default:
def html = """
<p>
<a href="${createLinkTo(dir:''+userDir,
file:''+filename)}">${filename}</a>
</p>
"""
out << html
break
}
}else{
out << "<!-- no file -->"
}
}
}
|
创建两个新的文本文件,以便测试这个新的行为:一个名为 test.html,另一个名为 noextension。将清单 15 中的内容添加到适当的文件中,上传该文件,确认 TagLib 是否按预期显示每个文件:
清单 15. 用于上传的两个示例文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| //test.html
<p>
This is some <b>test</b> HTML.
</p>
<p>
Here is a link to the <a href="http://grails.org">Grails</a> homepage.
</p>
<p>
And here is a link to the
<img src="//grails.org/images/grails-logo.png">Grails Logo</img>.
</p>
//noextension
This file doesn't have an extension.
|
Web 浏览器看上去应该如图 3 所示:
图 3. 显示所有 3 种类型的上传的文件 |
|
|
|
|
|