Dificuldades com VRaptor + Rest

22 respostas
guilhermehkr

Boa noite,

estou conhecendo VRaptor em um projeto que desenvolvo no momento, porém estou tendo dificuldades em ligar com Rest.

Eu não sei bem ao certo se estou fazendo as coisas correto, porém ai vai o que pensei em fazer:

  • preciso fazer um aplicativo que tenha um campo para busca, por exemplo, e que o que o visitante digitar neste campo apareça na URL após o nome do contexto, por exemplo:

Página principal: localhost:8089/aplicativo

Após digitado “java” pelo visitante no campo de busca

próxima página: localhost:8089/aplicativo/java

Eu estou usando o @Path, mas não estou obtendo o resultado esperado.
Segue os códigos

@Resource
public class VisitanteController {
	
	private VisitanteDao visitanteDao;
	private Result result;
	
	public VisitanteController(VisitanteDao visitanteDao, Result result) {
		this.visitanteDao = visitanteDao;
		this.result = result; 
	}

	@Path("/")    /* Tento fazer com que o endereço localhost:8089/aplicativo já chame este método e a página formulario.jsp*/
	public void formulario() {
	}
	
	@Put
	@Path("/{comentario.palavraChave}")
	public void processarFormulario(Visitante visitante, Comentario comentario) {
		System.out.println(comentario);
		System.out.println(visitante);
	}
}
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
		<link rel="stylesheet" type="text/css" href="css/estilo.css">
		<title>Blog</title>
	</head>
	<body>
		<form id="formPrincipal"  method="put" action="<core:url value="/${comentario.palavraChave }"/>" > /* desejo que a action seja  o método processarFormulario e que apareça o que o usuário digitou no campo palavraChave*/
			<label>Digite o email:</label>
			<input name="visitante.email" id="email" type="text"/>
			<br/>
			<br/>
			<label>Digite o que deseja procurar:</label>
			<input name="comentario.palavraChave" id="palavraChave" type="text"/>
			<br/>
			<br/>
			<input name="enviar" id="enviar" type="submit" value="Enviar"/>
		</form>
	</body>
</html>

Espero que alguém possa me ajuda.
Obrigado de qualquer forma pela abertura de espaço para tal.

Ah desculpem a não formatação do código no espaço correto, é que eu não sei onde fica esta opção.

22 Respostas

Rafael_Guerreiro

Então, vamos por partes:

  1. para formatar o código, utilize as tags code ([ code] e [ /code])

  2. O problema é que ele não está reconhecendo um PUT, por que você não pode colocá-lo direto no method da tag form…
    Então, para arrumar esse problema, podemos passar isso por parâmetro, da seguinte forma:

&lt;form id="formPrincipal" method="post" action="&lt;core:url value="/"/&gt;&quot; &gt; &lt;label&gt;Digite o email:&lt;/label&gt; &lt;input name="visitante.email" id="email" type="text"/&gt; <br/> <br/> &lt;label&gt;Digite o que deseja procurar:&lt;/label&gt; &lt;input name="comentario.palavraChave" id="palavraChave" type="text"/&gt; <br/> <br/> &lt;button name="_method" value="put" &gt;Enviar&lt;/button&gt; &lt;/form&gt;
Repare que o form executa um POST, mas que o value do botão muda o method para PUT

Rafael_Guerreiro

Ah, sim, tinha me esquecido da URL…

Então, é um pouco inviável fazer dessa forma. O que você deve ter em mente:
GET = Quando vou fazer uma requisição que não altera os dados do sistema (uma consulta)
POST = Quando estou incluindo um registro novo. (Usado para logins também, já q protege a senha)
PUT = Quando vou alterar um registro (ou uma parte dele).
DELETE = Quando vou remover um registro.

Tenha em mente que o PUT e DELETE se comportam como um POST, ou seja, os dados não aparecerão na URL.

Como você vai fazer uma consulta, eu sugiro que use o GET e passe esses dados como parâmetro e eles irão aparecer na URL (“aplicacao/url/?palavra=ABC”)

Tenho outra sugestão:
Se você usa a versão 3.3.1 ou superior do VRaptor, você pode omitir o @Path, da seguinte maneira:

Pois isso é só um atalho e o VRaptor irá entendê-lo como um:

@Get @Path("/url")

guilhermehkr

Muitissímo obrigado pela resposta.
Neste momento estou sem ter como testar, mas amanhã de dia no trabalho irei poder testar as suas dicas.

Muito obrigado pela disposição e pela as informações valiosas que me passou.

Amanhã farei o teste e colocarei o resultado, espero que seja positivo.

Voltaremos a nos falar.
Obrigado novamente.

guilhermehkr

Rafael, bom dia.

Eu fiz o que você solicitou, porém não fez uma diferença.
Ele continua sem apresentar erros, e se mantem na mesma tela inicial.

Ah sobre o que falou do GET não irei poder fazer por dois motivos:

  • Primeiro: eu preciso manter a URL sem parametros, somente apresentar a palavra chave após o contexto.
  • Segundo: Eu irei fazer uma gravação no banco, somente na próxima página irei fazer uma gravação com retorno de uma consulta.

Primeira página: alguns campos + o campo da palavra chave (o assunto que ele deseja comentar …)
Segunda página: Um text area para ele comentar sobre o assunto (palavra chave que esta na URL após o contexto) e um submit.
Terceira página: Um retorno de uma consulta relacionada a palavra que ele desejou comentar

Então, eu somente precisava que ele acionesse meu método que esta anotado com a mesma URL que esta no action do form, assim eu receberia os valores e gravaria-os e chamava outra página e seguiria o fluxo.

Se tiver mais alguma ideia seria muito bem vinda.

Obrigado.

guivirtuoso

Bom Dia Guilherme,

Sugiro que você implemente sua classe dessa forma:

@Resource
public class VisitanteController {
	
	private VisitanteDao visitanteDao;
	private Result result;
	
	public VisitanteController(VisitanteDao visitanteDao, Result result) {
		this.visitanteDao = visitanteDao;
		this.result = result; 
	}

	@Path("/")    /* Tento fazer com que o endereço localhost:8089/aplicativo já chame este método e a página formulario.jsp*/
	public void formulario() {
	}
	
	@Post
	@Path("/visitante/{visitante.id}/comentario/{comentario.palavraChave}")  // &lt;&lt;--- Alterado
	public void processarFormulario(Visitante visitante, Comentario comentario) {
		System.out.println(comentario);
		System.out.println(visitante);
	}
}

E o JSP alterei a action dele tbm…

&lt;%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%&gt;
&lt;%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="core" %&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
&lt;html&gt;
	&lt;head&gt;
		&lt;meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"&gt;
		&lt;link rel="stylesheet" type="text/css" href="css/estilo.css"&gt;
		&lt;title&gt;Blog&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id="formPrincipal"  method="post" action="&lt;core:url value="/visitante/${visitante.id}/comentario/${comentario.palavraChave }"/&gt;" &gt; /* desejo que a action seja  o método processarFormulario e que apareça o que o usuário digitou no campo palavraChave*/
			&lt;label&gt;Digite o email:&lt;/label&gt;
			&lt;input name="visitante.email" id="email" type="text"/&gt;
			<br/>
			<br/>
			&lt;label&gt;Digite o que deseja procurar:&lt;/label&gt;
			&lt;input name="comentario.palavraChave" id="palavraChave" type="text"/&gt;
			<br/>
			<br/>
			&lt;input name="enviar" id="enviar" type="submit" value="Enviar"/&gt;
		&lt;/form&gt;
	&lt;/body&gt;
&lt;/html&gt;

Tente isto.

Complementando oq nosso amigo Rafael disse sobre as anotacoes de Rest, o intuito maior delas é sobrecarregar metodo Rest, fazendo uso dos verbos http.
É normal no inicio confundir Get e Post, ficando sempre o Put e o Delete bem explicitos sobre quando usar.

Att.

guilhermehkr

Guilherme, obrigado pela resposta.

Então, o vraptor esta reclamando isto aqui: br.com.caelum.vraptor.http.route.MethodNotAllowedException: Method GET is not allowed for requested URI. Allowed Methods are [POST]

Mas a minha classe esta anotada com Post, só o método formulário não esta com nada, logo entendo que seja GET por padrão.

Mesmo assim isso não é o meu problema, o problema real é que não consigo SOMENTE colocar o valor do campo palavraChave na URL.
No meu exemplo vocês podem ver que eu coloco o parametro

@Path("/{comentario.palavraChave}")

para minha URL ficar somente localhost:8089/contextoAplicacao/palavraChave

Igual é no google Translator que você digita o que deseja e ele coloca na URL, mais ou menos isso.
Eu realmente não posso colocar todos os parametros na URL, não posso colocar visitante ou comentário, eu somente posso colocar o valor que o usuário digitou no campo palavraChave.

Obrigado pela força e disposição.
Abraços meus caros!

Lucas_Cavalcanti

qual erro tá dando que vc não consegue colocar essa url?

guilhermehkr

Lucas,

Ele não printa nenhum erro, não muda de página e somente coloca isto na URL

http://localhost:8089/aplicacao/;jsessionid=C7C26DD55B3A656560871539752BC060

A seguir esta o método do controller que ele deveria chamar, porém ele não acessa esta método

@Post
@Path("/{comentario.palavraChave }")
public void processarFormulario(Visitante visitante, Comentario comentario) {
	System.out.println(comentario);
	System.out.println(visitante);
}

Meu form no JSP esta desta forma:

<form id="formPrincipal"  method="post" action="<core:url value="/${comentario.palavraChave }"/>" >
                                                <label>Digite o email:</label>
			<input name="visitante.email" id="email" type="text"/>
			<br/>
			<br/>
			<label>Digite o que deseja procurar:</label>
			<input name="comentario.palavraChave" id="palavraChave" type="text"/>
			<br/>
			<br/>
			<input value="Enviar" type="submit"/> 
		</form>
Lucas_Cavalcanti

se vc chama direto a url com a sua palavraChave ele vai?

guilhermehkr

Lucas, obrigado pela disposição.

Então tentei fazer como disse, colocar a palavra TESTE direto na URL, porém desta vez deu um erro no log.

[Date: 11/10/11 13:48:32][Method: br.com.caelum.vraptor.http.DefaultResourceTranslator.translate][DEBUG] - trying to access /teste
[Date: 11/10/11 13:48:32][Method: br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept][DEBUG] - Method GET is not allowed for requested URI. Allowed Methods are [POST]
br.com.caelum.vraptor.http.route.MethodNotAllowedException: Method GET is not allowed for requested URI. Allowed Methods are [POST]
	at br.com.caelum.vraptor.http.route.DefaultRouter.routesMatchingUriAndMethod(DefaultRouter.java:110)
	at br.com.caelum.vraptor.http.route.DefaultRouter.parse(DefaultRouter.java:83)
	at br.com.caelum.vraptor.http.DefaultResourceTranslator.translate(DefaultResourceTranslator.java:59)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:66)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:44)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)
	at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:242)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:243)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:201)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:163)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:108)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:556)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:401)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:242)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:267)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:245)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:260)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
[Date: 11/10/11 13:48:32][Method: br.com.caelum.vraptor.VRaptor.doFilter][DEBUG] - VRaptor ended the request

Até onde viu, parece ter algo errado!?
Eu fui estudando e fazendo, seguindo os passos e apostila, porém modelei na minha necessidade. Na apostila eles utilizam um prefixo /produtos, porém eu preciso de tudo na raíz.

Obrigado.

guilhermehkr

estava tentando normalmento, ou seja, colocando os valores nos inputs em tela, analisei o log e encontrei isto:

[Date: 11/10/11 13:51:42][Method: br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute][DEBUG] - Invoking interceptor ResourceLookupInterceptor
[Date: 11/10/11 13:51:42][Method: br.com.caelum.vraptor.http.DefaultResourceTranslator.translate][DEBUG] - trying to access /
[Date: 11/10/11 13:51:42][Method: br.com.caelum.vraptor.http.DefaultResourceTranslator.translate][DEBUG] - found resource [DefaultResourceMethod: VisitanteController.formularioVisitanteController.formulario()]

Pelo o que entendi, ele não achou o método processarFormulario ou entendeu a <core:url … /> errado, e entendeu que deveria chamar o método VisitanteController.formulario que esta com o @Path("/") raíz, e depois deu um forward para a mesma página atual, por isso não demonstra erros e sempre carrega a mesma página sem os valores nos campos.

Como pode?!
Eu defini na action com <core:url …/> que deveria acionar o método processarFormulario que esta anotado com a mesma URL.

Ele só pode ter ido para o método formulario caso o valor do atributo comentario.palavraChave estivesse vázio

alguma ideia ?!

Lucas_Cavalcanti

se não existe a variavel ${comentario.palavraChave }, ele imprime em branco, então a url fica só “/”…

se vc queria que ao preencher o campo de texto mudasse a url vc precisa fazer em javascript, ou fazer o post/get para uma url que redireciona para a url bonitinha

guilhermehkr

É, realmente ainda não existe a variável, afinal o VRaptor irá criar os objetos para passar pro Controllere não já utilizar em tela.

legal, tenho esta alternativa do javascript vou tentar, mas eu não sou muito bom nisto, você teria alguma idéia para me apresentar?!
Já a parte do post/get não consigo imaginar como fazê-la, se puder também me apresentar algo.

Desculpe pedir tudo isso, mas realmente queria fazer algo legal e não uma pog, espero que me entenda.

abraços e obrigado.

Lucas_Cavalcanti

isso do post/get é só colocar a url de uma outra lógica que redireciona pra lógica que vc quer com o parâmetro setado

guilhermehkr

Lucas, muitissímo obrigado, consegui fazer um esquema aqui que fez o que eu desejava, porém ainda tenho uma dúvida:

  • Como posso fazer para manter a URL da mesma forma redirecionando para outra página?

Deixa eu tentar explicar melhor: Eu preciso que o método processarFormulario faça a regra dele, depois ele navegue para outra página que o usuário entrará com o comentário, logo tenho que passar a responsabilidade para o ComentarioController.

Eu tentei com esta linha aqui no final do método processarFormulario:
result.redirectTo( ComentarioController.class ).formularioAdicionarComentario(comentario);

Porém ele muda a URL, devo mapear o método formularioAdicionarComentario com o @Path igual do processarFormulario ???
Se sim, terei de mudar os verbos, mas se todas as páginas precisar se manter com esta URL, não terei verbos HTTP suficientes.

Obrigado pela força Lucas, mesmo!

Segue os códigos corretos para documentar a primeira dúvida que foi solucionada:

@Resource
public class VisitanteController {
	
	private VisitanteDao visitanteDao;
	private Result result;
	
	public VisitanteController(VisitanteDao visitanteDao, Result result) {
		this.visitanteDao = visitanteDao;
		this.result = result; 
	}
	
	@Get
	@Path("/")
	public void formulario() {
	}
	
	@Post
	@Path("/")
	public void validarFormulario(Visitante visitante, Comentario comentario) {
		// Nesta Linha será feita a validacao
		result.redirectTo( this ).processarFormulario(visitante, comentario);
	}
	
	@Path("/{comentario.palavraChave}")
	public void processarFormulario(Visitante visitante, Comentario comentario) {
		//visitanteDao.persistir( visitante );
		comentario.setVisitante( visitante );
	}
}

No JSP:

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
		<link rel="stylesheet" type="text/css" href="css/estilo.css">
		<title>Blog</title>
	</head>
	<body>
		<form id="formPrincipal"  method="post" action="<core:url value="/"/>" >
			<label>Digite o email:</label>
			<input name="visitante.email" id="email" type="text"/>
			<br/>
			<br/>
			<label>Digite o que deseja procurar:</label>
			<input name="comentario.palavraChave" id="palavraChave" type="text"/>
			<br/>
			<br/>
			<input value="Enviar" type="submit"/> 
		</form>
	</body>
</html>
Lucas_Cavalcanti

troque de redirect pra forward

guilhermehkr

Obrigado novamente, realmente o forward deu certinho, agora eu já chego na próxima página e consigo apresentar os dados corretamente, porém nesta página é onde ele deve inserir o comentario de fato, mas quando eu coloco o comentario e envio este formulário além dele não achar o método dentro do meu controller ele seta o valor da tag action dentro do meu objeto comentario.palavraChave

<body>
		<form action="gravarComentario" method="post" id="formComentario">
			<input name="comentario.numeroId"  type="hidden" value="${comentario.numeroId}"/>
			<label>Palavra a ser procurada</label>
			<input name="comentario.palavraChave"  type="text" value="${comentario.palavraChave}"/>
			<br/>
			<br/>
			<textarea id="textoComentario" name="comentario.comentario">${comentario.comentario}</textarea>
			<br/>
			<br/>
			<input type="submit" value="Enviar Comentário" />
		</form>
	</body>
@Post
	public void gravarComentario(Comentario comentario) {
		System.out.println("Entro no gravar");
	}

Tem alguma ideia do porque ele não acha o método ?!
Desculpa tantas perguntas, mas é realmente vital para mim.

Lucas_Cavalcanti

a action está como gravarComentario… não deveria ser nomeDoController/gravarComentario ?

guilhermehkr

Legal, era isto mesmo.

Porém eu fiquei bem confuso, pois tem lugar que colocamos só o nome do método, e tem lugar que devemos colocar nomeController/método.
Agora vou tentar utilizar rest com o @Path, tenho certeza de que será mais uma dureza! AHAHH!

Muito obrigado novamente Lucas!

Lucas_Cavalcanti

se vc não usa @Path (ou @Get,Post com url) ele segue a convenção nomeDoController/nomeDoMetodo

se vc usa, é o caminho que vc colocou

guilhermehkr

Obriagdo Lucas, agora entendi a convenção tanto dita nas apostilas.

Lucas, olha este problema: Eu tenho um valor que preciso guardar na troca de página, tipo um ID, aonde guardaria ?!
No request ?

Poderia guardar no banco, mas quando voltasse da tela não teria como acha-lo novamente.

Tem alguma ideia?!

Caso real: Eu to trocando de página passando o Comentario completo por parametro, porem quando eu volto da tela para o método que irá gravar o comentario perdi todo o objeto, afinal o escopo dele acabou e o controller nasceu de novo.

guilhermehkr

Lucas, obriagdo mesmo pela ajuda hoje.
Consegui chegar quase até o fim do que pretendia fazer, valeu mesmo.

Eu irei resolver o problema que perguntei acima, vou gravar no banco mesmo!
Valeu mesmooo!

Abraços a todo da comunidade!

Criado 10 de outubro de 2011
Ultima resposta 11 de out. de 2011
Respostas 22
Participantes 4