2010-09-19 23 views
8

Tengo el siguiente bloque de código que maneja la carga de archivo de una foto que estoy usando en mi aplicación web Spring MVC. Estoy utilizando Spring MVC CommonsMultipartFileResolver para manejar las cargas de archivos.Problema con Spring FileUpload

if(model.getPhoto() != null){ 
    if(!model.getPhoto().isEmpty()){ 
     MultipartFile file = model.getPhoto(); 
     String fileName = file.getOriginalFilename(); 
     String filePath = baseDirectory + fileName; 
     FileOutputStream fos = new FileOutputStream(filePath); 
     try 
     { 
      fos.write(file.getBytes()); 
      agentProfile.setPhotoUri(fileName); 
     } 
     catch (IllegalStateException e) 
     { 
      System.out.println(e); 

     } 
     finally 
     { 
      fos.close(); 
     } 
    } 
} 

En mi archivo app-servlet.xml tengo el siguiente código para configurar el bean de resolución MultipartFile.

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
</bean> 

Tengo algunos problemas al azar cuando estoy cargando fotos.

1) Si voy a subir una foto más pequeña, alrededor de 3 kb o menos, se cargará correctamente.

2) Si voy a subir una foto un poco más grande, creará el archivo en el directorio, pero con un tamaño de 0 bytes y aparecerá el siguiente mensaje de error.

java.lang.IllegalStateException: File has been moved - cannot be read again 
org.springframework.web.multipart.commons.CommonsMultipartFile.getBytes(CommonsMultipartFile.java:112) 
com.mmz.admin.mvc.controller.AddAgentController.processFinish(AddAgentController.java:145) 
org.springframework.web.servlet.mvc.AbstractWizardFormController.validatePagesAndFinish(AbstractWizardFormController.java:642) 
org.springframework.web.servlet.mvc.AbstractWizardFormController.processFormSubmission(AbstractWizardFormController.java:492) 
org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:265) 
org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153) 
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48) 
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:874) 
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:808) 
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:476) 
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:441) 
javax.servlet.http.HttpServlet.service(HttpServlet.java:637) 
javax.servlet.http.HttpServlet.service(HttpServlet.java:717) 

he intentado un par de diferentes opciones de configuración de la resolución de varias partes, como cambiar a manejar una CommonsMultipartFile objeto como se oponen a una llanura MultipartFile objeto, pero nada cambió.

También intenté configurar manualmente el tamaño máximo de carga en el bean CommonsMultipartFileResolver con la siguiente propiedad.

<property name="maxUploadSize" value="1024000000"/> 

nada ha cambiado también. No estoy seguro de qué es CommonsMultipartResolver predeterminado en cuanto al tamaño del archivo que se puede cargar, pero esa no es mi pregunta.

Me han dicho que el problema que estoy experimentando se debe a un problema en el analizador/controlador de Multipart que está usando la primavera. Tengo una publicación reciente sobre este mismo problema, y ​​debido a que se encontró nueva información, quise volver a publicar la nueva información. La publicación anterior se puede encontrar en CommonsMultipartFileResolver Problem

Creo que he comprobado casi todos los recursos en Internet para encontrar documentación adicional, pero no puedo resolver el problema.

Por favor, ayúdenme a descubrir qué está pasando con esto, y si hay una mejor, solución más simple para tal vez explorar esas opciones, pero preferiría seguir con mi método actual si puedo encontrar una solución.

EDITAR Nota-He estado experimentando con diferentes fotos de tamaño para cargar, y yo creo que el límite que me permite cargar es de alrededor de 10Kb. Cualquier cantidad superior a 10 Kb provoca que se rompa y me da el error anterior.

+0

ver http://stackoverflow.com/questions/11792107/multipartresolver-is-not-working – lrkwz

Respuesta

11

Después de investigar mucho, resolví mi problema. Resulta que no hay un límite predeterminado establecido para la cantidad máxima de bytes que puede cargar usando CommonsMultipartFileResolver Por supuesto, puede especificar en su bean lo que desee para este monto configurando la siguiente propiedad.

<property name="maxUploadSize" value="99999999999"/> 

Existe también una propiedad maxInMemorySize que le permite especificar el tamaño máximo permitido antes de que los archivos se escriben en el disco.Aunque esto funciona de la misma manera que el tamaño máximo de carga, si no especifica una cantidad, el valor predeterminado es 1024 bytes. Esto explicaría si se rompe si intento cargar un archivo grande.

Con el fin de permitir que los archivos por encima de 1024 bytes a subir, es necesario aumentar el valor maxInMemorySize a lo que usted necesita como el siguiente ...

Esto es lo que se hizo cargo de mi problema. Me enteré de que esta propiedad tiene un valor predeterminado de 1024 cuando estaba revisando la documentación de la documentación de CommonsFileUpload.

Usted puede ver esta documentación en CommonsFileUpload Documentation

Espero que esto ayude a nadie, ya que no es muy buena documentación sobre el uso de CommonsMultipartFile.

+1

Buen hallazgo, aunque tengo la sensación de que esta configuración predeterminada no debería haber dado lugar a cargas rotas. Informaría un problema a los chicos de Spring para ver qué tienen que decir sobre este tema. – BalusC

+0

Lo haré, voy a investigar más sobre el tema. Llega a ser una sorpresa que tendrían un valor por defecto de uno a 1024 si no se especifica nada, pero no el otro. – TheJediCowboy

+0

De acuerdo con el enlace al que hace referencia, el valor predeterminado es 10240 bytes (que explica su resultado empírico anterior). –

3

Me di cuenta de que este error solo se produce cuando el archivo tiene más de 1024 bytes Y intenta leer el archivo dos veces. Como menciona CitadelCSAlum, establecer maxInMemorySize = maxUploadSize solucionará este problema, pero se debe tener en cuenta el uso de la memoria. Si la memoria es una preocupación, otra opción es escribir los datos de archivos multiparte en un archivo temporal en la primera lectura y usar ese archivo para lecturas posteriores. Si no lo lee dos veces, no debería necesitar aumentar maxInMemorySize.

2

La excepción a la que hace referencia en su pregunta indica: "El archivo se ha movido, no se puede volver a leer". Esto se debe a que estamos tratando de leer inputstream más de una vez desde un archivo de varias partes.

También me enfrenté a este problema al mismo tiempo, y en mi caso, primero validé el contenido del archivo, y después de eso traté de guardarlo usando el método "transferTo" en Spring MultiPart. Esta excepción se produce cuando trato de usar el método "transferTo". Aquí estoy llamando para inputstream dos veces.

No me enfrento a este problema cuando el tamaño del archivo es demasiado pequeño. En el método "transferTo" hay una llamada interna para el método "isAvailable". Por favor, siga el segmento de código a continuación:

protected boolean More ...isAvailable() { 
      // If in memory, it's available. 
     if (this.fileItem.isInMemory()) { 
      return true; 
     } 
     // Check actual existence of temporary file. 
     if (this.fileItem instanceof DiskFileItem) { 
      return ((DiskFileItem) this.fileItem).getStoreLocation().exists(); 
     } 
     // Check whether current file size is different than original one. 
     return (this.fileItem.getSize() == this.size); 
    } 

enlace: http://grepcode.com/file/repo1.maven.org/maven2/org.springframework/spring-web/3.2.1.RELEASE/org/springframework/web/multipart/commons/CommonsMultipartFile.java#CommonsMultipartFile.isAvailable%28%29

Observaciones:

  1. Si es demasiado pequeño, primavera guardarla en la memoria y cuando nos pide el archivo que retrive de memoria. Podemos pedirlo varias veces porque el archivo está en la memoria.

  2. Si es lo suficientemente grande, Spring lo guardará como un archivo temporal que no conocemos la ubicación, pero después de leer inputstream una vez que el archivo puede ser borrado internamente por Spring. Luego, cuando solicitamos por segunda vez, el error dice "no se puede volver a leer".

Así que mi solución es primero tengo que guardarlo en loaction servidor utilizando el método de "TransferTo" y retrive ese archivo local para validar o cualquier otra necesidad segundo tiempo.

Creo que no es bueno aumentar "maxUploadSize" en el bean "multipartResolver" ya que consume más memoria si el archivo es demasiado grande.

+1

Esto realmente no responde la pregunta. Si tiene una pregunta diferente, puede formularla haciendo clic en [Preguntar pregunta] (http://stackoverflow.com/questions/ask). También puede [agregar una recompensa] (http://stackoverflow.com/help/privileges/set-bounties) para atraer más atención a esta pregunta una vez que tenga suficiente [reputación] (http://stackoverflow.com/help/ que-reputación). – apaul

+0

No estoy de acuerdo con ese punto. Esta excepción viene cuando se llama al método "getBytes" en la clase "CommonsMultipartFile". En mi caso uso el método "transferTo", y en ambos casos llamará al método "isAvailable". Si ya usamos el flujo de entrada de ese archivo multiparte, esta excepción ocurrirá. Entonces, mi solución es primero, tenemos que guardar ese archivo en una ubicación de servidor y obtener ese archivo para hacer validaciones. Porque si se supera ese límite, Spring almacenará ese archivo en el disco que no está en la memoria. Cuando lo leamos una vez, eliminará ese archivo temporal en el disco. Pero si es demasiado pequeño, residirá en la memoria. – Arosha

+0

disculpa por eso, dada la redacción/formato de tu respuesta, parecía un comentario de "Tengo el mismo problema". Me retracté de mi voto negativo. – apaul

Cuestiones relacionadas