form - subir imagen con spring mvc
SpringBoot: Carga de archivos de transmisiĆ³n grandes usando Apache Commons FileUpload (4)
Gracias a algunos comentarios muy útiles de M.Deinum, logré resolver el problema. He limpiado algunas de mis publicaciones originales y las publico como una respuesta completa para futuras referencias.
El primer error que estaba cometiendo no fue deshabilitar el MultipartResolver
predeterminado que proporciona Spring. Esto terminó en el programa de resolución que procesa HttpServeletRequest
y, por lo tanto, lo consume antes de que mi controlador pueda actuar sobre él.
La forma de desactivarlo, gracias a M. Deinum fue la siguiente:
multipart.enabled=false
Sin embargo, había otra trampa oculta esperándome después de esto. Tan pronto como deshabilité la resolución predeterminada de varias partes, comencé a recibir el siguiente error al intentar realizar una carga:
Fri Sep 25 20:23:47 IST 2015
There was an unexpected error (type=Method Not Allowed, status=405).
Request method ''POST'' not supported
En mi configuración de seguridad, había habilitado la protección CSRF. Eso requería que enviara mi solicitud POST de la siguiente manera:
<html>
<body>
<form method="POST" enctype="multipart/form-data" action="/upload?${_csrf.parameterName}=${_csrf.token}">
<input type="file" name="file"><br>
<input type="submit" value="Upload">
</form>
</body>
</html>
También modifiqué un poco mi controlador:
@Controller
public class FileUploadController {
@RequestMapping(value="/upload", method=RequestMethod.POST)
public @ResponseBody Response<String> upload(HttpServletRequest request) {
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
// Inform user about invalid request
Response<String> responseObject = new Response<String>(false, "Not a multipart request.", "");
return responseObject;
}
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (!item.isFormField()) {
String filename = item.getName();
// Process the input stream
OutputStream out = new FileOutputStream(filename);
IOUtils.copy(stream, out);
stream.close();
out.close();
}
}
} catch (FileUploadException e) {
return new Response<String>(false, "File upload error", e.toString());
} catch (IOException e) {
return new Response<String>(false, "Internal server IO error", e.toString());
}
return new Response<String>(true, "Success", "");
}
@RequestMapping(value = "/uploader", method = RequestMethod.GET)
public ModelAndView uploaderPage() {
ModelAndView model = new ModelAndView();
model.setViewName("uploader");
return model;
}
}
donde Response es solo un tipo de respuesta genérica simple que uso:
public class Response<T> {
/** Boolean indicating if request succeeded **/
private boolean status;
/** Message indicating error if any **/
private String message;
/** Additional data that is part of this response **/
private T data;
public Response(boolean status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
// Setters and getters
...
}
Estoy tratando de cargar un archivo grande usando la API de carga de archivos de Apache Commons de "transmisión".
La razón por la que estoy usando el Cargador de archivos de Apache Commons y no el cargador de Spring Multipart predeterminado es que falla cuando cargamos archivos de gran tamaño (~ 2 GB). Estoy trabajando en una aplicación GIS donde las cargas de archivos son bastante comunes.
El código completo para mi controlador de carga de archivos es el siguiente:
@Controller
public class FileUploadController {
@RequestMapping(value="/upload", method=RequestMethod.POST)
public void upload(HttpServletRequest request) {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
// Inform user about invalid request
return;
}
//String filename = request.getParameter("name");
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
try {
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
System.out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected.");
} else {
System.out.println("File field " + name + " with file name " + item.getName() + " detected.");
// Process the input stream
OutputStream out = new FileOutputStream("incoming.gz");
IOUtils.copy(stream, out);
stream.close();
out.close();
}
}
}catch (FileUploadException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
@RequestMapping(value = "/uploader", method = RequestMethod.GET)
public ModelAndView uploaderPage() {
ModelAndView model = new ModelAndView();
model.setViewName("uploader");
return model;
}
}
El problema es que el getItemIterator(request)
siempre devuelve un iterador que no tiene ningún elemento (es decir, iter.hasNext()
) siempre devuelve false
.
Mi archivo application.properties es el siguiente:
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:19095/authdb
spring.datasource.username=georbis
spring.datasource.password=asdf123
logging.level.org.springframework.web=DEBUG
spring.jpa.hibernate.ddl-auto=update
multipart.maxFileSize: 128000MB
multipart.maxRequestSize: 128000MB
server.port=19091
La vista JSP para el /uploader
es la siguiente:
<html>
<body>
<form method="POST" enctype="multipart/form-data" action="/upload">
File to upload: <input type="file" name="file"><br />
Name: <input type="text" name="name"><br /> <br />
Press here to upload the file!<input type="submit" value="Upload">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>
¿Qué podría estar haciendo mal?
Intente agregar spring.http.multipart.enabled=false
en el archivo application.properties .
Si está utilizando una versión reciente de Spring Boot (estoy usando 2.0.0.M7), los nombres de las propiedades han cambiado. Spring comenzó a usar nombres específicos de tecnología.
spring.servlet.multipart.maxFileSize = -1
spring.servlet.multipart.maxRequestSize = -1
spring.servlet.multipart.enabled = false
Si está obteniendo excepciones de StreamClosed causadas por la implementación de múltiples implementaciones, la última opción le permite desactivar la implementación Spring predeterminada.
Yo uso kindeditor + springboot. Cuando uso la solicitud (MultipartHttpServletRequest) Podría obtener el archivo, pero uso appeche-common-io: upload.parse (solicitud) el valor de retorno es nulo.
public BaseResult uploadImg(HttpServletRequest request,String type){
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultiValueMap<String, MultipartFile> multiFileMap = multipartRequest.getMultiFileMap();