Criando Template com Sitemesh

É 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:

Template Principal

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.

Template Usuário

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.jsp for chamada, esta será decorada pelo decorator usuario.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:

http://github.com/wbotelhos/criando-template-com-sitemesh

Share
  • Rodrigo

    outubro 30th, 2011

    Responder

    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

    Responder

    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

      Responder

      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

    Responder

    Maravilha, agora já estou livre dos include…

    Obrigado novamente.

  • Washington Machado

    abril 23rd, 2011

    Responder

    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

      Responder

      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

    Responder

    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

      Responder

      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 closed

      Achei 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

    Responder

    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

      Responder

      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

    Responder

    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

      Responder

      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

    Responder

    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

      Responder

      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

    Responder

    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

      Responder

      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 ready do 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

    Responder

    Obrigado pela informação e mais uma vez Parabens
    pelo artigo e por todo o site.

    Abraço

  • Felipe Viana

    outubro 19th, 2010

    Responder

    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

      Responder

      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 utilizar c para a JSTL Core, fmt para a Format, fn para a Functions etc.

  • Felipe Viana

    outubro 18th, 2010

    Responder

    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

      Responder

      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

    Responder

    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

      Responder

      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

    Responder

    ” 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

    Responder

    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

      Responder

      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 body ou head que deveria funcionar.

  • Jean Pierre Droguett Cortez

    julho 19th, 2010

    Responder

    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

      Responder

      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>
      

Leave a Comment

* are Required fields