Migrando de VRaptor 2 para 3 - Dúvida Ajax

30 respostas
ACDias

Olá,

Estou migrando do VRaptor2 para o 3 e estou com uma dúvida sobre como criar requisições ajax. Como não achei a documentação desta parte muito intuitiva, resolvi postar aqui.
No VRaptor2 eu simplesmente anotava um método com a annotation @Remotable e realizava uma requisição para “action.metodo.ajax.logic” para realizar a requisição. O framework automaticamente parseava todos os objetos a serem ejetados para JSON.
No VRaptor3, eu realizo a requisição para qual URL?
E eu sempre terei que criar um “descritor” para a resposta JSON (/WEB-INF/jsp/action/metodo.json.jsp)? (se for desta maneira mesmo, eu preferia da maneira q era feito no 2 - era mais produtiva)

Obrigado.

30 Respostas

Paulo_Silveira

oi ACDias. Estamos lancando na versao 3.0.2 um suporte inicial ao JSON/XML para AJAX sem ter de criar um jsp para tal. Deve sair essa semana ainda!

Lucas_Cavalcanti

No VRaptor3 vai ser a requisição para a URL normal, a mesma que você usaria se o resultado for uma jsp

G

Uma gambiarra que você pode fazer até esperar uma nova implementação é criar teu JSON dentro do método do controller e jogar para a saída como String mesmo. No meu caso eu criei um interceptor que intercepta (que redundante, hehe) todos métodos onde o retorno é um JsonObject (json.org/java), e então faço a impressão o jogo para o browser.

Silveira, outro dia você comentou na issue os planos de usar xstream. Vocês farão algo que possa gerar tanto XML como Json? Ou apenas Json?

Lucas_Cavalcanti

garcia-jj:

Silveira, outro dia você comentou na issue os planos de usar xstream. Vocês farão algo que possa gerar tanto XML como Json? Ou apenas Json?

Olá garcia,

isso já foi implementado, com o XStream por tras, está disponível no snapshot do repositório… e gera tanto xml quanto json:

result.use(json()).from(objeto).include("fieldNaoPrimitivo").exclude("fieldPrimitivo").serialize();
//ou
result.use(xml()).from(objeto).include("fieldNaoPrimitivo").exclude("fieldPrimitivo").serialize();

o suporte ainda é básico, são serializados por padrão todos os campos primitivos do objeto (String, números, enums e datas)
e você pode incluir os campos não primitivos com o include, e excluir os primitivos com o exclude…

[]'s

G

Faz anos que não acompanho o xstream, mas antigamente tinha um problema quando a ele precisar de permissões no security manager para criar classloaders (isso em JVM compartilhadas, onde o security manager é muito restrito)? Ainda é necessário ter o XPP3 ou instanciar o DOM driver manualmente? Para JSON será usado o Jetinson?

Olhei hoje por cima como ficou a implementação, ficou muito bom.

Abraços, e obrigado.

Edufa

Q maravilha, rs, acabei de terminar uma implementação usando xstream q tinha de exportar um monte de coisas em xml, hehehe se eu tivesse uma semana a mais de prazo teria ganho alguns dias, rs

Depois com tempo vou testar essa versão aqui, pois eu tenho algumas situações bem chatas de objetos bidirecionais q foi meio chato para tirar as referencias circulares sem contar q ficou feio, sem contar q eram entities do hibernate então tem coleções lazy para todos os lados.

exemplinho de cabeça, tem suporte ?

class Parent {
  List<Child> childList;
}

class Child {
  Parent parent;
}

sendo objet do tipo Parent, 
result.use(json()).from(objeto).include("childList").exclude("childList.parent").serialize();

@garcia-jj
Eu tive problemas em usar o xstream no gae, mas era algo bem especifico, se não me engano algo relacionado ao reflection, tem ou pelo menos tinha issue no site do xstream, mas até a ultima vez q eu vi ainda não tinham previsão de suporte completo para o gae, aí eu tive de compilar a minha versão do xstream com umas coisinhas a mais.

@vraptor-team
Parabéns !

Lucas_Cavalcanti

@garcia-jj
Estamos usando o XStream normal, portanto com o XPP parser, e para JSon estamos usando o JSonHierarchicalDriver, que não precisa do jettinson…
Mas você pode estender o serializer e criar o XStream do jeito que você quiser, passando outro ReflectionProvider, outro Driver, etc…

@Edufa
esse código que você passou funciona sim (ou pelo menos deveria, talvez tenha que adicionar alguns testes para listas de elementos):

result.use(json()).from(objeto).include("childList").exclude("childList.parent").serialize();

de qqer forma esse vai ser o jeito de excluir elementos… passando o caminho deles a partir do objeto principal

Lucas_Cavalcanti

@Edufa
agora funciona para collections também, com algumas limitações do XStream, mas funciona… (use implementações padrão de lista (ArrayList, LinkedList, etc)

G

lucascs:
Estamos usando o XStream normal, portanto com o XPP parser, e para JSon estamos usando o JSonHierarchicalDriver, que não precisa do jettinson…
Mas você pode estender o serializer e criar o XStream do jeito que você quiser, passando outro ReflectionProvider, outro Driver, etc….

Essa é uma das razões mais fortes de eu amar o vraptor. Está tudo lá, mas se você não gostar pode facilmente mudar com apenas uma simples classe Java.

Eu tive problemas com o xstream há algum tempo quando precisei implantar um projeto em um cliente, onde a jvm era compartilhada, então as policies eram bem rígidas. O rolo que eu tive foi quando a permissões de classloader (não lembro exatamente), então tive que usar outro parser.

Abraços

Y

Voltando um pouco o assunto, antes no vraptor 2 chamava assim:

retirar: function(id) {
			$.ajaxJson({
					    url: 'ajax.retirar.ajax.logic',
					    data: { 
							'id': id
								  },
						success: 
							function(data) {
								alert("funcionou");
							}
					});
			}

Agora no VRaptor3 mudei para:

retirar: function(id) {
			$.ajaxJson({
					    url: 'ajax/retirar',
					    data: { 
							'id': id
								  },
						success: 
							function(data) {
								alert("funcionou");
							}
					});
			}

Entrou no método retirar e fez tudo certo, porém não voltou para o success. Como fica isso com o VRaptor3?;

Lucas_Cavalcanti

toma cuidado com os caminhos relativos…

vc vai precisar colocar o contexto na url…

url : '<c:url value="/ajax/retirar" />'
Y

Não rolou, a url está certa. Entrou no meu Controller e executou tudo certo e só isso. Não voltou para o success do Json. Vi que tem o JsonOutjecter, tenho que usar isso? (só um chute)

Lucas_Cavalcanti

Se vc tiver o Firefox, instala o Firebug nele e vê qual é o status que essa chamada ajax está retornando… se estiver dando 404 ou 500 não vai pro success…

ou da uma olhada no log pra ver se ele tá tentando redirecionar pra jsp do método (não deveria fazer isso)…

Y

Está retornando 200 e não está retornando pra jsp

Lucas_Cavalcanti

se retornou 200 deveria ter ido pro success… tenta chamar a url na mão, e ver se ele tá retornando o json direitinho… talvez seja alguma configuração perdida desse $.ajaxJson…

tenta trocar pra $.getJSON ou simplesmente $.ajax com a property type: ‘json’

Y

Com $.getJSON entrou no sucess antes de entrar no Controller, e quando terminou o método na classe Controller não aconteceu nada.

Lucas_Cavalcanti

o jeito de usar o getJSON não é do mesmo jeito… é assim:

var resposta = $.getJSON(url, parametros);
//faça aqui o que vc faria no success
var nome = resposta.usuario.nome;
...
Y

Continuou a mesma coisa, mas agora eu fui ver que com o $.ajaxJson está indo como ‘POST’ em vez de ‘GET’

Lucas_Cavalcanti

como assim continuou a mesma coisa? posta o código que vc tá usando plz?

Y

ok, vamos lá.

Esse é o código que eu estou tentando fazer funcionar. O que eu mudei dele do VRaptor2 para o 3 foi a URL. Com o “success” não funcionou e então eu mudei para “complete” e entrou na function. No alert do meu data aparece um XMLHttpRequest, não sei se está certo ou como faço para ler o valor dele ou como o VRaptor trata isso. Enfim, esse é o código:

var ajaxCommon = {
		lerObservacao: function(idExame) {
	
			$.ajaxJson({
					    url: '/ajax/lerObservacao/'+idExame,
					    requestHeaders: {Accept: 'application/json'},
					    dataType: 'json',
						complete: 
							function(data) {
								alert(data);
								if (data.observacao != null){
									alert("uhul");
									exibir_mensagem('Informações Clínicas',data.observacao);
								}
								else{
									alert("haha");
									exibir_mensagem('Aviso','Não existem informações cadastradas.');
								}
							}
					});
			}
}

Tentando com $.getJSON, o alert do teste me jogou um undefined na tela e o alert apareceu antes de executar o método do Controller

ajaxCommon = {
		lerObservacao: function(idExame) {
			var teste = $.getJSON("/ajax/lerObservacao/"+idExame);
			alert(teste);
		}
}

O meu método atualmente, depois de várias mudanças está assim:

@Remotable
	@Post
	@Path("/ajax/lerObservacao/{idExame}")
	public void lerObservacao(Long idExame) {
		this.result.include("observacao", "teste");
	}
Lucas_Cavalcanti

Não é assim que se gera JSon no VRaptor3! a anotação @Remotable não existe mais, a que vc tah usando provavelmente é a do vraptor2…

no vraptor 3 vc vai fazer assim:

@Post  
@Path("/ajax/lerObservacao/{idExame}")  
public void lerObservacao(Long idExame) {  
     Observacao observacao = //...
     this.result.use(Results.json()).of(observacao).serialize();
}

assim vai funcionar… se vc quiser passar uma string mesmo vc vai ter usar isso pra poder dar um nome a ela:

this.result.use(Results.json()).of(observacao, "observacao").serialize();
Y

O @Remotable é porque estou utilizando a compatibilidade com o VRaptor2. Mas tudo bem, isso não fez diferença.

Para mim não aparece o método “of” nessa linha:

this.result.use(Results.json()).of(observacao).serialize();

Tentei utilizar o método from, mas continua a mesma coisa… to ficando loco já hehehe

Lucas_Cavalcanti

é o método from mesmo…

tenta acessar no browser a url desse método e vê o que tá retornando…

repare que tá com @Post… muda pra @Get que talvez funcione com o $.getJSON pelo menos

Y

Agora avançou um pouco:

@Path("/ajax/lerObservacao/{idExame}")
	public void lerObservacao(Long idExame) {
		String observacao = new ExameDAO().get(idExame, false).getObservacao();
		this.result.include("observacao", observacao);
		this.result.use(Results.json()).from(observacao).serialize();
	}
var ajaxCommon = {
		lerObservacao: function(idExame) {
	
			$.ajaxJson({
					    url: '/ajax/lerObservacao/'+idExame,
						complete: 
							function(observacao) {
					    		alert(observacao.responseText);//AQUI APARECEU ALGO ASSIM: {"string":"teste"} como pegar  o "teste" que é o valor que eu realmente quero??
					    		alert(observacao.status);
								if(observacao.status == 200){
									if (observacao != null){
										alert("uhul");
										exibir_mensagem('Informações Clínicas',observacao.responseText);
									}
									else{
										exibir_mensagem('Aviso','Não existem informações cadastradas.');
									}
								}
							}
					});
			}
}
Lucas_Cavalcanti
eval(observacao.responseText).string //==> "teste"

vc pode tb usar algo que já te dá um json… por exemplo o $.getJSON()

aí vc faria

$.getJSON(...).string
Y

ufa… agora sim. Valeu pela ajuda!!

cinei

Aproveitando o tópico, mas sem conhecimento de causa.
As poucas vezes que utilizei ajax, tanto no VRaptor2 quanto no 3, nunca dei qualquer tratamento especial no controller.
Os dados são disponibilizados para a view da forma comum, independetente de utilizar ou não ajax.

Na view deixo desta forma:

$.ajax({
		type:"POST",
		url:"caminho.....",
		data:"parametros...",
		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
		error: function(){
			alert('mensagem de rro!');
		},
		success: function(result){
			$("#lista").hide();
			$("#lista").append(result);
			$("#lista").fadeIn("slow");
		}
	});

Ou simplesmente:

$('#lista').load('..caminha/parametro?' + valorPrametro); 
		$('#lista').fadeIn('slow');

Será que tenho sido muito simplista?
Ou será por que sempre utilizei apenas JQuery?

Lucas_Cavalcanti

das duas formas vc tá fazendo uma requisição usando javascript, a diferença é que uma é assíncrona e outra é síncrona… mas vc pode chamar as duas formas de ajax…

Y

Mais uma… como receber dois valores?
Por exemplo:

this.result.use(Results.json()).from("teste1","teste1").serialize();
this.result.use(Results.json()).from("teste2,"teste2").serialize();

Recebo:
{“teste1”: “teste1”}{“teste2”: “teste2”}

Como separar isso em duas variáveis no javascript?

Lucas_Cavalcanti

Ou vc coloca dentro de uma lista e serializa a lista:

lista.add("teste1");
lista.add("teste2");

result.use(json()).from(lista, "teste").serialize(); 
// no javascript: var json = $.getJSON(...); json.teste[0]; json.teste[1];

ou vc cria uma classe que tem esses dois campos:

public class Testes {
   private String teste1;
   private String teste2;
   //construtor para esses dois campos
}
//...
result.use(json()).from(new Testes("teste1", "teste2")).serialize();
//no javascript: var json = $.getJSON(...); json.testes.teste1; json.testes.teste2;
Criado 11 de novembro de 2009
Ultima resposta 1 de mar. de 2010
Respostas 30
Participantes 7