martes, 16 de abril de 2013

SPRING 3 MVC - MULTIPLE FILE UPLOAD

En este tutorial vamos a explicar cómo crear una sencilla aplicación con SPRING 3 MVC que nos va a permitir subir ficheros a nuestro servidor para después descargarlos desde una página de enlaces.

El código fuente lo puedes descargar en este enlace:
subirFichero.jar

Contenido:

Pantallas aplicación

Una imagen vale más que mil palabras.

Inicialmente mostramos una pantalla desde la que el usuario va a seleccionar los ficheros a subir al servidor.


Al pinchar en el botón "Subir archivo", se inicia el proceso de carga de los ficheros. Si todo ha ido bien, se muestra una pantalla con un mensaje de confirmación de la correcta carga de éstos.


Si volvemos a la pantalla anterior, podemos acceder a través del enlace “Listado de ficheros” a una página con los enlaces a todos los ficheros que se han subido al servidor.



Añadir las dependencias a nuestro proyecto


Para poder subir los ficheros, añadimos a nuestro proyecto las siguientes dependencias: commons-fileupload y commons-io. El fichero pom.xml de nuestro proyecto quedará de la siguiente forma.

pom.xml

  4.0.0
  com.estructuradigital
  war
  0.0.1-SNAPSHOT
  subirFichero
  http://maven.apache.org
  
    
      junit
      junit
      3.8.1
      test
    
        
        org.springframework
        spring-webmvc
        3.1.2.RELEASE
     

    
        commons-fileupload
        commons-fileupload
        1.2.2
    
    
        org.apache.commons
        commons-io
        1.3.2
    
    
        jstl
        jstl
        1.2
    
   
    org.springframework
    spring-tx
    3.1.1.RELEASE
   
   
    org.springframework
    spring-orm
    3.1.1.RELEASE
   
  
  
    subirFichero
  
  subirFichero


Configuración de Spring


Configuración multipartresolver en applicationContext.xml


Para que Spring sea capaz de recibir peticiones que contengan ficheros, tenemos que configurar un multipart resolver en el contexto de la aplicación.


O lo que es lo mismo, escribiremos en nuestro fichero applicationContext.xml la siguiente definición.


        
        
    

De esta forma permitiremos que desde un formulario HTML se hagan peticiones en las que se incluyan ficheros y posteriormente acceder a éstos desde los controladores de la aplicación.


Crear el formulario HTML para solicitar y enviar fichero


Una vez de añadidas las dependencias necesarias y configurado el multipartresolver en el contexto de la aplicación, procedemos a crear dentro de la página subirFichero.jsp el formulario HTML desde el que se va a lanzar la petición de carga de los ficheros.
Mediante el atributo enctype="multipart/form-data" del formulario indicamos que la petición que se creará de este formulario contiene ficheros y por tanto como se tiene que gestionar.


Seleccione los ficheros a subir. Pulse elboton "Añadir fichero " para añadir más ficheros.

Utilizamos el campo action="subirarchivo.htm" para indicar el método del controlador sobre el que se mapera la petición.
Los ficheros se transportan en la petición almacenados un objeto listaFicheros del tipo ListaFicheros.class y que declaramos en el atributo del formulario “modelAttribute="listaFicheros”.
ListaFicheros es una clase que creamos nosotros que encapsula en una lista del tipo org.springframework.web.multipart.MultipartFile los diferentes archivos. MultipartFile es una clase que nos proporciona Spring para el manejo de ficheros y que nos va a permitir almacenar el contenido de estos así como su nombre,tamaño,etc.

ListaFicheros.java
package com.estructuradigital.subirFichero.modelo;

import java.util.List;
import org.springframework.web.multipart.MultipartFile;

public class ListaFicheros {
 
 private List archivos;

 public List getArchivos() {
  return archivos;
 }

 public void setArchivos(List archivos) {
  this.archivos = archivos;
 }

 public int size() {
  return archivos.size();
 }         
}

Se ha añadido el siguiente script en jquery para añadir dinámicamente, cada vez que se pulse sobre el botón “Añadir Fichero”, más botones y cajetines en los que seleccionar los ficheros a subir al servidor./p>


Todo este código lo escribimos en el fichero subirFichero.jsp

subirFichero.jsp



Controlador


El siguiente paso sera crear un controlador que maneje la carga de los ficheros.
El método del controlador que vamos a utilizar para procesar los ficheros es el siguiente:

@RequestMapping(value="/subirarchivo.htm",method= RequestMethod.POST)
    protected String subirFichero(@ModelAttribute("listaFicheros") ListaFicheros  listaFicheros,HttpServletRequest request) {

  logger.debug("ControladorSubirFichero: Inicializando proceso copia ficheros");
  
     List ficheros = listaFicheros.getArchivos();          
      
     
         if(null != ficheros && ficheros.size() > 0) {      
         
          for (MultipartFile fichero : ficheros) {       
               
           if (!fichero.isEmpty()){
               
                String nombreOriginalArchivo = fichero.getOriginalFilename();
                File ficheroDestino = new File(request.getSession().getServletContext().getRealPath("/ficheros/") +"/" + nombreOriginalArchivo);
                  
                logger.debug("copiando fichero en : " + request.getSession().getServletContext().getRealPath("/ficheros/"));
                try {
                      fichero.transferTo(ficheroDestino);
                } catch (IllegalStateException e) {
                 e.printStackTrace();
                 return "Error al subir el fichero: " + nombreOriginalArchivo ;
                } catch (IOException e) {
                 e.printStackTrace();
                 return "Error al subir el fichero: " + nombreOriginalArchivo ;
                }
                           
                   
                }else {
              
               return "errorSubirFichero" ;
              }  //fin del if 
          
          }   //fin del for  
          return "correctoSubirFichero";  
         }else {
          return "errorSubirFichero" ;
         }//fin del if,hay elementos seleccionados          
               
 }

Para leer el listado de ficheros creamos el siguiente método en el controlador.

@RequestMapping(value="/descargarFicheros.htm ")
  public ModelAndView contoladorListadoFicheros(HttpServletRequest request){
   
  //vamos a crear un objeto usario, despues tendremos una clase servicio 
  //que se va a encargar de hacer este trabajo
  logger.debug("contoladorListadoFicheros: obtener listado de ficheros");
  String[]  archivos = null;
  
  File directorio = new File (request.getSession().getServletContext().getRealPath("/ficheros/"));
  
  if ((directorio.exists()) && directorio.isDirectory() ){
   archivos = directorio.list();
  }
  
     ModelAndView map = new ModelAndView("descargaFicheros") ;
     map.addObject("archivos", archivos);
  return map;
  
  }

Este método lo invocamos desde un enlacen en la pagina subirFichero.jsp

Listado de ficheros 

Nuestra clase controlador finalmente quedará de la siguiente forma.

ControladorAplicacion.java

package com.estructuradigital.subirFichero.controladores;


import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.io.*;

import javax.servlet.http.HttpServletRequest;


import org.apache.log4j.Logger;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;


import com.estructuradigital.subirFichero.modelo.*;
import org.springframework.web.bind.annotation.ModelAttribute; 

import java.util.ArrayList; 
import java.util.List;



@Controller

public class ControladorAplicacion {


 protected static Logger logger = Logger.getLogger("controller");
 

 
 @InitBinder
 public void initBinder(WebDataBinder binder) 
 {
  SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
  dateFormat.setLenient(false);
  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
 }
  
 
 
 @RequestMapping(value="/inicio.htm")
  public String contoladorAplicacion(){
   
  //vamos a crear un objeto usario, despues tendremos una clase servicio 
  //que se va a encargar de hacer este trabajo
  logger.debug("ControladorAplicacion: Inicializando aplicacion");
  
 
  return "subirFichero";
  
  }
 
 @RequestMapping(value="/subirarchivo.htm",method= RequestMethod.POST)
    protected String subirFichero(@ModelAttribute("listaFicheros") ListaFicheros  listaFicheros,HttpServletRequest request) {

  logger.debug("ControladorSubirFichero: Inicializando proceso copia ficheros");
  
     List ficheros = listaFicheros.getArchivos();          
      
     
         if(null != ficheros && ficheros.size() > 0) {      
         
          for (MultipartFile fichero : ficheros) {       
               
           if (!fichero.isEmpty()){
               
                String nombreOriginalArchivo = fichero.getOriginalFilename();
                File ficheroDestino = new File(request.getSession().getServletContext().getRealPath("/ficheros/") +"/" + nombreOriginalArchivo);
                  
                logger.debug("copiando fichero en : " + request.getSession().getServletContext().getRealPath("/ficheros/"));
                try {
                      fichero.transferTo(ficheroDestino);
                } catch (IllegalStateException e) {
                 e.printStackTrace();
                 return "Error al subir el fichero: " + nombreOriginalArchivo ;
                } catch (IOException e) {
                 e.printStackTrace();
                 return "Error al subir el fichero: " + nombreOriginalArchivo ;
                }
                           
                   
                }else {
              
               return "errorSubirFichero" ;
              }  //fin del if 
          
          }   //fin del for  
          return "correctoSubirFichero";  
         }else {
          return "errorSubirFichero" ;
         }//fin del if,hay elementos seleccionados          
               
 }
        
  
 @RequestMapping(value="/descargarFicheros.htm ")
  public ModelAndView contoladorListadoFicheros(HttpServletRequest request){
   
  //vamos a crear un objeto usario, despues tendremos una clase servicio 
  //que se va a encargar de hacer este trabajo
  logger.debug("contoladorListadoFicheros: obtener listado de ficheros");
  String[]  archivos = null;
  
  File directorio = new File (request.getSession().getServletContext().getRealPath("/ficheros/"));
  
  if ((directorio.exists()) && directorio.isDirectory() ){
   archivos = directorio.list();
  }
  
     ModelAndView map = new ModelAndView("descargaFicheros") ;
     map.addObject("archivos", archivos);
  return map;
  
  }
 
}



3 comentarios:

  1. Excelente, me ayudó muchisimo.

    ResponderEliminar
  2. disculpa pero que iria en descargarFicheros.htm

    ResponderEliminar
    Respuestas
    1. Hola,

      descargarFicheros.htm no es una pagina html, es una etiqueta que indica que cuando llegue una petición del tipo href="descargarFicheros.htm" se tiene que ejecutar la función contoladorListadoFicheros del controlador.
      Esto se mapea en la siguiente anotación,
      @RequestMapping(value="/descargarFicheros.htm ").

      descargarFicheros.htm se podría sustituir por descargarFicheros.do o por una URI

      Eliminar