Subir ficheros al servidor con Spring MVC

4
31277

Subir ficheros al servidor con Spring MVC

Introducción

Los formularios en aplicaciones web son la forma básica de comunicación entre el cliente y el servidor. Una de las cosas que se puede hacer con ellos es subir ficheros para su tratamiento o almacenamiento. Desde el punto de vista de las tecnologías del lado cliente, esto es muy sencillo, puesto que sólo hay que definir un «input» de tipo «file» y un botón de envío del formulario… Las dificultades llegan cuando queremos recoger los datos subidos y tratarlos en la parte servidora.

Estas dificultades se reducen con el uso de frameworks, que nos proporcionan soluciones fáciles y sencillas para este tipo de tareas. A lo largo de los años hemos visto desfilar por esta página tutoriales para aprender a subrir ficheros desde un formulario usando diferentes tecnologías, como el proyecto FileUpload de Jakarta/Apache CommonsStrutsJSF o, incluso, .NET

Spring no va a ser menos y también nos proporciona una manera sencilla de llevar a cabo estas tareas. En este tutorial vamos a ver cómo hacerlo

Entorno del tutorial

El tutorial se ha desarrollado en el siguiente entorno

  • Mac Book Pro Intel Core i7 2,8GHz
  • Sistema operativo Mac OS X 10.6.8 (Snow Loepard)
  • Eclipse Indigo (Edición para desarrolladores JEE) con el plugin m2e para integración con Maven

«WebContent/uploadFileSpring/uploadFileSpring.html»

Crear un controlador que pinte un formulario

El primer paso en nuestro tutorial es tener un proyecto de Spring MVC funcionando. Podíes hacerlo como queráis… Yo lo he creado con el plugin de Maven para eclipse, seleccionando el arquetipo «spring-mvc webapp»

Seleccionar arquetipo spring-mvc-webapp

Este arquetipo tiene demasiadas funcionalidades para lo que nosotros vamos a necesitar, pero me crea el esqueleto de lo que necesito en cuestión de segundos. Hay que hacer un poco de limpieza para quitar todo lo relativo a JPA
, pero el resto os puede valer. Lo importante en este caso es la rapidez 🙂

Partiremos de un controlador muy sencillo, que simplemente nos redirigirá a una JSP que pintará el formulario

El controlador

package com.autentia.tutoriales.file.upload.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("greet")
public class GreetController {

    @RequestMapping(method = RequestMethod.GET)
    public void getInitialMessage() {
        
    }    
}

Formulario en JSP (greet.jsp)

<form method="post" action="greet" enctype="multipart/form-data">
    <table>
        <tr>
           <td>Selecciona fichero: </td>
           <td><input type="file" name="fichero"></td>
        </tr>
        <tr>
    
        </tr>
        <tr><td colspan="2" align="center">
    	<input type="submit" value="Subir fichero"></td>
        </tr>
     </table>
</form>

Esto nos da el el siguiente resultado en el navegador:

Formulario en el navegador

Es muy importante el atributo «enctype=multipart/form-data», ya que si no lo ponemos no funcionará el envío de ficheros

Modificar el controlador para gestionar los datos subidos

El primer paso es agregar a nuestra aplicacion la capacidad de manejar formularios «multipart». Para ello, instanciamos un «MultipartResolver» como un bean de Spring, en el spring-mvc-context.xml (el fichero donde se van a definir los beans que se emplearán desde los controladores)

<beans xmlns="..."
   xmlns:xsi="..." xmlns:context="..."
   xmlns:mvc="..."
   xsi:schemaLocation="...">

   <context:component-scan base-package="com.autentia.tutoriales.file.upload.web" ></context:component-scan>

   <mvc:annotation-driven ></mvc:annotation-driven>

   <bean
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/views/" />
      <property name="suffix" value=".jsp"></property>
   </bean>
   
   <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
   
</beans>

Ahora, nos crearemos una clase (un POJO) que recogerá el fichero del servidor. Esta clase tendrá un único atributo, que se llamará igual que el input de tipo file que hemos puesto en el formulario («fichero»), con su getter y su setter

package com.autentia.tutoriales.file.upload.web.formbean;

import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class FileFormBean {

	CommonsMultipartFile fichero;

	public CommonsMultipartFile getFichero() {
		return fichero;
	}

	public void setFichero(CommonsMultipartFile fichero) {
		this.fichero = fichero;
	}	
}

El atrobuto es de tipo «CommonsMultipartFile», que es la clase que empleará el «resolver» que hemos definido en el xml anteriormente para representar un fichero subido desde el cliente

A continuación, hacemos algunos pequeños cambios tanto en el controlador como en la JSP del formulario

El controlador:

package com.autentia.tutoriales.file.upload.web;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.autentia.tutoriales.file.upload.web.formbean.FileFormBean;

@Controller
@RequestMapping("greet")
public class GreetController {

    

    @RequestMapping(method = RequestMethod.GET)
    public @ModelAttribute("fileFormBean") FileFormBean getInitialMessage() {
        return new FileFormBean();
    }

    @RequestMapping(method = RequestMethod.POST)
    public @ModelAttribute("message") String guardaFichero(@ModelAttribute FileFormBean fileFormBean) {
    	
    	try {
			grabarFicheroALocal(fileFormBean);
		} catch (Exception e) {
			e.printStackTrace();
			return "No se ha podido grabar el fichero";
		}
    	
    	return "Fichero grabado correctamente";
    }

	private void grabarFicheroALocal(FileFormBean fileFormBean) throws Exception {
		CommonsMultipartFile uploaded = fileFormBean.getFichero();
    	File localFile = new File("/Ruta/A/Mi/Fichero/"+uploaded.getOriginalFilename());
    	FileOutputStream os = null;
    	
    	try {
    		
    		os = new FileOutputStream(localFile);
    		os.write(uploaded.getBytes());
    		
    	} finally {
    		if (os != null) {
    			try {
					os.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
    		}
    	}
	}
}

El formulario:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
...
<c:out value="${message}"/>
<form:form method="post" action="greet" enctype="multipart/form-data" commandName="fileFormBean">
    <table>
        <tr>
           <td>Selecciona fichero: </td>
           <td><input type="file" name="fichero" /></td>
        </tr>
        <tr>
    
        </tr>
        <tr><td colspan="2" align="center">
    	<input type="submit" value="Subir fichero"></td>
        </tr>
     </table>
</form:form>

Además, es necesario agregar al «pom.xml» las dependencias con «commons-fileupload» y «commons-io»

<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.2.2</version>
</dependency>
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.0</version>
</dependency>

Llega el momento de probar…

Tras compilar, empaquetar y redesplegar en el servidor, hacemos la prueba. Lanzamos nuestro formulario en el navegador…

Formulario de subida de ficheros

… Seleccionamos un fichero y enviamos el formulario, obteniendo un mensaje de éxito

fichero grabado correctamente

Consultamos el directorio de destino y…

Fichero en carpeta de destino

… ¡¡ahí lo tenemos!!

Conclusión

Como hemos visto, con Spring es muy sencillo subir un fichero al servidor… Es importante conocer bien los frameworks que manejamos e incluso los que no manejamos, puesto que en un momento dado nos pueden facilitar de manera decisiva una tarea que de otra manera sería muy costosa

4 COMENTARIOS

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad