En este tutorial aprenderemos a subir imágenes al directorio que elijamos mediante Spring Boot, Thymeleaf y File Input
1. Información General
En este tutorial rápido, veremos cómo podemos realizar la carga de imágenes mediante Spring Boot, Thymeleaf y el plugin de File Input.
2. Dependencias de Gradle
Para crear este ejemplo, usaremos las bibliotecas Spring Framework junto con las bibliotecas Thymeleaf.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
3. Estructura del Proyecto
Antes de saltar a la capa de vista, creemos la estructura MVC como se muestra a continuación:
4. Vista HTML
Ahora vamos a crear la vista HTML, para ello vamos a crear un nuevo “HTML file” en nuestro paquete, “templates” y la vamos a llamar “index.html”. Esta vista constará de un formulario con un input del tipo file.
Esta vista la vamos a realizar en Bootstrap 4. Para poder realizar la vista en Bootstrap 4 debemos incluir los siguientes archivos CSS y JS, estos se incluirán dentro de la etiqueta “head” y al final de la etiqueta “body”:
<!-- Fontawesome CSS -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css">
<!-- Bootstrap CSS -->
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<!-- FileInput CSS -->
<link th:href="@{/plugins/fileinput/css/fileinput.css}" media="all" rel="stylesheet" type="text/css">
<link th:href="@{/plugins/fileinput/themes/explorer-fas/theme.css}" media="all" rel="stylesheet" type="text/css"/>
<!-- Javascript -->
<script th:src="@{/js/jquery-3.4.1.min.js}"></script>
<script th:src="@{/js/popper.min.js}"></script>
<script th:src="@{/js/bootstrap.min.js}"></script>
<!-- FileInput -->
<script th:src="@{/plugins/fileinput/js/plugins/piexif.js}"></script>
<script th:src="@{/plugins/fileinput/js/plugins/sortable.js}"></script>
<script th:src="@{/plugins/fileinput/js/fileinput.js}"></script>
<script th:src="@{/plugins/fileinput/js/locales/es.js}"></script>
<script th:src="@{/plugins/fileinput/themes/fas/theme.js}"></script>
<script th:src="@{/plugins/fileinput/js/configuracion.js}"></script>
Ahora vamos a crear nuestro formulario:
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="form-row pt-2">
<div class="form-group col-12">
<div class="file-loading">
<input id="file-0a" class="file" name="file" type="file" multiple="true" data-min-file-count="0" data-theme="fas">
</div>
<div id="kv-error-1" style="margin-top:10px;display:none"></div>
<div id="kv-success-1" class="alert alert-success" style="margin-top:10px;display:none"></div>
<br>
</div>
</div>
</div>
</div>
</div>
5. Clase Controlador
Vamos a crear una clase “SubirImagenController” en nuestro paquete controladores. Lo primero que vamos a hacer es anotar la clase con un @Controller para indicar que esta clase es un controlador y procedemos a crear un método GET con un @GetMapping:
@GetMapping(path = "/")
public String inicio() {
return "index";
}
Como vemos en el primer método la dirección URL mediante la que accederemos a la vista creada anteriormente será “/”.
Ahora ya podemos dirigirnos a nuestro navegador favorito y acceder a nuestra vista HTML a través de la URL “localhost:8080”, el puerto por defecto de Spring es el 8080.
6. Método guardarImagen
En nuestrao paquete “servicios” vamos a crear una nueva interfaz llamada “GuardarImagenService” y procederemos a crear nuestro método de “guardarImagen”, posteriormente en nuestro paquete “impl” crearemos la clase “GuardarImagenServiceImpl”, está la anotaremos con el @Service y su respectivo nombre, que implementara el método de la interfaz “GuardarImagenService”.
public interface GuardarImagenService {
/**
* Guardar imagen.
*
* @param ruta the ruta
* @param file the file
* @throws IOException Signals that an I/O exception has occurred.
*/
void guardarImagen(String ruta, MultipartFile file) throws IOException;
}
@Service("guardarImagenService")
public class GuardarImagenServiceImpl implements GuardarImagenService {
/**
* Guardar imagen.
*
* @param ruta the ruta
* @param file the file
* @throws IOException Signals that an I/O exception has occurred.
*/
@Override
public void guardarImagen(String ruta, MultipartFile file) throws IOException {
Path path = Paths.get(ruta, file.getOriginalFilename());
Files.write(path, file.getBytes());
}
}
A continuación, crearemos nuestro método público, como parámetros pasamos un “String” el cual será la ruta dónde se almacenarán nuestras imágenes y un “MultipartFile” que contendrá nuestro archivo.
Por último, escribiremos en el “path” que hemos decidido, los bytes del archivo que hemos leído.
7. Clase Modelo
En nuestro paquete “modelos” crearemos una clase de nombre “RespuestaOperacionModel” con dos atributos, uno “respuesta” y otro “descripcion”, con sus respectivos “getters” y “setters” que nos proporcionará el poder enviar un mensaje al usuario.
public class RespuestaOperacionModel implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1793052093561825995L;
/** The respuesta. */
private boolean respuesta;
/** The descripcion. */
private String descripcion;
/**
* Instantiates a new respuesta operacion model.
*/
public RespuestaOperacionModel() {
super();
}
/**
* Checks if is respuesta.
*
* @return true, if is respuesta
*/
public boolean isRespuesta() {
return respuesta;
}
/**
* Sets the respuesta.
*
* @param respuesta the new respuesta
*/
public void setRespuesta(boolean respuesta) {
this.respuesta = respuesta;
}
/**
* Gets the descripcion.
*
* @return the descripcion
*/
public String getDescripcion() {
return descripcion;
}
/**
* Sets the descripcion.
*
* @param descripcion the new descripcion
*/
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("RespuestaOperacionModel [respuesta=").append(respuesta).append(", descripcion=")
.append(descripcion).append("]");
return builder.toString();
}
}
8. Método POST
Para finalizar vamos a crear un método POST donde le indicaremos a Spring que queremos usar nuestro servicio de guardar imagen mediante un @Autowired. Crearemos nuestro método POST con el path “/subirImagen”, como podemos ver este método devuelve un objeto de la clase “RespuestaOperacionModel”, esto lo único que nos proporciona es poder enviar una respuesta HTTP para el usuario.
@Controller
public class SubirImagenController {
/** Logger. */
private static final Logger logger = LoggerFactory.getLogger(SubirImagenController.class);
@Autowired
@Qualifier("guardarImagenService")
private GuardarImagenService guardarImagenService;
/**
* @return index
*/
@GetMapping(path = "/")
public String inicio() {
return "index";
}
/**
* @param request
* @param response
* @param file
* @return
*/
@PostMapping(path = "/subirImagen")
@ResponseBody
public RespuestaOperacionModel subirImagen(@RequestBody @RequestParam("file") MultipartFile file) {
RespuestaOperacionModel respuesta = new RespuestaOperacionModel();
respuesta.setRespuesta(true);
try {
logger.info("Empieza proceso para subir imagen");
guardarImagenService.guardarImagen("C:\\Imagenes", file);
respuesta.setDescripcion("Imagen subida correctamente");
} catch (Exception e) {
logger.error("Error al subir imagen: -> {0}", e);
respuesta.setRespuesta(false);
respuesta.setDescripcion("Error al subir imagen");
}
return respuesta;
}
}
La anotación “@RequestBody” asigna el cuerpo de “HttpRequest” a un objeto de transferencia o dominio, lo que permite la deserialización automática del cuerpo de “HttpRequest” entrante en un objeto Java.
La anotación “@ResponseBody” le dice a un controlador que el objeto devuelto se serializa automáticamente en JSON y se devuelve al objeto HttpResponse.
Este método tiene como parámetro un “@RequestPram(“file”) MultipatFile file”, con esto indicamos que tenemos un “MultipartFile” que no llega de la vista y la variable en la vista se llama “name=“file””, en la siguiente imagen se muestra que el formulario creado anteriormente tiene este nombre:
<input id="file-0a" class="file" name="file" type="file" multiple="true" data-min-file-count="0" data-theme="fas">
9. Resultado
Ahora ya podemos subir archivos con nuestro proyecto creado y comprobar que en nuestra ruta seleccionada se han subido correctamente las imágenes.
Hasta aquí este tutorial, ahora ya sabemos subir archivos mediante Spring Boot, usando Bootstrap 4, Thymeleaf y el plugin File Input.
Una versión funcional del código que se muestra en este tutorial está disponible en Gitlab.
Referencias
Baeldung. (03 de Septiembre de 2020). Baeldung. Obtenido de https://www.baeldung.com/spring-mvc-return-html
Baeldung. (26 de Noviembre de 2020). Baeldung. Obtenido de https://www.baeldung.com/spring-request-response-body
Visweswaran, K. (30 de Noviembre de 2020). Krajee. Obtenido de https://plugins.krajee.com/file-input-ajax-demo/11