功能丰富的 Perl: Perl 和 Amazon 云,第 5 部分--了解完整 mod_perl 站点的模板

这个共分 5 部分的系列文章向您介绍了如何使用 Perl 和 Apache 构建一个照片共享网站,从而访问 Amazon 的 Simple Storage Service (S3) 和 SimpleDB。在这最后一期文章中,我们将考察完整 mod_perl 站点的模板,包括一个用于索引的模板、三个用于上传的模板(通用模板、S3 表单和 URL 添加物)、一个用于浏览照片和评论的模板,以及一个用于递归式地浏览(即遍历浏览)照片评论的模板。

在最后一期文章中,我们将了解完整的 mod_perl 站点(这一次将讨论模板;代码库位于 功能丰富的 Perl:Perl 和 Amazon 云,第 4 部分)。我再一次鼓励您阅读源代码。该站点是功能性的,但是许多细节都没有在本系列中详细介绍,我希望您能理解这些细节或者了解还存在疑问的地方。您可以通过书店或搜索引擎查找信息。

从本系列中获得最大收益

本系列需要您掌握 HTTP 和 HTML 的入门级知识,以及 JavaScript 和 Perl(位于 Apache mod_perl 进程内部)的中级知识。掌握关系数据库、磁盘存储和网络知识也非常有帮助。

特别是,设置一个完整的 mod_perl 站点并使用 Template Toolkit 是非常广泛的主题,并且已经介绍过许多次,因此这里不再解释。最佳学习途径就是了解每一个问题和难点,直到网站可以正常运行。本系列将给出可以使网站正常运行所需的所有内容 — 但是需要由您来将所有内容结合起来。

和此前的文章一样,我将使用 share.lifelogs.com 作为域名。当在您自己的环境中使用时,应根据需要修改它。

index.tmpl

我们将按照从上而下的顺序讨论模板(policy.tmpl 在第 4 部分已作讨论)。有关 Template Toolkit 语法的解释,见参考资料小节。我将解释比较复杂的部分。

index.tmpl 是一个简单的 HTML 页面。这里惟一需要注意的是所有 URI 都是相关的,因此这个模板和其他所有模板都可以用于任何域。

清单 1. index.tmpl,简单的 HTML

<html> <head><title>Share Pictures</title></head><body><h1>Share Pictures</h1>You can<a href="/upload">upload or add images</a>or<a href="/browse">browse images and comments</a>.<address>Contact <a href="mailto:tzz@bu.edu">Ted Zlatanov</a> if you have lotsof money you're trying to get out of Nigeria. The breathis <strike>baited</strike>bated.</address></body></html>

upload.tmpl

现在,我们将了解一个优秀的模板,它集合了 JavaScript、HTML 和 Template Toolkit 语言。如果这还不能让 Web 设计师激动不已的话,那么我不知道还有什么能够拥有这种魔力。

清单 2. 足以让 Web 设计人员激动不已的 upload.tmpl

<html> <head> <title>Upload Page For [% username %]</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js" type="text/javascript"></script> </head> <body> <script language="JavaScript">function OnSubmitForm(){ var form = $('uploader'); var file = form['file']; var ct = form['Content-Type']; var name = form['name'].value; if (!name || name.length < 1) { alert("Sorry, you can't upload without a name."); return false; } var filename = ''+$F(file); var f = filename.toLowerCase(); // always compare against the lowercase version if (!navigator['mimeTypes']) { alert("Sorry, your browser can't tell us what type of file you're uploading."); return false; } var type = $A(navigator.mimeTypes).detect(function(m) { // does any of the suffixes match? return m.type.length > 3 && m.type.match('/') && $A(m.suffixes.split(',')).detect(function(suffix) { return f.match('\.' + suffix.toLowerCase() + '$'); }); }); if (!type || !type['type']) { type = { type : prompt("Enter your own MIME type, we couldn't find one through the browser", "image/jpeg") }; } if (type && type['type']) { ct.value = type.type; // fix up the redirect if we're about to submit var sar = form['success_action_redirect']; sar.value = sar.value + escape(name); return true; } alert("Sorry, we don't know the type for file " + filename); return false;}</script><h1>Hi, [% username %]</h1> <form id="uploader" action="https://images.share.lifelogs.com.s3.amazonaws.com/" method="post" enctype="multipart/form-data" onSubmit="return OnSubmitForm();"> <input type="hidden" name="key" value="${filename}"> <input type="hidden" name="AWSAccessKeyId" value="[% env.AWS_KEY %]"> <input type="hidden" name="acl" value="public-read"> <input type="hidden" name="success_action_redirect" value="http://share.lifelogs.com/s3uploaded?user=[% username %]&name="> <input type="hidden" name="policy" value="[% policy %]"> <input type="hidden" name="Content-Type" value="image/jpeg"> <input type="hidden" name="signature" value="[% signature %]"> Select File to upload to S3: <input name="file" type="file"> <br> Enter a Name: <input name="name" type="text"> <br> <input type="submit" value="Upload File to S3"> </form> <form id="adder" action="/urluploaded" method="post" enctype="multipart/form-data"> <input type="hidden" name="user" value="[% username %]"> Enter a URL: <input name="url" type="text"> <br> Enter a Name: <input name="name" type="text"> <br> <input type="submit" value="Add URL"> </form> </body></html>

上传页面展示了两个上传对话框。它们都可以添加照片,但是第二个对话框更加简单。在第二个对话框中,用户填入照片的 URL 和名称,这些内容随后被 POST 到 /urluploaded,后者正是 urluploaded.tmpl。在显示该模板时,将自动调用图像参数处理程序。用户名从服务器获得并且是一个隐藏了表单的 POST 参数。

第一个表单非常复杂。幸运的是,可以阅读本系列的 第 2 部分,其中解释了有关 S3 上传的所有内容,因此您应当不会感到陌生。

对第 2 部分的 s3form.pl(包含在下载小节)的主要修改包括:

success_action_redirect 将用户名和照片名作为参数传递。策略被修改为只需要字符串中截至用户名的一部分,但是不包括用户名。 策略和签名从服务器传递。 AWS 访问和秘密密匙被放到 env 散列中从服务器传递。 OnSubmitForm 函数需要一个名称并将其作为参数添加到 success_action_redirect 表单字段并转义(注意,在决定 MIME 类型之前 需要用到名称,但是名称只有在对表单执行 POST 前被添加到 URL。) 如果没有找到 MIME 类型,OnSubmitForm 函数就会失败,允许用户指定他们自己的类型。

s3uploaded.tmpl

在 S3 上传中将使用该模板。

清单 3. 在上传中使用 s3uploaded.tmpl 模板

[% success = params.result %]<html> <head> <title>[% IF success %]Successful[% ELSE %]Unsuccessful[% END %] Upload Page For [% params.user %]</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> [% IF success %]Congratulations[% ELSE %]Sorry[% END %], [% params.user %]. You have [% IF success %]successfully[% ELSE %]unsuccessfully[% END %] uploaded [% params.key %] to S3 bucket [% params.bucket %] named [% params.name %].<p> (etag is [% params.etag %] but I doubt you care.) <p>[% IF success %] <a href="http://[% params.bucket %].s3.amazonaws.com/[% params.key %]"> Your new upload is probably here. Let's see if it displays already. <img src="http://[% params.bucket %].s3.amazonaws.com/[% params.key %]"> </a>[% END %] <p> You can now go back to <a href="/upload">uploading</a> or <a href="/">the main page</a>. </body></html>

通过一些复杂的 Template Toolkit IF-ELSE 结构和 result 参数,页面可以处理成功的和不成功的上传。成功上传的关键在于添加了 SimpleDB;如果掌握了这点,那么就能够始终成功地将照片上传到 S3。在 SimpleDB 故障时从 S3 取回照片留给读者作为练习。

urluploaded.tmpl

该模板用于 URL 添加。

清单 4. urluploaded.tmpl 实现代码重用

[% success = params.result %]<html> <head> <title>[% IF success %]Successful[% ELSE %]Unsuccessful[% END %] URL add Page For [% params.user %]</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> [% IF success %]Congratulations[% ELSE %]Sorry[% END %], [% params.user %]. You have [% IF success %]successfully[% ELSE %]unsuccessfully[% END %] added [% params.url %] named [% params.name %].<p> <p>[% IF success %] <a href="[% params.url %]"> The URL you added is, perhaps, visible here. <img src="[% params.url %]"> </a>[% END %] <p> You can now go back to <a href="/upload">uploading</a> or <a href="/">the main page</a>. </body></html>

除了明显糟糕的 HTML 外,该模板类似于 s3uploaded.tmpl。通过使用这个模板,代码重用不再是问题。

browse.tmpl

该模板可以浏览照片和评论。

清单 5. 使用 browse.tmpl 浏览照片和评论

[% SET images = fimages() %][% SET comments = fcomments() %]<html> <head> <title>Browse</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <ul> [% FOR ik IN images.keys %] <li> [% SET image = images.$ik %] [% image.name %]<br> <img src="[% image.url %]"><br> [% IF image.bucket %](in S3)[% END %]<br> uploaded by [% image.user %]<br> <form action="/browse" method="post" enctype="multipart/form-data"> <input type="hidden" name="deleteimageid" value="[% ik %]"> <input type="submit" value="Delete"> </form> <form action="/browse" method="post" enctype="multipart/form-data"> <input type="hidden" name="imageid" value="[% ik %]"> Change Image Name: <input name="name" type="text" value="[% image.name|html %]"> <input type="submit" value="Rename"> </form> [% INCLUDE comments.tmpl ik=ik comments=comments %] <form action="/browse" method="post" enctype="multipart/form-data"> <input type="hidden" name="user" value="[% username %]"> <input type="hidden" name="refimageid" value="[% ik %]"> Enter a Comment (as user [% username %]): <input name="comment" type="text"> <input type="submit" value="Comment"> </form> <form action="/browse" method="post" enctype="multipart/form-data"> <input type="hidden" name="refimageid" value="[% ik %]"> Enter Anonymous Comment: <input name="comment" type="text"> <input type="submit" value="Comment"> </form> </li> [% END %] </ul> </body></html>

您可以使用这个模板浏览所有的照片和评论。但是这样做不太有效,而且在拥有数千照片和评论的真实网站中,这个模板几乎肯定会失效。您需要使用 SimpleDB 的优秀的 NextToken 分页模式(在这里 SimpleDB 实用函数没有有效地使用该分页模式)或您自己的工具对照片设置分页,然后只获得将要显示的照片的评论。

您肯定希望只在需要的时候收到评论。SimpleDB 请求的开销很大。因此模板每次都需要将评论传递到 comments.tmpl 模板。

模板使用了 Template Toolkit FOR 循环来遍历(未分类的)照片(如果需要进行分类,最好在 Template Toolkit 环境之外使用 Perl 代码完成这个操作)。这里要求使用照片键来选择与之匹配的评论。对于每张照片,您将显示照片名、URL、S3 状态、所有者。然后显示各种表单来删除照片、修改照片名或以匿名方式或作为用户发布评论。所有操作都很简单。

最后,comments.tmpl 模板和(INCLUDE)一些参数被包含在一起 — ik 是照片键而 comments 是评论列表 — 表示无论模板生成什么内容,都将针对每张照片从照片列表中删除。

comments.tmpl

该模板针对某张照片递归地浏览评论(遍历评论)。

清单 6. 使用 comments.tmpl 遍历评论

[% IF parent %] [% SET thread = comments.$ik.$parent %][% ELSE %] [% SET thread = comments.$ik.noparent %][% END %]<ul>[% FOR ck IN thread.keys %] [% SET comment = thread.$ck %] <li>[% comment.comment %] (by [% IF comment.user %][% comment.user %] [% ELSE %]Anonymous[% END %])<br> <form action="/browse" method="post" enctype="multipart/form-data"> <input type="hidden" name="deletecommentid" value="[% ck %]"> <input type="submit" value="Delete"> </form> <form action="/browse" method="post" enctype="multipart/form-data"> <input type="hidden" name="commentid" value="[% ck %]"> Edit Comment: <input name="comment" type="text" value="[% comment.comment|html %]"> <input type="submit" value="Edit"> </form> <form action="/browse" method="post" enctype="multipart/form-data"> <input type="hidden" name="user" value="[% username %]"> <input type="hidden" name="refimageid" value="[% ik %]"> <input type="hidden" name="refcommentid" value="[% ck %]"> Enter a Comment (as user [% username %]): <input name="comment" type="text"> <input type="submit" value="Comment"> </form> <form action="/browse" method="post" enctype="multipart/form-data"> <input type="hidden" name="refimageid" value="[% ik %]"> <input type="hidden" name="refcommentid" value="[% ck %]"> Enter Anonymous Comment: <input name="comment" type="text"> <input type="submit" value="Comment"> </form> [% INCLUDE comments.tmpl ik=ik comments=comments parent=ck %] </li>[% END %]</ul>

我将最好的、最困难的代码留到了最后。

对于照片键,该模板将查找该照片的所有评论,照片的父元素为一个特定的评论键。

对于相关的每张照片(具有给定的父元素或没有父元素,视情况而定),模板将显示评论本身,紧接着显示 HTML 表单来删除评论、进行编辑或输入新评论(以用户名或匿名的方式)。这与 browse.tmpl 中的表单几乎完全相同,惟一不同的是这里包含了 refcommentid 参数。

接下来是比较棘手的部分,这个模板针对找到的每个评论包含它自身,每次将 parent 设置为评论键的值。因此在伪语言(Template Toolkit)中使用递归,从而在 Perl 下运行的布局语言(HTML)中生成递归。

结束语

这份共 5 部分的系列文章现在已经全部结束。您在本文中了解了完整 mod_perl 站点的模板 — 使用了来自第 2 部分和第 3 部分的内容以及第 4 部分生成的代码。该站点使用 Template Toolkit、S3 和 SimpleDB 提供了照片上传、浏览、编辑、删除以及添加评论功能。

SimpleDB 实用函数,simpledb_utility.zip:temp_10030722238977.zip

样例脚本(来自第 2 部分),s3form.zip:temp_10030722244155.zip

样例脚本(来自第 3 部分),simple_go.zip:temp_10030722253847.zip

时间: 2024-09-12 23:50:35

功能丰富的 Perl: Perl 和 Amazon 云,第 5 部分--了解完整 mod_perl 站点的模板的相关文章

功能丰富的 Perl: Perl 和 Amazon 云,第 4 部分--深入探究完整 mod_perl 站点的代码库

这个共分 5 部分的系列文章向您介绍了如何使用 Perl 和 Apache 构建一个照片共享网站,从而访问 Amazon 的 Simple Storage Service (S3) 和 SimpleDB.在本期文章中,研究完整 mod_perl 站点的代码库,包括如何设置顶级配置.如何使用处理程序,以及如何设置外部依赖关系. 在本期文章中,我们将研究完整的 mod_perl 站点(只讨论代码:模板在下期文章讨论).前几期文章中,我们的节奏有些缓慢,现在,通过研究 mod_perl,我们将加快步伐

Amazon云基础设施采用英特尔芯片

Amazon公司坦言称,目前其云基础设施使用的正是英特尔的芯片.这一声明解开了长久以来困扰技术行业的猜测与疑惑. 这条声明来自本周二于旧金山召开IDF(Intel Developer Forum),此次Amazon史无前例地就其云基础设施处理器问题大谈特谈,并从细节角度重点强调了英特尔产品的卓越功能. Amazon表示引入英特尔芯片的做法是为了满足客户需求,而英特尔方面则指出这项协议是为了推动Amazon云的品牌号召力更上一层楼.不过面对我们提出的问题--AWS对芯片产品的批量性采购是否能获得来

报告称,Amazon云服务成为史上增长最快的企业级

摘要: 美国投行太平洋皇冠证券(Pacific Crest Securities)的最新数据显示, 2014年,Amazon云计算服务(Amazon Web Services, AWS)截至目前的收入已经达到了50亿美元. 这意味着Amazon来自其云计算服务 美国投行太平洋皇冠证券(Pacific Crest Securities)的最新数据显示,2014年,Amazon云计算服务(Amazon Web Services, AWS)截至目前的收入已经达到了50亿美元.这意味着Amazon来自其

功能丰富的 Perl: Perl 和 Amazon 云,第 3 部分--上传图像并创建、编辑和删除评论

这个共分 5 部分的系列文章向您介绍了如何使用 Perl 和 Apache 访问 Amazon 的 Simple Storage Service (S3) 和 SimpleDB,从而构建一个照片共享网站.在本期文章中,通过学习 URL 如何为上传的文件创建 SimpleDB 记录,实现站点与 SimpleDB 的交互.同时了解如何以 SimpleDB 记录的形式创建.编辑.删除某个用户的照片评论. 距离我的上一期文章已经有一段时间了,现在我们来回顾一下: 第 1 部分解释了 S3/SimpleD

功能丰富的 Perl: Perl 和 Amazon 云,第 1 部分--通过构建简单的照片共享网站学习 Amazon S3 和 SimpleDB 服务的基础知识

在这个 5 部分系列文章的第 1 部分中,Ted Zlatanov 解释了 Amazon 的 Simple Storage Service (S3) 和 SimpleDB 产品在构建 Web 站点方面的优势和不足.这个系列通过实际示例形象地介绍了 S3 和 SimpleDB 架构以及如何使用它们:在本文中,将使用 Perl 库构建一个简单的照片共享网站. 您需要学习 Amazon 的两个 Web 服务:Amazon S3 (Simple Storage Service) 和 Amazon Sim

功能丰富的 Perl: Perl 和 Amazon 云,第 2 部分--通过 HTML 表单将数据安全地上传到 S3

这个共5个部分的系列文章将带领您使用 Perl 和 Apache 构建一个简单的照片共享网站,访问 Amazon 的 Simple Storage Service (S3) 和 SimpleDB.在这一期文章中,理解如何通过一个 HTML 表单将一个文件从 Web 页面上传到 S3,最小化服务上的负载,同时维护严格的安全策略. 您可以通过多种方式将文件从一个 Web 页面上传到 Amazon 的 Simple Storage Service (S3): 使用来自 CPAN 的合适的模块从命令行上

教程:如何将Linux应用程序迁移到Amazon云

基础设施即服务(Infrastructure as a Service,IaaS)是一个极好的概念:您使用计算资源并支付费用.需要的资源越多,支付的费用也就越高.这个模式的不足之处在于,您看不到正在使用的计算机,您对那些计算机真的知之甚少.但一旦克服这一点,使用 IaaS 可以带来很多好处. 由于 IaaS 模式与传统的购买服务器的模式差别很大,因此您管理您的虚拟计算机的方法也随之发生改变.这还意味着,您在云中运行应用程序的方式也发生了改变.以前想当然的东西,比如服务器之间无足轻重的延迟,现在不

在线较量:iCloud与Amazon云服务谁强?

在2012年云计算无疑是个非常火爆的话题,即使2011年最火的苹果公司也不能"免俗".在2011年6月7日,苹果在旧金山MosconeWest会展中心召开全球开发者大会(简称WWDC2011)上,正式发布了iCloud云服务,该服务可以让现有苹果设备实现无缝对接.在云计算方面,苹国公司的iCloud只能算是云计算的"新兵",相比亚马逊则在这方面有了很多年的积累,正逐渐走向成熟. 而2012年随着云技术的不断完善,云基础的不断加强,云观念的不断形成等原因,云计算将会迎

如何接入阿里云短信服务 (完整指南)

目录 一.注册并实名认证 二.开通短信服务 三.获取AccessKey 四.设置短信内容 五.配置短信接口 六.发送短信 七.常见问题FAQ 一.注册并实名认证 使用阿里云短信服务,用户需要先在阿里云注册,并完成个人/企业实名认证. 注意:要发送营销短信的用户,必须完成企业实名认证 1.1 注册阿里云:点此注册  1.2 实名认证:点此认证  1.3 绑定企业支付宝: 点击绑定企业支付宝   二.开通短信服务 2.1.开通短信服务:点击开通短信服务 2.2 子账号页面:点击查看子账号页面 2.3