VRaptor 3 / Validação

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!!!

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.

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

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 =)

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

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.”

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…

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>

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

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/

[quote]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.[/quote]

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)

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.

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.

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

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.

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:

[code]<form id=“projetoForm” action="<c:url value="/projetos"/>" method=“post”>
<fmt:message key=“projeto.campo.nome”/>




<c:if test="${not empty errors[0].message}">
<fmt:message key="${errors[0].message}"/>
</c:if>

<fmt:message key=“projeto.botao.salvar”/>
<fmt:message key=“projeto.botao.deletar”/>

[/code]

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

[code]

remover cliente 5

[/code]

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.

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)

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.