diff --git a/DBHandlerJSON.bas b/DBHandlerJSON.bas index 4adaea3..d80d936 100644 --- a/DBHandlerJSON.bas +++ b/DBHandlerJSON.bas @@ -5,10 +5,6 @@ Type=Class Version=10.3 @EndOfDesignText@ ' Handler class for JSON requests from Web Clients (JavaScript/axios) -' VERSIÓN 16 (Comentarios y Mensajes en Español): -' - Se añaden comentarios detallados a la versión con mensajes de error en español. -' - Revisa que el 'query' exista en config.properties antes de continuar. -' - Asegura que la conexión a la BD se cierre en todos los 'Return' para evitar fugas. Sub Class_Globals ' Declara una variable privada para mantener una instancia del conector RDC. ' Este objeto maneja la comunicación con la base de datos. @@ -62,9 +58,17 @@ Sub Handle(req As ServletRequest, resp As ServletResponse) ' Extrae los datos necesarios del JSON. Dim execType As String = RootMap.GetDefault("exec", "") ' Tipo de ejecución: "executeQuery" o "executeCommand". - Dim queryName As String = RootMap.Get("query") ' Nombre del comando SQL (definido en config.properties). - Dim paramsMap As Map = RootMap.Get("params") ' Un mapa con los parámetros para la consulta. -' Log(RootMap) + Dim queryName As String = RootMap.Get("query") ' Nombre del comando SQL (definido en config.properties). + + ' Se obtiene "params" como una Lista en lugar de un Mapa. + Dim paramsList As List = RootMap.Get("params") + + ' Si la lista de parámetros es nula (no se proporcionó en el JSON), + ' la inicializamos como una lista vacía para evitar errores más adelante. + If paramsList = Null Or paramsList.IsInitialized = False Then + paramsList.Initialize + End If + ' Verifica si en el JSON se especificó un nombre de base de datos diferente con la clave "dbx". If RootMap.Get("dbx") <> Null Then DB = RootMap.Get("dbx") ' Si se especifica, usamos la BD indicada, si no, se queda "DB1". @@ -75,35 +79,12 @@ Sub Handle(req As ServletRequest, resp As ServletResponse) Return End If - ' Prepara una lista para almacenar las claves de los parámetros. - Dim paramKeys As List - paramKeys.Initialize - ' Si el mapa de parámetros existe y está inicializado... - If paramsMap <> Null And paramsMap.IsInitialized Then - ' ...itera sobre todas las claves y las añade a la lista 'paramKeys'. - For Each key As String In paramsMap.Keys - paramKeys.Add(key) - Next - End If - ' Ordena las claves alfabéticamente. Esto es crucial para asegurar que los parámetros - ' se pasen a la consulta SQL en un orden consistente y predecible. - paramKeys.Sort(True) - - ' Prepara una lista para almacenar los valores de los parámetros en el orden correcto. - Dim orderedParams As List - orderedParams.Initialize - ' Itera sobre la lista de claves ya ordenada. - For Each key As String In paramKeys - ' Añade el valor correspondiente a cada clave a la lista 'orderedParams'. - orderedParams.Add(paramsMap.Get(key)) - Next - ' Obtiene una conexión a la base de datos del pool de conexiones. con = Connector.GetConnection(DB) ' Obtiene la cadena SQL del archivo de configuración usando el nombre de la consulta (queryName). Dim sqlCommand As String = Connector.GetCommand(DB, queryName) - ' <<< INICIO NUEVA VALIDACIÓN: VERIFICAR SI EL COMANDO EXISTE >>> + ' <<< INICIO VALIDACIÓN: VERIFICAR SI EL COMANDO EXISTE >>> ' Comprueba si el comando SQL (query) especificado en el JSON fue encontrado en el archivo de configuración. If sqlCommand = Null Or sqlCommand = "null" Or sqlCommand.Trim = "" Then ' Si no se encontró el comando, crea un mensaje de error claro. @@ -117,7 +98,7 @@ Sub Handle(req As ServletRequest, resp As ServletResponse) ' Detiene la ejecución del método Handle para esta petición. Return End If - ' <<< FIN NUEVA VALIDACIÓN >>> + ' <<< FIN VALIDACIÓN >>> ' Comprueba el tipo de ejecución solicitado ("executeQuery" o "executeCommand"). If execType.ToLowerCase = "executequery" Then @@ -125,15 +106,15 @@ Sub Handle(req As ServletRequest, resp As ServletResponse) Dim rs As ResultSet ' Si el comando SQL contiene placeholders ('?'), significa que espera parámetros. - If sqlCommand.Contains("?") or orderedParams.Size > 0 Then + ' Se usa 'paramsList' directamente en lugar de 'orderedParams'. + If sqlCommand.Contains("?") Or paramsList.Size > 0 Then ' ================================================================= ' === VALIDACIÓN DE CONTEO DE PARÁMETROS ========================== ' ================================================================= ' Calcula cuántos parámetros espera la consulta contando el número de '?'. Dim expectedParams As Int = sqlCommand.Length - sqlCommand.Replace("?", "").Length - ' Obtiene cuántos parámetros se recibieron. - Dim receivedParams As Int = orderedParams.Size - ' Compara si la cantidad de parámetros esperados y recibidos es diferente. + ' Obtiene cuántos parámetros se recibieron de la lista. + Dim receivedParams As Int = paramsList.Size Log($"expectedParams: ${expectedParams}, receivedParams: ${receivedParams}"$) @@ -146,8 +127,8 @@ Sub Handle(req As ServletRequest, resp As ServletResponse) Return End If ' ================================================================= - ' Ejecuta la consulta pasando el comando SQL y la lista ordenada de parámetros. - rs = con.ExecQuery2(sqlCommand, orderedParams) + ' Ejecuta la consulta pasando el comando SQL y la lista de parámetros. + rs = con.ExecQuery2(sqlCommand, paramsList) Else ' Si no hay '?', ejecuta la consulta directamente sin parámetros. rs = con.ExecQuery(sqlCommand) @@ -193,7 +174,7 @@ Sub Handle(req As ServletRequest, resp As ServletResponse) ' === VALIDACIÓN DE CONTEO DE PARÁMETROS (para Comandos) ========== ' ================================================================= Dim expectedParams As Int = sqlCommand.Length - sqlCommand.Replace("?", "").Length - Dim receivedParams As Int = orderedParams.Size + Dim receivedParams As Int = paramsList.Size If expectedParams <> receivedParams Then SendErrorResponse(resp, 400, $"Número de parametros equivocado para '${queryName}'. Se esperaban ${expectedParams} y se recibieron ${receivedParams}."$) ' Cierra la conexión antes de salir. @@ -205,7 +186,7 @@ Sub Handle(req As ServletRequest, resp As ServletResponse) End If ' Ejecuta el comando que no devuelve resultados (NonQuery) con sus parámetros. - con.ExecNonQuery2(sqlCommand, orderedParams) + con.ExecNonQuery2(sqlCommand, paramsList) ' Envía una respuesta de éxito con un mensaje de confirmación. SendSuccessResponse(resp, CreateMap("message": "Command executed successfully")) @@ -262,5 +243,3 @@ Private Sub SendErrorResponse(resp As ServletResponse, statusCode As Int, errorM resp.ContentType = "application/json" resp.Write(jsonGenerator.ToString) End Sub - - diff --git a/faviconHandler.bas b/faviconHandler.bas new file mode 100644 index 0000000..30d5b16 --- /dev/null +++ b/faviconHandler.bas @@ -0,0 +1,39 @@ +B4J=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=10.3 +@EndOfDesignText@ +'Class module: FaviconHandler +' Manejador para la petición de /favicon.ico +' Simplemente devuelve un estado HTTP 204 (No Content) +' para indicar al navegador que no hay un favicon. + +Sub Class_Globals + ' No se necesitan variables globales para este manejador simple. +End Sub + +Public Sub Initialize + ' No se necesita inicialización específica para este manejador. +End Sub + +Public Sub Handle(req As ServletRequest, resp As ServletResponse) +' Registra la petición en el Log (opcional, para depuración) +' Log("Petición de Favicon recibida: " & req.RequestURI) +' +' Establece el código de estado HTTP a 204 (No Content). +' Esto le dice al navegador que la petición fue exitosa, pero no hay contenido que devolver. + resp.Status = 204 + +' Es buena práctica cerrar el OutputStream, aunque para 204 no haya contenido explícito. +' Algunos servidores web podrían requerir cerrar el stream de respuesta. + Try + resp.OutputStream.Close + Catch + Log("Error al cerrar el OutputStream en FaviconHandler: " & LastException) + End Try + +' El Return es fundamental para que el manejador termine su ejecución +' y no intente procesar la petición con otros manejadores o caiga en el "catch-all". + Return +End Sub \ No newline at end of file diff --git a/jRDC_Multi.b4j b/jRDC_Multi.b4j index d4ee163..17d9469 100644 --- a/jRDC_Multi.b4j +++ b/jRDC_Multi.b4j @@ -31,26 +31,27 @@ Library7=json Library8=jsql Library9=bcrypt Module1=ChangePassHandler -Module10=RDCConnector -Module11=TestHandler +Module10=ping +Module11=RDCConnector +Module12=TestHandler Module2=DBHandlerB4X Module3=DBHandlerJSON Module4=DoLoginHandler -Module5=GlobalParameters -Module6=LoginHandler -Module7=LogoutHandler -Module8=Manager -Module9=ping +Module5=faviconHandler +Module6=GlobalParameters +Module7=LoginHandler +Module8=LogoutHandler +Module9=Manager NumberOfFiles=10 NumberOfLibraries=9 -NumberOfModules=11 +NumberOfModules=12 Version=10.3 @EndOfDesignText@ 'Non-UI application (console / server application) #Region Project Attributes #CommandLineArgs: #MergeLibraries: True - ' VERSION 5.09.01 + ' VERSION 5.09.08 '########################################################################################################### '###################### PULL ############################################################# 'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull @@ -119,24 +120,25 @@ Sub AppStart (Args() As String) End If Next End If - srvr.AddHandler("/ping", "ping", False) ' Agrega un manejador a la ruta "/test", asignando las solicitudes a la clase TestHandler, el último parámetro indica si el manejador debe ejecutar en un nuevo hilo (False en este caso) - srvr.AddHandler("/test", "TestHandler", False) ' Agrega un manejador a la ruta "/test", asignando las solicitudes a la clase TestHandler, el último parámetro indica si el manejador debe ejecutar en un nuevo hilo (False en este caso) + srvr.AddHandler("/ping", "ping", True) ' Agrega un manejador a la ruta "/test", asignando las solicitudes a la clase TestHandler, el último parámetro indica si el manejador debe ejecutar en un nuevo hilo (False en este caso) + srvr.AddHandler("/test", "TestHandler", True) ' Agrega un manejador a la ruta "/test", asignando las solicitudes a la clase TestHandler, el último parámetro indica si el manejador debe ejecutar en un nuevo hilo (False en este caso) ' --- INICIO DE CAMBIOS --- ' 1. Rutas para el sistema de Login - srvr.AddHandler("/login", "LoginHandler", False) ' Sirve la página de login - srvr.AddHandler("/dologin", "DoLoginHandler", False) ' Procesa el intento de login - srvr.AddHandler("/logout", "LogoutHandler", False) ' Cierra la sesión - srvr.AddHandler("/changepass", "ChangePassHandler", False) + srvr.AddHandler("/login", "LoginHandler", True) ' Sirve la página de login + srvr.AddHandler("/dologin", "DoLoginHandler", True) ' Procesa el intento de login + srvr.AddHandler("/logout", "LogoutHandler", True) ' Cierra la sesión + srvr.AddHandler("/changepass", "ChangePassHandler", True) ' 2. El handler del manager se queda igual, pero ahora estará protegido - srvr.AddHandler("/manager", "Manager", False) + srvr.AddHandler("/manager", "Manager", True) ' --- FIN DE CAMBIOS --- - srvr.AddHandler("/DBJ", "DBHandlerJSON", False) - srvr.AddHandler("/dbrquery", "DBHandlerJSON", False) + srvr.AddHandler("/DBJ", "DBHandlerJSON", True) + srvr.AddHandler("/dbrquery", "DBHandlerJSON", True) + srvr.AddHandler("/favicon.ico", "faviconHandler", True) ' srvr.AddHandler("/*", "DB1Handler", False) ' Si no se especifica una base de datos, entonces asignamos la solicitud a la DB1. - srvr.AddHandler("/*", "DBHandlerB4X", False) + srvr.AddHandler("/*", "DBHandlerB4X", True) srvr.Start Log("===========================================================") diff --git a/jRDC_Multi.b4j.meta b/jRDC_Multi.b4j.meta index 678255c..1b70cf1 100644 --- a/jRDC_Multi.b4j.meta +++ b/jRDC_Multi.b4j.meta @@ -2,6 +2,7 @@ ModuleBookmarks1= ModuleBookmarks10= ModuleBookmarks11= +ModuleBookmarks12= ModuleBookmarks2= ModuleBookmarks3= ModuleBookmarks4= @@ -14,6 +15,7 @@ ModuleBreakpoints0= ModuleBreakpoints1= ModuleBreakpoints10= ModuleBreakpoints11= +ModuleBreakpoints12= ModuleBreakpoints2= ModuleBreakpoints3= ModuleBreakpoints4= @@ -26,6 +28,7 @@ ModuleClosedNodes0= ModuleClosedNodes1= ModuleClosedNodes10= ModuleClosedNodes11= +ModuleClosedNodes12= ModuleClosedNodes2= ModuleClosedNodes3= ModuleClosedNodes4= @@ -34,6 +37,6 @@ ModuleClosedNodes6= ModuleClosedNodes7= ModuleClosedNodes8= ModuleClosedNodes9= -NavigationStack=DoLoginHandler,Initialize,7,0,Manager,Initialize,98,0,ChangePassHandler,Handle,27,0,DoLoginHandler,Handle,9,0,Manager,Handle0,202,6,TestHandler,Handle,11,0,LoginHandler,Handle,16,1,Manager,Handle,110,6,Main,Process_Globals,24,0,Main,AppStart,85,0 +NavigationStack=DBHandlerJSON,Initialize,16,0,DBHandlerJSON,Handle,207,6,ChangePassHandler,Handle,15,0,DBHandlerB4X,Handle,80,0,Main,AppStart,88,0,DBHandlerJSON,Class_Globals,10,0,DBHandlerJSON,SendErrorResponse,239,0,RDCConnector,LoadConfigMap,86,0,RDCConnector,GetCommand,90,0,RDCConnector,Initialize,75,0,RDCConnector,Class_Globals,9,0 SelectedBuild=0 -VisibleModules=2,3,10,8,11,6 +VisibleModules=2,3,11,9,12,7,1