Download PREGUNTAS Y RESPUESTAS DEL FRAMEWORK 2.0 PARA LOS
Document related concepts
no text concepts found
Transcript
Preguntas y respuestas FRAMEWORK 2 (JAVA) PREGUNTAS Y RESPUESTAS DEL FRAMEWORK 2.0 PARA LOS DESARROLLOS JAVA EN ICM A. MENÚ DE LA APLICACIÓN ................................................................................................................................ 3 ¿CÓMO SE DEFINEN LOS ELEMENTOS DEL MENÚ?....................................................................................................... 3 ¿CÓMO ES EL ESQUEMA DE DEFINICIÓN DEL FICHERO MENU-APLICACION.XML? ....................................................... 4 ¿CÓMO PODRÍAMOS PINTAR EL MENÚ LATERAL DEPENDIENDO DEL PERFIL DE USUARIO?........................................ 5 ¿CÓMO PODRÍAMOS CREAR UNA APLICACIÓN SIN MENÚ?.......................................................................................... 5 ¿CÓMO HACEMOS PARA QUE SE MANTENGA EN EL MENÚ LA ENTRADA ANTERIORMENTE SELECCIONADA(EN NEGRITA)?. .................................................................................................................................................................... 6 B. GESTIÓN DE USUARIOS INTRANET.............................................................................................................. 6 ¿CÓMO SE OBTIENE EL LOGIN DEL USUARIO CONECTADO? ........................................................................................ 6 ¿CÓMO SE OBTIENE EL PERFIL/GRUPO DEL USUARIO CONECTADO? .......................................................................... 6 ¿CÓMO DAR DE ALTA USUARIOS EN LAS TABLAS DE USU? ....................................................................................... 6 ¿CÓMO PUEDO DESHABILITAR LA COMPROBACIÓN DEL LDAP EN DESARROLLO? ................................................... 7 ¿CUÁL ES LA CONFIGURACIÓN DEL LDAP EN DESARROLLO? ................................................................................... 7 ¿CÓMO BLOQUEAR UN USUARIO TRAS UN Nº DE INTENTOS FALLIDOS DE ACCESO?.................................................. 7 ¿CÓMO SE PUEDE PERMITIR/BLOQUEAR LA EJECUCIÓN DE ACCIONES A DETERMINADOS PERFILES? ...................... 8 C. GESTIÓN USUARIOS INTERNET...................................................................................................................... 9 ¿CÓMO SE OBTIENE EL NIF DEL USUARIO CONECTADO?............................................................................................ 9 ¿CÓMO SE OBTIENE EL PERFIL/GRUPO DEL USUARIO CONECTADO? .......................................................................... 9 ¿CÓMO PUEDO GENERAR EL MODELO DE DATOS USUI (EMPRESAS EXTERNAS)? ................................................... 9 ¿CÓMO SE OBTIENEN OTROS DATOS DEL USUARIO CONECTADO? ............................................................................. 9 D. LISTA DE VALORES .......................................................................................................................................... 10 ¿CÓMO SE PUEDE SACAR EN UNA LISTA DE VALORES DATOS DE DOS TABLAS DIFERENTES? ................................ 10 ¿CÓMO HACER QUE UNA LISTA DE VALORES SE CARGUE CON VALORES DISTINTOS DEPENDIENDO DE LA SELECCIÓN DE OTRA LISTA DE VALORES?.................................................................................................................. 10 ¿CÓMO TENER VARIOS FORMULARIOS EN UNA PÁGINA Y UNA LISTA DE VALORES? ................................................ 10 ¿CÓMO MOSTRAR UNA PÁGINA JSP DISTINTA PARA UNA LISTA EN CONCRETO? .................................................... 10 E. ENVIO DE CORREO ........................................................................................................................................... 11 ¿CÓMO SE PUEDEN MANDAR CORREOS A DIRECCIONES DE CORREO DE LA INTRANET? ......................................... 11 ¿CÓMO SE PUEDEN MANDAR CORREOS A DIRECCIONES DE CORREO DE INTERNET?............................................... 11 ¿CÓMO SE PUEDEN MANDAR CORREOS CON FICHEROS ADJUNTOS? ....................................................................... 11 ¿CÓMO SE PUEDEN MANDAR CORREOS A PARTIR DE UNA PLANTILLA HTML EN LA QUE SE INCORPORAN CAMPOS VARIABLES?................................................................................................................................................................. 11 F. ENVIO DE SMS.................................................................................................................................................... 12 ¿CÓMO SE PUEDEN ENVIAR SMS? .............................................................................................................................. 12 G. OTROS .................................................................................................................................................................. 13 ¿CÓMO HACER UNA REDIRECCIÓN A UNA PÁGINA WEB?........................................................................................... 13 ¿CÓMO HACER EL UPLOAD DE UN FICHERO DESDE EL CLIENTE A LA APLICACIÓN? ................................................ 13 ¿CÓMO SOLUCIONAR EL ERROR “EL IDENTIFICADOR 'SIS_FUNC_VALIDA_USUARIO' SE DEBE DECLARAR”? ..................................................................................................................................................................................... 14 ¿CÚAL ES LA FORMA CORRECTA PARA ESCRIBIR EN UN CAMPO BLOB?.................................................................. 14 PROBLEMAS CON LA RUTA DE LOS REPORTS AL USAR CRYSTALREPORT................................................................ 15 PROBLEMAS AL INSERTAR VARIAS VECES UN PDF CON DISTINTOS DATOS ............................................................... 15 ¿DÓNDE DEJAR LOS FICHEROS TEMPORALES CREADOS POR LAS APLICACIONES JAVA? ....................................... 16 ¿CÓMO COMPRIMIR Y DESCOMPRIMIR FICHEROS? .................................................................................................... 17 ¿ EVITAR REENVÍO DE FORMULARIOS SENSIBLES ? USO DE FORMULARIOS SENSIBLES.......................................... 18 ¿COMO MOSTRAR UNA PÁGINA JSP PARA UNA LISTA DE VALORES CONCRETA?.................................................... 21 Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 1 Preguntas y respuestas FRAMEWORK 2 (JAVA) ¿COMO IMPRIMIR UN PDF DE FORMA DIRECTA? ......................................................................................................... 21 ¿ERROR LECTURA PORTAL.XML?............................................................................................................................... 23 Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 2 Preguntas y respuestas A. FRAMEWORK 2 (JAVA) Menú de la aplicación ¿Cómo se definen los elementos del menú? Respuesta Los elementos del menú se definen en un fichero de configuración llamado menu-aplicacion.xml que se debe incluir en el directorio WEB-INF/config A continuación se muestra un ejemplo de menu_aplicacion.xml. <?xml version="1.0" encoding="ISO-8859-1"?> <menu-principal desplegar-todos="false"> <elemento id="1" nombre="Inicio" nombre-navegacion="Home" url="../../html/web/index.htm" > <elemento id="1_1" nombre="Elemento 1_1" nombre-navegacion="Elemento 1_1" url="../../html/web/elemento1_1.htm"/> <elemento id="1_2" nombre="Elemento 1_2" nombre-navegacion="Elemento 1_2" url="../../html/web/elemento1_2.htm"> <elemento id="1_2_1" nombre="Accion1" nombre-navegacion="Accion 1" url="Accion1.icm"/> <elemento id="1_2_2" nombre="Ejemplo de aplicación" nombre-navegacion="Ejemplo" url="../../html/web/ejemplo.htm"/> Ejemplo <elemento id="1_2_3" nombre="Ejemplo de paginacion" nombre-navegacion="Ejemplo de paginacion" url="IniciaListado.icm"/> <elemento id="1_2_4" nombre="Ejemplo de solapas" nombre-navegacion="Ejemplo de solapas" url="EjemploSolapas.icm"/> </elemento> <elemento id="1_3" nombre="Otro Elemento" nombre-navegacion="Elemento 1_3" url="../../html/web/elemento1_3.htm"/> </elemento> <elemento id="2" nombre="Novedades" nombre-navegacion="Novedades" url="../../html/web/novedades.htm" target="Nueva ventana"/> <elemento id="3" nombre="(c) ICM-2005" no-url="true"/> </menu-principal> Estas son las variables que debe incluir el fichero de configuración: Variables del fichero de configuración MuestraMenuAplicacion=sistemas.framework.acciones.comunes aplicacion.menu=/WEB-INF/conf/menu_aplicacion.xml aplicacion.usarMenu=true El fichero vistas.conf debe incluir la siguiente línea: Fichero vistas.conf Versión de Sistemas menu-aplicacion = menu_aplicacion.jsp Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 3 Preguntas y respuestas FRAMEWORK 2 (JAVA) ¿Cómo es el esquema de definición del fichero menu-aplicacion.xml? Respuesta Versión de Sistemas <?xml version="1.0" encoding="UTF-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:complexType name="elementoType"> <xs:sequence> <xs:element name="elemento" type="elementoType" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"> <xs:annotation> <xs:documentation>Nivel en el que se encuentra este menu e identificación interna de la opción.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="nombre" type="xs:string" use="required"> <xs:annotation> <xs:documentation>Identificacion que recibira este elemento del menú.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="nombre_navegacion" type="xs:string"> <xs:annotation> <xs:documentation>Identificacion que recibira esta opción en la barra de navegación</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="url" type="xs:string"> <xs:annotation> <xs:documentation>URL a la que se dirigira este el link generado por este elemento.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="perfil" type="xs:string" use="optional"> <xs:annotation> <xs:documentation>Perfil requerido para que se muestre este elemento. Se pueden poner distintos perfiles separados por un punto y coma.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="no-url" type="xs:boolean"> <xs:annotation> <xs:documentation>Variable que indica si el elemento generado sera un link o no.</xs:documentation> </xs:annotation> </xs:attribute> </xs:complexType> <xs:element name="menu-principal"> <xs:complexType> <xs:sequence> <xs:element name="elemento" type="elementoType" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 4 Preguntas y respuestas FRAMEWORK 2 (JAVA) ¿Cómo podríamos pintar el menú lateral dependiendo del perfil de usuario? Respuesta En cuanto a la pregunta del menú. En la definición del menú es dónde se puede especificar cada elemento del menú para que perfiles estará definible. Esto se hace mediante el tag perfil asignando a este tag el valor del código del grupo o grupos que tienen autorización para acceder a este elemento del menú. Si el tag perfil no aparece entonces el elemento del menú estará disponible para todos los usuarios. El Controlador será el encargado de visualizar el menú dependiendo del perfil o grupo al que pertenezca el usuario conectado. A continuación se muestra un ejemplo de menu_aplicacion.xml con definición de perfiles. Ejemplo Versión de Sistemas <?xml version="1.0" encoding="ISO-8859-1"?> <menu-principal desplegar-todos="false" imagen-menu="%IMG_ROOT%/samp2_downarrow.gif" imagen-opcion="%IMG_ROOT%/samp2_bullet_hl.gif" cellpadding="0" cellspacing="0" width="158"> <elemento id="1" nombre="Empleados" url="Inicio.icm" perfil="2;1"> <elemento id="1_1" nombre="Información" url="Inicio.icm" perfil="2;1"/> <elemento id="1_2" nombre="Registro" url="FormAltaEmpleado.icm" perfil="1"/> </elemento> <elemento id="2" nombre="Busqueda avanzada" url="Menu.icm?numero=1" perfil="2;1"/> <elemento id="3" nombre="Administracion" url="Inicio.icm" perfil="1"> <elemento id="3_1" nombre="Dirección" url="ListadoCatalogos.icm?CATALOGO=DIRECCION" perfil="1"/> <elemento id="3_2" nombre="Sexo" url="ListadoCatalogos.icm?CATALOGO=SEXO" perfil="1"/> <elemento id="3_3" nombre="Area" url="ListadoCatalogos.icm?CATALOGO=AREA" perfil="1"/> <elemento id="3_4" nombre="Nivel" url="ListadoCatalogos.icm?CATALOGO=NIVEL" perfil="1"/> </elemento> <elemento id="4" nombre="(c) ICM-2003" no-url="true" perfil="2;1"/> </menu-principal> Sistemas2.x ¿Cómo podríamos crear una aplicación sin menú? En el fichero de configuración de la aplicación cambiar el valor del parámetro aplicacion.usarMenu a false. En los ficheros estaticas.jsp y principal.jsp del directorio WEB-INF\jsp eliminar el código Respuesta <%@ taglib uri="menu" prefix="menu" %> <div id="menu_aplicacion"><rejilla:render region='menu'/></div> y cambiar <div id="contenido_aplicacion"> Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 5 Preguntas y respuestas FRAMEWORK 2 (JAVA) por <div id="contenido_aplicacion_sin_menu">. En los ficheros estaticas.jsp y principal.jsp del directorio WEB-INF\jsp\rejillas eliminar las líneas <jsp:useBean id="contenido_menu" scope="session" class="java.lang.String" /> <rejilla:put region='menu' content='<%=contenido_menu%>'/> Versión de Sistemas Sistemas2.x ¿Cómo hacemos para que se mantenga en el menú la entrada anteriormente seleccionada(en negrita)?. Para que no se pierda la entrada seleccionada en negrita del menú cuando se llama a una acción se ha de pasar el parámetro ESTADO_MENU con el valor correspondiente: Respuesta NombreAccion.icm?ESTADO_MENU=valor Versión de Sistemas B. Sistemas2.x Gestión de usuarios Intranet ¿Cómo se obtiene el login del usuario conectado? Respuesta Versión de Sistemas Para obtener el login del usuario conectado hay que utilizar la clase sistemas.servidores.ObtenerUsuario. Sistemas2.x ¿Cómo se obtiene el perfil/grupo del usuario conectado? Respuesta Para obtener el grupo (perfil) del usuario conectado hay que utilizar el método sistemas.acceso.ControlAcceso.dameCodigoGrupo Versión de Sistemas Sistemas2.x ¿Cómo dar de alta usuarios en las tablas de USU? Es necesario dar de alta datos en las siguientes tablas: Respuesta APLICACION: Catálogo de aplicaciones del sistema La clave principal es CD_APLICACION GRUPO: Catálogo de grupos (perfiles) Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 6 Preguntas y respuestas FRAMEWORK 2 (JAVA) La clave principal es COD_APLICACION, COD_GRUPO USUARIO: Catálogo de usuarios del sistema La clave principal es COD_USUARIO USUARIO_GRUPO: Catálogo de asignaciones de aplicaciones a usuarios del sistema, es decir, a que aplicaciones tienen acceso los usuarios y con qué perfil. La clave principal es COD_USUARIO, COD_APLICACION Versión de Sistemas Sistemas2.x ¿Cómo puedo deshabilitar la comprobación del LDAP en desarrollo? Para que las empresas externas puedan utilizar el ControladorPrivadoIntranet sin disponer de un servidor LDAP se puede incluir en el fichero de configuración el parámetro ldap.autentificacion=false. Respuesta Es necesario que el usuario esté dado de alta en las tablas de USU. Esta opción solamente se debe utilizar en los entornos de desarrollo propios de las empresas externas. En nuestro entorno de desarrollo se dispone de un directorio LDAP por lo tanto es obligatorio utilizarlo. Versión de Sistemas Sistemas2.x ¿Cuál es la configuración del LDAP en desarrollo? Fichero de configuración (app.conf) Versión de Sistemas ldap.autentificacion=true ldap.configuracion.cookieUsuario = cookie_usuario ldap.configuracion.credencialesOriginales= ldap.configuracion.url=ldap://nticmdes09:389 ldap.configuracion.claveOriginal= ldap.configuracion.DC= O=icm.es ldap.configuracion.nombreAplicacion=<nombre MIDAX> ldap.configuracion.grupoAplicacion=Servicios ldap.paginaAutentificacion=/WEB-INF/jsp/ldap.jsp ldap.servidor=sistemas.ldap.impl.ServidorLDAPNetscapeImpl Sistemas2.x ¿Cómo bloquear un usuario tras un nº de intentos fallidos de acceso? Respuesta Fichero de configuración (app.conf) Versión de Para bloquear un usuario despues de intentar conectarse un nº determinado de veces, normalmente 3, y no conseguirlo simplemente hay que añadir unas variables en el fichero de configuración. aplicacion.servidorBloqueoUsuarios=nticmdes01 aplicacion.puertoBloqueoUsuarios=9500 aplicacion.limiteIntentos=3 Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 7 Preguntas y respuestas FRAMEWORK 2 (JAVA) Sistemas ¿Cómo se puede permitir/bloquear la ejecución de acciones a determinados perfiles? Para bloquear/permitir la ejecución de acciones a determinados perfiles se necesitan dos cosas: 1) Crear un fichero llamado opciones.xml, en el directorio “/conf”, en el que se den de alta las acciones a las que queremos dar o no permiso con un código asociado. Un ejemplo de este fichero es: <?xml version="1.0" encoding="ISO-8859-1"?> <opciones> <opcion nombre="AltaEmpleado" codigo="10"/> <opcion nombre="FormAltaEmpleado" codigo="10"/> </opciones> Respuesta 2) Dar de alta una entrada en la tabla grupauto para cada grupo(perfil) con permiso para realizar esa acción. Por ejemplo: COD_APLICACION= EJPL COD_GRUPO = 1 COD_ACCION = 10 En este caso se da permiso al código de grupo 1 para el acceso a la acción AltaEmpleado. Si no hay mas entradas para ese código de acción no podrá acceder ningún usuario de otro grupo. Ficheros necesarios Fichero opciones.xml (directorio conf) Versión de Sistemas Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 8 Preguntas y respuestas C. FRAMEWORK 2 (JAVA) Gestión Usuarios Internet ¿Cómo se obtiene el NIF del usuario conectado? Respuesta Para saber el NIF del usuario conectado hay que utilizar el siguiente método: sistemas.acceso.ControlAcceso.dameNIF(con, request); Versión de Sistemas Sistemas2.x ¿Cómo se obtiene el perfil/grupo del usuario conectado? Respuesta Para obtener el grupo (perfil) del usuario conectado hay que utilizar el método sistemas.acceso.ControlAcceso.dameCodigoGrupo(con, request); Versión de Sistemas Sistemas2.x ¿Cómo puedo generar el modelo de datos USUI (Empresas Externas)? Respuesta En el DVD que ICM distribuye a las empresas externas, se encuentra el modelo en un fichero de ErWin (\BASE_DATOS\USUI.ER1). Una vez abierto el modelo nos vamos a Tools-Forward Engineer/Schema generation y hacemos click en “Preview” para obtener el script de creación. Podemos generar el modelo desde ErWin, para ello debemos hacer click en “Generate”. ¿Cómo se obtienen otros datos del usuario conectado? Existen dos clases dentro de la librería de Sistemas que sirven para consultar los datos del usuario conectado. Respuesta Estas clases son: sistemas.framework.beans.usui.DatosUsuarioBean sistemas.framework.modelo.usui.DatosUsuarioDAO DatosUsuarioBean datosUsuarioBean = new DatosUsuarioBean(); Ejemplo Versión de Sistemas datosUsuarioBean.setCdNif(ControlAcceso.dameNIF(con, request)); DatosUsuarioDAO duDAO = new DatosUsuarioDAO(); datosUsuarioBean =(DatosUsuarioBean) duDAO.consulta(con, datosUsuarioBean); Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 9 Preguntas y respuestas D. FRAMEWORK 2 (JAVA) Lista de Valores ¿Cómo se puede sacar en una lista de valores datos de dos tablas diferentes? Respuesta Versión de Sistemas Hay que crearse una vista con los datos de las dos tablas. Sistemas2.x ¿Cómo hacer que una lista de valores se cargue con valores distintos dependiendo de la selección de otra lista de valores? La primera lista se generará con el método genListaGenerica() incluido en el fichero sistemas.js. Para generar la segunda lista se tiene que hacer un método nuevo basandose en el genListaGenerica(). Por ejemplo genListaMunicipios() para el caso de que tengamos una lista de valores con provincias y queramos generar la lista municipios dependiendo del valor de la provincia. Respuesta Este método recibirá el valor seleccionado y añadirá a la variable “cadenaLlamada” el WHERE necesario. Por ejemplo “ WHERE CD_PROVINCIA=parametro_javascript_recogido”. Versión de Sistemas Sistemas2.x ¿Cómo tener varios formularios en una página y una lista de valores? En vez de generar una lista de valores de un formulario utilizando el método genListaGenerica(campo1, campo2…) hay que llamar al método pasandole también el nombre del formulario: Respuesta genListaGenerica(nombre_formulario,campo1,campo2…) Versión de Sistemas Sistemas2.x ¿Cómo mostrar una página JSP distinta para una lista en concreto? Respuesta Versión de Sistemas Para poder definir una página JSP distinta para una lista lo único que debemos hacer es incluir en el fichero de vistas una nueva linea que relacione el nombre lógico “lista-valores-”+[nombre de la lista] con la JSP que queremos mostrar. Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 10 Preguntas y respuestas E. FRAMEWORK 2 (JAVA) Envio de correo ¿Cómo se pueden mandar correos a direcciones de correo de la intranet? Respuesta Variables del fichero de configuración Usaremos el método enviarMensaje de un objeto de la clase sistemas.correo.MensajeCorreo. email.smtp.host = mail.madrid.org email.smtp.user= portal email.smtp.pass= 0FE593802CB3CECB Ejemplo Versión de Sistemas Sistemas2.x ¿Cómo se pueden mandar correos a direcciones de correo de internet? Respuesta Variables del fichero de configuración Usaremos el método enviarMensaje de un objeto de la clase sistemas.correo.MensajeCorreo. email.smtp.host = mail.madrid.org email.smtp.user= portal email.smtp.pass= 0FE593802CB3CECB Ejemplo Versión de Sistemas Sistemas2.x ¿Cómo se pueden mandar correos con ficheros adjuntos? Respuesta Variables del fichero de configuración Usaremos el método enviarMensajeConAdjuntos de un objeto de la clase sistemas.correo.MensajeCorreo , previamente hemos tenido que indicarle el fichero a adjuntar, ejecutando el método addFicheroAdjunto(<nombreCompletoFichero>) #A direcciones de correo de la Intranet email.smtp.host = smtp.madrid.org email.smtp.user= email.smtp.pass= #A direcciones de correo de internet email.smtp.host = mail.madrid.org email.smtp.user=<usuario> email.smtp.pass=<password encriptada> Ejemplo Versión de Sistemas Sistemas2.x ¿Cómo se pueden mandar correos a partir de una plantilla HTML en la que se incorporan campos variables? Respuesta Usaremos el método enviarMensajePlantillaHTML(<nombrePlantilla>,<tablaValores>) de un Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 11 Preguntas y respuestas FRAMEWORK 2 (JAVA) objeto de la clase sistemas.correo.MensajeCorreo. El parámetro <nombrePlantilla> contendrá el path de la plantilla a usar. Esta plantilla tiene que estar en el directorio plantillas. El parámetro <tablaValores> es un objeto de la clase java.util.Hastable que contiene las variables a sustituir en la plantilla y sus correspondientes valores. Ejemplo Versión de Sistemas F. Sistemas2.x Envio de sms ¿Cómo se pueden enviar sms? Respuesta Para el evío de sms se utilizará la plataforma MenTes, a través del servicio web mentes_ws. Es posible utiliza la librería MENT_LIB desde las aplicaciones. Dicha librería es cliente del servicio web mentes_ws de envío de SMSs, y nos facilita la llamada a todas las operaciones de envío de mensajes. Variables del fichero de configuración sms.usar.mentes=true aplicacion.nombre=NOMBRE_APLICACION que debe estar dada de alta en MENTES sms.url.mentes_ws=http://deswebservices.madrid.org/mentes_ws/services/ServicioSMSMenTes Ejemplo de evío de mensaje detallado, con planificación: Ejemplo private String enviaDetallados() throws AccionException{ SmsDetalladoBean[] mensajes = new SmsDetalladoBean[1]; SmsDetalladoBean sms = new SmsDetalladoBean(); String[] telefonos = new String[1]; telefonos [0] = request.getParameter("TELEFONO"); sms.setAplicacion(request.getParameter("APLICACION")); sms.setConfirmacion(Integer.parseInt(request.getParameter("CONFIRMACION"))); sms.setExpiracion(1); sms.setLunes(Integer.parseInt(request.getParameter("LUNES"))); sms.setMartes(Integer.parseInt(request.getParameter("MARTES"))); sms.setMiercoles(Integer.parseInt(request.getParameter("MIERCOLES"))); sms.setJueves(Integer.parseInt(request.getParameter("JUEVES"))); sms.setViernes(Integer.parseInt(request.getParameter("VIERNES"))); sms.setSabado(Integer.parseInt(request.getParameter("SABADO"))); sms.setDomingo(Integer.parseInt(request.getParameter("DOMINGO"))); sms.setHoraInicio(request.getParameter("HORAINI")); sms.setHoraFin(request.getParameter("HORAFIN")); sms.setMensaje(request.getParameter("MENSAJE")); sms.setTelefonos(telefonos); mensajes[0] = sms; EnvioSMS envio = new EnvioSMS(Config.getString(“sms.url.mentes_ws”)); try { return envio.enviaSMSDetallados(request.getParameter("APLICACION"), mensajes); } catch (Exception e) { throw new AccionException(e.getMessage()); } } Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 12 Preguntas y respuestas Versión de Sistemas FRAMEWORK 2 (JAVA) Sistemas2.x G. Otros ¿Cómo hacer una redirección a una página web? Para hacer una redireccion tienes que usar la clase Redireccion de la siguiente forma: Redireccion red = new Redireccion(con, request, response,nomFichero); return red.procesar(); Respuesta Siendo nomFichero la URL a la que te quieres dirigir. Ficheros necesarios redireccion.jsp (Seccion Download) Versión de Sistemas Sistemas2.x ¿Cómo hacer el Upload de un fichero desde el cliente a la aplicación? Para hacer el upload de un fichero hay que: - Respuesta - Definir el formulario como ENCTYPE=”multipart/form-data” Definir dentro del formulario el campo como type=”file” Incluir un campo de tipo hidden. Este campo se va a actualizar con el valor del campo de tipo file con el cual se corresponda, esto se va a hacer mediante javascript. Esto hace falta para que al request se le pueda preguntar por el nombre del fichero. En el submit del formulario habrá que llamar al método javascript que actualiza el valor del campo hidden. Implementar una clase de Accion que herede de ClaseAccionMultipart. Dentro del método procesar se puede utilizar el método getParametro para acceder a cualquier parámetro del request bien el de tipo file o de cualquier otro tipo. Para acceder al contenido del campo de tipo file hay que llamar al método getContenidoFichero. Este método devuelve un byte[]. <SCRIPT> function enviarFormulario(destino){ document.formulario.NOMBRE_REPORT.value = window.document.formulario.REPORT.value; document.formulario.action = destino; document.formulario.submit(); } </SCRIPT> Ejemplo de formulario … <form name="formulario" method="POST" enctype="multipart/form-data" action="UploadReport.icm"> … <input type="file" name="REPORT" size="93"> <input type="hidden" name="NOMBRE_REPORT"> … </form> Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 13 Preguntas y respuestas Ejemplo de código a utilizar en la ClaseAccion FRAMEWORK 2 (JAVA) String nombre_report = this.getParametro("NOMBRE_REPORT"); … byte[] contenido_report = this.getContenidoFichero("REPORT"); ¿Cómo solucionar el error “El identificador 'SIS_FUNC_VALIDA_USUARIO' se debe declarar”? Respuesta Desde el DVD que accederemos a la carpeta Base_Datos: 1. Se ejecutará el script de creacción de la base de datos de USU para ello, se abrirá el modelo Erwing USU.ER1. Desde el menú Tools se accede a Forward Engineer/Schema Generation… Se pulsará OK para su ejecución o bien se pulsará el botón de Preview para obtener el script de creacción para posteriormente ejecutarlo. 2. Se ejecutara el script de creacción de las tablas de infraestructura, para ello se ejecutara el script que esta en el fichero Tablas_Infraestructura.sql. Con esto se creará una función llamada SIS_FUNC_VALIDA_USUARIO que comprueba el acceso de un usuario a la base de datos de USU. 3. Añadir datos a las tablas de USU: USUARIO (GAT_T002), APLICACIÓN (GAT_T001), GRUPO ,GRUPAUTO (GAT_T039), USUARIO-GRUPO (GAT_T022), ACCION (GAT_T038) Versión de Sistemas Sistemas2.x ¿Cúal es la forma correcta para escribir en un campo Blob? Para escribir en un campo Blob lo que hay que hacer es lo siguiente: FileInputStream inStream = new FileInputStream(new File(nombreArchivo)); byte[] b_1 = new byte[inStream.available()]; inStream.read(b_1); int reg_afectados = 0; Connection con = Conexion.getConnection(); PreparedStatement pStmt = null; PreparedStatement pStmt_primera = null; ResultSet rs = null; ResultSet rs_primera = null; String update = "UPDATE JFORUM_POSTS_TEXT SET POST_TEXT=empty_blob() WHERE POST_ID="+ post_id; Ejemplo String select = "SELECT POST_TEXT FROM JFORUM_POSTS_TEXT WHERE POST_ID=" + post_id+ " FOR UPDATE NOWAIT"; try { Trazas.impLog("\n preparando pStmt"); /* * Realizando primero el vaciado del campo BLOB * en este caso se realiza un UPDATE porque ya tenemos un valor insertado previamente */ pStmt = con.prepareStatement(update); reg_afectados = pStmt.executeUpdate(); Trazas.impLog("\n ejecutando pStmt"); /* * Ciere del preparedStatement del UPDATE */ if (pStmt != null) pStmt.close(); Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 14 Preguntas y respuestas FRAMEWORK 2 (JAVA) pStmt = null; /* * Realizando la select sobre el campo BLOB deseado, * dicha operación es la que realiza la actualización del campo blob */ pStmt = con.prepareStatement(select); rs = pStmt.executeQuery(); Trazas.impLog("\n ha ejecutado pStmt"); /* * Hay que reseñar que la actualización de este campo * BLOB tendrá el tamaño máximo indicado en la primera inserción, * es decir, si en la primera inserción el campo BLOB tenia tamaño de 5 kb, * NUNCA podremos insertar un tamaño mayor que ese. */ if (rs.next()) { BLOB blob = ((OracleResultSet) rs).getBLOB("POST_TEXT"); OutputStream os = blob.getBinaryOutputStream(); byte[] buffer = new byte[blob.getBufferSize()]; int length = b_1.length; ByteArrayInputStream contenido = new ByteArrayInputStream(array_bytes); while ((length = contenido.read(buffer)) != -1) { os.write(buffer, 0, length); } os.flush(); os.close(); } Versión de Sistemas Problemas con la ruta de los reports al usar CrystalReport Respuesta Deberemos comprobar que el fichero CrystalReportEngine-config.xml tiene la etiqueta <reportlocation> apuntando al directorio donde se encuentran nuestros reports. Este fichero xml se encuentra en el directorio <nombre_aplicacion>\java\fuentes\src Versión de Sistemas Sistemas2.x Problemas al insertar varias veces un pdf con distintos datos Deberemos usar el método pdf.insertaPDF(<pdf_a_insertar>, <número_veces_a_insertar>, false) de la clase PDFDispatch. Respuesta Donde: pdf: es el PDFDispatch del pdf en el que queremos realizar la inserción. Pdf_a_insertar: es el PDFDispatch del pdf a insertar. Número_veces_a_insertar: es el número de veces que queremos insertarlo. False: Se pone false, si se quiere insertar al final del documento. Los campos del pdf que hemos insertado, tomarán el nombre que tenían seguido de “_1” para la primera copia, seguido de “_2” para la segunda y así sucesivamente. Gracias a eso podremos meter en las distintas copias valores diferentes. Versión de Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 15 Preguntas y respuestas FRAMEWORK 2 (JAVA) Sistemas ¿Dónde dejar los ficheros temporales creados por las aplicaciones java? El directorio de los ficheros temporales de las aplicaciones Java debe ser siempre el directorio /usr/aplic_ICM/prod/web/temp/pdf en el entorno de desarrollo Solaris y el directorio /usr/PRODUCTO/oracle/j2ee904/j2ee/temp en el entorno de desarrollo Linux, tengan la extensión que tengan. Si se dejan ficheros temporales en otro directorio distinto y hay balanceo de cargas, pueden producirse errores ya que puede que no se encuentre el fichero que se intenta visualizar. Tipos de aplicaciones que utilizan ficheros temporales: Aplicaciones que generan PDF. Siempre que se genere un fichero PDF se debería incluir las siguientes variables en el fichero de configuración en el entorno de desarrollo Solaris pdf.directorio = /usr/aplic_ICM/prod/web/temp/pdf pdf.outPDF = ../../../download Si la aplicación está desplegada en el entorno de desarrollo Linux las variables son pdf.directorio = /usr/PRODUCTO/oracle/j2ee904/j2ee/temp pdf.outPDF = ../../../download Respuesta Aplicaciones que se integran con Vignette. Usa la variable de configuración: vignette.directorioTemporal = /usr/aplic_ICM/prod/web/temp/pdf Para Linux: vignette.directorioTemporal = /usr/PRODUCTO/oracle/j2ee904/j2ee/temp Aplicaciones que generan gráficos (por ejemplo mapas). No hay ninguna variable estándar definida, pero igualmente deberían generarse en ‘/usr/aplic_ICM/prod/web/temp/pdf’ en el entorno de desarrollo Solaris y ‘/usr/PRODUCTO/oracle/j2ee904/j2ee/temp’ en el entorno de desarrollo Linux. Se debería incluir una variable propia en el fichero de configuración en el entorno de desarrollo Solaris de la forma: aplicacion.directorio.temporal = /usr/aplic_ICM/prod/web/temp/pdf Para el entorno de desarrollo Linux de la forma: aplicacion.directorio.temporal = /usr/PRODUCTO/oracle/j2ee904/j2ee/temp Y para enviar los ficheros generados al navegador hay que utilizar una url: http://icmweb01/download/nombrefichero en Solaris y http://desarrollo.madrid.org/download/nombrefichero en Linux. Por lo tanto necesitamos otra variable que nos apunte a este servlet: aplicacion.dowload = ../../../download Versión de Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 16 Preguntas y respuestas FRAMEWORK 2 (JAVA) Sistemas ¿Cómo comprimir y descomprimir ficheros? /* Método para comprimir en un fichero de salida. */ public void comprimeFisico(String ficheroSalida){ try{ CompresorZIP comprimeZip = new CompresorZIP(ficheroSalida); String fichero1 = "d:/ejemplo1.xml"; String fichero2 = "d:/ejemplo2.xml"; comprimeZip.addFichero(fichero1); comprimeZip.addFichero(fichero2); comprimeZip.close(); }catch(java.io.IOException ie){ } } /* Método para comprimir en memoria un fichero. */ Respuesta public byte[] comprimeMemoria(){ byte[] salida = null; try{ CompresorZIP comprimeZip = new CompresorZIP(); String fichero1 = "d:/ejemplo1.xml"; String fichero2 = "d:/ejemplo2.xml"; comprimeZip.addFichero(fichero1); comprimeZip.addFichero(fichero2); comprimeZip.close(); salida = comprimeZip.getContenidoZIP(); }catch(java.io.IOException ie){ } return salida; } /* Método de descompresión fichero. */ public int descomprime(String entrada) { int nm_ficheros = 0; try{ DescompresorZIP descomprimeZip = new DescompresorZIP(entrada); do{ // Obtenemos el nombre y el contenido de cada fichero en el zip. DescompresorZIP.DescriptorFichero ds = descomprimeZip.getFichero(); String nombreFichero = ds.getNombre(); byte[]contenidoFichero = ds.getContenido(); nm_ficheros++; }while(descomprimeZip.hayMasFicheros()); descomprimeZip.close(); }catch(java.io.IOException ie){ } Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 17 Preguntas y respuestas FRAMEWORK 2 (JAVA) return nm_ficheros; } /* Método de descompresión memoria. */ public int descomprime(byte[] entrada) { int nm_ficheros = 0; try{ DescompresorZIP descomprimeZip = new DescompresorZIP(entrada); do{ // Obtenemos el nombre y el contenido de cada fichero en el zip. DescompresorZIP.DescriptorFichero ds = descomprimeZip.getFichero(); String nombreFichero = ds.getNombre(); byte[]contenidoFichero = ds.getContenido(); nm_ficheros++; }while(descomprimeZip.hayMasFicheros()); descomprimeZip.close(); }catch(java.io.IOException ie){ } return nm_ficheros; } Versión de Sistemas Sistemas2.x ¿ Evitar reenvío de formularios sensibles ? Uso de formularios sensibles Respuesta Es fácil reenviar accidentalmente formularios mediante los marcadores o el botón actualizar del navegador. Debido a este comportamiento no deseable, las aplicaciones Web deben estar protegidas contra el reenvió de formularios sensibles. En primer lugar tenemos que distinguir entre dos tipo de acciones: • Acciones que van contienen formularios sensibles: FormBajaEmpleado • Acciones que son sensibles: BajaEmpleado En el código Java de la acción hay que indicarle que es sensible. Los siguientes ejemplos nos van a mostrar la forma de hacerlo. Para las acciones que tienen un formulario sensible, es decir, aquellas cuya jsp asociada no va poder ser reenviada dentro del flujo correcto la aplicación. Introducimos: public FormBajaEmpleado() { super.tieneFormulariosSensibles = true; } Para las acciones que son sensibles, es decir, aquellas que no se pueden ejecutarse de manera accidental más de una vez en el flujo normal de la aplicación. Introducimos: public BajaEmpleado() { super.esSensible = true; } Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 18 Preguntas y respuestas FRAMEWORK 2 (JAVA) En la página JSP tenemos que introducir un testigo que es el que nos va a indicar si ya se ha enviado o no, dicho testigo (token) se indica como sigue: <input type=hidden name="token" value="<%=token%>"> El siguiente ejemplo muestra como introducir dicho testigo (token) en un formulario sensible: Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 19 Preguntas y respuestas FRAMEWORK 2 (JAVA) <html> <head> <meta http-equiv="Content-Language" content="es"> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <meta name="GENERATOR" content="Microsoft FrontPage 5.0"> <meta name="ProgId" content="FrontPage.Editor.Document"> <title>Baja Empleado</title> <meta name="Microsoft Border" content="none"> </head> <jsp:useBean id="empleadosBeanId" scope="session" class="empleadosmvc.bean.EmpleadosBean" /> <jsp:useBean id="token" scope="request" class="java.lang.String" /> <body> <form method="POST" action="BajaEmpleado.icm?CODIGO=<%=empleadosBeanId.getCodigo()%>"> <input type=hidden name="token" value="<%=token%>"> <table border="0" width="100%" height="341"> <tr> <td width="100%" colspan="2" bordercolor="#000000" bgcolor="#FFCC66" height="16"> <div align="center"> <center> <p><font face="Arial" size="2"><b>Supresión Empleado</b></font></p> </center> </div> </td> </tr> <tr align="center"> <td width="35%" bgcolor="#FFEABD" height="19"> <div align="right"> <font face="Arial" size="2">Código empleado: </font></div> </td> <td width="65%" height="19"> <div align="left"><%=empleadosBeanId.getCodigo()%></div> </td> </tr> <tr> <td width="35%" bgcolor="#FFEABD" height="19"> <div align="right"> <font face="Arial" size="2">Nombre: </font></div> </td> <td width="65%" height="19"> <div align="left"><%=empleadosBeanId.getNombre()%></div> </td> </tr> .... <div align="center"> <center><p> <input type="submit" class="boton" name="Aceptar" value="Aceptar"> <input type="button" class="boton" value="Cancelar" onclick="javascript:history.back()" name="B2"> </p></center> </div> </form></body></html> Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 20 Preguntas y respuestas FRAMEWORK 2 (JAVA) El Controlador va a ser el encargado de comprobar al recibir una petición de una acción sensible si ya la ha realizado o no, y responderá con un mensaje de error en caso de reenvío indicando “Este formulario no puede ser reenviado”. Versión de Sistemas Sistemas2.x ¿Como mostrar una página JSP para una lista de valores concreta? En el fichero de vistas.conf hay que añadir una nueva linea que sea: lista-valores-[NOMBRE_DE_LA_LISTA_EN_LISTAS.XML] = [NOMBRE_DE_LA_JSP_QUE_SE_QUIERE_MOSTRAR_PARA_ESA_LISTA] Respuesta sin eliminar el valor por defecto para lista de valores. Ejemplo: lista-valores = listavalores.jsp lista-valores-1 = listavalores_provincias.jsp Versión de Sistemas Sistemas2.x ¿Como imprimir un pdf de forma directa? Respuesta Se modifica el pdf con iText para añadirle el javascript que hace la impresión directa del documento. public String procesar() throws AccionException { try { byte[] contenido = getContenidoFichero("fichero_pdf"); String ruta_fichero = getParametro("ruta_fichero"); ruta_fichero = Utilidades.replace(ruta_fichero,"\\","/"); String nombre_fichero = ruta_fichero.substring(ruta_fichero.lastIndexOf("/")+1, ruta_fichero.length()); String extension = nombre_fichero.substring(nombre_fichero.lastIndexOf(".")+1, nombre_fichero.length()); if(extension.equals("pdf")){ File file = new File(Config.get("pdf.directorio") + "/" + nombre_fichero); Ejemplo FileOutputStream fos; try { fos = new FileOutputStream(file); fos.write(contenido); fos.flush(); fos.close(); } catch (FileNotFoundException fnfex) { Trazas.imprimeErrorExtendido(fnfex); throw new AccionException(fnfex); } catch (IOException ioex) { Trazas.imprimeErrorExtendido(ioex); throw new AccionException(ioex); } modifica_pdf(nombre_fichero); ByteArrayOutputStream resultado = response.setHeader("Expires", "0"); response.setHeader("Cache-Control", "must-revalidate, postcheck=0, pre-check=0"); Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 21 Preguntas y respuestas FRAMEWORK 2 (JAVA) response.setHeader("Pragma", "public"); response.setContentType("application/pdf"); response.setContentLength(resultado.size()); ServletOutputStream out; try { out = response.getOutputStream(); resultado.writeTo(out); out.flush(); } catch (IOException ioex) { Trazas.imprimeErrorExtendido(ioex); throw new AccionException(ioex); } }else{ throw new AccionException("El documento no es un fichero con extension pdf."); } } catch (CargableException cex) { Trazas.imprimeErrorExtendido(cex); throw new AccionException(cex); } return null; } public ByteArrayOutputStream modifica_pdf(String nombre_fichero) throws AccionException{ /* Variables */ Document document = new Document(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); /* Generar el documento */ try { FileOutputStream b = new FileOutputStream(Config.get("pdf.directorio") + "/copia_" + nombre_fichero); /* Crea el writer */ PdfReader reader = new PdfReader(Config.get("pdf.directorio") + "/" + nombre_fichero); PdfCopy copy = new PdfCopy(document, b); /* Abre el documento */ document.open(); copy.addJavaScript("this.print({bUI: false,bSilent: false,bShrinkToFit: true});"+"\r\n" +"this.closeDoc();"); copy.addJavaScript("this.print(false);", false); for (int i=1; i <= reader.getNumberOfPages(); i++){ PdfImportedPage page = copy.getImportedPage(reader, i); copy.addPage(page); } /* Cerrar el documento*/ document.close(); FileInputStream in = new FileInputStream(Config.get("pdf.directorio") + "/copia_" + nombre_fichero); int c; final int BUFSIZE = 2048; byte[] b_2 = new byte[BUFSIZE]; while ((c = in.read(b_2)) != -1) { baos.write(b_2,0,c); baos.flush(); } File file = new File(Config.get("pdf.directorio") + "/copia_" + nombre_fichero); FileOutputStream fos = new FileOutputStream(file); fos.write(baos.toByteArray()); fos.flush(); fos.close(); return baos; }catch (Exception e){ Trazas.imprimeErrorExtendido(e); Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 22 Preguntas y respuestas FRAMEWORK 2 (JAVA) throw new AccionException(e); } Versión de Sistemas } Sistemas2.x ¿Error lectura portal.xml? Debido a un cambio en las librerías de parseo de XML hecho recientemente puede aparecer el error Error en la lectura del fichero xml ('Error general:Content is not allowed in prolog.') cuando se actualice la aplicación o al ir a utilizarla después de un reinicio, para solventar el error hay que eliminar la primera linea del XML si es similar a esta <?xml version="1.0" encoding="UTF-8"?> y grabar el fichero con codificación UTF-8 y formato de archivo UNIX. Estas opciones se pueden especificar seleccionando la opción "Guardar como..." de Textpad. Respuesta Si el error es como este: sistemas.excepciones.PortalException: Error en la lectura del fichero xml ('Error general:Content is not allowed in prolog.') at sistemas.portal.DefinicionPortal.<init>(DefinicionPortal.java:49) at sistemas.portal.DefinicionPortal.getInstance(DefinicionPortal.java:93) Entonces el fichero que esta mal es portal.xml y hay que hacer lo anteriormente mencionado. Versión de Sistemas Sistemas2.x Subdirección General de Desarrollo, Tecnología e Infraestructuras. Dirección de Planificación e Innovación Tecnológica. Área de Soporte Técnico a Desarrollo Página: 23