VRaptor 3 / Validação

38 respostas
B

Olá pessoal

Aqui eu tenho uma validação que fiz e funciona:

JAVA

public class ProjetoController {

	private Result result;
	private ProjetoDao dao = new ProjetoDao();
	private Validator validator;
	
	public ProjetoController(Result result, Validator validator){
		this.result = result;
		this.validator = validator;
	}

        @Path("/projetos")  
        @Post
        public void insert(Projeto projeto){
	        //Validação
	        if(projeto.getNome().equals("")){
		      validator.add(new ValidationMessage("Nome em Branco","nomeEmBranco"));
	        }
	        validator.onErrorUse(Results.page()).of(getClass()).erro();
	        //validator.onErrorUse(Results.logic()).redirectTo(getClass()).list();
		
	        //Inserção e redirecionamento de página
	        dao.insert(projeto);
	        result.use(Results.logic()).redirectTo(getClass()).list();
        }


        public void erro(){
		
	    }
//...
}

erro.jsp

<HTML>
<BODY>
<c:forEach var="error" items="${errors}">  
	${error.message}
</c:forEach>
</BODY>
</HTML>

Porém, eu gostaria de exibir a mensagem de erro no próprio formulário:

list.jsp

<form action="<c:url value="/projetos"/>"/>
	Projeto: <br><input name="projeto.nome"/><br>
	<button type="submit" name="_method" value="POST">SALVAR</button>  
	<button type="submit" name="_method" value="DELETE">DELETAR</button><br>
</form>

Tentei direcionar para o método list() e inserir o código do erro.jsp no list.jsp mas não apareceu nada.

Se alguém puder me ajudar, agradeço desde já!!!
Obrigado.

38 Respostas

G

Se você colocar isso no seu JSP funciona?

<form action="<c:url value="/projetos"/>"/>  
<ul>
    <c:forEach var="error" items="${errors}">    
        <li>${error.message}</li>
    </c:forEach>  

     Projeto: <br><input name="projeto.nome"/><br>  
     <button type="submit" name="_method" value="POST">SALVAR</button>    
     <button type="submit" name="_method" value="DELETE">DELETAR</button><br>  
</form>

E o controller redirecionando para o proprio form

validator.onErrorUse(Results.page()).of(getClass()).erro();

Ao invés de mandar para o método erro() envie para o métod responsável por chamar o teu formulário.

B

Blza Garcia, valeu mais uma vez. Eu cheguei a fazer isso, e funcionou. Só que tem um detalhe.

Meu form na verdade é minha list também.

Então, quando eu fiz dessa forma, depois que eu validei, ao invés de eu redirecionar para a minha página do formulário, eu estou redirecionando para o meu método list(), e dessa forma não está funcionando.

Quando eu fiz dessa forma, ele me retornou o formulário, com a mensagem de erro, mas com minha lista em branco.

G

Bruno, às ordem, hehehe.

Não sei se entendi bem sua dúvida… mas o list e form são na mesma tela? Você pode postar seu controller?

Abraços

Lucas_Cavalcanti
validator.onErrorUse(logic()).forwardTo(MeuController.class).list();
B

Vamo lá!!!

package bsr.vraptor.controller;

import java.util.List;

import br.com.caelum.vraptor.Delete;
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Post;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.Validator;
import br.com.caelum.vraptor.validator.ValidationMessage;
import br.com.caelum.vraptor.view.Results;
import bsr.hibernate.dao.ProjetoDao;
import bsr.hibernate.tabela.Projeto;


@Resource
public class ProjetoController {

	private Result result;
	private ProjetoDao dao = new ProjetoDao();
	private Validator validator;
	
	public ProjetoController(Result result, Validator validator){
		this.result = result;
		this.validator = validator;
	}
	
	@Path("/projetos")  
	@Post
	public void insert(Projeto projeto){
		//Validação
		if(projeto.getNome().equals("")){
			validator.add(new ValidationMessage("Nome em Branco","nomeEmBranco"));
		}
		//validator.onErrorUse(Results.page()).of(getClass()).erro();
		validator.onErrorUse(Results.logic()).redirectTo(getClass()).list();
		
		//Inserção e redirecionamento de página
		dao.insert(projeto);
		result.use(Results.logic()).redirectTo(getClass()).list();
	}
	
	@Path("/projetos")  
	@Delete 
	public void delete(Projeto projeto){
		dao.delete(projeto);
		result.use(Results.logic()).redirectTo(getClass()).list();
	}
	
	public List<Projeto> list(){
		return new ProjetoDao().list();
	}
	
}

E o JSP, que contém meu formulário num quadrante e minha lista em outro. Fora que cada linha minha possui a mesma estrutura do formulário.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<HTML>
<BODY>


<FONT FACE="Verdana" COLOR="DarkBlue">

	<c:import url="/WEB-INF/cabecalho.html"/>
	<FONT SIZE=-4><h1 ALIGN=CENTER>PROJETOS</h1></FONT>
	
	

	<table border="1" width="100%" cellpadding="10">
	<tr>
	
		<td width="30%" valign="top">
		<form action="<c:url value="/projetos"/>"/>
		
			<c:forEach var="error" items="${errors}">  
				${error.message}
			</c:forEach>
			
			Projeto: <br><input name="projeto.nome"/><br>
			<button type="submit" name="_method" value="POST">SALVAR</button>  
			<button type="submit" name="_method" value="DELETE">DELETAR</button><br>
		</form>
		</td>
		
		<td width="70%" valign="top">
		<table border="0" align="center" width="100%" cellspacing="0">
		<tr><th>Nome do Projeto</th></tr>
		<c:forEach var="projeto" items="${projetoList}">
			<tr>
				<td width="80%" valign="top">
				<form action="<c:url value="/projetos"/>"/>
					<input name="projeto.nome" value="${projeto.nome}" size="120" style="background-color: orange; color: darkblue; font-weight: bold"/>
				</td>
				<td width="10%" valign="top">
					<button type="submit" name="_method" value="POST" style="background-color: darkblue; color: white; font-weight: bold">SALVAR</button> 
				</td>
				<td width="10%" valign="top">
					<button type="submit" name="_method" value="DELETE" style="background-color: darkblue; color: white; font-weight: bold">DELETAR</button>  
				</td>
				</form>
			</tr>
		</c:forEach>
		</table>
		</td>
	
	</tr>
	</table>
	
</FONT>
</BODY>
</HTML>

Então, o código:

<c:forEach var="error" items="${errors}">    
       ${error.message}  
</c:forEach>

Não está escrevendo a mensagem.

G

Linha 37: validator.onErrorUse(Results.logic()).redirectTo(getClass()).list();

Os erros possuem escopo request, sendo assim se você fizer redirect perde os dados. Altere para forward.

Abraços

Lucas_Cavalcanti

muda a validação para:

validator.onErrorUse(Results.logic()).forwardTo(getClass()).list();
B

Pois é, eu fiz isso tbm, e até fiz de novo agora pra ter certeza, porém ele não lista

G

Bruno, só não entendi uma coisa: com o forward não mostra as mensagens ou tua lista de projetos?

Lucas_Cavalcanti

troca o

public List<Projeto> list(){  
         return new ProjetoDao().list();  
  }

por

public void list(){  
         result.include("projetoList", new ProjetoDao().list());  
  }

que vai funcionar…

é um bug no vraptor… ele não está adicionando o retorno do método nem no escopo flash (que faria funcionar o redirect) nem no forward… =(

faz essa alteração e usa o redirectTo que deve funcionar (na verdade era pra ele já estar funcionando antes… vou ver aqui)
senão troca pra forwardTo

vou cadastrar essa issue no github

obrigado

B

Valeu Garcia e Lucas

Ele mostrava as mensagens mas não listava meus projetos. Mas agora que o usei o:

result.include("projetoList", new ProjetoDao().list());

ele está funcionando. Deu um erro no console que eu não consegui entender, mas funcionou.

15:18:17,046  WARN JstlLocalization:50 - couldn't find message bundle, creating an empty one
java.util.MissingResourceException: Can't find bundle for base name messages, locale pt_BR
	at java.util.ResourceBundle.throwMissingResourceException(Unknown Source)
	at java.util.ResourceBundle.getBundleImpl(Unknown Source)
	at java.util.ResourceBundle.getBundle(Unknown Source)
	at br.com.caelum.vraptor.core.JstlLocalization.getBundle(JstlLocalization.java:48)
	at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:81)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:57)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:71)
	at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:54)
	at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:51)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:71)
	at br.com.caelum.vraptor.interceptor.multipart.MultipartInterceptor.intercept(MultipartInterceptor.java:58)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:57)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:71)
	at br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:58)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:57)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:71)
	at br.com.caelum.vraptor.core.URLParameterExtractorInterceptor.intercept(URLParameterExtractorInterceptor.java:45)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:57)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:71)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:70)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:57)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:71)
	at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:71)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:99)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:37)
	at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:97)
	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(Unknown Source)

Valeu mesmo!!!

Lucas_Cavalcanti

esse erro que deu é pq você não deve ter um messages.properties no classpath, daí ele cria um vazio…

você deve criar esse arquivo se vc quiser internacionalizar sua aplicação, ou simplesmente externalizar as strings dos jsps

B

Olha eu de novo!!!

A boa prática pede para eu validar no cliente primeiro para não enviar requisições desnecessárias para o servidor. Bom, usei javascript então.

<script language="javascript">
//validação de formulário
function validaForm(){
 	if (document.getElementById("projeto_nome").value == ""){
 		alert("Campo NOME em branco");
 		document.projeto.nome.focus();
        return false;
	}
	return true;
}  
</script>
<BODY onload="validaForm">


<FONT FACE="Verdana" COLOR="DarkBlue">

	<c:import url="/WEB-INF/cabecalho.html"/>
	<FONT SIZE=-4><h1 ALIGN=CENTER>PROJETOS</h1></FONT>
	
	

	<table border="1" width="100%" cellpadding="10">
	<tr>
	
		<td width="30%" valign="top">
		<form onSubmit="return validaForm();"
			  action="<c:url value="/projetos"/>">
			Projeto: <br><input name="projeto.nome" id="projeto_nome"/><br>
			<small><FONT COLOR="Red"><c:out value='${errors[0].message}'/></FONT></small>
			<button type="submit" name="_method" value="POST">SALVAR</button>  
			<button type="submit" name="_method" value="DELETE">DELETAR</button><br>
		</form>
		</td>
...

O problema é o seguinte: eu valido no cliente mas não to conseguindo escapar da validação no servidor. Eu gostaria de executar o “return validaForm()” e não ir para a url do meu action, e nem para url nenhuma, ou seja, não fazer nada, continuar no meu formulário.

Como fazer isso?
Agradeço mais uma vez!!!
Obrigado!

Lucas_Cavalcanti

Dá uma olhada nesse plugin do jquery:

http://docs.jquery.com/Plugins/Validation

Lucas_Cavalcanti

Olá, o bug anterior, do retorno do método, foi corrigido… quando sair a nova versão, você vai poder dar forwards para métodos que retornam valores sem problemas

Paulo_Silveira

e se preferir, baixe o codigo fonte e basta execuar o ant para obter um SNAPSHOT da versao mais recente!

B

Pô, bem bacana esse JQuery hein. Bem simples e melhor do que o javascript que eu tinha feito :slight_smile:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<HTML>

<HEAD>

<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript" src="http://dev.jquery.com/view/trunk/plugins/validate/jquery.validate.js"></script>
<script>
	$(document).ready(function(){
    	$("#projetoForm").validate({
        	rules:{
    			"projeto.nome":{required:true}
        	},
        	messages:{
        		"projeto.nome":{required:"O campo NOME está em branco"}
        	}
    	});
  	});
</script>

<BODY>
<FONT FACE="Verdana" COLOR="DarkBlue">

	<c:import url="/WEB-INF/cabecalho.html"/>
	<FONT SIZE=-4><h1 ALIGN=CENTER>PROJETOS</h1></FONT>
	
	<table border="1" width="100%" cellpadding="10">
	<tr>
	
		<td width="30%" valign="top">
		<form id="projetoForm"
			  action="<c:url value="/projetos"/>">
			
			Projeto: <br><input name="projeto.nome" id="projeto_nome"/><br>
			<small><FONT COLOR="Red"><c:out value='${errors[0].message}'/></FONT></small>
			<button type="submit" name="_method" value="POST">SALVAR</button>  
			<button type="submit" name="_method" value="DELETE">DELETAR</button><br>
			
		</form>
		</td>
...

Valeu!!!

B

Eh galera, não achei que negócio de validação / internacionalização seriam o maior dos meus problemas.

Achei esse link que meu deu um norte na tentativa de solução do meu problema:
[url]http://celodemelo.wordpress.com/2007/11/05/internacionalizacao-de-mensagens-no-javascript/[/url]

Consiste numa Servlet que lê as mensagens de acordo com meu locale e retorna na forma de um JSON. No entanto, ao invés de Servlet, fiz uma Controller para internacionalizar as mensagens na minha Jquery:

@Resource
public class I18nController {

	private Result result;
	private HttpServletRequest request;
	private HttpServletResponse response;

	
	public I18nController(Result result, HttpServletRequest request,HttpServletResponse response)
	throws Exception{
		this.result = result;
		this.request = request;
		this.response = response;
		Locale locale = this.request.getLocale();
		PrintWriter out = this.response.getWriter();
		out.print(getJsonMensagens(locale));
		out.flush();
		out.close();
	}
	
	private String getJsonMensagens(Locale locale){
		ResourceBundle mensagens = ResourceBundle.getBundle("messages",locale);
		StringBuilder json = new StringBuilder();
		json.append("[");
		Set<String> keys = mensagens.keySet();
		for(String key:keys){
			json.append("{key:'" + key + "', value:'" + mensagens.getString(key)+ "'},");
		}
		int i = json.lastIndexOf(",");
		json.replace(i,i+1,"");
		json.append("]");
		
		return json.toString();
	}
}
Jquery:
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript" src="http://dev.jquery.com/view/trunk/plugins/validate/jquery.validate.js"></script>

<script>

	var bundle = new ResourceBundle();

	$.get("i18n",function(data){
		bundle.initialize(data);
	});

	function ResourceBundle(){
		this.messages = [];
	};

	ResourceBundle.prototype.initialize = function(json){
		var objs = eval(json);
		for(var i = 0; i < objs.length;i++){
			var obj = objs[i];
			this.messages[obj.key] = obj.value;
		}
	};

	ResourceBundle.prototype.get = function(pKey){
		return this.messages[pKey];
	};

        //VALIDAÇÃO QUE ESTÁ FUNCIONANDO
	$(document).ready(
		function(){
    		$("#projetoForm").validate({
        		rules:{
    				"projeto.nome":{required:true}
        		},
        		messages:{
        			"projeto.nome":{required:bundle.get("projeto.valida.nome")}
        		}
    		});
  		}
  	);

	
</script>

Mas parece que meu código Jquery não está requisitando o controller. Não nenhum erro, mas a mensagem de validação que retorna é a mensagem padrão, e não a internacionalizada.

Na chamada do controller:
$.get("i18n",function(data){
coloque "i18n" pela convenção do Vraptor. Será que é isso que está errado?

Agradeço desde já a ajuda que tenho recebido.
Obrigado!!!

G

Não entendi muito bem. O código do controller nem sequer chega a ser executado?

Creio que você não possa fazer tudo no construtor. Lembre-se do Java básico que nem sempre você tem todos os recursos da classe antes do construtor ser completamente finalizado. Tente algo como:

@Resource
public class I18nController {

    private Result result;
    private final PrintWriter writer;
    private final Locale locale;

    public I18nController(Result result, HttpServletRequest request, HttpServletResponse response)
        throws Exception {
        this.result = result;
        locale = request.getLocale();
        writer = response.getWriter();
        response.setContentType("application/json"); // jquery exige que o content-type seja json
    }

    @Path("/i18n")
    public void getJsonMensagens() {
        ResourceBundle mensagens = ResourceBundle.getBundle("messages", locale);
        StringBuilder json = new StringBuilder();
        json.append("[");
        Set<String> keys = mensagens.keySet();
        for (String key : keys) {
            json.append("{key:'" + key + "', value:'" + mensagens.getString(key) + "'},");
        }
        int i = json.lastIndexOf(",");
        json.replace(i, i + 1, "");
        json.append("]");

        writer.print(json.toString());

        result.use(Results.nothing()); // vai para lugar algum
    }
}

A propósito, fiz um componente para tratar json, você tem interesse?

B

E ae Garcia

Isso mesmo. Eu tinha a impressão que o código nem chegava a ser executado. Coloquei um System.out.println e o print nem apareceu no console.
Tentei dessa maneira que vc passou mas continuou na mesma.

Sobre o componente de tratar JSON, tenho interesse sim. Vc tem algum link?

Valeu!!!

G

Bruno, te passo esse componente logo mais, pois não estou no escritório.

Você pode fazer um teste… comente a linha 13 do código que te passei, onde fiz response.setContentType. Depois tente acessar o URL direto, algo como localhost:8080/teu-contexto/i18n

Provavelmente ele vá imprimir algo, ou te mostrar alguma mensagem de erro.

G

Bruno, achei um post que eu comentei sobre esse componente para Json: http://guj.com.br/posts/list/142493.java#768230

Nesse meu caso eu usei a lib do json.org (www.json.org/java) como result do meu método. Então criei um componente que quando o retorno do método for JsonObject ele imprime o resultado. Ficou bem simples.

Creio que logo vá sair suporte a isso no vraptor, pois há uma issue lá no github para isso: http://github.com/caelum/vraptor/issues/#issue/78

Na verdade há diversas formas de fazer json. Da forma que você fez está correto. A única vantagem no meu caso é que basta você retornar um objeto JsonObject e não precisar trabalhar com o request e response no controller.

Abraços

Lucas_Cavalcanti

O bug de não conseguir redirecionar pra logica lista que retorna coisas foi corrigido, então
na próxima versão do VRaptor, você pode usar o código do jeito certo =)

Lucas_Cavalcanti

Olá, tenta fazer no seu javascript

$.get('<c:url value="/i18n"/>',function(data){

e com o código java do jeito que o garcia passou:

@Path("/i18n")  
public void getJsonMensagens() {

[]'s

B

OK!!! Funcionou. Acessou o servidor, porém, pra testar tive que chamar o bundle.get(“projeto.valida.nome”) num Alert()

Na minha validação:

$(document).ready(
		function(){
    		$("#projetoForm").validate({
        		rules:{
    				"projeto.nome":{required:true}
        		},
        		messages:{
        			"projeto.nome":{required:bundle.get("projeto.valida.nome")}
        		}
    		});
  		}
  	);

não funciona. Na verdade nem sei se posso chamar a função desta maneira.
Ele valida mas com mensagem padrão: “This field is required.”

Lucas_Cavalcanti

se esse bundle é um objeto java, você não consegue chamar assim…

se o que você quer é chamar o serviço de i18n seu, vc tem que chamá-lo ali…

B

Terminei, não do jeito que eu queria, mas deu certo. Como eu to fazendo esse esquema pra estudar o que aprendi no curso de java web, resolvi não me aprofundar ainda nesse negócio de Jquery, Ajax… Vou deixar isso pra depois. Não achei que internacionalizar no servidor e cliente, principalmente no cliente fosse me custar tanto tempo, huahaua.

Ainda tem uma coisa que não entendo me incomodando no JSP. A minha validação no cliente está funcionando certinho quando insiro o JS dessa maneira:

Mas quando baixo os arquivos JS, coloco no WebContent e insiro da seguinte forma:

depois de carregada a página, a primeira vez que clico no botão de inserir, ele não mostra a mensagem de validação, só à partir do segundo clique. Muiii Éxtranho!!!

Além disso, inseri o response.setContentType(?text/html; charset=ISO-8859-1″); no Controller de Validação no Cliente e não funcionou. Ainda não exibe minhas mensagens Javascript com acentuação.

Segue meus códigos prontos para compartilhar:

CARACTERÍSTICAS
VRAPTOR3
Validação servidor/cliente
Internacionalização (messages.properties)
Formulário com dois submits
Lista e formulário no mesmo JSP
Cada linha da lista com um botão para salvar alterações e outro pra deletar (como se cada linha fosse um formulário).
Javascript / Jquery / Json

SELECIONAR IDIOMA
JSP (quebra galho)

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
	<a href="http://localhost:8080/bc/language/change/pt_BR">Brasil</a>
	<a href="http://localhost:8080/bc/language/change/en_US">USA</a>
	<a href="http://localhost:8080/bc/projeto/list"><fmt:message key="projeto.titulo"/></a>
</html>

CONTROLLER

@Resource
public class LanguageController {

	private Result result;
	private HttpServletRequest request;

	public LanguageController(Result result, HttpServletRequest request)throws Exception{
		this.result = result;
		this.request = request;
	}
	
	@Path("/language/change/{lingua}")
	public void change(){
		String language = request.getParameter("lingua");
		String[] splitlang = language.split("_");
        Locale locale = new Locale(splitlang[0],splitlang[1]);
        Config.set(request.getSession(), Config.FMT_LOCALE, locale);
        Config.set(request.getSession(), Config.FMT_FALLBACK_LOCALE, locale);
        result.use(Results.page()).forward("/index.jsp");
	}
}

PROJETOS
CONTROLLER (Insert, Delete e Validação no Servidor)

@Resource
public class ProjetoController {

	private Result result;
	private ProjetoDao dao = new ProjetoDao();
	private Validator validator;
	
	public ProjetoController(Result result, Validator validator){
		this.result = result;
		this.validator = validator;
	}
	
	@Path("/projetos")  
	@Post
	public void insert(Projeto projeto){
	
		//Validação
		if(projeto.getNome().equals("")){
			validator.add(new ValidationMessage("projeto.valida.nome","projeto.nome"));
		}
		validator.onErrorUse(Results.logic()).forwardTo(getClass()).list();
		
		//Inserção e redirecionamento de página
		dao.insert(projeto);
		result.use(Results.logic()).redirectTo(getClass()).list();
	}
	
	@Path("/projetos")
	@Delete 
	public void delete(Projeto projeto){
		dao.delete(projeto);
		result.use(Results.logic()).redirectTo(getClass()).list();
	}
	
	public void list(){
		result.include("projetoList", new ProjetoDao().list()); 
		//return new ProjetoDao().list();
	}
}

CONTROLLER DE VALIDAÇÃO NO CLIENTE

/*http://celodemelo.wordpress.com/2007/11/05/internacionalizacao-de-mensagens-no-javascript/
		Recupera as mensagens de acordo com o locale do usuário e as transforma num JSON
	 */

	/*MAIS SOBRE JSON
	  http://guj.com.br/posts/list/142493.java#768230
	  www.json.org/java
	*/

@Resource
public class I18nController {

	private Result result;
	private final PrintWriter writer;  
	private final Locale locale;
	private HttpServletResponse response;

	public I18nController(Result result, HttpServletRequest request,HttpServletResponse response)
	throws Exception{
		this.result = result;  
		locale = (Locale)Config.get(request.getSession(), Config.FMT_LOCALE);
		writer = response.getWriter();  
		this.response = response;
		this.response.setContentType("application/json"); // jquery exige que o content-type seja json  
	}
	
	@Path("/i18n")
	public void getJsonMensagens(){
		ResourceBundle mensagens = ResourceBundle.getBundle("messages", locale);  
		StringBuilder json = new StringBuilder();  
		json.append("[");  
		Set<String> keys = mensagens.keySet();  
		for (String key : keys) {  
			json.append("{key:'" + key + "', value:'" + mensagens.getString(key) + "'},");  
		}  
		int i = json.lastIndexOf(",");  
		json.replace(i, i + 1, "");  
		json.append("]");  
		writer.print(json.toString());
		result.use(Results.nothing()); // vai para lugar algum  
	}
}

LIST.JSP

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>


<HTML>
<?xml version="1.0" encoding="UTF-8"?>

<HEAD>

<!-- VALIDAÇÃO NO CLIENTE -->

<script src="jquery-latest.js"></script>
<script type="text/javascript" src="jquery.validate.js"></script>

<script>

	var bundle = new ResourceBundle();

	$.get('<c:url value="/i18n"/>',function(data){
		bundle.initialize(data);
	});

	function ResourceBundle(){
		this.messages = [];
	};

	ResourceBundle.prototype.initialize = function(json){
		var objs = eval(json);
		for(var i = 0; i < objs.length;i++){
			var obj = objs[i];
			this.messages[obj.key] = obj.value;
		}
	};

	ResourceBundle.prototype.get = function(pKey){
		return this.messages[pKey];
	};


	function validaForm(){
		if (document.getElementById("projeto_nome").value == ""){
		 	alert(bundle.get("projeto.valida.nome"));
		 	document.projeto.nome.focus();
	        return false;
		}
		
		return true;
	}  

	
</script>


<BODY>
<FONT FACE="Verdana" COLOR="DarkBlue">

	<c:import url="/WEB-INF/cabecalho.html"/>
	
	
	<FONT SIZE=-4><h1 ALIGN=CENTER><fmt:message key="projeto.titulo"/></h1></FONT>
	
	<table border="1" width="100%" cellpadding="10">
	<tr>
	
                <!-- FORMULÁRIO -->
		<td width="30%" valign="top">
		
		<form id="projetoForm"
			  action="<c:url value="/projetos"/>">
			
			<fmt:message key="projeto.campo.nome"/><br>
			<input name="projeto.nome" id="projeto_nome"/><br>
			<noscript><small><FONT COLOR="Red">
				<c:if test="${not empty errors[0].message}">
					<fmt:message key="${errors[0].message}"/>
				</c:if>	
			</FONT></small></noscript>
			<button type="submit" name="_method" value="POST" onClick="validaForm()"><fmt:message key="projeto.botao.salvar"/></button>  
			<button type="submit" name="_method" value="DELETE"><fmt:message key="projeto.botao.deletar"/></button><br>
			
		</form>
		</td>
		
                <!-- LISTAR -->
		<td width="70%" valign="top">
		<table border="0" align="center" width="100%" cellspacing="0">
		<tr><th><fmt:message key="projeto.lista.nome"/></th></tr>
		<c:forEach var="projeto" items="${projetoList}">
			<tr>
				<td width="80%" valign="top">
				<form action="<c:url value="/projetos"/>"/>
					<input name="projeto.nome" value="${projeto.nome}" size="120" style="background-color: orange; color: darkblue; font-weight: bold"/>
				</td>
				<td width="10%" valign="top">
					<button type="submit" name="_method" value="POST" style="background-color: darkblue; color: white; font-weight: bold">
					<fmt:message key="projeto.botao.salvar"/></button> 
				</td>
				<td width="10%" valign="top">
					<button type="submit" name="_method" value="DELETE" style="background-color: darkblue; color: white; font-weight: bold">
					<fmt:message key="projeto.botao.deletar"/></button>  
				</td>
				</form>
			</tr>
		</c:forEach>
		</table>
		</td>
	
	</tr>
	</table>
	
</FONT>
</BODY>
</HEAD>
</HTML>
Lucas_Cavalcanti

tenta usar response.setCharacterEncoding(“ISO-8859-1”); ao invés do content type…
e tenta ver também se todos os seus arquivos estão nesse encoding

G

Há no vraptor um interceptor que faz isso, não?

http://vraptor.caelum.com.br/documentacao/configuracoes-avancadas-sobrescrevendo-as-convencoes-e-comportamento-do-vraptor/

Se você quiser que todas as requisições da sua aplicação sejam de um encoding determinado, para evitar problemas de acentuação por exemplo, você pode colocar o seguinte parâmetro no seu web.xml:

br.com.caelum.vraptor.encoding
UTF-8

Assim todas as suas páginas e dados passados para formulário usarão o encoding UTF-8, evitando problemas de acentuação.

B

Com relação aos acentos, que é só no javascript, tentei todas as formas que achei, mas acho que vou fazer replaces de acordo com a tabela unicode.

O que está me matando é o fato de, depois de ter chamado os arquivos JS dentro da minha aplicação, a validação no cliente só mostrar as mensagens à partir do segundo clique. Às vezes esqueço, vou fazer uns testes, não aparece nada e eu já acho q deu pau em tudo, hauhauhauh. Nisso eu tenho uma pergunta: qual a vantagem de manter o js no meu WebContent ao invés de invocá-lo pela url? Porque quando invoco pela url, não dá esse problema.

Nossa, e outra, quanto mais a gente mexe pior. Já funcionando no FF, fui testar meu código no IE e dá esse erro quando tento salvar um item. Pra deletar, também, ou seja, qualquer um dos dois botões do meu form.

SEVERE: Servlet.service() for servlet default threw exception
java.lang.IllegalArgumentException: No enum const class br.com.caelum.vraptor.resource.HttpMethod.SALVAR
	at java.lang.Enum.valueOf(Unknown Source)
	at br.com.caelum.vraptor.resource.HttpMethod.valueOf(HttpMethod.java:43)
	at br.com.caelum.vraptor.resource.HttpMethod.of(HttpMethod.java:63)
	at br.com.caelum.vraptor.http.DefaultResourceTranslator.translate(DefaultResourceTranslator.java:65)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:64)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:57)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:71)
	at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:71)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:99)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:37)
	at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:97)
	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(Unknown Source)
G

Quando ao charset eu parei de me incomodar quando toquei tudo para utf-8. Desde os arquivos até o charset do response.

Quanto ao seu erro, você usou por acaso você tem algo como isso?

Caso positivo, isso só vale para os valores POST, GET, DELETE, TRACE (existe mesmo?) e PUT. Esses são os método que o protocolo HTTP suporta. Lembrando que browsers somente suportam POST e GET, por isso o pessoal do vraptor dispoe essa variável _method. Porém webservices possuem todos esses métodos.

B

Usei isso:

<button type="submit" name="_method" value="POST" onClick="validaForm()"><fmt:message key="projeto.botao.salvar"/></button>

sendo que o fmt retorna “SALVAR”, que está relacionado ao HttpMethod.SALVAR do erro. É o label do botão.

G

Ao invés de especificar o método http no botão, use no próprio form.

B

E ae garcia

Não posso cara pq tenho dois botões no mesmo form.

<form id="projetoForm"  
               action="<c:url value="/projetos"/>">  
               
             <fmt:message key="projeto.campo.nome"/><br>  
             <input name="projeto.nome" id="projeto_nome"/><br>  
             <noscript><small><FONT COLOR="Red">  
                 <c:if test="${not empty errors[0].message}">  
                     <fmt:message key="${errors[0].message}"/>  
                 </c:if>     
             </FONT></small></noscript>  
             <button type="submit" name="_method" value="POST" onClick="validaForm()"><fmt:message key="projeto.botao.salvar"/></button>    
             <button type="submit" name="_method" value="DELETE"><fmt:message key="projeto.botao.deletar"/></button><br>            
</form>

Além disso no Firefox funciona.

G

Pode sim. Aliás você DEVE sempre usar post quando usa submuit no form, caso contrário todos os seus dados serão enviados na URL, pois o padrão do form é sempre set GET. Na verdade browsers suportam apenas POST e GET. Esse _method é um artificio usado no vraptor3 para permitir que você use DELETE, PUT e afins.

Porém isso é artificio, pois na verdade quando você envia esse teu form o método será GET. Porém o _method sobrescreve esse comportamento no vraptor, então ele "faz de conta" que você usou outro método http. Tente isso abaixo:

<form id="projetoForm" action="<c:url value="/projetos"/>" method="post">
	<fmt:message key="projeto.campo.nome"/><br>
	<input name="projeto.nome" id="projeto_nome"/><br>
	<noscript><small><FONT COLOR="Red">
	<c:if test="${not empty errors[0].message}">
		<fmt:message key="${errors[0].message}"/>
	</c:if>
	</FONT></small></noscript>
	<button type="submit" onClick="validaForm()"><fmt:message key="projeto.botao.salvar"/></button>
	<button type="submit" name="_method" value="DELETE"><fmt:message key="projeto.botao.deletar"/></button><br>
</form>

Conforme documentação no site do vraptor em http://vraptor.caelum.com.br/documentacao/resources-rest/

<form action="/cliente" method="post">
    <input name="cliente.id" value="5" type="hidden" />
    <button type="submit" name="_method" value="DELETE">remover cliente 5</button>
</form>
B

Sim, porém meu delete continua não funcionando

@Path("/projetos")  
	@Post
	public void insert(Projeto projeto){
	
		//Validação
		if(projeto.getNome().equals("")){
			validator.add(new ValidationMessage("projeto.valida.nome","projeto.nome"));
		}
		validator.onErrorUse(Results.logic()).forwardTo(getClass()).list();
		
		//Inserção e redirecionamento de página
		dao.insert(projeto);
		result.use(Results.logic()).redirectTo(getClass()).list();
	}
	
	@Path("/projetos")
	@Delete 
	public void delete(Projeto projeto){
		dao.delete(projeto);
		result.use(Results.logic()).redirectTo(getClass()).list();
	}

Eu pensei em colocar PATHs diferentes mas não sei se tem como eu poder ter a opção de dois PATHs no mesmo form.

G

Bruno, se você colocar um System.out.println(“chamando delete”); no teu método delete(Projeto) ele passa alí? Estou na dúvida se ele não está chamando teu método ou se por alguma razão o registro não está sendo excluído. É sempre melhor isolar os problemas para saber o que está acontecendo.

Eu uso paths diferentes. Porém eu não tenho o delete no mesmo form. No meu caso a tela de listagem é que contém o botão de delete, então eu uso URLs como:

/project/ listagem (chama o método ProjectController.list)
/project/page-1/ listagem paginado (chama o método ProjectController.list)
/project/edit/150/ tela de edição (chama o método ProjectController.edit)
/project/new/ tela de adição (chama o método ProjectController.edit)
/project/store/ grava o registro (chama o método ProjectController.store)
/project/delete/150/ exclui registro (chama o método ProjectController.delete)

B

Na verdade, no meu list, é como se cada linha fosse um formulário com botão de salvar (para editar) e deletar. Eu altero direto ali sem precisar chamar outra url para edição. Vou dar uma olhada na displaytag pra ver se isso me ajuda.

Criado 28 de outubro de 2009
Ultima resposta 13 de nov. de 2009
Respostas 38
Participantes 4