[RESOLVIDO] VRaptor - Recuperar de um SizeLimitExceededException e dar um erro de validação

14 respostas
jaabax

tudo bom pessoal
se meu limite de upload é de 10MB e eu envio um arquivo de 30MB mais ou menos a seguinte exceção é gerada

org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (31458797) exceeds the configured maximum (10485760)
	...

no meu caso a exceção esta sendo printada no console toda vez q acontece
eu não consigo capturar ela no meu interceptor de exceções tb
e quando eu faço validator.onErrorUsePageOf(TheClass.class).blank(); a requisição não é enviada de volta (o mouse fica carregando pra sempre)
como me recuperar desta exceção e apresentar uma mensagem amigável ao usuário?
tem como manter os dados que o usuário havia digitado anteriormente também?
obrigado

14 Respostas

G

Quando você tem erros de upload eles são expostos pela interface Validation.getErrors(). No JSP você pode simplesmente fazer um loop no atributo ${errors} e imprimir a mensagem.

Lucas_Cavalcanti

o ideal é separar o form do upload do form que muda os outros dados…

é bem chato pro usuário descobrir que não conseguiu adicionar um cara no sistema só depois de ter feito 5MB de upload

jaabax

o problema é que dps que a exceção acontece e o VRaptor printa ela no console eu não consigo continuar o processo do JSP
tipo
a exceção é printada e o controller é executado
no controller eu faço

// Ví que houve um erro de validação, então executo:
validator.onErrorUsePageOf(MyController.class).blank();

mas a resposta da requisição não volta pro JSP, isso é, o controller redireciona pro blank mas não acontece nada
o JSP fica do mesmo jeito de quando a requisição foi feita
e o cursor do mouse fica aguardando (tipo, muda pra antiga ampulheta) pra sempre, indicando que um processo está acontecendo
por que isso pode estar acontecendo?

Lucas_Cavalcanti

se o arquivo for grande ele pode estar fazendo o upload…

tenta fazer o upload de um arquivo bem pequeno

jaabax

vc quer dizer que quando eu chamo o blank(); o upload ainda pode estar sendo feito?
vou tentar colocando o limite de upload pra 100KB e fazer upload de um arquivo de 150KB (seria este o teste que vc sugeriu?)
mas acho improvável pois o servidor está local, na minha máquina
o upload de 30MB acontece em menos de meio segundo (quando eu aumento o limite de tamanho pra mais de 30MB)

Lucas_Cavalcanti

entendi…

se o arquivo é menor que o limite funciona?

o jsp do blank tem algo de especial?

aparece algo de diferente no log de debug do vraptor?

jaabax

sim
se o arquivo é menor que o limite de upload, o upload funciona normalmente
esse problema é só quando excede o limite mesmo
o blank(); é a primeira chamada dps de checar se teve erros de validação no método do meu controller
e todos os parâmetros do método do meu controller vêm nulos (exceto os primitivos que recebem valores padrão)
tipo
e o que vc quer dizer com algo especial?
acho q não… é um JSP normal
simples, apenas um form com 15 inputs do tipo texto e um text area
quanto ao debug do VRaptor, não sabia que tinha um específico, pois, já peguei a estrutura montada nesse projeto
como faço pra habilitar (ou pra checar se já está habilitado)?

Lucas_Cavalcanti

vc precisa de um log4j parecido com esse:

de qqer forma é estranho isso estar acontecendo…

tenta com outro browser e ve se acontece a mesma coisa

jaabax

no meu log4j.xml adicionei

<category name="org.vraptor">
	<priority value="DEBUG" />
	<appender-ref ref="stdout" />
</category>
<category name="com.thoughtworks">
	<priority value="INFO" />
	<appender-ref ref="stdout" />
</category>
<category name="br.com.caelum.vraptor">
	<priority value="DEBUG" />
	<appender-ref ref="stdout" />
</category>

a única coisa que apareceu no log antes de lançar a exceção que postei foi:

11:37:53,214 INFO  [CommonsUploadMultipartInterceptor] Request contains multipart data. Try to parse with commons-upload.
11:37:53,231 WARN  [CommonsUploadMultipartInterceptor] The file size limit was exceeded.

no IE, FF e Chrome aconteceu a mesma coisa
estranho isso msm
pior q to meio boiando :confused:
era pra requisição estar voltando pro JSP como acontece em todas as páginas
mais alguma sugestão? :smiley:

Lucas_Cavalcanti

tenta trocar o onErrorUsePageOf por onErrorRedirectTo

jaabax

funcionou Lucas
vc pode me dizer qual a diferença entre onErrorUsePageOf e onErrorRedirectTo? (detalhes por favor :D)

e pra adicionar uma mensagem de validação customizada eu criei umas classes… me diz oq q vc acha

a interface do meu validator customizado:

public interface IValidatorCustom {

	int getErrorIndexByCategory(final String category);
	int getErrorIndexByMessage(final String message);
	boolean hasErrorCategory(final String category);
	boolean hasErrorMessage(final String message);
	void changeErrorDetailsByCategory(final String category, final String newCategory, final String newMessage);
	void changeErrorDetailsByMessage(final String message, final String newMessage, final String newCategory);

}

a implementação do meu validator customizado:

import java.util.List;

import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.core.Localization;
import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.RequestScoped;
import br.com.caelum.vraptor.proxy.Proxifier;
import br.com.caelum.vraptor.validator.BeanValidator;
import br.com.caelum.vraptor.validator.DefaultValidator;
import br.com.caelum.vraptor.validator.Message;
import br.com.caelum.vraptor.validator.Outjector;
import br.com.caelum.vraptor.validator.ValidationMessage;
import br.com.caelum.vraptor.view.ValidationViewsFactory;

/**
 * Overrides VRaptor's DefaultValidator object. Provides new methods to manage validations.
 */
@Component
@RequestScoped
public class ValidatorCustom extends DefaultValidator implements IValidatorCustom {

	//--------------------------------------------------------------------------
	// Constructors:

	public ValidatorCustom(final Result result, final ValidationViewsFactory factory, final Outjector outjector, final Proxifier proxifier, final List<BeanValidator> beanValidators, final Localization localization) {
		super(result, factory, outjector, proxifier, beanValidators, localization);
	}

	//--------------------------------------------------------------------------
	// IValidatorCustom interface implementation:

	public int getErrorIndexByCategory(final String category) {
		final List<Message> errors = getErrors();

		for (final Message error : errors) {
			if (error.getCategory().equals(category)) {
				return errors.indexOf(error);
			}
		}

		return -1;
	}

	public int getErrorIndexByMessage(final String message) {
		final List<Message> errors = getErrors();

		for (final Message error : errors) {
			if (error.getMessage().equals(message)) {
				return errors.indexOf(error);
			}
		}

		return -1;
	}

	public boolean hasErrorCategory(final String category) {
		return getErrorIndexByCategory(category) > -1 ? true : false;
	}

	public boolean hasErrorMessage(final String message) {
		return getErrorIndexByMessage(message) > -1 ? true : false;
	}

	public void changeErrorDetailsByCategory(final String category, final String newCategory, final String newMessage) {
		getErrors().set(
			getErrorIndexByCategory(category), 
			new ValidationMessage(newMessage, newCategory));
	}

	public void changeErrorDetailsByMessage(final String message, final String newMessage, final String newCategory) {
		getErrors().set(
			getErrorIndexByMessage(message), 
			new ValidationMessage(newMessage, newCategory));
	}

	//--------------------------------------------------------------------------
}

no meu controller eu faço:

// validator é do tipo ValidatorCustom.

final String fileLimitExceeded = "???file.limit.exceeded???";

if (validator.hasErrorMessage(fileLimitExceeded)) {
	validator.changeErrorDetailsByMessage(
		fileLimitExceeded,
		(new StringBuilder())
			.append("Tamanho do arquivo excedeu o permitido (")
			.append("<TAMANHO_AQUI>")
			.append(" MB)")
			.toString(),
		"Erro no envio de arquivo");

	validator.onErrorRedirectTo(MyController.class).novoRegistro(/*AQUI DEVERIA VIR O OBJETO Q VEM NULL DO VRAPTOR*/);
}

a estrutura de validação aqui do projeto que eu estou já está pronta no template da página
não dá pra mudar muito (elas sempre aparecem na parte de baixo e é iterada no JSP)
então criei essa maneira pra colocar uma mensagem customizada

agora to com outro problema
gostaria de saber como eu faço pra manter os dados no formulário depois do onErrorRedirectTo
qd acontece um erro por limite de tamanho excedido, todos os parâmetros do método do controller chegam nulos (exceto os primitivos)
acho q isso não deveria acontecer

Lucas_Cavalcanti

o pageOf vai direto pra jsp da outra lógica. o Redirect redireciona para a outra e executa.

qdo o upload falha os dados vêem nulos mesmo. Isso pq o upload vem junto com os dados do formulário, então eu só consigo ler os dados depois que eu pego o arquivo do upload. Quando falha não dá pra pegar os dados e manter.

por isso que a gente separa o upload do resto do cadastro

jaabax

fala Lucas
vlw d+ velho
acho q isso jah fecha o tópico
mas antes
tava vendo esse tópico aqui:
http://www.guj.com.br/java/198694-resolvido-upload-de-arquivos-no-vraptor-3-configurando-tamanho-maximo-do-arquivo
não testei mas parece q o cara conseguiu
desse jeito q ele fez, o upload precisa terminar todo pra poder dah a msg de validação?
do jeito do VRaptor vc não precisa esperar o arquivo (por exemplo 300MB) acabar pra poder dar o erro de validação né?
essa modificação q ele disse que fez no objeto da apache precisar ir dentro do JAR do apache commons?
abraço

Lucas_Cavalcanti

teoricamente não precisa esperar não… vc não precisa fazer nada

Criado 20 de julho de 2011
Ultima resposta 22 de jul. de 2011
Respostas 14
Participantes 3