Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Problemas Com Upload via Ajax

Olá a todos, estou com um problema ao realizar um upload com ajax. Acredito que o problema ocorre quando envio arquivos com tamanho maior que o padrão permitido pelo Vraptor. Pra mim não é solução aumentar o tamanho do arquivo de upload com @UploadSizeLimit ou extendendo a classe DefaultMultipartConfig pois para o meu negócio faz muito sentido que o tamanho da imaagem seja pequena. Pelo que li o Vrptor deveria lançar um erro de validação quando o tamanho do arquivo excedesse o valor máximo permitido, mas isso não está acontecendo, o arquivo simplesmente chega nulo no controller. Como posso solucionar isso?

segue meu código

<form id="form" method="post" action="<c:url value="/destaques"/>">

<div class="row">
                <div class="col-md-12  form-group  bw-required">
                    <label class="control-label">Banner</label> <input type="hidden"
                        id="banner" name="destaque.banner" value="${destaque.banner}" />
                    <input type="hidden" id="novobanner" name="destaque.novoBanner" value="${destaque.novoBanner}" />

                    <div class="js-container-banner-destaque">
                        <div id="upload-drop" class="bw-upload">

                            <i class="glyphicon glyphicon-cloud-upload"></i> <span>Arraste
                                a foto aqui ou</span> <a class="bw-upload-form-file">selecione<input
                                id="upload-select" type="file" accept=".jpg,.jpeg,.png" /></a>
                        </div>
                    </div>
                </div>
            </div>
</form>
<script type="text/javascript">
        $(function() {

            var settings = {
                type : 'json',
                filelimit : 1,
                allow : '*(jpg|jpeg|png)',
                action : '<c:url value="/fotos"/>',
                complete : function(resposta) {
                    completeUpload(resposta);
                }
            };

            UIkit.uploadSelect($("#upload-select"), settings);
            UIkit.uploadDrop($("#upload-drop"), settings);


            var arquivo = $("#banner").val();
            $("#novobanner").val('');
            var preenchido = Boolean(arquivo);
            if (preenchido) {
                renderizarFoto($("#banner").val());
            }

            function completeUpload(resposta) {
                $("#novobanner").val('true');
                renderizarFoto(resposta);
            }

            function renderizarFoto(resposta) {

                $("#banner").val(resposta);
                var source = $("#banner-destaque").html();
                var template = Handlebars.compile(source);
                var foto = '';
                if ($("#novobanner").val() == 'true') {

                    foto = 'temp/';
                }
                foto += resposta;
                var html = template({
                    foto : foto
                });
                var containerBannerDestaque = $('.js-container-banner-destaque');
                $("#upload-drop").addClass('hidden');
                containerBannerDestaque.append(html);
                $(".js-remove-foto").on('click', function() {
                    $("#foto").val('');
                    $("#upload-drop").removeClass('hidden');
                    $(".js-banner-destaque").remove();
                    $("#novobanner").val('false');
                });

            }
</script>
<script id="logo-estabelecimento" type="text/x-handlebars-template">
<div class="row js-logo-estabelecimento">
                            <div class="col-md-4"></div>
                            <div class="col-md-4 text-center">
                                <a href="#" class="thumbnail"> <img
                                    src="<c:url value="/fotos/{{logo}}"/>">
                                </a>
                                <button type="button" class="btn btn-link">
                                    <span class="glyphicon glyphicon-remove js-remove-logo"></span>
                                </button>
                            </div>
                        </div>
                        </script>

utilizo o UIkit para fazer o upload. Com imagens menores que 2MB tudo funciona normal,mas quando excedo esse limite, o arquivo simplesmente chega nulo, sem disparar nenhum erro:

@Controller
public class FotoController {

    private Result result;
    private FotoStorage fotoStorage;


    @Deprecated
    public FotoController() {
    this(null,null);
    }

    @Inject
    public FotoController(Result result,FotoStorage fotoStorage) {

        this.result = result;
        this.fotoStorage = fotoStorage;
    }

    @Post("/fotos")
    public void uploadFile(UploadedFile files){

        if(files == null){
            System.out.println("sou nulo");
        }

        String nomeFoto = fotoStorage.salvarTemporariamente(files);         
         result.use(Results.json()).withoutRoot().from(nomeFoto).serialize();       
    }

    @Get("/fotos/temp/{nome}")
    public byte[] recuperarFotoTemporaria(String nome){
        return fotoStorage.recuperarFotoTemporaria(nome);
    }

    @Get("/fotos/{nome}")
    public byte[] recuperar(String nome){
        return fotoStorage.recuperar(nome);
    }

}
4 respostas

Opa Ricardo, passei sua dúvida para uma pessoa que manja mais de vraptor que eu :). Estou assumindo que tudo está funcionando e o problema pode ser no vraptor. Vamos ver o que ele diz :).

Oi Ricardo, tudo bem?

Parece ser algum problema do lado do VRaptor mesmo, ele deveria estar te alertando. Você consegue conferir se esse log aparece no seu console?

https://github.com/caelum/vraptor4/blob/60bdbaaeb9282f30f303a4e7be41b1c4bd56c64a/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/upload/CommonsUploadMultipartObserver.java#L124

Se não estiver com o Log4j instalado, tem instruções simples de como fazer isso por aqui:

http://www.vraptor.org/en/docs/dependencies-and-prerequisites/#logging

se puder colocar o VRaptor como debug, e mandar a saída dos logs, vai ajudar bastante na investigação.

abracos

Oi Alberto, Turini obrigado por responder

Fiquei com uma dúvida, quando o arquivo excede o máximo permitido, a requisição era pra chegar no controller?

porque percebi que a requisição chega no controller e o arquivo vem null, e apesar de não exibir nada no console, se eu imprimir a resposta no console do crome, a mensagem está lá, então fiz o seguinte:

    @Post("/fotos")
    public void uploadFile(UploadedFile files){

if(files == null){
System.out.println("sou nulo");
}
          /**se tiro esta linha dá erro na serialização pois o arquivo chega null no controller **/
        validator.onErrorSendBadRequest();
        String nomeFoto = fotoStorage.salvarTemporariamente(files);         
         result.use(Results.json()).withoutRoot().from(nomeFoto).serialize();       
    }

no script, verifico o status da requisição

var settings = {
                type : 'json',
                filelimit : 1,
                allow : '*(jpg|jpeg|png)',
                action : '<c:url value="/fotos"/>',
                complete : function(resposta,xhr){
                    console.log(resposta);
                    console.log(xhr);
                    if(xhr.status == 400){
                        swal("Oops...", "O tamanho máximo do arquivo deve ser 2MB!", "error");

                        }else{
                            completeUpload(resposta);
                            }
                    }
            };

quando o tamanho do arquivo excede o permitido, o console do navegador printa

Object errors: Array[1]0: Objectcategory: "upload"message: "???file.limit.exceeded???"__proto__: Objectlength: 1__proto__: Array[0]__proto__: Object
novo:184 XMLHttpRequestonabort: nullonerror: nullonload: nullonloadend: nullonloadstart: nullonprogress: nullonreadystatechange: ()ontimeout: nullreadyState: 4response: "{"errors":[{"category":"upload","message":"???file.limit.exceeded???"}]}"responseText: "{"errors":[{"category":"upload","message":"???file.limit.exceeded???"}]}"responseType: ""responseURL: "http://localhost:8080/tropical/fotos"responseXML: nullstatus: 400statusText: "Bad Request"timeout: 0upload: XMLHttpRequestUploadwithCredentials: false__proto__: XMLHttpRequest

A dúvida mesmo agora é se quando o tamanho máximo do arquivo excede o permitido a requisição nem deveria chegar no controller ?

solução!

Oi Ricardo

legal que conseguiu contornar dessa forma e chegar na solução. boa saída.

repare no link do código fonte que eu mandei que o VRaptor está adicionando uma mensagem de validação no request avisando que o download excedeu o limite. Aqui a linha:

https://github.com/caelum/vraptor4/blob/60bdbaaeb9282f30f303a4e7be41b1c4bd56c64a/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/upload/CommonsUploadMultipartObserver.java#L123

entao o código bate no controller sim, e a saída é exatamente essa que você fez, adicionar um validator.onError(...) na primeira linha do seu controller, apontando como o código deve se comportar em caso de problema na validacao dos parametros.

Faz sentido?