Vraptor3 + Velocity

Amigos,

Estou tentando configurar o vraptor para trabalhar com o velocity.
Contudo estou tendo alguns problemas.

1o) só estou conseguindo configurar através do sitemesh

[code]
sitemesh-velocity
com.opensymphony.module.sitemesh.velocity.VelocityDecoratorServlet
10

sitemesh-velocity *.vm [/code]

Qual seria outra forma de se fazer essa configuração sem o sitemesh?
2o) Não estou conseguindo fazer a configuração de templates com o velocity, por exemplo:

[code] Template template = Velocity.getTemplate( “form.vm” );

	VelocityContext context = new VelocityContext();
    context.put("name", "World");[/code]

Dá o seguinte erro:

SEVERE: Servlet.service() for servlet default threw exception br.com.caelum.vraptor.InterceptionException: org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'form.vm' at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:76) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:48) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:72) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:42) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:48) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.util.hibernate.HibernateTransactionInterceptor.intercept(HibernateTransactionInterceptor.java:45) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:46) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:80) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:62) at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91) at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:55) at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454) at java.lang.Thread.run(Thread.java:595) Caused by: org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'form.vm' at org.apache.velocity.runtime.resource.ResourceManagerImpl.loadResource(ResourceManagerImpl.java:483) at org.apache.velocity.runtime.resource.ResourceManagerImpl.getResource(ResourceManagerImpl.java:354) at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1400) at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1380) at org.apache.velocity.runtime.RuntimeSingleton.getTemplate(RuntimeSingleton.java:305) at org.apache.velocity.app.Velocity.getTemplate(Velocity.java:383) at br.com.lojavirtual.controller.IndexController.form(IndexController.java:34) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:50) ... 40 more

Na linha:

Na parte do código “form.vm” já tentei fazer de outras formas (“WEB-INF/jsp/index/form.vm”, etc)

tenta fazer o seguinte:

nos arquivos de template use a convenção do VRaptor substituindo jsp por vm (/WEB-INF/vm/<nome_do_controller>/<nome_do_metodo>.vm)

crie a classe:

	@Component
	public class VelocityPathResolver extends DefaultPathResolver {
		protected String getPrefix() {
			return "/WEB-INF/vm/";
		}
		
		protected String getExtension() {
			return "vm";
		}
	}

registre o filtro do velocity antes do filtro do vraptor…

não carregue o arquivo do velocity na mão… o filtro dele deve fazer isso…

acho que isso deve resolver uma parte dos problemas… fala o que ficou faltando,por favor?

[quote=lucascs]tenta fazer o seguinte:

registre o filtro do velocity antes do filtro do vraptor…

não carregue o arquivo do velocity na mão… o filtro dele deve fazer isso…

acho que isso deve resolver uma parte dos problemas… fala o que ficou faltando,por favor?[/quote]
Olá Lucas,
Ok, vamos por partes.
Já implementei o VelocityPathResolver, já coloquei o filter e chamando normalmente os metodos do controler, ele já está renderizando “quase” corretamente minha página.

Eu tenho o seguinte metodo:

[code] @Get
@Path("/index/index")
public void index() throws Exception {

	VelocityContext context = new VelocityContext();
	context.put("name", "World");

}

[/code]
E quero que na view, essa variavel $name seja exibida como World.
Atualmente, na hora de renderizar a página deste metodo, está renderizando $name, embora o velocity em si, esteja funcionando (consigo fazer
#foreach($i in [1…5]) $i #end na página por exemplo).
Obviamente deve estar faltando codigo nesse meu metodo acima.

*ps: sei que poderia facilmente obter essa variavel atraves do result.include(“name”, “world”), mas gostaria de trabalhar com o velocity para estudar outras implementações.
Alguma dica?

com o result.include funciona?

o problema desse new VelocityContext() é que ele não tem nenhuma relação com o context que será usado no filter para mostrar de fato o template…

pra isso funcionar vc precisaria do acesso ao context usado no filtro…

se vc não for fazer nada além de context.put, usa o result.include mesmo… se vc for precisar fazer outro tipo de configuração no velocity (que não dá pra fazer nos parâmetros do filtro) vc vai ter que implementar umas coisinhas no vraptor pra que seja usado o mesmo context em todo lugar…

[quote=lucascs]com o result.include funciona?
[/quote]

Funciona! :lol:
Fiquei na duvida, mas testei agora e funciona.

O que eu precisaria implementar?

Precisa fazer algum código de infraestrutura… Se o filtro + aquele VelocityPathResolver já é o suficiente, vc não deve
criar código a mais de infra…

mas enfim… a infra seria algo do tipo:

  • Uma classe que cria o VelocityContext e disponibiliza pra todas as classes. Essa classe vai ser um ComponentFactory:
@Component
public class VelocityContextFactory implements ComponentFactory<VelocityContext> {
    private VelocityContext context = new VelocityContext();
    public VelocityContextFactory() {
         //configurações no context;
    }

    public VelocityContext getInstance() {
          return context;
    }
}

Assim vc pode receber um VelocityContext no construtor de qualquer classe do sistema (anotada com anotações do VRaptor)

  • criar um interceptor que renderiza o template na mão. Esse interceptor vai receber o VelocityContext no construtor e usá-lo
    para renderizar o template e mostrar na tela… Não vou colocar o código aqui, seria o código que está dentro do filtro do Velocity…

Lucas,

Criei o VelocityContextFactory , já coloquei no meu controller e inicializei no contrutor.
Já criei o interceptor que recebe este velocityContext também.
Só não entendi como ele vai renderizar o template (nem entendi o que vc quiz dizer sobre 'codigo que está no filtro do velocity).
Ficou assim:

[code]@Intercepts
@RequestScoped
public class VelocityInterceptor implements Interceptor{

Logger log = Logger.getLogger(getClass());

private final VelocityContext velocityContext;

public VelocityInterceptor(VelocityContext velocityContext) {
	this.velocityContext = velocityContext;
}

public boolean accepts(ResourceMethod arg0) {
	return true;
}

public void intercept(InterceptorStack stack, ResourceMethod method, Object resourceInstance) throws InterceptionException {
	velocityContext.put("valor", "Testando");
	stack.next(method, resourceInstance);
}

}
[/code]

aquele filtro que vc colocou no web.xml que roda Velocity…

NÃO faça a renderização do template na mão, se o filtro for suficiente…

o interceptor seria algo do tipo: (lembrando que vc não deveria fazer isso na mão)
(corrija os erros de compilação )

@Intercepts
public class VelocityInterceptor {
 
    public VelocityInterceptor(PathResolver resolver, Result result, VelocityContext context, HttpServletResponse response) {
         this.resolver = resolver;
         this.result = result;
         this.context = context;
         this.response = response;
    }


    public boolean accepts(...) { return true;}

    public void intercept(stack, method, instance) {
         stack.next(method, instance);

         if (!result.used()) {
              String path =resolver.pathFor(method);
              Template template = velocity.getTemplate(path);
               //não sei qual é o método certo, mas vai ser algo do tipo:
               template.render(response.getOutputStream());

              result.use(Results.nothing());
         }
    }
}