Subida de Imágenes e Interceptores en Struts2

Implementar la funcionalidad de carga de imágenes es una tarea común en muchas aplicaciones web modernas. Este artículo explora una solución basada en el framework Struts2.

El proceso fundamental implica seleccionar un archivo desde el cliente y transferirlo al servidor mediante flujos de E/S. Existen varias estrategias de almacenamiento:

  • Almacenar directamente en el servidor de aplicaciones (por ejemplo, Tomcat).
  • Guardar en un direcotrio específico y configurar un mapeo en el servidor para desacoplar los archivos de la aplicación.
  • Utilizar un servidor de archivos dedicado.
  • Guardar los datos binarios directamente en un campo de la base de datos.

Paso 1: Configuración del Esquema de Base de Datos

Se crea una tabla para almacenar la información del curso y la ruta de la imagen.

Paso 2: Capa de Acceso a Datos (DAO)

Se define una clase DAO genérica para operaciones CRUD. Un ejemplo simplificado para un curso:

public class CursoDao extends BaseDao<Curso> { public List<Curso> listar(Curso filtro, PageBean paginador) throws SQLException { String consulta = "SELECT * FROM tabla_cursos WHERE 1=1 "; String nombre = filtro.getNombre(); int id = filtro.getId(); if (id > 0) { consulta += " AND id = " + id; } if (StringUtils.isNotBlank(nombre)) { consulta += " AND nombre LIKE '%" + nombre + "%'"; } return ejecutarConsulta(consulta, paginador, Curso.class); }

public int insertar(Curso curso) throws Exception {
    String sql = "INSERT INTO tabla_cursos VALUES(?,?,?)";
    return ejecutarActualizacion(sql, new String[]{"nombre", "instructor", "imagenRuta"}, curso);
}

public int actualizar(Curso curso) throws Exception {
    String sql = "UPDATE tabla_cursos SET nombre=?, instructor=?, imagenRuta=? WHERE id=?";
    return ejecutarActualizacion(sql, new String[]{"id", "nombre", "instructor", "imagenRuta"}, curso);
}

}


</div>### Paso 3: Capa Web (Action)

Se crea una acción base para manejar las solicitudes HTTP y una acción específica para el manejo de cursos y archivos.

#### Acción Base (BaseAction)

<div>```
package com.example.web;
import javax.servlet.http.*;
import org.apache.struts2.interceptor.*;

public abstract class BaseAction implements ServletRequestAware, ServletResponseAware {
    protected HttpServletRequest peticion;
    protected HttpServletResponse respuesta;
    protected HttpSession sesion;
    protected static final String EXITO = "exito";
    protected static final String FALLO = "fallo";
    protected static final String LISTADO = "listado";
    protected Object resultado;

    public void setServletRequest(HttpServletRequest req) {
        this.peticion = req;
        this.sesion = req.getSession();
    }

    public void setServletResponse(HttpServletResponse resp) {
        this.respuesta = resp;
    }
}

public class CursoAction extends BaseAction implements ModelDriven<Curso> { private CursoDao cursoDao = new CursoDao(); private Curso modelo = new Curso(); // Propiedades para la subida de archivos de Struts2 private File archivoAdjunto; private String archivoAdjuntoContentType; private String archivoAdjuntoFileName;

public String listar() {
    PageBean paginador = new PageBean();
    paginador.setRequest(peticion);
    try {
        List<Curso> cursos = cursoDao.listar(modelo, paginador);
        peticion.setAttribute("listaCursos", cursos);
        peticion.setAttribute("paginador", paginador);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "listado";
}

public String subirImagen() {
    String rutaDestinoServidor = "/ruta/al/almacenamiento";
    String rutaAlmacenamientoLocal = "/data/app/uploads"; // Ruta configurable
    try {
        // Copia el archivo al sistema de archivos local
        FileUtils.copyFile(archivoAdjunto, new File(rutaAlmacenamientoLocal + "/" + archivoAdjuntoFileName));
        // Guarda la ruta relativa (URL) en la base de datos
        modelo.setImagenRuta(rutaDestinoServidor + "/" + archivoAdjuntoFileName);
        cursoDao.actualizar(modelo);
    } catch (Exception e) {
        e.printStackTrace();
        return FALLO;
    }
    return "redirigirListado";
}

// Getters y Setters para las propiedades del archivo...
@Override
public Curso getModel() {
    return modelo;
}

}


</div>### Paso 4: Interfaz de Usuario (Vistas JSP)

#### Lista de Cursos (listado.jsp)

<div>```
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
<h1>Gestión de Cursos</h1>
<a href="${pageContext.request.contextPath}/accion/curso_prepararNuevo.action">Nuevo Curso</a>
<table border="1">
    <tr><th>ID</th><th>Nombre</th><th>Instructor</th><th>Imagen</th><th>Acciones</th></tr>
    <c:forEach items="${listaCursos}" var="curso">
        <tr>
            <td>${curso.id}</td>
            <td>${curso.nombre}</td>
            <td>${curso.instructor}</td>
            <td><img src="${pageContext.request.contextPath}/${curso.imagenRuta}" width="60" height="60"/></td>
            <td>
                <a href="${pageContext.request.contextPath}/accion/curso_prepararEdicion.action?id=${curso.id}">Editar</a>
                <a href="${pageContext.request.contextPath}/accion/curso_eliminar.action?id=${curso.id}">Eliminar</a>
                <a href="${pageContext.request.contextPath}/accion/curso_prepararSubida.action?id=${curso.id}">Subir Imagen</a>
            </td>
        </tr>
    </c:forEach>
</table>
</body>
</html>


</div>### Paso 5: Interceptores en Struts2

Los interceptores permiten ejecutar lógica antes o después de la invocación de una acción. Se pueden implementar de dos formas principales.

#### Interceptores Personalizados

<div>```
package com.example.interceptor;
import com.opensymphony.xwork2.*;
import com.opensymphony.xwork2.interceptor.*;

public class InterceptoresAutenticacion extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocacion) throws Exception {
        System.out.println("Ejecutando lógica PRE-Acción");
        // Aquí iría la lógica de verificación, por ejemplo: comprobar sesión.
        String resultado = invocacion.invoke();
        System.out.println("Ejecutando lógica POST-Acción");
        return resultado;
    }
}

public class InterceptoresLogging extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocacion) throws Exception {
        long tiempoInicio = System.currentTimeMillis();
        String resultado = invocacion.invoke();
        long duracion = System.currentTimeMillis() - tiempoInicio;
        System.out.println("La acción tardó: " + duracion + " ms");
        return resultado;
    }
}

Prnicipio de Funcionamiento

Cuando una solicitud llega, la cadena de interceptores definida para la acción se ejecuta secuencialmente en orden. Cada interceptor realiza su tarea y luego invoca al siguiente en la cadena. Al llegar al final, se ejecuta la acción propiamente dicha. Luego, los interceptores se ejecutan en orden inverso (la fase "post-acción"), permitiendo realizar tareas de limpieza o logging final. Este patrón es fundamental para la modularidad y reutilización de código transversal en Struts2.

Etiquetas: struts2 subida de archivos interceptores Java Web jsp

Publicado el 7-10 22:27