Upload de imagem - servelt - Erro fácil

12 respostas
101574

Bom dia Galera,
Estou fazendo uma aplicação web.
Onde, tenho o seguinte formulário.

<form action="mvc" method="post" enctype="multipart/form-data">
<input type="hidden" name="logica" value="AdicionaSistema"/>
Nome Sistema: &lt;input type="text" name="nome" /&gt; <br />
Descrição do Sistema: &lt;input type="text" name="descricao" /&gt;<br />
Ativo? &lt;input type=radio name="ativo" value="1"&gt; Sim   &lt;input type=radio name="ativo" value="0"&gt; Não<br></br>
Url &lt;input type="text" name="url" /&gt;<br />
Imagem do Sistema &lt;input type="file" name="imagem"/&gt;<br />
&lt;input type="submit" value="Gravar" /&gt;
&lt;/form&gt;

Como vcs podem ver. Utilizo, uma servlet que recebe o metodo, e manda para a servlet especificada.

&lt;input type="hidden" name="logica" value="AdicionaSistema"/&gt;

Minha mvc está assim.

protected void service(HttpServletRequest request,HttpServletResponse response) throws ServletException,
	IOException{
		String parametro = request.getParameter("logica");
		String nomeDaClasse = "br.com.softsolweb.servlet."+ parametro;
		try{
			Class classe = Class.forName(nomeDaClasse);
			
			Logica logica = (Logica) classe.newInstance();
			logica.executa(request, response);
		}catch (Exception e){
			throw new ServletException("A lógica de negócios causou uma exceção ",e);
			}
		}

Minha AdicionaSistema.

public void executa(HttpServletRequest request, HttpServletResponse response)
				throws Exception {
			
			Sistemas sistemas = new Sistemas();
			//montando o objeto
			sistemas.setNome(request.getParameter("nome"));
			sistemas.setAtivo(request.getParameter("ativo"));
			sistemas.setDescricao(request.getParameter("descricao"));
			
			//Adicionando imagem.
			boolean isMultipart = FileUpload.isMultipartContent(request);    
	           if (isMultipart) {    
	              // Create a new file upload handler    
	              DiskFileUpload upload = new DiskFileUpload();    
	                  
	              // Set upload parameters    
	              upload.setSizeMax(50*1024*1024); //50Mb    
	             // upload.setRepositoryPath("/home/kde/file");    
	                  
	              // Parse the request    
	              List items = upload.parseRequest(request);    
	                  
	              Iterator it = items.iterator();    
	              while (it.hasNext()) {    
	                 FileItem fitem = (FileItem) it.next();    
	                 if (!fitem.isFormField()) {    
	                	 File uploadedFile = new File("/home/kde/file/"+new Date().getTime()+"_"+fitem.getName());
	                	 fitem.write(uploadedFile);
	                	 System.out.println("Nome do arquivo: " + fitem.getName() + " -  "  + fitem.getSize() + "bytes");
	                	 //sistemas.setImagem(fitem.getName());
	                }    
	              }    
	           }    
	           				sistemas.setUrl(request.getParameter("url"));
			
			//DAO
			SistemasDAO dao = new SistemasDAO();
			dao.adiciona(sistemas);
			RequestDispatcher rd = request.getRequestDispatcher("/sucesso/adicionadosucesso.jsp");
			rd.forward(request, response);
			
		}

Quando eu utilizo.

enctype="multipart/form-data"

Dá o seguinte erro.

A lógica de negócios causou uma exceção

e

br.com.softsolweb.servlet.null

Como se eu não tivesse enviado o parametro logica preenchido.

Já quando eu retiro.

enctype="multipart/form-data"

Dá o seginte erro.

A lógica de negócios causou uma exceção

Claro né.
e

Column 'imagemsistemas' cannot be null

Pelo que eu entendi, quando eu estou utilizando o enctype, a minha mvc não consegue ler o meu hidden.
E quando retiro, a minha imagem não está ‘chegando’ na minha AdicionaSistema.

Vocês poderiam a me ajudar.
Sei que é uma besteirinha de nada.

Já está quase pronto o sistema.
Fiz todo em jsp, servlet.
Ficou muito bom.
Só falta enviar a imagem.
Outra coisa, to salvando a imagem em uma pasta, e o nome do arquivo no banco. Para depois recuperar.

sistemas.setImagem(fitem.getName());

Gratos.

Wesley Martins.

12 Respostas

Rodrigo_Sasaki

Com formulários que possuem o enctype multipart/form-data o buraco é mais embaixo, você não vai conseguir recuperar os valores da maneira que costuma fazer.

a lib de fileupload da apache pode te ajudar com isso aí.

101574

Como eu vou fazer então.
Terei que alterar tudo?
Tipo, alterar minha classe mvc.
Pra ler enctype?
Mas assim eu não quero.rsrsrs.
Teria outra solução não???
Porque assim, são várias paginas que enviam para a mvc.
Terei que alterar todas. Por causa de uma.
Que vou precisar enviar uma imagem?

E como eu faço isso?
Teria um me ajudar com isso?

Grato.

diogozero

Acontece que quando você utiliza no enctype o valor ?application/x-www-form-urlencoded? é ineficiente quando está tratando grandes quantidades de dados binários ou texto com caracteres não-ASCII.

A requisição vai de uma forma diferente, de modo que request.getParameter(); não funciona. Por isso o seu hidden não é lido pela servlet.

Nesse post eu fiz um exemplo de upload de arquivo com servlets. Vê ai se serve de apoio pra você!
http://blogdiogomoreira.wordpress.com/2012/03/30/upload-de-arquivos-utilizando-servlets/

101574

Valeu pela resposta.
Estou vendo esse artigo aqui.
E vou ter que alterar minha mvc.
http://www.coffeecode.com.br/upload-de-arquivos-com-java/
Vou implementar, e assim que consiguir. Posto aqui.
O seu código ta ótimo, mas aqui não estou usando ainda servlet 3.0.
Então esse está mais próximo do que preciso.
E tem uma coisa, preciso de isso para hoje. Então, não tem como estudarmuito.
E deixar pronto. E depois … e depois.

Abraço.
Valeu.

diogozero

Servlet 3.0 nesse caso do post é só não precisar mapear as servlets no web.xml.

De todo modo, espero que dê certo!
Abraço!

101574

Bom,
Já implementei o código. Mas estacionei aqui.

boolean isMultipart = ServletFileUpload.isMultipartContent(request);
			 	        if(isMultipart) {
			 	            try {
			 	                FileItemFactory factory = new DiskFileItemFactory();
			 	                ServletFileUpload upload = new ServletFileUpload(factory);
			 	                List&lt;FileItem&gt; items = (List&lt;FileItem&gt;)upload.parseRequest(request);
			 	                for(FileItem item : items) {
			 	                    if(item.isFormField()) {
			 	                    	//se for um campo normal de form
			 	                    sistemas.setNome(item.getFieldName());
			 	           			sistemas.setAtivo(item.getFieldName());
			 	           			sistemas.setDescricao(item.getFieldName());
			           				sistemas.setUrl(item.getFieldName());

			 	                        
			 	                    } else {
			 	                        //caso seja um campo do tipo file
			 	                         File uploadedFile = new File("/home/kde/file/"+new Date().getTime()+"_"+item.getName());
			 		                	 item.write(uploadedFile);
			 		                	 System.out.println("Nome do arquivo: " + item.getName() + " -  "  + item.getSize() + "bytes");
			 		                	 sistemas.setImagem(fitem.getName());
			 	                    }
			 	                }
			 	            } catch (Exception e) {
			 	                response.getWriter().println("ocorreu um problema ao fazer o upload: " + e.getMessage());
			 	            }
			 	 
			 	        }
			 	
			
			//DAO
			SistemasDAO dao = new SistemasDAO();
			dao.adiciona(sistemas);
			RequestDispatcher rd = request.getRequestDispatcher("/sucesso/adicionadosucesso.jsp");
			rd.forward(request, response);
			
		}

Pelo que entendi, vamos fazer uma listagem de todos os campos do meu form.
Mas como eu vou saber, quem é quem?

E para finalizar, o erro que mais gosto do apache.

A lógica de negócios causou uma exceção 

Column 'nomesistemas' cannot be null

Realmente a coluna nomesistemas não pode ser nula.rsrs.
Teria como vocês me ajudar com isso.
Preciso disso urgente.

Valeu.
Wesley Martins.

diogozero

Você pode fazer um switch com um contador, os campos vem na ordem que você os declarou lá no HTML.
Logo, você vai saber como tratar cada campo dentro do switch.

101574

Valeu pela resposta.

Mas não consegui resolver.
Olha só, como eu estava fazendo, e funcionava perfeitamente.

Form
&lt;form action="mvc" method="post"&gt;
&lt;input type="hidden" name="logica" value="AdicionaSistema"/&gt;
Nome Sistema: &lt;input type="text" name="nome" /&gt; <br />
Descrição do Sistema: &lt;input type="text" name="descricao" /&gt;<br />
Ativo? &lt;input type=radio name="ativo" value="1"&gt; Sim   &lt;input type=radio name="ativo" value="0"&gt; Não<br></br>
Url &lt;input type="text" name="url" /&gt;<br />
Imagem do Sistema &lt;input type="file" name="imagem"/&gt;<br />
&lt;input type="submit" value="Gravar" /&gt;
&lt;/form&gt;
O meu form, envia para o mvc. A classe ControlSerlvet mapeada. Classe ControlSerlvet.
public class ControllerServlet extends HttpServlet{
	
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request,HttpServletResponse response) throws ServletException,
	IOException{
		String parametro = request.getParameter("logica");
		String nomeDaClasse = "br.com.softsolweb.servlet."+parametro;
		try{
			Class classe = Class.forName(nomeDaClasse);
			
			Logica logica = (Logica) classe.newInstance();
			logica.executa(request, response);
		}catch (Exception e){
			throw new ServletException("A lógica de negócios causou uma exceção ",e);
			}
		}
	}

Ela recebia do form, a classe que devia chamar.
Com isso, eu tinha apenas um mapeamento.

Agora minha classe AdicionaSistema.
public class AdicionaSistema implements Logica{
	
		public void executa(HttpServletRequest request, HttpServletResponse response)
				throws Exception {
			
			Sistemas sistemas = new Sistemas();
			//montando o objeto
			sistemas.setNome(request.getParameter("nome"));
			sistemas.setAtivo(request.getParameter("ativo"));
			sistemas.setDescricao(request.getParameter("descricao"));
			sistemas.setImagem(request.getParameter("imagem"));
			sistemas.setUrl(request.getParameter("url"));
			
			//DAO
			SistemasDAO dao = new SistemasDAO();
			dao.adiciona(sistemas);
			RequestDispatcher rd = request.getRequestDispatcher("/sucesso/adicionadosucesso.jsp");
			rd.forward(request, response);
			
		}

	}

Está funcionando corretamente.
Só que eu recebia somente o nome da imagem. Não recebia a imagem em si.

Ai eu mudei o meu form para.

&lt;form action="mvc" method="post" enctype="multipart/form-data"&gt;

Ai parou de funcionar.
Disseram que eu precisa tratar, os diferente.
Fiz as alterações.

No meu form, somente
enctype="multipart/form-data
Na minha mvc. Eu deixei ela assim.
public class ControllerServlet extends HttpServlet{
	
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request,HttpServletResponse response) throws ServletException,
	IOException{
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
			        if(isMultipart) {
			            try {
			                FileItemFactory factory = new DiskFileItemFactory();
			                ServletFileUpload upload = new ServletFileUpload(factory);
			                List&lt;FileItem&gt; items = (List&lt;FileItem&gt;)upload.parseRequest(request);
			                for(FileItem item : items) {
			                    if(item.isFormField()) {
			                        //se for um campo normal de form
			                        
			                        String parametro = item.getString();
			                        String nomeDaClasse = "br.com.softsolweb.servlet."+ parametro;
			                		try{
			                			Class classe = Class.forName(nomeDaClasse);
			                			
			                			Logica logica = (Logica) classe.newInstance();
			                			logica.executa(request, response);
			                		}catch (Exception e){
			                			throw new ServletException("A lógica de negócios causou uma exceção ",e);
			                			}
			                    }
			                }
			            } catch (FileUploadException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}finally{
			            	System.out.println("finally");
			            }
			        }
	}
}
E minha ServelAdicionaSistema.
public class AdicionaSistema implements Logica{
	
		public void executa(HttpServletRequest request, HttpServletResponse response)
				throws Exception {
			
			Sistemas sistemas = new Sistemas();
			//montando o objeto
			 boolean isMultipart = ServletFileUpload.isMultipartContent(request);
			 	        if(isMultipart) {
			 	            try {
			 	                FileItemFactory factory = new DiskFileItemFactory();
			 	                ServletFileUpload upload = new ServletFileUpload(factory);
			 	                List&lt;FileItem&gt; items = (List&lt;FileItem&gt;)upload.parseRequest(request);
			 	                for(FileItem item : items) {
			 	                    sistemas.setNome(item.getFieldName());
			 	           			sistemas.setDescricao(item.getFieldName());
			 	           			sistemas.setAtivo(item.getFieldName());
			           				sistemas.setUrl(item.getFieldName());
			           				//imagem
	 	                         File uploadedFile = new File("/home/kde/file/"+new Date().getTime()+"_"+item.getName());
			 		                	 item.write(uploadedFile);
			 		                	 System.out.println("Nome do arquivo: " + item.getName() + " -  "  + item.getSize() + "bytes");
			 		                	 sistemas.setImagem(item.getName());
			 		                	//DAO
			 		       			SistemasDAO dao = new SistemasDAO();
			 		       			dao.adiciona(sistemas);
			 		       			RequestDispatcher rd = request.getRequestDispatcher("/sucesso/adicionadosucesso.jsp");
			 		       			rd.forward(request, response);
			 	            }
			 	}finally{
			 	
		}

		}
}
}

Não funciona.
Qual a forma correta de se fazer isso?
Porque, minha aplicação estava funcionando corretamente. E agora não.
Porcausa de uma imagem, tive que mudar tanta coisa e não funciona mais.rsrs.

Grato.

murilo.ramos

Para campos mutipart form data é diferente o modo de receber os parametros

Use a biblioteca da apache “fileupload” proccura aki no forum que vc acha sobre ela.
Ai pra pegar os parametros que vem do formulario, use o seguinte código:

DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload sfu = new ServletFileUpload(factory);

        try {

            if (request.getContentType()==null || !request.getContentType().startsWith("multipart/form-data")){
                //se não for multipart/form-data não pode ser tratado aqui, senão gera exception 
                return;
            }

            List list = sfu.parseRequest(request);
            Iterator iterator = list.iterator();

            while (iterator.hasNext()) {
                FileItem item = (FileItem) iterator.next();                

                if (item.isFormField()) { //para campo comum de formulario
                    if (item.getFieldName().equals("nome_do_campo_comum_no_form")){ 
                        this.seuvalor = item.getString();
                    }                    
                } else { //para campo file                   
                    String filename = item.getName();
                    if ((filename != null) && (!filename.equals(""))) {                        
                        if (item.getFieldName().equals("nome_do_campo_file_no_form")){
                            this.seuFileBytes = item.get(); //aqui estou pegando como array de bytes, ai vc pode escreve-lo em um arquivo depois
                        }                            
                    }                                            
                }                

            }

        } catch (FileUploadException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

Assim vc consegue misturar campos comuns do form com campos do type “file”, que vem como um array gigante de bytes.
Outra dica é que quando vc executar o metodo acima, SEMPRE jogue os valores para uma variavel, pq (não sei o motivo) uma vez que vc varrer o request atras dos parametros, eles somem do request e vc não consegue mais acessá-los.

101574

Desculpa, mas esse código eu uso em qual servlet.

Controler.
ou Adiciona?

Eu poderia, já fazer assim então.

if (item.isFormField()) { //para campo comum de formulario  
            if (item.getFieldName().equals("nome")){   
                String nome = item.getString(); 
            }
murilo.ramos

o código é um exemplo básico, vc deve adaptá-lo as suas necessidades.

Pelo que vi, vc usa um parametro do form para instanciar um classe (logica) certo? isso parece bem problematico.
Nesse seu caso acho que a melhor coisa é vc criar uma terceira classe (se vc é acostumado com web, leia-se “bean”) para tratar a request, ai na sua servlet vc instancia ela e trata os parametros, utilizando depois como objeto, exemplo:

ClasseBlah cb = new ClasseBlah(request); // aki ela recebe a request no construtor e realiza as atribuições para os atributos de acordo com os parametros

ai depois vc usa os atributos desse objeto para o resto, exemplo:

protected void service(HttpServletRequest request,HttpServletResponse response) throws ServletException,  
    IOException{  

        ClasseBlah cb = new ClasseBlah(request); // aki ela recebe a request no construtor e realiza as atribuições para os atributos de acordo com os parametros

        String parametro = cb.getParametro();
        String nomeDaClasse = "br.com.softsolweb.servlet."+parametro;  
        try{  
            Class classe = Class.forName(nomeDaClasse);  
              
            Logica logica = (Logica) classe.newInstance();  
            logica.executa(cb, response);  // ai aqui vc passa o seu objeto contendo seus atributos
        }catch (Exception e){  
            throw new ServletException("A lógica de negócios causou uma exceção ",e);  
            }  
        }  
    }

Isso trará mudanças na sua outra classe também, porém irá ficar bem mais fácil !!!

101574

Entendi, mas você concorda comigo que é muito trabalho. Para uma simples função?

Porque assim…

Eu tenho um form.
Que envia para uma serlvelt.
Essa servelt, recebe o paramentro, com o nome da outra servlet que fará o serviço.
Porque asssim, eu tenho um mapeamento apenas.
Entende.

Eu retirei esse exemplo da classe control - mvc.
Da apostila da Caelum fj21.
Será que eles não previam o envio de um arquivo, no form?
Porque essa ideia e deles.rsrs.

Agora, eu terei qe criar uma outra bean.
Para receber, os dados,e depois enviar.
Nossa, tenho uns 15 cadastros com foto.
Terei que alterar tudo.
E sem falar, nas serlvelts correspodentes.

Obrigado pela atenção.

Criado 21 de agosto de 2012
Ultima resposta 22 de ago. de 2012
Respostas 12
Participantes 4