Sistema de Apoyo a la Decisión Empresarial con Spring Boot y Vue.js

Este artículo detalla la implementación de un sistema de apoyo a la decisión empresarial utilizando las tecnologías Spring Boot para el backend y Vue.js para el frontend. Se abordan las tecnologías clave, el proceso de testing y ejemplos de código y estructura de base de datos.

Tecnologías Utilizadas

Backend: Spring Boot

Spring Boot simplifica el desarrollo de aplicaciones Java al proporcionar configuración automática y embeber servidores como Tomcat o Jetty, eliminando la necesidad de configuraciones externas. Su característica principal es la auto-configuración, que detecta dependencias y configura la aplicación automáticamente. Ofrece un ecosistema robusto con módulos como Spring Data, Spring Security y Spring Cloud, acelerando la construcción y escalabilidad de aplicaciones.

Frontend: Vue.js

Vue.js es un framework progresivo de JavaScript que destaca por su uso de Virtual DOM para optimizar las actualizaciones de la interfaz de usuario. Emplea data binding reactivo y un enfoque basado en componentes, permitiendo a los desarrolladores centrarse en la lógica de datos en lugar de la manipulación manual del DOM. Esto resulta en un desarrollo más ágil, flexible y mantenible.

Capa de Persistencia: MyBatis-Plus

MyBatis-Plus es una extensión de MyBatis diseñada para simplificar el desarrollo ORM en Java. Soporta múltiples bases de datos y proporciona una API rica y anotaciones para reducir la escritura de SQL. Incluye un generador de código que automatiza la creación de entidades, Mappers y archivos de mapeo XML. Además, ofrece funcionalidades avanzadas como paginación, consultas dinámicas y manejo de concurrencia (optimistic locking), mejorando significativamente la eficiencia en el desarrollo de la capa de acceso a datos.

Pruebas del Sistema

Objetivos de las Pruebas

Las pruebas del sistema son cruciales para asegurar la calidad y fiabilidad del producto final. El objetivo principal es identificar y corregir defectos para garantizar que el sistema cumpla con los requisitos del cliente y ofrezca una experiencia de usuario óptima. Se busca validar la funcionalidad, la lógica y la robustez del sistema bajo diversas condiciones simuladas.

Pruebas de Funcionalidad

Se emplean técnicas de caja negra para probar los diferentes módulos del sistema, incluyendo la validación de entradas, casos de borde y campos obligatorios. Se diseñan casos de prueba para verificar funcionalidades específicas.

Plan de Pruebas: Inicio de Sesión

Esta prueba valida el proceso de autenticación del usuario. Se verifica que el sistema maneje correctamente las credenciales válidas e inválidas, así como los códigos de verificación. También se comprueba la restricción de acceso basada en roles.

Datos de Entrada Resultado Esperado Resultado Real Análisis
Usuario: admin, Contraseña: 123456, Captcha: Correcto Acceso al sistema Acceso exitoso Coincide con la expectativa
Usuario: admin, Contraseña: 111111, Captcha: Correcto Error de contraseña Contraseña incorrecta, reintente Coincide con la expectativa
Usuario: admin, Contraseña: 123456, Captcha: Incorrecto Error de Captcha Captcha inválido Coincide con la expectativa
Usuario: (vacío), Contraseña: 123456, Captcha: Correcto Campo de usuario obligatorio Ingrese el nombre de usuario Coincide con la expectativa
Usuario: admin, Contraseña: (vacío), Captcha: Correcto Campo de contraseña obligatorio Ingrese la contraseña Coincide con la expectativa

Plan de Pruebas: Gestión de Usuarios

Esta prueba cubre las operaciones de añadir, editar, eliminar y buscar usuarios. Se verifica la validación de campos obligatorios, la detección de nombres de usuario duplicados, las confirmaciones de eliminación y la correcta visualización de la información actualizada.

Datos de Entrada Resultado Esperado Resultado Real Análisis
Información básica de usuario válida Usuario añadido exitosamente, aparece en la lista Usuario aparece en la lista Coincide con la expectativa
Modificación de información de usuario Edición exitosa, información actualizada en la vista Información del usuario modificada Coincide con la expectativa
Seleccionar usuario para eliminar y confirmar Confirmación de eliminación, usuario no encontrado tras la acción Confirmación de eliminación, usuario eliminado Coincide con la expectativa
Intentar añadir usuario sin nombre de usuario Error: nombre de usuario no puede estar vacío Error: nombre de usuario no puede estar vacío Coincide con la expectativa
Intentar añadir usuario con nombre de usuario existente Error: nombre de usuario ya existe Error: nombre de usuario ya existe Coincide con la expectativa

Conclusión de las Pruebas del Sistema

Mediante la aplicación de pruebas de caja negra y la creación de casos de prueba, se ha validado la corrección de los flujos y funcionalidades del sistema. Las pruebas son esenciales para refinar el sistema y mejorar su usabilidad. El objetivo final de las pruebas es asegurar que el sistema satisfaga las necesidades del usuario y cumpla con los objetivos de diseño, tento en funcionalidad como en rendimiento.

Ejemplos de Código

Controlador de Autenticación (Fragmento)


@IgnoreAuth
@PostMapping(value = "/login")
public R authenticateUser(String username, String password, String captcha, HttpServletRequest request) {
   // Busca al usuario por nombre de usuario
   UsersEntity user = userService.getOne(new QueryWrapper<UsersEntity>().eq("username", username));

   // Verifica si el usuario existe y la contraseña es correcta
   if (user == null || !user.getPassword().equals(password)) {
       return R.error("Nombre de usuario o contraseña incorrectos");
   }

   // Genera un token de autenticación
   String token = tokenService.generateAuthToken(user.getId(), username, "users", user.getRole());
   return R.ok().put("token", token);
}

   @Override
   public String generateAuthToken(Long userId, String username, String tableName, String role) {
       TokenEntity existingToken = tokenService.getToken(userId, role);
       String newToken = generateRandomString(32); // Función auxiliar para generar cadena aleatoria

       // Calcula la fecha de expiración (1 hora desde ahora)
       Calendar expiration = Calendar.getInstance();
       expiration.add(Calendar.HOUR_OF_DAY, 1);

       if (existingToken != null) {
           // Actualiza el token existente
           existingToken.setToken(newToken);
           existingToken.setExpirationTime(expiration.getTime());
           tokenService.updateToken(existingToken);
       } else {
           // Crea un nuevo token
           tokenService.saveToken(new TokenEntity(userId, username, tableName, role, newToken, expiration.getTime()));
       }
       return newToken;
   }
   

Interceptor de Autorización (Fragmento)


@Component
public class AuthInterceptor implements HandlerInterceptor {

   private static final String AUTH_TOKEN_HEADER = "Token";

   @Autowired
   private TokenService tokenService;

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       // Configuración de CORS
       response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
       response.setHeader("Access-Control-Max-Age", "3600");
       response.setHeader("Access-Control-Allow-Credentials", "true");
       response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
       response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

       // Manejo de peticiones OPTIONS para CORS
       if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
           response.setStatus(HttpStatus.OK.value());
           return false;
       }

       // Ignorar autenticación si el método está anotado con @IgnoreAuth
       HandlerMethod handlerMethod = (HandlerMethod) handler;
       if (handlerMethod.getMethodAnnotation(IgnoreAuth.class) != null) {
           return true;
       }

       // Obtener token de la cabecera
       String tokenValue = request.getHeader(AUTH_TOKEN_HEADER);
       TokenEntity tokenDetails = null;

       if (StringUtils.isNotBlank(tokenValue)) {
           tokenDetails = tokenService.getTokenDetails(tokenValue);
       }

       // Validar token y establecer atributos de sesión
       if (tokenDetails != null) {
           request.getSession().setAttribute("userId", tokenDetails.getUserId());
           request.getSession().setAttribute("role", tokenDetails.getRole());
           request.getSession().setAttribute("tableName", tokenDetails.getTableName());
           request.getSession().setAttribute("username", tokenDetails.getUsername());
           return true;
       }

       // Si el token no es válido o no existe, devolver error 401
       response.setCharacterEncoding("UTF-8");
       response.setContentType("application/json; charset=utf-8");
       PrintWriter writer = response.getWriter();
       writer.print(JSONObject.toJSONString(R.error(401, "Por favor, inicie sesión primero")));
       if (writer != null) {
           writer.close();
       }
       return false;
   }
}
   

Estructura de la Base de Datos

Tabla: token

Esta tabla almacena la información de los tokens de autenticación para gestionar las sesiones de usuario.


-- Table structure for token
DROP TABLE IF EXISTS `token`;
CREATE TABLE `token` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
 `user_id` bigint(20) NOT NULL COMMENT 'User ID',
 `username` varchar(100) NOT NULL COMMENT 'Username',
 `table_name` varchar(100) DEFAULT NULL COMMENT 'Associated Table Name',
 `role` varchar(100) DEFAULT NULL COMMENT 'User Role',
 `token_value` varchar(200) NOT NULL COMMENT 'Authentication Token',
 `creation_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Timestamp',
 `expiration_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Expiration Timestamp',
 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Token table';

-- Sample Records (truncated for brevity)
INSERT INTO `token` VALUES ('9', '23', 'cd01', 'xuesheng', 'student', 'al6svx5qkei1wljry5o1npswhdpqcpcg', '2023-02-23 21:46:45', '2023-03-15 14:01:36');
INSERT INTO `token` VALUES ('10', '11', 'xh01', 'xuesheng', 'student', 'fahmrd9bkhqy04sq0fzrl4h9m86cu6kx', '2023-02-27 18:33:52', '2023-03-17 18:27:42');
INSERT INTO `token` VALUES ('12', '1', 'admin', 'users', 'administrator', 'h1pqzsb9bldh93m92j9m2sljy9bt1wdh', '2023-02-27 19:37:01', '2023-03-17 18:23:02');
-- ... more records
   

Etiquetas: Spring Boot vue.js MyBatis-Plus java JavaScript

Publicado el 6-8 22:10