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

Importar arquivo com angular e spring

Conforme imagem, tenho um array com vários arquivos a serem importados.

Mas dá erro 500. http://localhost:8080/des-if-web/arquivoImportadoRecurso/salvar 500 (Internal Server Error)

O que pode ser ?

Código JAVA

  @RestController
    public class ArquivoImportadoController {
    @PostMapping(value = "/arquivoImportadoRecurso/salvar", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
        public RetornoJackson gravarBanco(
                @PathVariable("file") List<MultipartFile> file,
                @PathVariable("idEntidade") String idEntidade,
                @PathVariable("idEmpresa") String idEmpresa) {
            RetornoJackson retorno = new RetornoJackson();
            ArquivoImportadoEntity entidade = new ArquivoImportadoEntity();
            try {
                arquivoImportadoServico.validarCampos(entidade);
                EmpresaEntity empresa = new EmpresaEntity();
                empresa.setId(new Long(idEmpresa));
                entidade.setEmpresa(empresa);
                EntidadeEntity entidadeEntidade = new EntidadeEntity();
                entidadeEntidade.setId(new Long(idEntidade));
                entidade.setEntidade(entidadeEntidade);
                aplicacaoAuditoria(entidade);
                arquivoImportadoServico.salvar(entidade);
                retorno.setTipo(TipoRetornoMensagemEnum.SUCESSO);
                retorno.setMensagem(Constantes.SALVA_SUCESSO);
            } catch (RegraNegocioException e) {
                logger.error(Constantes.erroSalvar(entidade.getClass().getName()),
                        e);
                retorno.setTipo(TipoRetornoMensagemEnum.ERRO);
                retorno.setMensagem(e.getMessage());
            } catch (Exception e) {
                logger.error(Constantes.erroSalvar(entidade.getClass().getName()),
                        e);
                retorno.setTipo(TipoRetornoMensagemEnum.ERRO);
                retorno.setMensagem(e.getMessage());
            }
            return retorno;
        }
    }
52 respostas

Boa tarde, Guilherme! Como vai?

Cole aqui a stacktrace completa para que seja possível analisá-la e te ajudar!

Tenho esta dependência no pom

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.3</version>
    </dependency>

É isto: Do angular:

POST http://localhost:8080/des-if-web/arquivoImportadoRecurso/salvar 500 (Internal Server Error)
(anonymous) @ angular.min.js:103
n @ angular.min.js:99
(anonymous) @ angular.min.js:96
(anonymous) @ angular.min.js:131
$eval @ angular.min.js:145
$digest @ angular.min.js:142
$apply @ angular.min.js:146
(anonymous) @ angular.min.js:276
Sf @ angular.min.js:37
d @ angular.min.js:37

Não tem do JAVA

Guilherme, o status HTTP 500 indica erro no servidor, ou seja, tem que ter uma stacktrace do Java pq o problema é no código Java! Verifique a saída do console onde vc está rodando o seu servidor e lá vc irá encontrar o log do Java!

Entendo que o problema está no código JAVA.

Mas no console do eclipse não mostra nada mesmo. Por isto coloquei o código do JAVA.

Só se tem outro lugar ou está faltando alguma configuração.

Qual o servidor que vc está utilizando para rodar a sua aplicação Java?

Wildfly 8

E vc iniciou o Wildfly por onde?

Sempre inicio pela aba Server do eclipse.

Então, na aba "Console" irá aparecer todo o log do seu servidor! Tanto o de inicialização quanto os logs de qualquais quer erros que ocorram! Vc consegue encontrar essa aba Console? Se não consegue, vá no menu Window > Show View > Console para ativar essa aba.

Após isso, inicie o seu Jboss e verá que na aba Console irá aparecer o log de inicialização. Depois que o Jboss iniciar, faça a requisição que gera o problema, volte no Eclipse e copie todo o conteúdo da aba Console e cole aqui.

Sim sei da aba de console.

O que estou dizendo é que quando o angular chama o método salvar no JAVA, no console do navegador mostra o erro que informei acima. Mas no console do JAVA fica em branco. Entendeu ?

Todos os outros método que tenho, mostra no console caso tenha erro ou a consulta SQL, mas este não.

Testando no Restlet Client, ele fala em Unsupported Media Type, conforme imagem

Aproveitando, como faço teste de post no Restket Cliente ?

Faça um build da sua aplicação Angular, crie um zip delo projeto "buildado" e um zip do seu projeto Java. Compartilhe ambos os zips cmg (pelo github, dropbox, google drive, a forma que preferir) colando o link aqui. E eu darei uma olhada no que está acontecendo!

Em relação ao Restlet Client, nunca o utilizei... Normalmente utilizo o Postman e pra enviar uma requisição POST eu só preciso selecionar numa lista o método que quero utilizar. Imagino que no Restlet Client deve ser algo parecido.

E em relação ao erro que vc obteve é pq a action do seu controller está configurada para consumir MediaType.MULTIPART_FORM_DATA_VALUE e no cabeçalho da requisição que vc enviou está dizendo que vc está enviando "text/html" que e por isso a resposta é Unsupported Media Type.

Qual é seu e-mail ?

Prefiro te enviar por e-mail.

Você quer os fontes ?

Guilherme, não preciso de tudo!

Vc pode deixar só as partes relativas ao problema, o resto nem precisa mandar! O que eu quero é exatamente o que vc já colocou aqui.

Sim, entendi. Mas pode ser por e-mail ?

Pois vou te dar acesso ao GIT.

Não precisa me dar acesso não, Guilherme! Com o link eu já consigo baixar os arquivos. O acesso só seria necessário se eu fosse contribuir com commits o que não é o caso.

Quais códigos você quer ?

Controler do JAVA, Controller do Angular ?

Quais mais?

Mas pode passar e-mail ou não ?

Guilherme, faz essa modificação no seu código e tente fazer a requisição novamente para ver se agora a stacktrace irá aparecer no Console.

@RestController
    public class ArquivoImportadoController {
    @PostMapping(value = "/arquivoImportadoRecurso/salvar", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
        public RetornoJackson gravarBanco(
                @PathVariable("file") List<MultipartFile> file,
                @PathVariable("idEntidade") String idEntidade,
                @PathVariable("idEmpresa") String idEmpresa) {
            RetornoJackson retorno = new RetornoJackson();
            ArquivoImportadoEntity entidade = new ArquivoImportadoEntity();
            try {
                // restante do código
            } catch (RegraNegocioException e) {
                e.printStackTrace();
                // restante do código
            } catch (Exception e) {
                e.printStackTrace();
                // restante do código
            }
            return retorno;
        }
    }

Continua não aparecendo nada no console do eclipse.

Cole aqui o seu código após a alteração pra eu ver como ficou.

Esquisito, parece que o angular não acha este REST. ou é por causa do Arquivo.

@PostMapping(value = "/arquivoImportadoRecurso/salvar", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public RetornoJackson gravarBanco(
            @PathVariable("file") List<MultipartFile> file,
            @PathVariable("idEntidade") String idEntidade,
            @PathVariable("idEmpresa") String idEmpresa) {
        RetornoJackson retorno = new RetornoJackson();
        ArquivoImportadoEntity entidade = new ArquivoImportadoEntity();
        try {
            arquivoImportadoServico.validarCampos(entidade);
            EmpresaEntity empresa = new EmpresaEntity();
            empresa.setId(Long.parseLong(idEmpresa));
            entidade.setEmpresa(empresa);
            EntidadeEntity entidadeEntidade = new EntidadeEntity();
            entidadeEntidade.setId(Long.parseLong(idEntidade));
            entidade.setEntidade(entidadeEntidade);
            aplicacaoAuditoria(entidade);
            arquivoImportadoServico.salvar(entidade);
            retorno.setTipo(TipoRetornoMensagemEnum.SUCESSO);
            retorno.setMensagem(Constantes.SALVA_SUCESSO);
        } catch (RegraNegocioException e) {
            e.printStackTrace();
            logger.error(Constantes.erroSalvar(entidade.getClass().getName()),
                    e);
            retorno.setTipo(TipoRetornoMensagemEnum.ERRO);
            retorno.setMensagem(e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(Constantes.erroSalvar(entidade.getClass().getName()),
                    e);
            retorno.setTipo(TipoRetornoMensagemEnum.ERRO);
            retorno.setMensagem(e.getMessage());
        }
        return retorno;
    }

Pq vc está dizendo que "parece que o angular não acha este REST"?

Porque entendo que está tudo correto até então é o único método que não entra na parte server.

Faz o seguinte: coloca um breakpoint na primeira linha da sua action e inicia o jboss em modo de debug. Aí vc vai poder "debugar" o código e ver o que está acontecendo quando vc recebe a requisição.

Já está com o breakpoint nesta linha RetornoJackson retorno = new RetornoJackson();

Mas não executa o JAVA

Que estranho! Mas blz...

Como falei antes, faça um build da sua aplicação Angular, crie um zip delo projeto "buildado" e um zip do seu projeto Java. Compartilhe ambos os zips cmg (pelo github, dropbox, google drive, a forma que preferir) colando o link aqui. E eu darei uma olhada no que está acontecendo! Vc só precisa mandar os códigos estritamente necessários para fazer funcionar essa parte problemática!

Em relação ao meu email não será necessário pq não há necessidade de me colocar como colaborador do repositório.

Se não for possível compartilhar o código ficará difícil tentar adivinhar o que está acontecendo pq aparentemente pelas partes que vc postou aqui parece não haver nenhum problema.

Opa, Guilherme! Com os arquivos que vc passou pra mim não conseguirei fazer o projeto funcionar como eu disse na última msg.

Eu preciso do seu pom.xml uma vez que o problema pode ser de alguma biblioteca faltando, vou precisar dos arquivos que configuram o Spring no seu projeto. Sem essas coisas não tem como fazer a aplicação a parte que está dando problema funcionar.

O ideal é que vc faça o processo de export do Eclipse selecionando apenas os arquivos necessários para que poder importar o projeto aqui e fazer ele funcionar no Jboss 8 pq caso contrário não terei como te ajudar.

Então Gabriel, te perguntei na mensagem acima.

Sei que está querendo me ajudar, e eu fico grato, mas eu vou te passar o projeto por completo, mas quero passar somente para seu e-mail, pode me passar seu e-mail.

Eclipse é o Luna.

Não posso colocar meu email aqui pq o fórum é público! Se há restrição no seu projeto que não o possibilite compartilhar ele publicamente por completo, faça o que eu falei, faça o export do Eclipse apenas com as classes necessárias para que eu consiga fazer o deploy dele aqui e executar apenas essa action que está dando problema. E, depois que eu fizer o download, vc remove o compartilhamento de modo que o link não funcione mais.

http://www.netsoft.eti.br/outrosCodigos.rar

Então no primeiro zip tem a classe java e os arquivos js do angular.

Neste tem o pom.xml e a configuração do Spring.

Mas algum arquivo ?

Por enquanto, não. Vou ver o que consigo descobrir com esses arquivos e se precisar de algo mais eu falo!

O que tem extends , basta tirar

Preciso da classe SpringWebConfig e das classes que ela depende.

Guilherme, não consegui fazer funcionar aqui! O Jboss nem inicializa com o projeto que eu montei. Infelizmente não tá dando certo sem que eu possa ter o seu projeto já configurado...

No entanto, uma coisa que eu observei é que vc está anotando os parâmetros do método onde dá problema com @PathVariable, dessa forma:

@PathVariable("file") List<MultipartFile> file,
@PathVariable("idEntidade") String idEntidade,
@PathVariable("idEmpresa") String idEmpresa

No entanto, a anotação @PathVariable é utilizada quando vc quer pegar um valor passado na URL, por exemplo, o id de um livro: livro/1. Mas esse não é o caso aqui pq vc está querendo pegar as informações vindas do corpo da requisição POST.

E talvez essa seja a raiz do poblema (só continuo sem entender pq não é gerada nenhuma stacktrace)! Acho que vc terá que substituir os seus parâmetros por

@RequestBody MultiValueMap<String, Object> formData

Onde o MultiValueMap formData irá armazenar as informações vindas no corpo da requisição POST.

Isso foi a única coisa que eu pude observar no seu código que aparenta estar incorreta. Se não for isso eu fico sem ideia do que pode ser e sem poder ter acesso ao código fica complicado demais de ajudar, infelizmente.

Agora o erro é 400

Esta é a mensagem Required Long parameter 'idEntidade' is not present

Mudei no arquivo Java..

public RetornoJackson gravarBanco(
    @RequestParam("files") List<MultipartFile> files,
    @RequestParam("idEntidade") Long idEntidade,
    @RequestParam("idEmpresa") Long idEmpresa) {

Olhei outros exemplos aqui e está @RequestParam o inves de @PathVariable.

Sobre o que vc falou, não entendi.

O que vc não entendeu?

De como mudar

No java entendi que tenho que mudar

de

@RequestParam("files") List<MultipartFile> files,
    @RequestParam("idEntidade") Long idEntidade,
    @RequestParam("idEmpresa") Long idEmpresa

para

@RequestBody MultiValueMap<String, Object> formData

E no Angular ?

No angular vc não faz nada.

Erro 415

<html><head><title>Error</title></head><body>Unsupported Media Type</body></html>

Opa, agora sim! Isso quer dizer que a requisição chegou onde devia! \o/

O problema agora está no Angular! Vc tem que setar o cabeçalho "Content-Type" com o valor "multipart/form-data" antes de enviar a requisição.

Continuo sem saber o que fazer kkkkk

Seria isto:

salvar : function(files, idEntidade, idEmpresa, callback) {
                Upload.upload({
                    url: 'arquivoImportadoRecurso/salvar',
                    data: {
                        'files' : files,
                        'idEntidade' : idEntidade,
                        'idEmpresa' : idEmpresa
                    }
                    , arrayKey: '[]',
                    headers: {
                        "Content-Type": "application/json"
                    }
                }).progress(function (evt) {
                }).success(callback);
            }

Aí eu não tenho como saber, Guilherme. Vc não me deu acesso aos arquivos, não sei o que é essa classe Upload e nem essa função upload() que vc está executando. Sem saber o que está por trás dessas coisas todas não tem como eu saber.

Dê uma olhada nesse link que explica como setar o cabeçalho "Content-Type" nas requisições em Angular.

No entanto, repare que o valor deve ser "multipart/form-data".

Upload é ng-file-upload

Guilherme, eu nunce mexi com AngularJS. Mas, aparentemente é pra fazer o que vc falou.

No entanto, não esqueça que o valor de "Content-Type" deve ser "multipart/form-data".

Correto. Mesmo incluindo o erro 415 continua.

É, aí saiu completamente da minha alçada pq nunca mexi com AngularJS, somente com Angular 2+. A boa notícia é que ao menos ao que tudo indica agora as requisições estão chegando na action o que antes nem acontecia.

Fiz uma busca rápida no Google e encontrei esses três links, vê se algum deles te ajuda!

https://github.com/danialfarid/ng-file-upload/wiki/spring-mvc-example

https://stackoverflow.com/questions/35160483/empty-listmultipartfile-when-trying-to-upload-many-files-in-spring-with-ng-fil

https://shazwazza.com/post/uploading-files-and-json-data-in-the-same-request-with-angular-js/

P.S.: Só a título experimental, me diz o que acontece se vc tirar essa parte da sua action consumes = MediaType.MULTIPART_FORM_DATA_VALUE.

solução!

Então Funcionou assim:

Na classe de configuração coloquei o código abaixo,

@Bean
public MultipartResolver multipartResolver() {
    return new CommonsMultipartResolver();
}

No método alterei para:

@ResponseStatus(HttpStatus.OK)
    @PostMapping(value = "/arquivoImportadoRecurso/salvar", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public RetornoJackson gravarBanco(
            @RequestParam("files") MultipartFile files,
            @RequestParam("idEntidade") Long idEntidade,
            @RequestParam("idEmpresa") Long idEmpresa) {

Agora consigo parar com breackpoint dentro do JAVA

Ufa.

Boa, Guilherme! Agora sim! \o/

Sempre que tiver qualquer dúvida é só procurar o pessoal aqui no fórum!

Grande abraço!