 | Nível: Intermediário Teodor ZlatanovGold Software Systems
23/Jun/2009 Esta
série em cinco partes
percorre a construção de um Web site simples de compartilhamento de fotos usando Perl e Apache para acessar Simple Storage Service (S3) e SimpleDB da Amazon. Nesta parte, examine o modelo integral do site mod_perl , incluindo um para indexação, três para upload (geral, formulários do S3 e inclusões de URL), um para navegação de imagens e comentários e um para navegar por comentários de forma recursiva para uma imagem (ou usando thread).
Nesta última parte, prepare-se para testemunhar um site
mod_perl integral (modelos desta vez; o código base está na
Parte 4).
Novamente, incentivo muito a leitura do código de origem. O site é funcional, mas muitos detalhes não estão integralmente explicados nesta série, pois espero que você os entenda ou possa aprender o que não entendeu. Sua livraria local ou remota e mecanismos de procura são seus amigos.
 |
Para Obter o Máximo desta Série
Esta série requer conhecimento de nível principiante de HTTP e HTML, assim como conhecimento de nível intermediário de JavaScript e Perl (em um processo mod_perl Apache). Algum conhecimento de bancos de dados relacionais, armazenamento em disco e redes será útil.
A série é relativamente técnica, portanto, consulte a seção
Recursos se precisar de ajuda com qualquer um desses tópicos.
|
|
Especificamente, configurar um site mod_perl integral e usar o Template Toolkit são tópicos amplos, portanto, não vou explicar tudo nesta série. A melhor maneira de aprender é trabalhar cada questão e obstáculo até o site estar em execução. Lembre-se, eu dei o motor, as rodas, o chassi, etc.—agora, você precisa por gasolina e colocar o carro na estrada.
Uso share.lifelogs.com nesta série como o nome de domínio. Lembre-se de alterá-lo conforme necessário para seu próprio ambiente.
index.tmpl
Vamos iniciar com os modelos (
policy.tmpl descendentes que foram discutidos na Parte 4).
Para obter explicações sobre a sintaxe do Template Toolkit, consulte a seção
Recursos . Vou tentar explicar as pegadinhas.
O index.tmpl é uma página HTML simples.
A única coisa a observar aqui é que todos os URIs são relativos, de forma que este e todos os outros modelos funcionarão com qualquer domínio.
Lista 1. O index.tmpl, HTML simples
<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 lots
of money you're trying to get out of Nigeria. The breath
is <strike>baited</strike>bated.
</address>
</body>
</html>
|
upload.tmpl
Agora, estamos prontos para a parte boa. Linguagem JavaScript, HTML e Template Toolkit em um local.
Se isso não faz um designer da Web chorar, não sei o que fará.
Lista 2. O upload.tmpl, o suficiente para fazer um Web designer derramar lágrimas de alegria
<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>
|
A página de upload mostra dois diálogos de upload. Ambos incluem uma imagem, mas o segundo é muito mais simples.
No segundo, o usuário preenche a URL e o nome para a imagem e isso é
POSTado em
/urluploaded, que é apenas
urluploaded.tmpl. O manipulador de parâmetro de imagem será chamado automaticamente quando esse modelo for exibido.
O nome de usuário é obtido do servidor e é um parâmetro
POST oculto no formulário.
O primeiro formulário é o realmente complicado. Felizmente, você pode ler a
Parte 2 desta série, que explicou tudo sobre uploads do S3, portanto, não deve estar surpreso com nada disso.
As principais mudanças em s3form.pl com relação à Parte 2 (e novamente incluídas na seção
Downloads ):
success_action_redirect passa o nome de usuário e o nome de imagem como parâmetros.
A política é ajustada para requerer somente uma parte dessa cadeia de caracteres, até o nome de usuário, mas sem incluir o nome.
- A política e a assinatura são passadas a partir do servidor.
- As chaves de acesso e secreta de AWS são passadas no hash
env a partir do servidor.
- A função
OnSubmitForm requer um nome inclui o mesmo no campo de formulário
success_action_redirect
como um parâmetro, escapado (observe que o nome é pedido
antes do tipo MIME ser determinado, mas é incluído na URL somente
imediatamente antes do formulário ser
POSTado).
- A função
OnSubmitForm falha com categoria se o tipo MIME não puder ser localizado, permitindo que os usuários especifiquem seu próprio.
s3uploaded.tmpl
Em um upload do S3, esse modelo é usado.
Lista 3. O s3uploaded.tmpl para uploads bem e mal sucedidos
[% 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>
|
Através de algumas construções IF-ELSE
desagradáveis do Template Toolkit e do parâmetro result , a página trata de uploads bem e mal sucedidos. O êxito está relacionado à inclusão de
SimpleDB; a imagem sempre foi transferida por upload para o S3, se chegar a este ponto.
Retroceder a imagem do S3 em uma falha do SimpleDB é deixado como um exercício para o leitor (hua hua).
urluploaded.tmpl
Em uma inclusão de URL, esse modelo é usado.
Lista 4. O urluploaded.tmpl, o sonho de reutilização do código
[% 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>
|
Além do HTML obviamente inválido, isso é semelhante a s3uploaded.tmpl.
A reutilização de código, obviamente, não é um problema no mundo dos sonhos deste escritor.
browse.tmpl
Esse modelo navega por imagens e comentários.
Lista 5. O browse.tmpl, imagens e comentários de uma vez
[% 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>
|
Com isso, você obtém todas as imagens e comentários de uma vez. Isso não é eficiente e muito provavelmente falhará de forma terrível em um Web site real, assim que tiver alguns milhares de imagens e comentários nele.
É necessário configurar paginação para as imagens usando o belo esquema de paginação NextToken do SimpleDB (que as funções de utilitário SimpleDB apresentadas aqui não usam de forma eficiente) ou algo próprio e, então, apenas obter os comentários para as imagens que você está prestes a exibir.
Você realmente deseja evitar a obtenção de comentários, a menos que realmente precise deles. Os pedidos do SimpleDB são caros.
É por isso que esse modelo passa os comentários para o modelo comments.tmpl todas as vezes.
O modelo usa um loop FOR Template Toolkit para iterar as imagens, não classificadas (se precisar de classificação, é melhor que o código Perl faça isso fora do ambiente Template Toolkit). A chave da imagem é necessária aqui para selecionar os comentários que correspondem a ela.
Para cada imagem, são mostrados o nome da imagem, a URL, o status do S3, o proprietário.
São então mostrados formulários para excluir a imagem, alterar seu nome ou postar um comentário de forma anônima ou como um usuário.
É bem direto.
Por fim (bem, no meio, mas não pensamos de forma linear, certo?), o modelo comments.tmpl tem INCLUDE efetuado com alguns parâmetros
—ik é a chave da imagem e
comments é a lista de comentários—o que significa que o que o modelo gerar será solto bem no meio da lista de nossas imagens para cada imagem.
comments.tmpl
Esse modelo navega por comentários de forma recursiva por uma imagem (usando thread).
Lista 6. Usando thread com o 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>
|
Guardei o código melhor e mais desagradável por último.
Considerando uma chave de imagem, esse modelo localiza todos os comentários para a imagem cujo pai é igual a de uma chave de comentário específica.
Para cada comentário de interesse (com o pai em questão ou sem um pai, conforme o caso), o modelo mostra o comentário em si seguido pelos formulários HTML para excluir o comentário, editá-lo ou inserir um novo comentário (sob um nome de usuário ou de forma anônima).
São praticamente iguais aos formulários de
browse.tmpl, exceto por incluírem um parâmetro refcommentid
.
Agora, e esta é a parte complicada ou horrível, dependendo de se você meramente estuda Ciência da Computação ou ensina, esse modelo inclui ele mesmo novamente para cada comentário que localizar, configurando
parent para o valor da chave de comentário toda vez.
Portanto, há recursão em uma pseudo-linguagem (Template Toolkit) para gerar recursão em uma linguagem de layout (HTML) em execução sob Perl.
Conclusão
Esta série em cinco partes está completa. Agora, você viu os modelos para um site
mod_perl integral—usando os trechos que gravamos nas Partes 2 e 3 e o código gerado na Parte 4. Este site usa o Template Toolkit, S3 e
SimpleDB para fornecer uploads de imagens, navegação, edição, exclusão, assim como inclusão de comentário (anônimo ou não), navegação (com thread) e exclusão.
Downloads | Descrição | Nome | Tamanho | Método de download |
|---|
| SimpleDB utility functions | simpledb_utility.zip | 3KB | HTTP |
|---|
| Sample script (from Part 2) | s3form.zip | 2KB | HTTP |
|---|
| Sample script (from Part 3) | simple_go.zip | 4KB | HTTP |
|---|
Recursos Aprender
- Inicie com
"Perl Elaborado: Perl e a Nuvem Amazon, Parte 1"
(developerWorks, março de 2009) para entender os benefícios e desvantagens de usar S3 e SimpleDB da Amazon para construção de Web site. Continue então com a
Parte 2 (abril de 2009) para fazer upload de um arquivo para o S3 a partir de uma página da Web através de um formulário HTML para minimizar a carga no servidor, a Parte 3 (junho de 2009) para fazer upload de imagens através de URLs em uma tabela e gerenciar imagens e comentários e a Parte 4 para percorrer o código base do site integral.
- Detalhes da oferta de serviço e recursos para desenvolvedores estão em Amazon.com:
- Aprenda sobre o incrível
JavaScript MimeType, uma propriedade do objeto navegador, um objeto de nível superior que é a representação de objeto do navegador da Internet do cliente ou do programa navegador da Web que está sendo usado.
-
mod_perl reúne todo o poder de Perl e do Apache HTTP Server.
-
Prototype é uma estrutura JavaScript que facilita o desenvolvimento de aplicativos da Web dinâmicos através de um kit de ferramentas para desenvolvimento orientado por classes e a biblioteca Ajax "mais legal" do mundo. E há um excelente artigo sobre como usá-lo:
"Developer Notes for prototype.js" de Sergio Pereira.
- Sim, Virgínia, é um serviço baseado na Web e, portanto, pode sofrer
interrupções; uma consideração importante.
- Computação em nuvem com serviços da Amazon é um tópico interessante.
Esta série é sobre como acessar os serviços usando Perl, mas para obter uma visão geral mais ampla das ofertas, leia a série
"Computação em Nuvem com Serviços da Web da Amazon"
(developerWorks, julho de 2008 - fevereiro de 2009).
-
Na
zona do Linux do developerWorks, encontre mais recursos para desenvolvedores do Linux e verifique nossos
artigos e tutoriais mais populares.
-
Consulte todas as
dicas do Linux e
tutoriais do Linux no developerWorks.
-
Permaneça atualizado com os
eventos técnicos e Webcasts do developerWorks.
Obter produtos e tecnologias
- Visite CPAN para downloads, listas de módulos e documentação sobre o
Template-Toolkit-2.20, um kit de construção rápida de modelo. O'Reilly lançou um livro,
Perl Template Toolkit
, escrito pelos principais membros da equipe de desenvolvimento ta tecnologia.
- No site
CPAN (Comprehensive Perl Archive Network)
, é possível encontrar uma quantidade enorme de módulos. E documentação de módulos.
-
S3Fox, o Organizador FireFox do Amazon S3,o complemento de gerenciamento do S3 para Firefox, coloca um front end de fácil utilização no S3.
-
Com o
software de avaliação da IBM, disponível para download diretamente a partir do developerWorks, construa seu próximo projeto de desenvolvimento no Linux.
Discutir
-
Envolva-se com a
comunidade My developerWorks; com seu perfil pessoal e página inicial customizada, é possível padronizar o developerWorks para seus interesses e interagir com outros usuários do developerWorks.
Sobre o autor  | |  | Teodor Zlatanov surgiu com um Mestrado em Ciências em engenharia da computação da Boston University em 1999. Trabalha como programador desde 1992, usando Perl, Java, C e C++. Seus interesses estão em trabalho em análise de textos de software livre, arquiteturas de banco de dados, interfaces com o usuário e administração do sistema UNIX. |
Avalie esta página
|  |