Implementación de un Sistema de Gestión Estudiantil con SSM

La digitalización ha revolucionado la gestión de datos en entornos educativos, eliminando procesos manuales propensos a errores. Los sistemas tradicionales basados en papel generan ineficiencias en la administración académica, mientras que soluciones electrónicas optimizan recursos y garantizan precisión. Este artículo detalla la construcción de un sistema de gestión estudiantil utilizando el framework SSM (Spring, Spring MVC, MyBatis), enfocándose en su arquitectura, diseño y implementación práctica.

Tecnologías Clave

Framework SSM

La combinación de Spring para inyección de dependencias, Spring MVC para manejo de peticiones web y MyBatis para persistencia ofrece un equilibrio óptimo entre flexibilidad y estructura. A diferencia de SSH (pesado y complejo), SSM reduce la configuración necesaria. MyBatis permite consultas SQL personalizadas, mejorando el rendimiento frente a frameworks ORM tradicionales como Hibernate.

Arquitectura B/S

El modelo Browser/Server centraliza la lógica de negocio en el servidor, permitiendo acceso desde cualquier dispositivo con navegador. Esto elimina la necesidad de instalación en clientes, simplificando el mantenimiento y actualizaciones. La comunicación HTTP asegura compatibilidad multiplataforma, ideal para entornos educativos heterogéneos.

Base de Datos MySQL

MySQL se destaca por su rendimiento, seguridad y soporte ACID. Su capacidad para manejar grandes volúmenes de datos con transacciones confiables lo convierte en la elección ideal para sistemas académicos. La compatibilidad con herramientas de modelado como MySQL Workbench facilita el diseño de esquemas complejos.

Aálisis del Sistema

Factibilidad Técnica

Java proporciona robustez y portabilidad, con bibliotecas maduras como Spring Boot y MyBatis. La disponibilidad de documentación y comunidades activas reduce riesgos técnicos. Herramientas como Maven y Git permiten gestión efciiente de dependencias y control de versiones.

Factibilidad Operativa

La arquitectura B/S permite acceso desde dispositivos móviles y escritorio sin configuraciones adicionales. La interfaz intuitiva reduce la curva de aprendizaje para usuarios no técnicos, como personal administrativo de instituciones educativas.

Requisitos de Seguridad

La autenticación basada en tokens JWT garantiza acceso seguro. La validación de parámetros en capas de control previene inyecciones SQL. Los permisos por rol (administrador, profesor, estudiante) restringen operaciones críticas, asegurando la integridad de los datos.

Diseño del Sistema

Modelo de Datos

Las entidades principales incluyen Estudiante, Profesor, Notificaciones y Registro de Premios. Las relaciones entre entidades se definen mediante claves foráneas, minimizando redundancia. Por ejemplo, un Estudiante puede tener múltiples registros de premios, mientras que un Profesor gestiona las aprobaciones.

Estructura de Tablas

La tabla diccionarios almacena valores codificados para campos como tipos de premios o categorías, permitiendo cambios en la lógica sin modificar el código fuente. La tabla estudiantes incluye campos como numero_identificacion (único), email y foto_perfil, optimizando consultas frecuentes.

Implementación Práctica

Controlador de Diccionarios


package com.controller;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.entity.EntidadDiccionario;
import com.service.DiccionarioService;
import com.utils.Response;

@RestController
@RequestMapping("/diccionarios")
public class DiccionarioController {
    private static final Logger logger = LoggerFactory.getLogger(DiccionarioController.class);
    
    @Autowired
    private DiccionarioService diccionarioService;
    
    @PostMapping("/guardar")
    public Response guardar(@RequestBody EntidadDiccionario entidad, HttpServletRequest solicitud) {
        logger.debug("Guardando nueva entrada: {}", entidad);
        
        String rol = (String) solicitud.getSession().getAttribute("rol");
        if (rol == null) {
            return Response.error(403, "Acceso no autorizado");
        }
        
        EntityWrapper<entidaddiccionario> consulta = new EntityWrapper<>();
        consulta.eq("codigo", entidad.getCodigo());
        consulta.eq("nombre_indice", entidad.getNombreIndice());
        
        if (entidad.getCodigo().contains("_subtipo")) {
            consulta.eq("id_padre", entidad.getIdPadre());
        }
        
        logger.info("Consulta SQL: {}", consulta.getSqlSegment());
        EntidadDiccionario existente = diccionarioService.seleccionarUno(consulta);
        
        if (existente == null) {
            entidad.setFechaCreacion(new Date());
            diccionarioService.insertar(entidad);
            
            // Actualizar caché en contexto
            List<entidaddiccionario> todos = diccionarioService.seleccionarTodos();
            Map<string map="" string="">> mapaDiccionarios = new HashMap<>();
            for (EntidadDiccionario item : todos) {
                String clave = item.getCodigo();
                Map<integer string=""> subMap = mapaDiccionarios.computeIfAbsent(clave, k -> new HashMap<>());
                subMap.put(item.getIndiceCodigo(), item.getNombreIndice());
            }
            solicitud.getServletContext().setAttribute("diccionariosCachados", mapaDiccionarios);
            return Response.success();
        } else {
            return Response.error(409, "Duplicado detectado");
        }
    }
}
</integer></string></entidaddiccionario></entidaddiccionario>

Controlador de Profesores


package com.controller;

import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.entity.Profesor;
import com.service.ProfesorService;
import com.service.DiccionarioService;
import com.utils.Response;

@RestController
@RequestMapping("/profesores")
public class ProfesorController {
    private static final Logger logger = LoggerFactory.getLogger(ProfesorController.class);
    
    @Autowired
    private ProfesorService profesorService;
    @Autowired
    private DiccionarioService diccionarioService;
    
    @PostMapping("/registro")
    public Response registrar(@RequestBody Profesor profesor, HttpServletRequest solicitud) {
        logger.debug("Registrando nuevo profesor: {}", profesor);
        
        EntityWrapper<profesor> consulta = new EntityWrapper<>();
        consulta.eq("usuario", profesor.getUsuario())
                .or()
                .eq("telefono", profesor.getTelefono())
                .or()
                .eq("documento_identidad", profesor.getDocumentoIdentidad());
        
        if (profesorService.seleccionarUno(consulta) != null) {
            return Response.error(400, "Datos duplicados detectados");
        }
        
        profesor.setFechaCreacion(new Date());
        profesor.setPassword("123456"); // Contraseña inicial
        profesorService.insertar(profesor);
        return Response.success();
    }
    
    @GetMapping("/autenticar")
    public Response autenticar(@RequestParam String usuario, @RequestParam String clave) {
        Profesor profesor = profesorService.seleccionarUno(new EntityWrapper<profesor>().eq("usuario", usuario));
        if (profesor == null || !profesor.getPassword().equals(clave)) {
            return Response.error(401, "Credenciales inválidas");
        }
        // Generar token JWT
        return Response.success().put("token", "JWT_TOKEN_GENERADO");
    }
}
</profesor></profesor>

Servicio de Usuarios


package com.service.impl;

import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.dao.UsuarioDao;
import com.entity.Usuario;
import com.service.UsuarioService;
import com.utils.PageUtils;
import com.utils.Query;

@Service("usuarioService")
public class UsuarioServiceImpl extends ServiceImpl<usuariodao usuario=""> implements UsuarioService {
    
    @Override
    public PageUtils obtenerPagina(Map<string object=""> parametros) {
        Page<usuario> pagina = this.selectPage(
            new Query<usuario>(parametros).getPage(),
            new EntityWrapper<usuario>()
        );
        return new PageUtils(pagina);
    }
    
    @Override
    public List<usuario> obtenerVistas(EntityWrapper<usuario> filtro) {
        return baseMapper.selectListView(filtro);
    }
}
</usuario></usuario></usuario></usuario></usuario></string></usuariodao>

Etiquetas: SSM spring-mvc MyBatis MySQL b/s-architecture

Publicado el 10-2 21:47