- VERSION 5.09.08

- Se cambio el codigo para que en lugar de esperar un mapa con los parametros del query y nombres de los parametros (par1, par2, etc) paradefinir el ordenamiento, ahora se espera una lista [1,"2",3], y el orden de los parametros se toma directamente del orden en el que se mandan, de la misma forma que en B4A.
This commit is contained in:
2025-09-08 22:04:15 -06:00
parent 2f9569b585
commit 48dbd1f034
4 changed files with 86 additions and 63 deletions

View File

@@ -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

39
faviconHandler.bas Normal file
View File

@@ -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

View File

@@ -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("===========================================================")

View File

@@ -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