É comum trabalharmos com includes em nossas páginas para evitarmos a repetição de códigos que não serão alterados. Essa com certeza é uma ótima solução, mas já pensou se tivéssemos 100 páginas? Todas elas precisariam de includes, estes em sua maioria iguais. Então por que não automatizar isso?
Para essa tarefa temos alguns web-page layouts como o Tiles famoso no mundo Struts, o Facelets do mundo JSF e o Sitemesh, que se destaca por ser simples e poderoso.
Objetivo:
Criar alguns templates (decorators) com diferentes configurações utilizando o Sitemesh para automatizar a inclusão (decoração) de nossas páginas.
Para servir de decorator podemos aproveitar o layout do artigo “Criando Layout com CSS“, assim veremos como aplicar o Sitemesh e seus benefícios.
Criando o esboço dos templates:
Criaremos 2 (dois) diferentes decorators, principal.jsp e usuario.jsp:

O decorator principal.jsp composto por quase todos os número, menos o 4 que será o conteúdo dinâmico, será o decorator default do sistema, que irá decorar as páginas requisitadas.

O decorator usuario.jsp com o container número 3 sendo a parte dinâmica, será um decorator alternativo, no qual teremos opção de incluí-lo no lugar do default.
Para comerçarmos as configurações vamos baixar a última versão do Sitemesh no site oficial e adicionar a lib sitemesh-2.x.x.jar na pasta WEB-INF/lib do nosso projeto.
Ativando o Sitemesh (web.xml):
<filter> <filter-name>sitemesh</filter-name> <filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class> </filter> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
No nosso arquivo web.xml indicamos qual é o filtro responsável por decorar nossas páginas requisitadas e qual o padrão de URL que será interceptada. Repare que poderíamos colocar /*.jsp, porém estaríamos amarrados a este padrão, então deixamos interceptar tudo a princípio e refinamos isso mais tarde.
Flexibilidade de configuração:
O Sitemesh não nos obrigam a especificar um caminho completo, até a estensão do arquivo, isso nos da uma maior flexibilidade, pois podemos fazer regras baseado em apenas uma parte da URI. Pra quem trabalha com frameworks que desfrutam de URIs amigáveis como o VRaptor, pode fazer regras no seguinte estilo:
/*/exibir/*: http://localhost:8080/usuario/exibir/1/*?_format=json*: http://localhost:8080/usuario/loadByAjax/1?_format=json
Configurando os decorators (decorators.xml):
Este arquivo que também se encontra dentro da pasta WEB-INF manterá toda nossa lógica de decoração.
<decorators defaultdir="/decorators"> <decorator name="principal" page="principal.jsp"> <pattern>/*</pattern> </decorator> <decorator name="usuario" page="usuario.jsp"> <pattern>/usuario.jsp</pattern> </decorator> </decorators>
- Primeiro indico o diretório onde se encontra meus decorators através do atributo
defaultdir. Isso evita a repetição desse caminho; - Depois coloco minha primeira regra de decoração dizendo que qualquer tipo de URL acionada terá seu conteúdo decorado por
principal.jsp. Também dou um nome para esta regra, isso é necessário; - Outra regra especializada falando que se a página
usuario.jspfor chamada, esta será decorada pelo decoratorusuario.jsp.
Bem, nossa configuração esta pronta, mas precisamos agora criar os decorators.
De acordo com o exemplo do artigo “Criando Layout com CSS” a única coisa que irá mudar será o conteúdo dinâmico, pois agora não podemos simplesmente colocar em tal container um include fixo desta forma:
<div id="sub-conteudo"><%@ include file="/index.jsp" %></div>
Sem utilizar uma solução mais primitiva que passei nesse comentário, o Sitemesh nos possibilita a inclusão do conteúdo requisitado diretamente da seguinte forma:
<div id="sub-conteudo"><decorator:body/></div>
Isso faz com que o body da página requisitada seja capturado e incluído em nosso decorator, e em vez de ser renderizada a página requisitada, é renderizado o decorator com este conteúdo incluso, e esta é a mágica.
Temos outras tags de inclusão mais utilisadas como:
<decorator:title default="Título padrão"/>: Captura o título da página interceptada; e<decorator:head/>: Captura o cabeçalho.
Você pode deixar suas páginas sem os conteúdo <head/>, e o colocando diretamente no decorator. Se sua página não tiver nem mesmo a tag <body/> toda a página será considerada body.
Trabalhando com excludes:
Também podemos criar regras para evitar a decoração, sendo útil principalmente para conteúdos requisitados via ajax nos formatos JSON ou XML, já que ambos não podem conter nada mais além do que seus dados bem formados.
<excludes>
<pattern>/sobre.jsp</pattern>
<pattern>/*/exibir*</pattern>
<pattern>/*?exclude*</pattern>
</excludes>
Desta forma sempre que for chamado a página sobre.jsp nenhuma decoração será acionada.
Podemos utilizar o caracter * (asterisco) para indicar qualquer coisa em seu lugar e criar um padrão de exclusão.
Podemos também utilizar os nomes de parâmetros para indicarmos uma exclusão, no caso optei por sempre evitar a decoração quando houver o parâmetro chamado exclude, desta forma evito de escrever todas as combinações de URIs que quero excluir, deixando essa decisão ser feita diretamente em minhas páginas.
Chamadas com retorno em formato JSON ou XML sempre são excluídas, então um parâmetro ajuda muito, pois precisamos apenas adicioná-lo para capturarmos o conteúdo puro sem o código adicional dos decorators.
No site do Sitemesh você encontra algumas outas configurações, mas posso te garantir que para a maioria das aplicações você não precisará mais do que isso. (:
Veja o Sitemesh funcionando em: http://moviecollection.com.br
Link do projeto:
Rodrigo
outubro 30th, 2011
Não, a dúvida era só qual versão usar em um projeto iniciando, mas estou usando a versão 2 mesmo. Valeu!
Rodrigo
outubro 1st, 2011
Parece que o sitemesh morreu, não há updates desde fevereiro.
Alguma sugestão? Usar o a versão antiga? outro framework semelhante?
wbotelhos
outubro 8th, 2011
Oi Rodrigo,
Estão criando a versão nova do Sitemesh sim, a versão 3: http://www.sitemesh.org.
Existem alernativas como o FreeMaker, mas pessoalmente gosto do Sitemesh e enquando ele atender minhas necessidades que é simplesmente decorar estará de ótimo tamanho. (:
Você encarou algum problema? Precisou de algo além?
Washington Machado
abril 23rd, 2011
Maravilha, agora já estou livre dos include…
Obrigado novamente.
Washington Machado
abril 23rd, 2011
Realmente era só inverter a declaração do filtro no xml… já que funcionou vou ficar na versão 2 por ora.
Há alguma explicação pra termos que inverter essa declaração do filtro?
Obrigado pela ajuda.
[]s
wbotelhos
abril 23rd, 2011
Oi Washington,
O filtro do Sitemesh deve vir primeiro, pois se o VRaptor capturar a requisição o Sitemesh não terá mais oportunidade de decorar, pois ele não reconhece o dispatcher do VRaptor.
Washington Machado
abril 23rd, 2011
Estou precisando de uma dica… o decorator funciona aqui para qualquer página do diretório web, acredito que equivalente ao WebContent do eclipse (estou usando Netbeans).
Mas esse mesmo projeto usa Vraptor e não consigo que o decorator renderize para as páginas que estão em web/WEB-INF/jsp/*, tem alguma dica de como posso arrumar?
Obs.: no meu projeto uso a versão 2.4.1 do sitemesh que retirei do seu exemplo.
—————————————————————-
Notei que a página de download do sitemesh está fora do ar e a versão 3.0-alpha2 está disponível em sitemesh.org. Você chegou a testar esse beta? Se sim, o que achou?
Obrigado.
wbotelhos
abril 23rd, 2011
Oi Washington (xará),
Nunca usei o VRaptor no Netbeans junto com o Sitemesh, mas deveria decorar, já que o Sitemesh pega o resultado em tempo de execução. Verifica se o mapeamento do Sitemesh esta escrito primeiro que o do VRaptor no web.xml.
Acabei de testar a versão 3.0-alpha2 e me parece que ela gera uma exception com o provider de transação, que é um interceptor, da JPA:
java.lang.IllegalStateException: EntityManager is closedAchei a declaração de tag mais burocrática;
O XML é mais poderoso em suas configurações, além de ser possível configurar via Java;
É legal não precisar mais de importar a taglib, apesar do Eclipse ficar apresentando um warning de unknow;
Gostei do novo nome sitemesh3.xml, mas poderiam tirar o número da versão pra ficar mais genérico.
Acho que vou ficar na versão 2 até que a 3 esteja estável. (:
Dev.softhouse
março 31st, 2011
Bom dia Botelhos tudo bem?
To olhando seus posts e vi que vc tem bastante coisa da camada de apresentação, to fazendo uma sistema usando VRaptor e as regras de negócio e a estrutura do programa está saindo, mas com relação a camada de apresentação to vendo que ela está muito pobre, gostaria de saber se posso empregar essas técnicas no meu projeto (se são compatíveis com o VRaptor) e também quais vc recomenda.
Eu queria chamar um Form de dentro de outro form como acontece em aplicações desktop onde temos que fazer isso para buscar um item que depende de outro no banco de dados.
wbotelhos
abril 2nd, 2011
Oi Dev,
O VRaptor é a parte Java, ou seja, o backend da sua aplicação, logo ele é totalmente compatível, pois são duas coisas diferentes.
Eu gosto de usar o jQuery UI junto com layouts criados com CSS mesmo. Ele já vem com estilos de barra 3D, janelas modais, ícones, barra de loading, efeitos e tudo mais que se fóssemos criar na mão daria mais trabalho.
Para buscar estes dados você já pode listá-los em uma combobox restringindo o tamanho da mesma para o usuário fazer um scroll. Ou você pode fazer um campo de consulta usando autocomplete.
No http://www.moviecollection.com.br eu busco os artistas e diretores para adicioná-los no filme dessa forma e não sobrecarrega o servidor, já que pode ser configurado para a busca ser feita só a partir de tantos caracteres digitados e com um intervalo de tempo para não haver várias requisições.
Felipe
novembro 15th, 2010
Boa noite,
Tenho um projeto o qual uso dois decoradores
o principal.jsp que irá decorar todas as urls /*
e outro que irá decorar apenas jsps espedificos
que estão dentro de uma pasta no contexto do meu projeto, porém ao configurar este segundo decorador com a pattern \pasta\* ,
ele não renderiza como devia ,
se alguem puder ajudar agradeço…
wbotelhos
novembro 16th, 2010
Oi Felipe,
Qual URI exatamente você tentou acessar?
Como esta o mapeamento do seu decorators.xml?
Vou deduzir que utilizou literalmente, “\pasta\*”, e o restante esta tudo correto.
Então o problema pode ser a barra invertida. tenta mapear da seguinte forma:
<decorator name="secundario page="secundario.jsp"> <pattern>/pasta/*</pattern> <!-- barra normal --> </decorator>Henrique
novembro 4th, 2010
Olá cara!
vlw por responder!
mais surgiu outra dúvida aqui!
então se eu quiser que o javascript funcione apenas em uma pagina específica que eu carregar , o javascript é declarado em cada jsp, ou só posso declarar no frame.jsp?
wbotelhos
novembro 4th, 2010
Henrique,
Neste caso você deve escrever ou importar o JS diretamente em cada página específica.
Se você colocar o script no decorator, todos as outras páginas irão compartilhá-lo.
Henrique
outubro 29th, 2010
Cara estou tentando por um javascript para fazer uma máscara no campo de data de um formulário, mais não tá funcionando com o sitemesh, só contigo fazer funcionar, com um arquivo html fora do projeto. Existe alguma configuração para o sitemesh aceitar esse tipo de código?
Parabéns pelo site!
wbotelhos
outubro 29th, 2010
Oi Henrique,
O javascript funciona normalmente no decorator do Sitemesh.
Inclusive a cada refresh o decorator é recarregado e o javascript é executado novamente.
Verifique se seu script esta dentro de uma função
readydo jQuery para que ele seja executado somente após a página estar carregada, já que para aplicar a máscara o elemento HTML deve estar carregado:<script type="text/javascript"> $(function() { // Seu código que necessita do elemento existir para ser executado corretamente. }); </script>Felipe Viana
outubro 19th, 2010
Obrigado pela informação e mais uma vez Parabens
pelo artigo e por todo o site.
Abraço
Felipe Viana
outubro 19th, 2010
Obrigado , ja consegui configurar, o meu erro era que
tinha esquecido de colocar a taglib para o meu principal.jsp.
Podes me explicar para que serve ela ?
e por que o “prefix=”decorator” ?
Grato
Obrigado
wbotelhos
outubro 19th, 2010
Oi Felipe,
A taglib é o import da biblioteca do Sitemesh. Sem ela você não consegue chamar as funcionalidades do Sitemesh.
O atributo
prefixé o nome pelo qual você irá invocar essas funcionalidades.Pode ser qualquer nome, mas por convenção
decoratoré o nome utilizado, assim como utilizarcpara a JSTL Core,fmtpara a Format,fnpara a Functions etc.Felipe Viana
outubro 18th, 2010
Parabens pelo Artigo…
Sou iniciante em Java para Web e estou com dificuldades para configuração do ambiente elcipse com o Sitemesh.
Se puder ajudar ficarei grato.
Tenho que instalar algum plugin ?
Estou com o Eclipse Ganymede
Grato Felipe Viana
wbotelhos
outubro 18th, 2010
Oi Felipe,
Você não precisa de instalar nenhum plugin.
Basta colocar a lib do Sitemesh na pasta lib, mapear o filtro dele no web.xml e criar o decorator.xml para criar as regras.
Tudo que é necessário para que ele funcione esta descrito no artigo.
Qual exatamente é o seu problema?
Facundo
outubro 1st, 2010
Muito obrigado amigo, desculpa a demora, aconteceu que tive que deijar aquele projeto para fazer um outro mais urgente. Aquele problema eu solucionei de um outro jeito. Com PageDecoraterMapper nessa explicação http://tim.oreilly.com/pub/a/onjava/2004/09/22/sitemesh.html?page=3 (adicionando un attributo no META tag que diz a que decorator correponde a pagina ) Ainda assim o que vocei falou me ajudo com outro problema que tive ahora com uma pagina na cual estava usando ajax . Agreguei aquele parametro em cada link no href gerado por javascrypt e funcionou. Obrigado amigo,
wbotelhos
outubro 1st, 2010
Oi Facundo,
Nunca testei o Sitemesh no Struts para ver se de fato se faz necessário o
PageDecoraterMapper.Eu prefiro deixar as configurações centralizadas no decorators.xml e evitar criar o sitemesh.xml e sair distribuindo meta tag. Mas se dessa forma resolveu, que bom! Fica a dica ai para futuros problemas com o Struts. :)
Muito obrigado pelo feedback.
Abraço.
Facundo
agosto 24th, 2010
” Outra cosa , dixei o “jsp:include” por que o “decorator:body” no esttava carregando nada, não ta faltando alguma coisa, como carregar os tags do sitemesh nos decorators alguma coisa assim?
Facundo
agosto 24th, 2010
OI W, muito bom suas dicas, sou iniciante e meu idioma é o espanhol assim que disculpe meu portugês se esta errado. O problema com este método no meu caso é que no topofilme no layout “principal” eu coloquei um FormBean do struts para o acceso, um a vez validado pasaria ao layout de usuario, mas eu tenho que colocar que exclua *.do, se não no permite o foward do struts, fica no principal. Fazendo isto,ainda assim não consigo carregar o layout de usuario no caso de validacion exitosa. Outra cosa , dixei o por que o no taba carregando nada não ta faltando alguma coisa, como carregar os tags do sitemesh nos decorators alguma coisa assim?
wbotelhos
agosto 26th, 2010
Oi @Facundo,
Seu problema possa estar na URL que você esta usando para fazer sua action e seu forward.
Quando você precisar de fazer uma action, inclua um parâmetro que esteja mapeado como exclude, na URL para evitar que o Sitemesh intercepte esta ação.
Você pode usar por exemplo:
<excludes> <pattern>/*?exclude*</pattern> </excludes>Então você não precisará fazer *.do e generalizar sua exclusão, fazendo esta exclusão manualmente quando necessário.
Verifique se a lib esta no projeto, depois se você a declarou no topo do seu decorator, depois é só adicionar a tag
bodyouheadque deveria funcionar.Jean Pierre Droguett Cortez
julho 19th, 2010
Washington parabens pelo trabalho … to tentando implementar aqui em um projeto
que estou fazendo ..e o design que eu tinha em mente é praticamente o
mesmo que vc definiu porem sem a sessao da direita … só que eu to
com um problema ao implementar o sitemesh …
no menu superior eu tenho uns botões que eu chamo de modulos e de
acordo com o modulo que o cara esta (quando ele clica em um modulo) o
menu da esquerda tem que mudar de acordo com o modulo selecionado e as
permissoes de usuario .. eu fazia isso via ajax porem com o uso de
decorators tudo ficou um pouco mais dificil .. e nao tenho a menor
idéia de como implementar isso no sitemesh.
Ex: quando o cara clica no Usuario no menu do lado aparece Cadastrar
Usuario, Buscar Usuario, Alter Usuario
quando o cara clica em Membro no menu do lado aparece Cadastrar
membro, bucar Membro e por ai vai
Cara me da uma luz por favor
Att,
wbotelhos
julho 19th, 2010
Fala Jean,
Para cada tela diferente, você precisa criar um decorator.
Se cada tela o menu da esquerda irá mudar, no seu decorator, você muda isso também atravéz do
import, ou seja, cada decorator irá importar um página (menu) diferente:decorators/membro.jsp: (o import do menu será o menuMembro.jsp)
decorators/usuario.jsp: (o import do menu será o menuUsuario.jsp)
Depois só adicionar a regra no decorator.xml:
<decorator name="usuario" page="usuario.jsp"> <pattern>/usuario.jsp</pattern> </decorator><decorator name="membro" page="membro.jsp"> <pattern>/membro.jsp</pattern> </decorator>