Cargar archivos con Spring Boot

C

Introducción

Cargar archivos en un sitio web no es una tarea poco común, pero tampoco es muy sencillo de lograr. Algunos casos de uso de por qué querría cargar un archivo en un sitio web incluyen servicios que ofrecen conversiones de archivos en línea y sitios web para compartir fotos. En ciertas aplicaciones, es posible que incluso queramos enviar un archivo a otro usuario, etc.

La Spring proporciona una MultipartFile interfaz para manejar solicitudes HTTP de varias partes para cargar archivos. Las solicitudes de archivos de varias partes dividen los archivos grandes en trozos más pequeños, lo que lo hace eficiente para la carga de archivos. Se puede encontrar más información al respecto. aquí.

Configuración del proyecto

Para demostrar la carga de archivos, crearemos una aplicación Spring MVC típica que consta de un Controller, un Service para el procesamiento de backend, y Thymeleaf para ver la representación.

La forma más sencilla de comenzar con un proyecto esqueleto de Spring Boot, como siempre, es usando Spring Initializr. Seleccione su versión preferida de Spring Boot y agregue el Web y Thymeleaf dependencias:

Después de esto, generelo como un proyecto de Maven y ¡listo!

Construyendo la Aplicación

Clase de servicio

Empecemos por construir el Service capa primero. Lo nombraremos como FileService.java:

@Service
public class FileService {

    @Value("${app.upload.dir:${user.home}}")
    public String uploadDir;

    public void uploadFile(MultipartFile file) {

        try {
            Path copyLocation = Paths
                .get(uploadDir + File.separator + StringUtils.cleanPath(file.getOriginalFilename()));
            Files.copy(file.getInputStream(), copyLocation, StandardCopyOption.REPLACE_EXISTING);
        } catch (Exception e) {
            e.printStackTrace();
            throw new FileStorageException("Could not store file " + file.getOriginalFilename()
                + ". Please try again!");
        }
    }
}

Vamos a dividirlo línea por línea:

  • @Service es una especialización del @Component anotación. Le dice a Spring que esta es una clase de servicio. Normalmente, toda la lógica empresarial se escribe en esta capa.
  • Entonces tenemos una variable uploadDir, que usaremos para almacenar la ruta del directorio en el que queremos que se cargue nuestro archivo. Está anotado con @Value, lo que significa que su valor puede ser establecido por el application.properties archivo por el app.upload.dir llave. En caso de que esta clave no esté definida, el valor predeterminado es user.home – que se encuentra en una variable de entorno de cada sistema operativo.
  • Entonces tenemos un método público uploadFile que toma en un MultipartFile como argumento.
  • Luego creamos el Path del archivo utilizando el Paths clase proporcionada por Java. StringUtils.cleanPath se usa para limpiar el camino y simplemente agregamos uploadDir a ella usando un File.separator. Utilice siempre métodos de utilidad para manejar rutas en el código porque manejará automáticamente diferentes implementaciones de SO. Por ejemplo, en Windows, el separador de archivos es mientras que en Linux es /.
  • Luego copiamos el archivo a la ubicación usando Files.copy. los REPLACE_EXISTING La opción de copia anulará cualquier archivo con el mismo nombre allí.
  • Si hay un Exception en todo este proceso lo capturamos y lanzamos una costumbre FileStorageException excepción.

Excepción personalizada

Escribimos una costumbre FileStorageException para cualquier excepción durante el proceso de carga del archivo. Es una clase simple que se extiende RuntimeException:

public class FileStorageException extends RuntimeException {

    private static final long serialVersionUID = 1L;
    private String msg;

    public FileStorageException(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }
}

Para poder usar la excepción de la forma en que lo hicimos, Spring necesita saber cómo lidiar con ella si se encuentra. Para eso, hemos creado un AppExceptionHandler que está anotado con @ControllerAdvice y tiene un @ExceptionHandler definido para FileStorageException:

@ControllerAdvice
public class AppExceptionHandler {

    @ExceptionHandler(FileStorageException.class)
    public ModelAndView handleException(FileStorageException exception, RedirectAttributes redirectAttributes) {

        ModelAndView mav = new ModelAndView();
        mav.addObject("message", exception.getMsg());
        mav.setViewName("error");
        return mav;
    }
}

En el handleException método simplemente devolvimos el ModelAndView objeto que devolverá el error message en una vista de error, que es solo una plantilla de Thymeleaf llamada error.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>ERROR</title>
</head>
<body>
  <h1>Error!!!</h1>
  <div th:if="${message}">
    <h2 th:text="${message}"/>
  </div>
</body>
</html>

Si desea leer más sobre las excepciones en Java y Spring, lo cubrimos en detalle en los siguientes artículos:

  • Manejo de excepciones en Java: una guía completa con las mejores y las peores prácticas
  • Cómo hacer excepciones personalizadas en Java
  • Manejo de excepciones en Spring

Controlador y Frontend

Creemos ahora un sencillo FileController clase que usará el FileService para manejar la carga de archivos:

@Controller
public class FileController {

    @Autowired
    FileService fileService;

    @GetMapping("/")
    public String index() {
        return "upload";
    }

    @PostMapping("/uploadFile")
    public String uploadFile(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {

        fileService.uploadFile(file);

        redirectAttributes.addFlashAttribute("message",
            "You successfully uploaded " + file.getOriginalFilename() + "!");

        return "redirect:/";
    }
}

Vamos a dividirlo línea por línea:

  • @Controller La anotación es también una especialización de @Component anotación. Hace que una clase acepte la solicitud HTTP y responda en consecuencia. También se encarga de las diversas conversiones de la carga útil de la solicitud a una estructura de datos interna.
  • Luego, nosotros @Autowired la FileService frijol para que podamos usar su uploadFile método.
  • Entonces tenemos un simple GetMapping a / que simplemente devolverá String upload. Al ser una clase de controlador, Spring buscará upload.html y sírvasela en el navegador.
  • A continuación, tenemos un PostMapping de /uploadFile, que tienen un RequestParam de MultipartFile que es un objeto que tiene nuestro archivo y sus detalles de metadatos.
  • Luego usamos el FileService uploadFile método para cargar el archivo. RedirectAttributes es una especialización de Spring Model interfaz que se utiliza para seleccionar atributos para un escenario de redireccionamiento.
  • Si la operación anterior es exitosa, configuramos el mensaje de éxito en redirectAttributes y redirigir a la misma página.

Ahora hagamos otra plantilla de Thymeleaf,upload.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
  <h1>Spring Boot File Upload Example</h1>
  <hr/>
  <h4>Upload Single File:</h4>
  <form method="POST" th:action="@{/uploadFile}" enctype="multipart/form-data">
    <input type="file" name="file"/> <br/><br/>
    <button type="submit">Submit</button>
  </form>
  <hr/>
  <div th:if="${message}">
    <h2 th:text="${message}"/>
  </div>
</body>
</html>

Arriba, tenemos un sencillo form que se asigna al /uploadFile URL. Note que es enctype es multipart/form-data y input escribir como file. En la parte inferior tiene un mensaje div para mostrar el mensaje de éxito.

Nuestra clase principal es una clase principal típica de Spring Boot:

@SpringBootApplication
public class FileIoApplication {

    public static void main(String[] args) {
        SpringApplication.run(FileIoApplication.class, args);
    }
}

Ejecutemos nuestra aplicación y naveguemos a http://localhost:8080:

Elija un archivo y cárguelo, debería ver algo como:

Carga de varios archivos

Del mismo modo, podemos escribir código para cargar varios archivos. Agregue el siguiente mapeo en FileController.java:

@PostMapping("/uploadFiles")
public String uploadFiles(@RequestParam("files") MultipartFile[] files, RedirectAttributes redirectAttributes) {

    Arrays.asList(files)
        .stream()
        .forEach(file -> fileService.uploadFile(file));

    redirectAttributes.addFlashAttribute("message",
        "You successfully uploaded all files!");

    return "redirect:/";
}

Como puede ver, el /uploadFiles El mapeo es similar al anterior, excepto que tiene un MultipartFile[] como argumento. Usamos la API de Java 8 Stream para cargar cada archivo en la matriz.

Al igual que antes, si la operación anterior es exitosa, configuramos el mensaje de éxito en redirectAttributes y redirigir a la misma página.

Ahora, solo necesitamos actualizar el código en la plantilla upload.html para manejar esto:

<h4>Upload Multiple Files:</h4>
<form method="POST" th:action="@{/uploadFiles}" enctype="multipart/form-data">
  <input type="file" name="files" multiple/> <br/><br/>
  <button type="submit">Submit</button>
</form>

<hr/>

Lo único diferente del HTML anterior es que el mapeo es al /uploadFiles punto final y el input tiene un multiple atributo, lo que le permite seleccionar más de un archivo. También desde el @RequestParam es files, tenemos que usar el mismo name en HTML.

Ejecutemos nuestra aplicación nuevamente y naveguemos a http://localhost:8080:

Elegir la segunda opción ahora nos permite seleccionar más de un archivo de nuestro sistema de archivos y cargarlos todos.

Limitar el tamaño del archivo

Puede ajustar los límites de carga de archivos utilizando spring.servlet.multipart.max-file-size y spring.servlet.multipart.max-request-size en application.properties:

spring.servlet.multipart.max-file-size = 5MB
spring.servlet.multipart.max-request-size = 5MB

Puedes establecer los límites en KB, MB, GBetc.

El valor predeterminado para spring.servlet.multipart.max-file-size es 1 MB y el valor predeterminado para spring.servlet.multipart.max-request-size es de 10 MB. Aumentando el límite para max-file-size Probablemente sea una buena idea ya que el valor predeterminado es muy bajo, pero tenga cuidado de no establecerlo demasiado alto, lo que podría sobrecargar su servidor.

Conclusión

En este artículo, hemos cubierto cómo cargar un solo archivo y varios archivos en una aplicación Spring Boot. Usamos Spring’s MultipartFile interfaz para capturar el archivo en la solicitud HTTP y las plantillas Thymeleaf como nuestro motor de renderizado.

Como siempre, el código de los ejemplos utilizados en este artículo se puede encontrar en GitHub.

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad