Download Seleccionar una Tabla
Document related concepts
no text concepts found
Transcript
Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Taller de Java Enterprise Edition Practicas: Instalación del SDK de java: Se descarga de: http://java.sun.com/javaee/downloads/index.jsp Se ejecuta Al pedir un administrador poner un usuario y clave (comúnmente admin es usuario) Se habilita la opción de manejar como un servicio de Windows el servidor de java. Se habilita la opción de agregar el path. Se selecciona la opcion de inicializar el servidor y listo. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Instalación de Macromedia DreamWeaver: Se descarga de: http://www.adobe.com/products/dreamweaver/ en la sección de free trial. Se ejecuta el archivo descargado y se siguen las instrucciones para su instalación. JSP Primero vamos a configurar el entorno de dreamweaver y dar de alta un nuevo proyecto con los datos del servidor Se crea la siguiente ubicación C:\Sun\AppServer\domains\domain1\docroot\tjava\jsp\ Abre el macromedia dreamweaver. En la primera ventana que aparece ponle en el sitio de dreamweaver. En el nombre ponle Taller Java. En la pagina pon http://localhost:8080/tjava/jsp/. En la siguiente parte selecciona que si quieres usar alguna tecnología Selecciona jsp. En la siguiente parte selecciona editar localmente y probar en red. Selecciona alguna ubicación valida donde se guardaran los archivos. En la sección siguiente selecciona local y escribe la siguiente ubicación C:\Sun\AppServer\domains\domain1\docroot\tjava\jsp\ En la siguiente sección escribir la siguiente dirección http://localhost:8080/tjava/jsp/ y probarla En la siguiente parte selecciona no y finaliza Primer Ejercicio (Hola Mundo) Ahora vamos a crear una pagina jsp Le damos en más en la ventana que actualmente aparece, seleccionamos dinamica y jsp. Ahora Ahí tres tipos de etiquetas seleccionamos la de codigo e insertamos un código dentro de las etiquetas de cuerpo: <% out.println("<b>Hola Mundo</b>"); %> Se guarda y se prueba con el F12 Felicidades ya has creado tu primera pagina con JSP!!!! =) Taller Aplicaciones Web con JSP Ejercicio #2: Combinación de html dinamico y estatico. Dante Mendoza Ruelas Vamos a crear una pagina en la cual incluya html dinámico creado por java y estático; Se trata de hacer una tabla en html y con código java llenarla de dos maneras con código html y código java embebido o al revés código java con código html adentro. Primera opción: Creamos una nueva página con una tabla e ingresamos el siguiente código java: <%@ page import="java.util.*"%> <% String[] nombres = {"Dante", "De Avila", "Llama", "Vicky", "Oswaldo", "Monse", "Ciseña", "Cortinas", "Gina", "Tere", "Mayela"}; Random aleatorio = new Random(); int num; %> Y en cada celda de la tabla ingresamos: <td><% num = aleatorio.nextInt(10); out.println(nombres[num]); %></td> <td><% out.println(num + 1); %></td> ¿Qué es lo que hace? Primero generamos un arreglo de nombres inicializamos la función de números aleatorios generamos una variable entera donde guardaremos el número aleatorio generado. Después en cada celda de la tabla generaremos un numero aleatorio con el cual obtendremos un nombre y mostraremos el numero generado Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Segunda opción: Ahora meteremos codigo html dentro del codigo java: En una pagina nueva insertamos el siguiente codigo: <%@ page import="java.util.*"%> <% String[] nombres = {"Dante", "De Avila", "Llama", "Vicky", "Oswaldo", "Monse", "Ciseña", "Cortinas", "Gina", "Tere", "Mayela"}; Random aleatorio = new Random(); int num, num2; num = aleatorio.nextInt(10); num2 = num + 1; out.println("<table width=\"200\" border=\"1\">" + "<tr>" + "<td>" + nombres[num] + "</td>" + "<td>" + num2 + "</td>" + "</tr>"); num = aleatorio.nextInt(10); num2 = num + 1; out.println("<tr>" + "<td>" + nombres[num] + "</td>" + "<td>" + num2 + "</td>" + "</tr>"); num = aleatorio.nextInt(10); num2 = num + 1; out.println("<tr>" + "<td>" + nombres[num] + "</td>" + "<td>" + num2 + "</td>" + "</tr>"); num = aleatorio.nextInt(10); num2 = num + 1; out.println("<tr>" + "<td>" + nombres[num] + "</td>" + "<td>" + num2 + "</td>" + "</tr>"); num = aleatorio.nextInt(10); num2 = num + 1; out.println("<tr>" + "<td>" + nombres[num] + "</td>" + "<td>" + num2 + "</td>" + "</tr>" + "</table>"); %> ¿Qué es lo que hace? Primero lo mismo que el pasado ejercicio solo que esta ves usamos el método out.println no solo para mostrar datos de java si no para mostrar el código de la tabla también. Taller Aplicaciones Web con JSP Ejercicio #2 (parámetros) Dante Mendoza Ruelas Manejar Datos de Formularios Introducción Si alguna vez has usado un motor de búsqueda Web, visitado un tienda de libros on-line, etc., probablemente habrás encontrado URLs de búsqueda divertidas como: http://host/path?user=Marty+Hall&origin=bwi&dest=lax. La parte posterior a la interrogación (user=Marty+Hall&origin=bwi&dest=lax) es conocida como datos de formulario, y es la forma más común de obtener datos desde una página Web para un programa del lado del servidor. Puede añadirse al final de la URL después de la interrogación (como arriba) para peticiones GET o enviada al servidor en una línea separada, para peticiones POST. Extraer la información necesaria desde estos datos de formulario es adicionalmente una de las partes más tediosas de la programación CGI Primero de todo, tenemos que leer los datos de una forma para las peticiones GET (en CGI tradicional, esto se hace mediante QUERY_STRING), y de otra forma para peticiones POST (normalmente leyendo la entrada estándard). Segundo, tenemos que separar las parejas de los ampersands, luego separar los nombres de los parámetros (a la izquierda de los signos igual) del valor del parámetro (a la derecha de los signos igual). Tercero, tenemos que decodificar los valores. Los valores alfanuméricos no cambian, pero los espacios son convertidos a signos más y otros caracteres se convierten como %XX donde XX es el valor ASCII (o ISO Latin-1) del carácter, en hexadecimal. Por ejemplo, si alguien introduce un valor de "~hall, ~gates, y ~mcnealy" en un campo de texto con el nombre "users" en un formulario HTML, los datos serían enviados como users=%7Ehall%2C+%7Egates%2C+and+%7Emcnealy". Finalmente, la cuarta razón que hace que el análisis de los datos de formulario sea tedioso es que los valores pueden ser omitidos (por ejemplo, param1=val1¶m2=¶m3=val3) y un parámetro puede tener más de un valor y que el mismo parámetro puede aparecer más de una vez (por ejemplo: param1=val1¶m2=val2¶m1=val3). Una de las mejores características de los servlets Java es que todos estos análisis de formularios son manejados automáticamente. Simplemente llamamos al método getParameter de HttpServletRequest, y suministramos el nombre del parámetro como un argumento. Observa que los nombres de parámetros son sensibles a la mayúsculas. Hacemos esto exactamente igual que cuando los datos son enviados mediante GET o como si los enviaramos mediante POST. El valor de retorno es un String correspondiente al valor uudecode de la primera ocurrencia del parámetro. Se devuelve un String vacío si el parámetro existe pero no tiene valor, y se devuelve null si no existe dicho parámetro. Si el parámetro pudiera tener más de un valor, como en el ejemplo anterior, deberíamos llamar a getParameterValues en vez de a getParameter. Este devuelve un array de strings. Finalmente, aunque en aplicaciones reales nuestras aplicaciones probablemente tengan un conjunto específico de Taller Aplicaciones Web con JSP Dante Mendoza Ruelas nombres de parámetros por los que buscar. Usamos getParameterNames para esto, que devuelve una Enumeration, cada entrada puede ser forzada a String y usada en una llamada a getParameter. Ejercicio 3: Vamos a ejemplificar más esto con otro ejemplo: Vamos a crear una nueva página. En vista de diseño ingresamos un formulario. Creamos tres campos te texto y los etiquetamos como nom, apell y nctrl. En action del formulario ponemos fresp.jsp. Creamos otra pagina llamada fresp.jsp. En el cuerpo ingresamos el siguiente codigo java embebido: <p>Holas: <% out.println(request.getParameter("nom")); %></p> <p>Tus Apellidos son: <% out.println(request.getParameter("Apell")); %></p> <p>tu numero de control es: <% out.println(request.getParameter("nctrl")); %> </p> Como puedes ver ahí código html combinado con código java la variable request puede obtener los parámetros enviados por un formulario previamente de distintas formas como ya habíamos hablado. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Ejercicio 4: Ahora vamos a ver un ejemplo un poco mas complicado: Primero creamos un formulario que tenga varias entradas y minimo una repetida: Insertamos dentro de la etiqueta body el siguiente codigo java: Import java.util.*; Enumeration paramNames = request.getParameterNames(); while(paramNames.hasMoreElements()) { String paramName = (String)paramNames.nextElement(); out.println(paramName); String[] paramValues = request.getParameterValues(paramName); if (paramValues.length == 1) { String paramValue = paramValues[0]; if (paramValue.length() == 0) out.print("sin valores"); else out.print(paramValue); } else { for(int i=0; i<paramValues.length; i++) { out.println(paramValues[i]); } } } Lo que hace primero guarda todos los parámetros en un enumerado. Luego va de uno en uno y checa si tiene varios valores o ninguno. Si tiene ninguno muestra sin valor. Si tiene varios los muestra. Y así se va con todos los parámetros. Además de los parámetros también se puede extraer información acerca del cliente que se conecta, cuando te conectas se le puede pedir información al navegador y alguna que es obligatoria, como puede ser el agente del navegador, host, etc. Una lista de cabeceras de html que se puede extraer del cliente: Accept Los tipos MIME que prefiere el navegador. Accept-Charset El conjunto de caracteres que espera el navegador. Accept-Encoding Los tipos de codificación de datos (como gzip) para que el navegador sepa como decoficarlos. Los servlets pueden chequear explícitamente el soporte para gzip y devolver páginas HTML comprimidas con gzip para navegadores que las soportan, seleccionando la cabecera de respuesta Content-Encoding para indicar que están comprimidas con gzip. En Taller Aplicaciones Web con JSP Dante Mendoza Ruelas muchos casos, esto puede reducir el tiempo de descarga por un factor de cinco o diez. Accept-Language El idioma que está esperando el navegador, en el caso de que el servidor tenga versiones en más de un idioma. Authorization Información de autorización, usualmente en respuesta a una cabecera WWW-Authenticate desde el servidor. Connection ¿Usamos conexiones persistentes? Sí un servlet obtiene un valor Keep-Alive aquí, u obtiene una línea de petición indicando HTTP 1.1 (donde las conexiones persistentes son por defecto), podría ser posible tomar ventaja de las conexiones persisentes, ahorrando un tiempo significante para las páginas Web que incluyen muchas piezas pequeñas (imágenes o clases de applets). Para hacer esto, necesita envíar una cabecera Content-Length en la respuesta, que es fácimente conseguido escribiendo en un ByteArrayOutputStream, y preguntando por el tamaño antes de escribir la salida. Content-Length (para mensajes POST, cúantos datos se han añadido) Cookie (una de las cabeceras más importantes, puedes ver la sección independiente de esta tutorial dedicada a los Cookies). From (dirección email del peticionarios; sólo usado por aceleradores Web, no por clientes personalizados ni por navegadores). Host (host y puerto escuchado en la URL original). If-Modified-Since (sólo devuelve documentos más nuevos que éste, de otra forma se envía una respuesta 304 "Not Modified" response). Pragma (el valor no-cache indica que el servidor debería devolver un documento nuevo, incluso si es un proxy con una copia local). Referer (la URL de la página que contiene el enlace que el usuario siguió para obtener la página actual). User-Agent (tipo de navegador, útil si el servlets está devolviendo contenido específico para un navegador). UA-Pixels, UA-Color, UA-OS, UA-CPU (cabeceras no estándard envíadas por algunas versiones de Internet Explorer, indicando el tamaño de la pantalla, la profundidad del color, el sistema operativo, y el tipo de CPU usada por el sistema del navegador). Para ver todos los detalles sobre las cabeceras HTTP, puedes ver las especificaciones en http://www.w3.org/Protocols/. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Ejercicio 5: Veamos un ejemplo de extracción de cabeceras de html del cliente: Creamos una nueva pagina En el cuerpo introducimos el siguiente codigo: <%@ page import="java.util.*" %> <% out.println("Request Method: " + request.getMethod()); out.println("Request URI: " + request.getRequestURI()); out.println("Request Protocol: " + request.getProtocol()); out.println("Lista de Cabezeras: "); Enumeration headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String headerName = (String)headerNames.nextElement(); out.println("<p>" + headerName + "</p>"); out.println("<p>" + request.getHeader(headerName) + "</p>"); } %> Lo que hace el codigo es extrae de uno en uno las principales cabeceras por sus nombres Luego con un ciclo extrae otras cabeceras Taller Aplicaciones Web con JSP Ejercicio 6: Dante Mendoza Ruelas Ahora que ya estamos familiarizados realicemos un ejemplo en el que pasemos parámetros pero a una pagina externa: Primero crea una pagina Ahora crea un formulario en el cual pida cadena a buscar, numero de resultados y que seleccione entre 4 buscadores: Google, Yahoo, Altavista y Ask.com El formulario se enviara a otra pagina: En la otra pagina pegamos este codigo: <% String url=""; String searchString = request.getParameter("buscar"); String numResults = request.getParameter("nresultados"); String searchEngine = request.getParameter("Buscador"); if (searchEngine.equals("1")) url="http://www.google.com/search?q=" + searchString + "&num=" + numResults; else if (searchEngine.equals("2")) url="http://search.yahoo.com/search?_adv_prop=web&va=" + searchString + "&n=" + numResults; else if (searchEngine.equals("3")) url="http://www.altavista.com/web/results?itag=ody&pg=aq&aqmode=s &aqa=" + searchString + "&nbq=" + numResults; else if (searchEngine.equals("4")) url="http://www.ask.com/web?q=" + searchString + "&qsrc=0&o=0&l=dir"; response.sendRedirect(response.encodeRedirectUrl(url)); %> Lo que hace, guarda los parametros y compara el parametro del buscador y dependiendo redirecciona a la pagina del buscador enviandole los parametros de cadena a buscar y numero de paginas. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas FORMAS DE SEGUIR LA TRAYECTORIA DE LOS USUARIOS (CLIENTES) Java te permite seguir la trayectoria de un cliente, es decir, obtener y mantener una determinada información acerca del cliente. De esta forma se puede tener identificado a un cliente (usuario que está utilizando un browser) durante un determinado tiempo. Por ejemplo: Un claro ejemplo de aplicación de esta técnica es el de los comercios vía Internet que permiten llevar un carrito de la compra en el que se van guardando aquellos productos solicitados por el cliente. Evitar el nombre de usuario y la password. Muchas grandes sites requieren registrarse para poder usar sus servicios, pero es un inconveniente recordar el nombre de usuario y la password. Los cookies son una buena alternativa para sites de baja seguridad. Cuando un usuario se registra, se envía una cookie con un único ID de usuario. Cuando el cliente se reconecta más tarde, se devuelve el ID de usuario, el servidor los busca, determina que pertenece a un usuario registrado, y no requiere explícitamente el nombre de usuario y la password. Personalizar una Site. Muchos "portales" nos permiten personalizar el aspecto de la página principal. Usan cookies para recordar lo que queremos, para que obtengamos el mismo resultado inicial la próxima vez. Publicidad enfocada. Los motores de búsqueda cobran más a sus clientes por mostrar anuncios "directos" que por anuncios "aleatorios". Es decir, si hacemos una búsqueda sobre "Java Servlets", un motor de búsqueda cobra más por un anuncio de un entorno de desarrollo de Servlets que por el de una agencia de viajes on-line. El problema es que tienen que enseñarnos un anuncio aleatorio la primera vez que llegamos y no hemos realizado la búsqueda, así como cuando buscamos algo que no corresponde con las caegorías de anuncios. Los cookies les permiten recordar "Oh, esta es la persona que buscó por esto y esto anteriormente" y muestra un anunció apropiado (lease "caro") en vez de uno aleatorio (lease "barato"). El mantener información sobre un cliente a lo largo de un proceso que implica múltiples conexiones se puede realizar de tres formas distintas: 1. Mediante cookies 2. Mediante seguimiento de sesiones (Session Tracking) 3. Mediante la reescritura de URLs Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Cookies: Los cookies son algo que se utiliza para que un servidor HTTP reconozca a un cliente como alguien que ya se había conectado anteriormente. El empleo de cookies requiere que el cliente sea capaz de soportarlas. Se requiere que este habilitada la opcion de cookies Cada cookie tiene un nombre que puede ser el mismo para varias cookies. Se almacenan en un directorio o fichero predeterminado en el disco duro del cliente. Puede mantenerse información acerca del cliente durante días. La información guardada no es indefinidamente, pues las cookies tienen una fecha de caducidad. Es posible incluir otros parámetros adicionales, tales como comentarios. Para enviar una cookie es preciso: 1. Crear un objeto Cookie 2. Establecer sus atributos 3. Enviar la cookie Por otra parte, para obtener información de una cookie, es necesario: 1. Recoger todas las cookies de la petición del cliente 2. Encontrar la cookie precisa 3. Obtener el valor recogido en la misma Taller Aplicaciones Web con JSP Ejercicio 7 Crear un objeto Cookie Dante Mendoza Ruelas El constructor de los cookies recibe dos argumentos del tipo string: el identificador y el valor. Veamos un ejemplo: Crear tres paginas. Una con un formulario preguntando dos cosas: color y nombre. Otra en la que guarde el cookie. Otra en la que lea el cookie. Cookie1: Para la pagina uno, simplemente mandar de parámetros el codigo del color que se selecciona dar como opcion dos colores minimos y que escriba algun dato extra Cookie2: Para la cookie2 leer parámetros y guardarlos: <% String nombre = request.getParameter("nom"); String color = request.getParameter("color"); Cookie dato1 = new Cookie("nom",nombre); Cookie dato2 = new Cookie("col",color); response.addCookie(dato1); response.addCookie(dato2); %> Cookie3: Para la cookie3 leer cookie y mostrar información al igual que cambiar el fondo de la pagina por el color seleccionado anteriormente. <style type="text/css"> <!-body { background-color: <% String color= ""; Cookie[] acookies = request.getCookies(); for (int i=0; i< acookies.length; i++) { Cookie aux = acookies[i]; if (aux.getName().equals("col")) color=aux.getValue(); } out.println(color); %>; } --> </style> Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Establecer los atributos de la cookie La clase Cookie proporciona varios métodos para establecer los valores de una cookie y sus atributos. Entre otros: Todos estos métodos tienen sus métodos getX() correspondientes incluidos en la misma clase. Sessions: Una sesión es una conexión continuada de un mismo browser a un servidor durante un tiempo prefijado. Este tiempo depende habitualmente del servidor o se puede establecer manualmente. Una sesion es lo mismo que una cookie solamente que la session se encuentra en el lado del servidor, y trabaja igual que las cookies, se diferencian por identificadores, igual tienen un limite de tiempo y pueden guardar cualquier tipo de objetos. La forma de obtener una sesión es mediante el método getSession(boolean) de un objeto HttpServletRequest. Si este boolean es true, se crea una sesión nueva si es necesario mientras que si es false, el método devolverá la sesión actual. Por ejemplo: Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Ejercicio : Vamos a crear una pagina en la cual pidamos datos como nombre, identificación y alguna clave. A continuación creamos otra pagina en la cual leeremos esos datos crearemos una sesion en otra pagina con los datos recogidos. <% String nom = request.getParameter("nom"); String ide = request.getParameter("id"); String clave = request.getParameter("clve"); HttpSession misesion = request.getSession(true); misesion.putValue("nombre",nom); misesion.putValue("identificador",ide); misesion.putValue("pass",clave); %> Lo que hace es primero lee los datos y los guarda en variables Luego crea un objeto de tipo sesion Luego se agrega los datos con algun nombre para identificarlos Ejercicio : Ahora vamos a hacer una pagina en la cual lea los datos de la sesion para verificar que realmente se creo la sesion. <% HttpSession misesion = request.getSession(true); out.println(misesion.getValue("nombre")); %> </b> <p>Tu identificacion es: <b><% out.println(misesion.getValue("identificador")); %></b></p> <p>Tu clave es: <b><% out.println(misesion.getValue("pass")); %></b></p> Taller Aplicaciones Web con JSP ¿Que es lo que se hizo? Se creo un objeto del tipo sesion Se leyo de uno en uno los valores Dante Mendoza Ruelas En la mayoría de los casos, tenemos un nombre atributo específico en mente, y queremos encontrar el valor (si existe) ya asociado con él. Sin embargo, también podemos descubrir todos los nombres de atributos en una sesión dada llamando a getValueNames, que devuelve un array de String o getAttributeNames, y devuelve una Enumeration. getId. Este método devuelve un identificador único generado para cada sesión. Algunas veces es usado como el nombre clave cuando hay un sólo valor asociado con una sesión, o cuando se uso la información de logging en sesiones anteriores. isNew. Esto devuelve true si el cliente (navegador) nunca ha visto la sesión, normalmente porque acaba de ser creada en vez de empezar una referencia a un petición de cliente entrante. Devuelve false para sesión preexistentes. getCreationTime. Devuelve la hora, en milisegundos desde 1970, en la que se creo la sesión. Para obtener un valor útil para impresión, pasamos el valor al constructor de Date o al método setTimeInMillis de GregorianCalendar. getLastAccessedTime. Esto devuelve la hora, en milisegundos desde 1970, en que la sesión fue enviada por última vez al cliente. getMaxInactiveInterval. Devuelve la cantidad de tiempo, en segundos, que la sesión debería seguir sin accesos antes de ser invalidada automáticamente. Un valor negativo indica que la sesión nunca se debe desactivar. Ejercicio: Vamos a probar la lectura de estados de una sesion. Crearemos una pagina en la cual mostraremos todos los estados de la sesion al igual que una lista de atributos. <body> <p>Hola seas Bienvenido!!!!</p> <p>que bueno que estas de vuelta.... </p> <p>Aqui ahi unos datos de tu sesion:</p> <%@ page import="java.util.*" %> <% HttpSession misesion = request.getSession(true); %> <table width="200" border="1"> <tr> <td>Tipo de Información </td> Taller Aplicaciones Web con JSP Dante Mendoza Ruelas <td>Valor</td> </tr> <tr> <td>Identificador:</td> <td><% out.println(misesion.getId()); %> </td> </tr> <tr> <td>¿Es nueva? </td> <td><% out.println(misesion.isNew()); %> </td> </tr> <tr> <td>Tiempo de creación </td> <td><% out.println(new java.util.Date(misesion.getCreationTime())); %></td> </tr> <tr> <td>Ultimo acceso </td> <td><%out.println(new java.util.Date(misesion.getLastAccessedTime())); %></td> </tr> <tr> <td>Intervalo Maximo de Inactividad </td> <td><% out.println(misesion.getMaxInactiveInterval()); %> </td> </tr> </table> <p>Datos Guardados: </p> <table width="200" border="1"> <tr> <td>Nombre</td> <td>Contenido</td> </tr> <%Enumeration lista = misesion.getAttributeNames(); while(lista.hasMoreElements()) { String valor = (String)lista.nextElement(); out.println("<tr>"); out.println("<td>" + valor + "</td>" + "<td>" + misesion.getValue(valor) + "</td>" + "</tr>"); } %> </table> ¿Que es lo que se hace? Primero se declaran las clases a usar. Despues se obtiene una sesion. Se obtiene información de la sesion. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Se crea un objeto de tipo enumerado con los valores de la sesion. Se lee de uno en uno. Variables de Tiempo Manejo de fechas en java Los Milisegundos Trabajar con fechas en java no es algo del otro mundo ni tiene demasiadas complicaciones, pero la cantidad de formas que hay para hacerlo puede confundirnos, o peor aún, puede que sólo conozcamos la más mala para hacerlo. Las clases java.util.Date y java.sql.Date. Son dos de las clases más usadas cuando una aplicación implica el trabajo con fechas: java.util.Date: Representa un instante de tiempo específico, con precisión de milisegundos. Antes del jdk1.1 la clase java.util.Date tenía dos funciones. Una era la interpretación de datos que tenían que ver con fechas, como años, días, segundos, entre otros. La otra era el formateo (la forma como se muestra) y parseo (convertir un String a java.util.Date). Pero debido a las dificultades que presentaban estas funcionalidades a la hora de internacionalizar los programas, esos métodos ya está obsoletos y la clase java.util.Calendar se encargó de esto. Así que en este momento esta clase, sólo hace lo que se mencionó al principio. El año "y" está representado por un entero igual a ("y" - 1900). Por ejemplo el año 2004 se representa como 104 (2004 - 1900). Los meses son representados por números entre 0 y 11, donde enero es 0 y diciembre es 11. Los días y minutos se representan de forma corriente. Entre 1 - 31 y 0 59 respectivamente. Las horas van entre 0 y 23, donde la medianoche es 0 y el medio día 12. Los segundos van entre 0 y 61. 61 solo ocurre cuando se agrega el segundo adicional para ajustar la diferencia entre el reloj atómico y el tiempo de rotación de la tierra. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas java.sql.Date: Esta clase hereda de java.util.Date y es la representación de la fecha cuando trabajamos con JDBC. son los campos almacenados en una base de datos cuyo tipo es una fecha que puede o no incluir la hora, aunque la clase java.sql.Date siempre lo hace. Al igual que su clase padre, tiene una precisión de milisegundos, con la excepción que al mostrarla en la salida estándar con el formato por defecto solo muestra el día, mes y año. Hay que anotar también que para campos que almacenen solamente horas existen otras clases para manejarlos. En resumen ambas clases, sólo se encargan de almacenar la cantidad de milisegundos que han pasado desde las 12 de la noche del primero de enero de 1970 en el meridiano de Greenwich. Aquí vienen dos puntos importantes: a) Si la fecha que almacena cualquiera de las clases es menor a las 00:00:00 enero 1 de 1970 GMT, su valor el milisegundos será negativo. b) La fecha es susceptible a la zona horaria. Por ejemplo en Colombia los milisegundos no se empiezan a contar desde enero 1 de 1970, sino a partir de las 19:00 de diciembre 31 de 1969. Ambas clases se pueden instanciar directamente mediante new(), pero la clase java.sql.Date necesita un parámetro en el constructor: el tiempo en milisegundos, así que las siguientes instrucciones son válidas: java.util.Date fechaActual = new java.util.Date(); //Fecha actual del sistema java.sql.Date inicioLocal = new java.sql.Date(0); //Milisegundo cero //también se puede crear una instancia de java.util.Date con parámetros //iniciales java.util.Date otraFecha = new java.util.Date(1000); //El primer segundo a partir del inicio Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Se puede pasar de java.sql.Date a java.util.Date de dos formas, una de ellas es con una asignación simple: java.util.Date utilDate = null; java.sql.Date sqlDate = new java.sql.Date(0); utilDate = sqlDate; /* aunque es java.util.Date, si la imprimes tendrá el formato de java.sql.Date, recordemos que java.sql.Date hereda de java.util.Date */ System.out.println(utilDate); También se pueden tomar los milisegundos de java.sql.Date y pasarlos al constructor de java.util.Date: java.util.Date utilDate = null; java.sql.Date sqlDate = new java.sql.Date(0); utilDate = new java.util.Date(sqlDate.getTime()); //esta vez se mostrará con el formato de java.util.Date System.out.println(utilDate); Para pasar de java.util.Date a java.sql.Date se deben tomar los milisegundos de la primera y pasarlos al constructor de la segunda: java.util.Date utilDate = new java.util.Date(); java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime()); //Con formato de java.sql.Date System.out.println(sqlDate); Para comparar fechas usamos el método compareTo() que internamente compara los milisegundos entre ellas usando directamente los métodos getTime() de ambas clases. java.util.Date utilDate = new java.util.Date(); java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime()); if (utilDate.compareTo(sqlDate) == 0){ System.out.println("IGUALES"); }else{ System.out.println("DIFERENTES"); } Taller Aplicaciones Web con JSP O lo que es equivalente: Dante Mendoza Ruelas java.util.Date utilDate = new java.util.Date(); java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime()); if (utilDate.getTime() == sqlDate.getTime()){ System.out.println("IGUALES"); }else{ System.out.println("DIFERENTES"); } Las clases Time y Timestamp Al igual que java.sql.Date, son hijas (heredan) de java.util.Date, es decir, su núcleo son los milisegundos. La clase Time es un envoltorio de la clase java.util.Date para representar los datos que consisten de horas, minutos, segundos y milisegundos, mientras Timestamp representa estos mísmos datos más un atributo con nanosegundos, de acuerdo a las especificaciones del lenguaje SQL para campos de tipo TIMESTAMP. Como ambas clases heredan del java.util.Date, es muy fácil pasar de un tipo de dato a otro; tanto Time como Timestamp se pueden instanciar directamente y su constructor tiene como parámetro el número de milisegundos; La clase Time sólamente muestra la hora, minutos y segundo, mientras timestamp agrega fracciones de segundo a la cadena. Para convertir entre tipos de datos diferentes debemos usar los milisegundos de una clase y asignarlos a las instancias de las otras. Note que aún cuando todos los objetos tienen los mismos milisegundos el formato con el que se muestran dependen de la clase que realmente los contiene. Si creamos nuevas instancias con los milisegundos los formatos con que se muestran son los mismos. Formateo de Fechas: Para formatear fechas existen infinidad de formas pero una de las mas sencillas es con la clase SimpleDateFormat : SimpleDateFormat miformato = new SimpleDateFormat("dd/MM/yy"); out.println(miformato.format(utilfecha)); Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Ejercicio: Vamos a englobar todo lo de tiempo en un solo ejercicio: <p>La fecha actual es:<% java.util.Date fechaActual = new java.util.Date(); //Fecha actual del sistema java.sql.Date inicioLocal = new java.sql.Date(0); //Milisegundo cero //también se puede crear una instancia de java.util.Date con parámetros iniciales java.util.Date otraFecha = new java.util.Date(1000); //El primer segundo a partir del inicio out.println(fechaActual); %></p> <p>La fecha inicial de SqlDate: <% out.println(inicioLocal);%></p> <p>La fecha inicial mas 1000 segundos: <% out.println(otraFecha);%></p> <p>Comparacion de dos fechas:<% java.util.Date utilfecha = new java.util.Date(); java.sql.Date sqlfecha = new java.sql.Date(utilfecha.getTime()); if (utilfecha.compareTo(sqlfecha) == 0){ out.println("IGUALES"); }else{ out.println("DIFERENTES"); } utilfecha = new java.util.Date(); //fecha actual long lnMilisegundos = utilfecha.getTime(); sqlfecha = new java.sql.Date(lnMilisegundos); java.sql.Time sqltiempo = new java.sql.Time(lnMilisegundos); java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(lnMilisegundos); out.println("<p>util.Date: "+utilfecha + "</p>"); out.println("<p>sql.Date: "+sqlfecha + "</p>"); out.println("<p>sql.Time: "+sqltiempo + "</p>"); out.println("<p>sql.Timestamp: "+sqlTimestamp + "</p>"); utilfecha = sqltiempo; out.println("<p>util.Date apuntando a sql.Time: ["+sqltiempo+"]" + "</p>"); utilfecha = sqlTimestamp; out.println("util.Date apuntando a sql.Timestamp: ["+sqlTimestamp+"]" + "</p>"); utilfecha = new java.util.Date(sqltiempo.getTime()); out.println("<p>util.Date con milisegundos de sql.Time: ["+utilfecha+"]</p>"); utilfecha = new java.util.Date(sqlTimestamp.getTime()); out.println("<p>util.Date con milisegundos de sql.Timestamp: ["+utilfecha+"]</p>"); SimpleDateFormat miformato = new SimpleDateFormat("dd/MM/yy"); out.println(miformato.format(utilfecha)); %> Taller Aplicaciones Web con JSP Dante Mendoza Ruelas JDBC: La API JBDC es una interfaz de acceso a RDBMS(Relational Database Management System) independiente de la plataforma y del gestor de bases de datos utilizado.Se relaciona muy a menudo con el acronimo ODBC por lo que se suele expresar como Java Database Connectivity pero oficialmente,según javasoft,JDBC no significa nada ni es acronimo de nada. El API consiste en una serie de interfaces Java implementadas por un controlador.Este programa de gestión se encarga de la traducción a las llamadas estandar que requiere la base de datos compatible con el.De esta manera el programador puede abstraerse de la programación especifica de la base de datos creando codigo que funcionará para todas los RDBMS que cuenten con un driver JDBC con solo cambiar tal driver. En la actualidad se encuentran drivers JDBC para todos los sistemas de gestión de bases de datos mas populares(e incluso podriamos decir existentes) como Informix,Oracle,SQLServer, DB2,InterBase, SyBase... y otros productos de indole no comercial como mSql,mySql y PostGress,etc,. Aun asi existe un tipo especial de drivers denominados puentes JDBCODBC que traducen las llamadas en JDBC a llamadas en el estandar de comunicación con bases de datos desarrollado por Microsoft ODBC por lo que en ultimo termino siempre se podrá utilizar uno de estos drivers ya que la totalidad de los sistemas de gestión de bases de datos cuentan con un driver de este ultimo tipo.Esto nos lleva a la clasificación de los distintos drivers que cumplen la especificación JDBC. Tipos de drivers JDBC A continuación se señalan y describen los cuatro tipos distintos de drivers JDBC existentes: Nivel 1: Puente JDBC:ODBC. Esta categoría de controladores se remite al controlador de puente JDBC-ODBC original. Este ultimo utiliza el controlador ODBC de Microsoft para comunicarse con los servidores de base de datos.Se implementa tanto en codigo binario como en Java y debe ser instalado previamente en la computadora cliente antes de poder usarlo. Nivel 2: Controlador JDBC de protocolo nativo en Java y binario. Esta categoría esta compuesta por controladores que hablan con los servidores de bases de datos en el protocolo nativo de la base de datos.Se implementan como una combinación de codigo binario y Java y deben ser instalados en el cliente antes de poder ser usados. Nivel 3:Controlador JDBC de protocolo no nativo en Java puro. Esta categoría esta formada por controladores de Java puro( no hay codigo binario) que hablan un protocolo de red estandar(como http) con un servidor de acceso a bases de datos.Este servidor traduce el protocolo de red a uno de base de datos específicos de la marca.No necesita instalación en cliente. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Nivel 4: Controlador JDBC de protocolo nativo en Java puro Está formada por controladores de Java puro que hablan el protocolo de la base de datos específico de la marca del servidor de bases de datos que se haya designado para servir de interfaz. No necesita instalación en cliente. Como se observa la clasificación de los niveles de controladores JDBC se hace en función de que hablen el protocolo nativo de la base de datos y de que se encuentren implementados en Java puro o parcialmente estén escritos en código binario dependiente de la plataforma. Con respecto a lo primero la eliminación de las capas de traducción en el caso de que la llamada del driver no sea nativa pueden degradar el rendimiento pero hay ocasiones en que no hay otra opción. Por otra parte el hecho de que el driver esté escrito en Java puro consigue, aparte de independencia de la plataforma de ejecución, que no sea necesaria instalación ni configuración(como el caso del DSN del ODBC) en el cliente lo que facilita la gestión y siendo la única solución en casos en que el cliente sea un applet. Si encontramos los 4 niveles de drivers el más adecuado en el 95% de las ocasiones será el de nivel 4. Configuración del Driver: En nuestros ejemplos usaremos un driver del tipo fuente, debido a la comodidad, de cierta forma “generico” y que todos si no es que la mayoria tenemos ODBC. Primero daremos de alta el ODBC de nuestra base de datos, en este caso SQL. Ahí que tener mucho cuidado en seleccionar un ODBC de tipo System DSN y no USER. Una vez dado de alta para configurar el driver no tenemos que hacer nada ya viene incluido en el servidor y solo basta con mandarlo a hablar. Establecer una Conexión Lo primero que tenemos que hacer es establecer una conexión con el controlador de base de datos que queremos utilizar. Esto implica dos pasos: (1) cargar el driver y (2) hacer la conexión. Taller Aplicaciones Web con JSP Cargar los Drivers Dante Mendoza Ruelas Cargar el driver o drivers que queremos utilizar es muy sencillo y sólo implica una línea de código. En nuestro caso por ejemplo, queremos utilizar el puente JDBC-ODBC, se cargaría la siguiente línea de código. Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); La documentación del driver nos dará el nombre de la clase a utilizar. Por ejemplo, si el nombre de la clase es jdbc.DriverXYZ, cargaríamos el driver con esta línea de código. Class.forName("jdbc.DriverXYZ"); No necesitamos crear un ejemplar de un driver y registrarlo con el DriverManager porque la llamada a Class.forName lo hace automáticamente. Si hubiéramos creado nuestro propio ejemplar, creariamos un duplicado innecesario, pero no pasaría nada. Una vez cargado el driver, es posible hacer una conexión con un controlador de base de datos. Hacer la Conexión El segundo paso para establecer una conexión es tener el driver apropiado conectado al controlador de base de datos. La siguiente línea de código ilustra la idea general. Connection con = DriverManager.getConnection(url, "myLogin", "myPassword"); Este paso también es sencillo, lo “difícil” es saber qué suministrar para url. Si estamos utilizando el puente JDBC-ODBC, el JDBC URL empezará con jdbc:odbc:. el resto de la URL normalmente es la fuente de nuestros datos o el sistema de base de datos. Por eso, si estamos utilizando ODBC para acceder a una fuente de datos ODBC llamada "Dante," por ejemplo, nuestro URL podría ser jdbc:odbc:Dante. En lugar de "myLogin" pondríamos el nombre utilizado para entrar en el controlador de la base de datos; en lugar de "myPassword" pondríamos nuestra password para el controlador de la base de datos. Por eso si entramos en el controlador con el nombre "DaN" y la password de "fuga" estas dos líneas de código estableceran una conexión. String url = "jdbc:odbc:Dante"; Connection con = DriverManager.getConnection(url, "DaN", "fuga"); Si estamos utilizando un puente JDBC desarrollado por una tercera parte, la documentación nos dirá el subprotocolo a utilizar, es decir, qué poner despues Taller Aplicaciones Web con JSP Dante Mendoza Ruelas de jdbc: en la URL. Por ejemplo, si el desarrollador ha registrado el nombre "acme" como el subprotocolo, la primera y segunda parte de la URL de JDBC serán jdbc:acme:. La documentación del driver también nos dará las guías para el resto de la URL del JDBC. Esta última parte de la URL suministra información para la identificación de los datos fuente. Si uno de los drivers que hemos cargado reconoce la URL suministada por el método DriverManager.getConnection, dicho driver establecerá una conexión con el controlador de base de datos especificado en la URL del JDBC. La clase DriverManager, como su nombre indica, maneja todos los detalles del establecimiento de la conexión detrás de la escena. A menos que estemos escribiendo un driver, posiblemente nunca utilizaremos ningún método del interface Driver, y el único método de DriverManager que realmente necesitaremos conocer es DriverManager.getConnection. La conexión devuelta por el método DriverManager.getConnection es una conexión abierta que se puede utilizar para crear sentencias JDBC que pasen nuestras sentencias SQL al controlador de la base de datos. En el ejemplo anterior, con es una conexión abierta, y se utilizará en los ejemplos posteriores. Seleccionar una Tabla Primero, crearemos una de las tablas de nuestro ejemplo. Esta tabla, ALUMNOS, contiene la información esencial sobre los alumnos inscritos en el taller de java "Aplicaciones Orientadas a Web con JSP", incluyendo los nombres, sus apellidos, sus numeros de control, su semestre en el que cursan y el sexo. Aquí puedes ver la tabla ALUMNOS, que describiremos más adelante. alum_nom Sex apell no_ctrl c_id Laura F xx 03130307 1 Esperanza F 8.99 324 2 Vicky F 9.99 0435 03 Lala M 8.99 0435 4 Fuga Fuga 49 9.99 0546 5 La columna que almacena el nombre del alumno es alum_nom, y contiene valores con el tipo VARCHAR de SQL y una longitud máxima de 15 caracteres. La segunda columna, llamada sex, contiene un carácter indicando el sexo de la persona; este carácter será un tipo CHAR de SQL. La tercera columna, llamada apell, almacena valores del tipo VARCHAR de longitud de 30. La columna llamada noctrl almacena valores del tipo INTEGER de SQL e indica el número Taller Aplicaciones Web con JSP Dante Mendoza Ruelas de control del alumno; El número de control servirá de clave primaria.. La columna final, c_id, contiene obviamente la carrera de tipo INTEGER de SQL. MATERIAS, la segunda tabla de nuestra base de datos, tiene información sobre cada materia. mat_id Mat_nom mat_sem c_id m_cred A100 Base de Datos II 3 1 10 A101 Programación III 4 2 10 A102 Simulación 3 10 5 La siguiente sentencia SQL crea la tabla ALUMNOS. CREATE TABLE ALUMNOS (alum_nom VARCHAR(15), sex CHAR(1), apell VARCHAR(30), no_ctrl INT, c_id INT) Este código no termina con un terminador de sentencia de un controlador de base de datos, que puede variar de un controlador a otro. Por ejemplo, Oracle utiliza un punto y coma (;) para finalizar una sentencia, y Sybase utiliza la plabra go. El driver que estamos utilizado proporcionará automáticamente el terminador de sentencia apropiado, y no necesitaremos introducirlo en nuestro código JDBC. Otra cosa que debíamos apuntar sobre las sentencias SQL es su forma. En la sentencia CREATE TABLE, las palabras clave se han imprimido en letras máyusculas, y cada ítem en una línea separada. SQL no requiere nada de esto, estas convenciones son sólo para una fácil lectura. El estándard SQL dice que la palabras claves no son sensibles a las mayúsculas, así, por ejemplo, la anterior sentencia SELECT pude escribirse de varias formas. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Hasta ahora hemos escrito la sentencia SQL que crea la tabla ALUMNOS. Ahora le pondremos comillas (crearemos un string) y asignaremos el string a la variable createTableAlumnos. Como hemos visto, al controlador de base de datos no le importa si las líneas están divididas, pero en el lenguaje Java, un objeto String que se extienda más allá de una línea no será compilado. Consecuentemente, cuando estamos entregando cadenas, necesitamos encerrar cada línea entre comillas y utilizar el signo más (+) para concatenarlas. String createTableAlumnos = "CREATE TABLE ALUMNOS " + "( alum_nom VARCHAR(15),sex CHAR(1),apell VARCHAR(30),” + “no_ctrl INT, c_id INT )"; Crear sentencias JDBC Un objeto Statement es el que envía nuestras sentencias SQL al controlador de la base de datos. Simplemente creamos un objeto Statement y lo ejecutamos, suministando el método SQL apropiado con la sentencia SQL que queremos enviar. Para una sentencia SELECT, el método a ejecutar es executeQuery. Para sentencias que crean o modifican tablas, el método a utilizar es executeUpdate. Se toma un ejemplar de una conexión activa para crear un objeto Statement. En el siguiente ejemplo, utilizamos nuestro objeto Connection: con para crear el objeto Statement: stmt. Statement stmt = con.createStatement(); En este momento stmt existe, pero no tiene ninguna sentencia SQL que pasarle al controlador de la base de datos. Necesitamos suministrarle el metodo que utilizaremos para ejecutar stmt. Por ejemplo, en el siguiente fragmento de código, suministramos executeUpdate con la sentencia SQL del ejemplo anterior. stmt.executeUpdate("CREATE TABLE ALUMNOS " + "( alum_nom VARCHAR(15),sex CHAR(1),apell VARCHAR(30),” + “no_ctrl INT, c_id INT )"; Al igual podemos crear un String y pasarlo como parametro. String insert = “stmt.executeUpdate(createTableAlumnos); Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Ejecutar Sentencias Utilizamos el método executeUpdate porque la sentencia SQL contenida en createTableAlumnos es una sentencia DDL (data definition language). Las sentencias que crean, modifican o eliminan tablas son todas ejemplos de sentencias DDL y se ejecutan con el método executeUpdate. Cómo se podría esperar de su nombre, el método executeUpdate también se utiliza para ejecutar sentencias SQL que actualizan un tabla. El método más utilizado para ejecutar sentencias SQL es executeQuery. Este método se utiliza para ejecutar sentencias SELECT, que comprenden la amplia mayoría de las sentencias SQL. Ejercicio: Vamos a crear una nueva tabla en la base de datos pubs Creamos una pagina nueva con un formulario preguntando el nombre de la base de la tabla. En otra pagina leemos el parámetro y creamos la tabla. <% String usuario = request.getParameter("user"); String clave = request.getParameter("pass"); String nom = request.getParameter("nombre"); String url = "jdbc:odbc:dbtaller"; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection con = DriverManager.getConnection(url, usuario, clave); String createTableAlumnos = "CREATE TABLE ALUMNOS " + "(alum_nom VARCHAR(15),sex CHAR(1),apell VARCHAR(30)," + "no_ctrl INT, c_id INT )"; Statement stmt = con.createStatement(); stmt.executeUpdate(createTableAlumnos); %> Felicidades tu tabla ha sido creada!!! ¿Que se esta haciendo? Pues lo mismo que se había explicado anteriormente Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Introducir Datos en una Tabla Ahora introduciremos datos en nuestra tabla una fila cada vez, suministrando la información a almacenar en cada columna de la fila. Statement stmt = con.createStatement(); stmt.executeUpdate( "INSERT INTO ALUMNOS " + "VALUES ('Dante', 'm', 'Mendoza Ruelas', '03130307', '1')"); El siguiente código inserta una segunda línea dentro de la tabla COFFEES. Observa que hemos reutilizado el objeto Statement: stmt en vez de tener que crear uno nuevo para cada ejecución. Ejercicio : Vamos a insertar a nuestra tabla datos de la siguiente manera: Cremamos una pagina en la cual reciba los datos y otra en que los guarde en la base de datos. Asi se veria la segunda: <% String d1 = request.getParameter("nom"); String d2 = request.getParameter("apell"); String d3 = request.getParameter("sexo"); String d4 = request.getParameter("ncontrol"); String d5 = request.getParameter("carrera"); String usuario = "DaN"; String clave = "perfidia"; String url = "jdbc:odbc:dbtaller"; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection con = DriverManager.getConnection(url, usuario, clave); Statement stmt = con.createStatement(); stmt.executeUpdate("insert into ALUMNOS values ('" + d1 + "','" + d3 + "','" + d2 + "','" + d4 + "','" + d5 + "')"); %> <p>Se han insertado los siguientes datos: </p> <p>Nombre: <% out.println(d1); %></p> <p>Apellidos: <% out.println(d2); %></p> <p>Sexo: <% out.println(d3); %></p> <p>Numero de control: <% out.println(d4); %></p> <p>Carrera: <% out.println(d5); %></p> Taller Aplicaciones Web con JSP Obtener Datos desde una Tabla Dante Mendoza Ruelas JDBC devuelve los resultados en un objeto ResultSet, por eso necesitamos declarar un ejemplar de la clase ResultSet para contener los resultados. El siguiente código presenta el objeto ResultSet: rs y le asigna el resultado de una consulta anterior. ResultSet rs = stmt.executeQuery("SELECT alum_nom, apell FROM ALUMNOS"); Utilizar el Método next La variable rs, que es un ejemplar de ResultSet, contiene las filas de alumnos y sus apellidos mostrados en el juego de resultados de la página anterior. Para acceder a los nombres y apellidos, iremos a la fila y recuperaremos los valores de acuerdo con sus tipos. El método next mueve el cursor a la siguiente fila y hace que esa fila (llamada fila actual) sea con la que podamos operar. Como el cursor inicialmente se posiciona justo encima de la primera fila de un objeto ResultSet, primero debemos llamar al método next para mover el cursor a la primera fila y convertirla en la fila actual. Sucesivas invocaciones del método next moverán el cursor de línea en línea de arriba a abajo. Utilizar los métodos getXXX Los métodos getXXX del tipo apropiado se utilizan para recuperar el valor de cada columna. Por ejemplo, la primera columna de cada fila de rs es ALUM_NOM, que almacena un valor del tipo VARCHAR de SQL. El método para recuperar un valor VARCHAR es getString. JDBC ofrece dos formas para identificar la columna de la que un método getXXX obtiene un valor. Una forma es dar el nombre de la columna, como se ha hecho arriba. La segunda forma es dar el índice de la columna (el número de columna), con un 1 significando la primera columna, un 2 para la segunda, etc. Métodos para Recuperar Tipos SQL muestra qué métodos pueden utilizarse legalmente para recuperar tipos SQL, y más importante, qué métodos están recomendados para recuperar los distintos tipos SQL. Observa que esta tabla utiliza el término "JDBC type" en lugar de "SQL type." Ambos términos se refieren a los tipos genéricos de SQL definidos en java.sql.Types, y ambos son intercambiables. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Utilizar los métodos de ResultSet.getXXX para Recuperar tipos JDBC Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Una "x" indica que el método getXXX se puede utilizar legalmente para recuperar el tipo JDBC dado. Una "X" indica que el método getXXX está recomendado para recuperar el tipo JDBC dado. Ejercicio: Vamos a hacer una consulta de la base de datos: <p>Se han leido los siguientes datos: </p> <% String usuario = "DaN"; String clave = "perfidia"; String url = "jdbc:odbc:dbtaller"; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection con = DriverManager.getConnection(url, usuario, clave); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("select * from ALUMNOS"); while (rs.next()) { String d1 = rs.getString("alum_nom"); String d3 = rs.getString("sex"); String d2 = rs.getString("apell"); String d4 = rs.getString("no_ctrl"); String d5 = rs.getString("c_id"); out.println("<p>Nombre: " + d1 + "</p>"); out.println("<p>Apellidos: " + d2 + "</p>"); out.println("<p>Sexo: " + d3 + "</p>"); out.println("<p>Numero de control: " + d4 + "</p>"); out.println("<p>Carrera: " + d5 + "</p>"); } %> Taller Aplicaciones Web con JSP Utilizar Sentencias Preparadas Dante Mendoza Ruelas Algunas veces es más conveniente o eficiente utilizar objetos PreparedStatement para enviar sentencias SQL a la base de datos. Este tipo especial de sentencias se deriva de una clase más general, Statement, que ya conocemos. Cuándo utilizar un Objeto PreparedStatement Si queremos ejecutar muchas veces un objeto Statement, reduciremos el tiempo de ejecución si utilizamos un objeto PreparedStatement, en su lugar. La característica principal de un objeto PreparedStatement es que, al contrario que un objeto Statement, se le entrega una sentencia SQL cuando se crea. La ventaja de esto es que en la mayoría de los casos, esta sentencia SQL se enviará al controlador de la base de datos inmediatamente, donde será compilado. Como resultado, el objeto PreparedStatement no sólo contiene una sentencia SQL, sino una sentencia SQL que ha sido precompilada. Esto significa que cuando se ejecuta la PreparedStatement, el controlador de base de datos puede ejecutarla sin tener que compilarla primero. Aunque los objetos PreparedStatement se pueden utilizar con sentencias SQL sin parámetros, probablemente nosotros utilizaremos más frecuentemente sentencias con parámetros. La ventaja de utilizar sentencias SQL que utilizan parámetros es que podemos utilizar la misma sentencia y suministrar distintos valores cada vez que la ejecutemos. Crear un Objeto PreparedStatement Al igual que los objetos Statement, creamos un objeto PreparedStatement con un objeto Connection. Utilizando nuestra conexión con abierta en ejemplos anteriores, podríamos escribir lo siguiente para crear un objeto PreparedStatement que tome dos parámetros de entrada. PreparedStatement actualizar = con.prepareStatement( "UPDATE ALUMNOS SET c_id = ? WHERE no_ctrl LIKE ?"); Suministrar Valores para los Parámetros de un PreparedStatement Necesitamos suministrar los valores que se utilizarán en los lugares donde están las marcas de interrogación, si hay alguno, antes de ejecutar un objeto PreparedStatement. Podemos hacer esto llamado a uno de los métodos setXXX definidos en la clase PreparedStatement. Si el valor que queremos sustituir por una marca de interrogación es un int de Java, podemos llamar al método setInt. Si el valor que queremos sustituir es un String de Java, podemos llamar Taller Aplicaciones Web con JSP Dante Mendoza Ruelas al método setString, etc. En general, hay un método setXXX para cada tipo Java. Utilizando el objeto actualizar del ejemplo anterior, la siguiente línea de código selecciona la primera marca de interrogación para un int de Java, con un valor de 5. actualizar.setInt(1, 5); Cómo podríamos asumir a partir de este ejemplo, el primer argumento de un método setXXX indica la marca de interrogación que queremos seleccionar, y el segundo argumento el valor que queremos ponerle. El siguiente ejemplo selecciona la segunda marca de interrogación con el int "03130307". updateSales.setInt(2, 03130307); Valores de retorno del método executeUpdate Siempre que executeQuery devuelve un objeto ResultSet que contiene los resultados de una petición al controlador de la base datos, el valor devuelto por executeUpdate es un int que indica cuántas líneas de la tabla fueron actualizadas. Si realizo una creación de una tabla devuelve un 0 o si realizo una consulta un numero dependiendo de los resultados encontrados. Ejercicio: Hagamos una pagina en la cual actualizemos datos de la tabla ALUMNOS usando una sentencia previamente preparada. <% String usuario = "DaN"; String clave = "perfidia"; String url = "jdbc:odbc:dbtaller"; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection con = DriverManager.getConnection(url, usuario, clave); PreparedStatement actualizar = con.prepareStatement("UPDATE ALUMNOS SET c_id = ? WHERE no_ctrl = ?"); actualizar.setInt(1, 5); actualizar.setInt(2, 3130307); actualizar.executeUpdate(); %> Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Procedimientos almacenados del lado del servidor Hagamos un procedimiento almacenado en el sql y ejecutemoslo en una pagina <% String usuario = "DaN"; String clave = "perfidia"; String url = "jdbc:odbc:dbtaller"; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection con = DriverManager.getConnection(url, usuario, clave); CallableStatement cs = con.prepareCall("exec taller 3130307"); cs.execute(); %> Taller Aplicaciones Web con JSP Dante Mendoza Ruelas ENVIO DE EMAILS Introducción al API JavaMail El API JavaMail es un paquete opcional (extensión estándard) para leer, componer, y enviar mensajes electrónicos. Usamos este paquete para crear programas del tipo MUA (Mail User Agent), similares a Eudora, Pine, y Microsoft Outlook. Su propósito principal no es transportar, enviar, o reenviar mensajes como sendmail u otros programas del tipo MTA (Mail Transfer Agent). En otras palabras, los usuarios interactúan con los programas para leer y escribir e-mails. Los programas MUA tratan con los programas MTA para el envío real. El API JavaMail está diseñado para proporcionar acceso independiente del protocolo para enviar y recibir mensajes dividiendose en dos partes: La primera parte del API básicamente es, cómo enviar y recibir mensajes independientemente del proveedor/protocolo. La segunda parte habla de lenguajes especificos del protocolo como SMTP, POP, IMAP, y NNTP. Con el API, JavaMail para poder comunicar con un servidor, necesitamos un proveedor para un protocolo. Revisión de los Protocolos Relacionados Antes de mirar dentro de las especificaciones del API JavaMail, echemos un vistazo a los protocolos usados con el API. Básicamente son cuatro: SMTP POP IMAP MIME SMTP El protocolo Simple Mail Transfer Protocol (SMTP) está definido por la RFC 821. Define el mecanismo para enviar e-mail. En el contexto del API JavaMail, nuestro programa basado en JavaMail comunicará con el servidor SMTP de nuestro proveedor de servicios (ISP). Este servidor SMTP dejará el mensaje en el servidor SMTP del recipiente(s) para que sea recogido por los usuarios a través de POP o IMAP. Esto no requiere que nuestro servidor SMTP sea vulnerable, pues se utiliza la autentificación, pero es nuestra responsabilidad asegurarnos de que el servidor SMTP se configure correctamente. No hay nada en el API JavaMail sobre tareas como el configuración de un servidor para retransmitir mensajes o para agregar y para quitar cuentas del e-mail. POP POP viene de Post Office Protocol. Actualmante en la versión 3, también conocido como POP3, la RFC 1939 define este protocolo. POP es el mecanismo que la mayoría de la gente usa en Internet para conseguir su correo. Define el soporte de un sólo mailbox por cada usuario. Ésto es todo lo que lo hace, y ésta también es la fuente de la mayoría de la confusión. Muchas de las cosas con que gente se familiariza cuando usa POP, como la capacidad de ver cuántos mensajes de correo nuevos tienen, no lo soporta POP en absoluto. Estas capacidades se construyen en programas como Eudora o Microsoft Outlook, que recuerdan cosas como los últimos correos recibidos y calculan cuántos tenemos nuevos. Así pues, al usar el API JavaMail, si queremos este tipo de información tendremos que calcularla nosotros mismos. Taller Aplicaciones Web con JSP Dante Mendoza Ruelas IMAP IMAP es un protocolo más avanzado para recibir mensajes. Definido en la RFC 2060, IMAP viene de Internet Message Access Protocol, y está actualmente en la versión 4, también conocida como IMAP4. Para usar el IMAP, nuestro servidor de correo debe soportar este protocolo. No podemos simplemente cambiar nuestro programa para usar IMAP en vez de POP y que se soporte todo IMAP. Si asumimos que nuestro servidor de correo soporta IMAP, nuestro programa basado en JavaMail puede aprovecharse de los usuario que tienen carpetas múltiples en el servidor y estas carpetas se pueden compartir por varios usuarios. Debido a las capacidades más avanzadas, podríamos pensar que IMAP sería utilizado por todos. Pero no es así. Sobrecarga mucho el servidor de correo, requiriendo que el servidor reciba los nuevos mensajes, los entrege a los usuarios cuando sean solicitados, y los mantiene en las distintas carpetas de cada usuario. Aunque que esto centraliza las copias de seguridad, también hace que las carpetas de correo a largo plazo de los usuarios se hagan cada vez más grandes, y todo el mundo sufre cuando se agota el espacio en el disco. Con POP, los mensajes recuperados son eliminados del servidor de correo. MIME MIME viene de Multipurpose Internet Mail Extensions. No es un protocolo de transferencia de e-mail. En su lugar, define el contenido de lo que se está transfiriendo: el formato de los mensajes, los attachments, etc. Hay muchos documentos que tienen efecto sobre esto: las RFC 822, RFC 2045, RFC 2046, y RFC 2047. Como usuario del API JavaMail, normalmente no tendremos que preocuparnos sobre estos formatos. Sin embargo, estos formatos existen y son utilizados por nuestros programas. Las clases Corazón Revisar las Clases Corazón Antes de profundizar en las classes de JavaMail, veremos las clases corazón que componen el API: Session, Message, Address, Authenticator, Transport, Store, y Folder. Todas estas clases se encuentran en el paquete del nivel superior del API JavaMail: javax.mail, aunque frecuentemente nos veremos utilizando clases del paquete javax.mail.internet. Session La clase Session define una sesión de correo básica. Es a través de esta de sesión de la que todas las demás funcionan. El objeto Session se aprovecha de un objeto java.util.Properties para obtener información como el servidor de correo, el nombre de usuario, la password, y otra información que puede compartirse a lo largo de toda la aplicación. El constructor para las clases es privado. Podemos obtener una sola sesión por defecto que puede ser compartida con el método getDefaultInstance(): Taller Aplicaciones Web con JSP Message Dante Mendoza Ruelas Una vez que tenemos nuestro objeto Session, es hora de empezar a crear un mensaje para enviar. Esto se hace con un objeto Message. Siendo una clase abstracta, debemos trabajar con una subcalse, en la mayoría de los casos será javax.mail.internet.MimeMessage. Un MimeMessage es un mensaje de e-mail que entiende los tipos MIME, definidos en las distintas RFCs. Para crear un Message, le pasamos el objeto Session al constructor de MimeMessage: MimeMessage message = new MimeMessage(session); El mecanismo básico para configurar el contenidos es el método setContent(), con los argumentos para el contenido y tipo mime: message.setContent("Hello", "text/plain"); Sin embargo, si sabemos que estámos trabajando con un MimeMessage y nuestro mensaje es texto plano, podemos usar su método setText() que sólo requiere el contenido real, dejando por defecto el tipo MIME a text/plain: message.setText("Hello"); Para seleccionar el subject, usamos el método setSubject(): message.setSubject("First"); Address Una vez que hemos creado la Session y el Message, y también hemos rellenado el mensaje con contenido, es hora de poner dirección a nuestra carta con un objeto Address. Para crear una dirección con sólo la dirección e-mail, se la pasamos al constructor: Address address = new InternetAddress("yuju@yupi.com"); Taller Aplicaciones Web con JSP Dante Mendoza Ruelas Si queremos que aparezca el nombre junto a la dirección e-mail, también podemos pasárselo al constructor: Address address = new InternetAddress("yupi@yuju.com", "Dante"); Necesitaremos crear objetos address para los campos from y to del mensaje. A menos que el servidor lo evite, no hay nada que nos impida enviar un mensaje que parezca que viene de otra persona. Una vez que hemos creado las direcciones, las conectamos al mensaje de una de estas dos formas. Para identificar al que lo envía, usamos los métodos setFrom() y setReplyTo(). message.setFrom(address) Si nuestro mensaje necesita varias direcciones "from", usamos el método addFrom(): Address address[] = ...; message.addFrom(address); Para identificar a los receptores del mensaje, usamos el método addRecipient(). Este método requiere un Message.RecipientType junto a la dirección. message.addRecipient(type, address) Los tres tipos predefinidos de direcciones son: Message.RecipientType.TO Message.RecipientType.CC Message.RecipientType.BCC Por eso, si el mensaje fuera dirigido a alguien con copia a otra persona, esto sería lo apropiado: Address toAddress = new InternetAddress("yyy@yy.yy"); Address ccAddress = new InternetAddress("lalala@lelele.lolo"); message.addRecipient(Message.RecipientType.TO, toAddress); message.addRecipient(Message.RecipientType.CC, ccAddress); Taller Aplicaciones Web con JSP Authenticator Dante Mendoza Ruelas Para usar el Authenticator, subclasificamos la clase abstracta y devolvemos un ejemplar PasswordAuthentication del método getPasswordAuthentication(). Debemos registrar el Authenticator con la sesión cuando se crea. Luego, nuestro Authenticator será notificado cuando sea necesaria una autentificación. Transport La parte final del envío de un mensaje es usar la clase Transport. Estas clase habla el lenguaje específico del protocolo para enviar mensajes (normalmente SMTP). Es una clase abstracta y funciona como Session. Podemos usar la versión por defecto de la clase sólo llamando al método estático send(): Transport.send(message); Store y Folder Obtener los mensajes empieza de forma similar a enviar mensajes, con una Session. // Store store = session.getStore("imap"); Store store = session.getStore("pop3"); store.connect(host, username, password); Después de conectar al Store, podemos obtener un Folder, que debe estar abierto antes de poder leer los mensajes que hay en su interior: Folder folder = store.getFolder("INBOX"); folder.open(Folder.READ_ONLY); Message message[] = folder.getMessages(); Para POP3, la única carpeta disponible es INBOX. Si estamos usando IMAP, podremos disponer de otras carpetas. Una vez que tenemos un Message para leer, podemos obtener sus contenidos con getContent() o escribir sus contenidos en un stream con writeTo(). Después de haber leído el e-mail, cerramos la conexión al folder y al store. folder.close(aBoolean); store.close(); Taller Aplicaciones Web con JSP Dante Mendoza Ruelas El valor boleano pasado al método close() del folder significa si actualizamos o no la carpeta eliminando los mensajes borrados. Ejercicio: <%@ page import = "java.util.Properties" %> <%@ page import = "javax.mail.*" %> <%@ page import = "javax.mail.internet.*" %> <% // Obtener las propiedades del sistema Properties props = System.getProperties(); // Armar el servidor props.put("mail.smtp.host", "smtp.mail.yahoo.com.mx"); props.put("mail.smtp.auth", "true"); //Authenticathor Authenticator auth = new Authenticator(){ private PasswordAuthentication pwdAuth = new PasswordAuthentication("ing_dantemr", "xxx"); protected PasswordAuthentication getPasswordAuthentication() { return pwdAuth; } }; // Obtener una sesion Session misesion = Session.getDefaultInstance(props, auth); // Definir el mensaje MimeMessage message = new MimeMessage(misesion); message.setFrom(new InternetAddress("ing_dantemr@yahoo.com.mx")); message.addRecipient(Message.RecipientType.TO, new InternetAddress("eck3ko@gmail.com")); message.setSubject("Hello JavaMail"); message.setText("Welcome to JavaMail"); // Enviar el mensaje Transport.send(message); %>