06 Usando tiles com VRaptor3

por Otávio Scherer Garcia

Caso você queira integrar Tiles 2 com VRaptor fazendo com que seja feito forward diretamente para o tiles e não para o JSP (padrão no VRaptor3), basta escrever uma classe que implemente PathResolver com sua convenção. A primeira coisa a fazer é colocar o tiles para responder como servlet. Assim, toda requisição vinda por *.tiles será redirecionada ao tiles, e não ao VRaptor. Lembre-se de colocar a declaração do tiles servlet antes do vraptor filter.

Coloque o seguinte conteúdo no web.xml:

<!-- arquivo de definições do tiles -->
<context-param>
 <param-name>org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</param-name>
  <param-value>/WEB-INF/classes/tiles.xml</param-value>
</context-param>

<!-- servlet de inicialização do tiles -->
<servlet>
  <servlet-name>TilesServlet</servlet-name>
  <servlet-class>org.apache.tiles.web.startup.TilesServlet</servlet-class>
  <load-on-startup>2</load-on-startup>
</servlet>

<!-- servlet que responde as requisições do tiles -->
<servlet>
  <servlet-name>TilesDispatchServlet</servlet-name>
 <servlet-class>org.apache.tiles.web.util.TilesDispatchServlet</servlet-class>
</servlet>

<!-- o tiles responderá por toda requisição *.tiles -->
<servlet-mapping>
  <servlet-name>TilesDispatchServlet</servlet-name>
  <url-pattern>*.tiles</url-pattern>
</servlet-mapping>

No meu caso usei como padrão para o tiles a convenção /package.controller.metodo. Sendo assim criei o seguinte path resolver.

@Component
public class TilesPathResolver
  implements PathResolver {

  static final String VIEW_SUFIX = ".tiles";
  static final String CLASS_SUFIX = "Controller";

  @Override
  public String pathFor(ResourceMethod method) {
      final Class<?> clazz = method.getResource().getType();

      final StringBuilder s = new StringBuilder();
      s.append("/");
      // retorna apenas o nome do último pacote
      s.append(StringUtils.substringAfterLast(clazz.getPackage().getName(), "."));
      s.append(".");
      //remove o sufixo controller
      s.append(StringUtils.substringBefore(clazz.getSimpleName(), CLASS_SUFIX));
      s.append(".");
      s.append(method.getMethod().getName());
      s.append(VIEW_SUFIX);

   // definições do tile em minusculo, mas você pode alterar isso
      return s.toString().toLowerCase();
  }
}

Se você não quiser utilizar a classe StringUtils do projeto commons-lang, você pode alterar o metodo para:

final Class<?> clazz = method.getResource().getType();
String pkgname = clazz.getPackage().getName();

final StringBuilder s = new StringBuilder();
s.append("/");
// retorna apenas o nome do último pacote
s.append(pkgname.substring(pkgname.lastIndexOf(".") + 1));
s.append(".");
//remove o sufixo controller
s.append(clazz.getSimpleName().substring(0, clazz.getSimpleName().indexOf(CLASS_SUFIX)));
s.append(".");
s.append(method.getMethod().getName());
s.append(VIEW_SUFIX);

// definições do tile em minusculo, mas você pode alterar isso
return s.toString().toLowerCase();

Nesse caso se você tiver o controler CustomerController e chamar o método list, a view será redirecionada ao URI /admin.customer.list.tiles, que será executado pelo tiles servlet.

package xpto.admin;

@Resource
public class CustomerController {
  public List<Customer> list() {
      return myServiceClass.listAllCustomers();
      // será redirecionado para a definição admin.customer.list
  }
}
<definition name="admin.customer.list" extends="default">
  <put-attribute name="body" value="/WEB-INF/jspx/admin/customer.list.jspx" />
</definition>

Referências: