Está en la página 1de 660
Desarrollo en Java Temas • Applets y aplicaciones con interfaz gráfica AWT y Swing • Excepciones, Hilos y Flujos • Acceso a base de datos • Aplicaciones distribuidas en Internet y WEB – Conexión a redes – Servlets, JSPs – Cookies y sesiones Introducción Java “Java is a simple, object oriented, distributed, interpreted, architecture neutral, portable, robusto, secure, high-performance, multi threaded, and dynamic language” Sun Microsystems Java es un lenguaje simple, orientado a objetos, distribuido, interpretado, de arquitectura neutral, transportable, robusto, seguro, de alto rendimiento, multiproceso y dinámico Características de Java • • • • • • • • • • • Simple y familiar Orientado a Objetos Distribuido Interpretado Arquitectura Neutral Transportable Robusto Seguro Alto Rendimiento Multiproceso Dinámico Programa Fuente Compilador Código Intermedio (Byte-Codes) Interpretador Ejecución Byte-Codes Máquina Virtual (JVM) Sistema Operativo Computadora Java como lenguaje • • • • • Características de muchos lenguajes Fácil de aprender y utilizar Independiente de la plataforma Seguro como ninguno Distribuido Obtención e Instalación del j2sdk (Java 2 Standard Development Kit) Y Primer programa j2sdk • Bajar la última versión del JDK del sitio de SUN (JDK 1.7.2) • www.javasoft.com • Instalar el JDK en la máquina • Bajar la documentación • Instalar la documentación • Comenzar a programar en Java Instalación del j2sdk • Ejecutar j2sdk1_7_2_03-windows-i586.exe • Seleccionar un directorio destino – Ej: c:\Program Files\j2sdk1.7.2 • Modificar la variable de entorno path – Donde el sistema encuentra los archivos ejecutables que no están en el directorio actual – ej: path=%path%;c:\Program Files\j2sdk1.7.2\bin – java y javac . . . . entre otros El primer programa public class Primero{ public static void main (String[] args){ System.out.println("Hola que tal!"); } } • Grabar como Primero.java, mismo nombre que la clase principal….siempre!!! Compilación y ejecución • Compilación – javac Primero.java – genera Primero.class • Ejecución – java Primero • Sensible a mayúsculas y minúsculas! Conceptos generales de Programación Orientada a Objetos OOP (Object Oriented Programming) Objetos • Estado – Nombre, color, raza, contento • Comportamiento – Ladrando, durmiendo, corriendo Objetos Perro Representa Objetos de Software Objetos reales Objeto (Software) • Estado – Representado por sus Variables • Comportamiento – Modificado por sus Métodos Los objetos en programación representan objetos reales y objetos abstractos (conceptos), ej. Eventos Objetos de Software Detalles de la “implementación” API pública Application Program Interface El Objeto Perro cambiaColor nombre color raza ladrando durmiendo ladra brinca duerme Encapsulación Ocultar las Variables y acceder a ellas solamente por medio de los Métodos Encapsulación • Modularidad • Transparencia – Facilidad del uso de un objeto – Puede cambiar la implementación sin afectar su utilización A veces se hacen públicas las variables y se esconden algunos métodos por razones de eficiencia Mensajes • Permiten la interacción entre objetos • Mandar a ejecutar un método Mensaje Acelera, frena, etc. Parámetros • A veces los métodos necesitan más información para realizar una acción • Esta información adicional se pasa en forma de parámetros enciende enciende (%) Mensajes • Expresan el comportamiento de un objeto, cambiando el estado de éste • Ocultan la necesidad de exponer las variables • Los objetos pueden estar en procesos y/o máquinas diferentes Mensajes • Objeto destino • Nombre del método a ejecutar • Parámetros necesarios focoSala.enciende(porcentaje) Clases • Prototipo de objetos • Definen sus variables y métodos • Los objetos son ejemplares de clases (instancias) • Los objetos de una clase comparten las características generales de la clase a que pertenecen Clases y Objetos • Los objetos de una clase comparten el comportamiento (métodos) • Cada objeto tiene su propio estado (variables) Clase Perro Clases y Objetos • Prototipo de los objetos Clases y Objetos Clases y Objetos Variables y Métodos • De ejemplar – Se crea una copia particular de las variables y se tiene acceso a los métodos • De clase – Todos los objetos de una clase comparten la misma copia – No se necesita crear un objeto para el acceso a variables y métodos – Si un objeto cambia una variable de clase, esa variable se cambia para todos los objetos de la clase Herencia • Definición de clases con base en otras clases • Subclases se definen con base en Superclases • La subclase hereda las variables y métodos de la superclase • La subclase define sus propias variables y métodos los cuales se agregan a los de la superclase Herencia Figura Triángulo Rectángulo Ovalo Rombo Una subclase puede redefinir (override) métodos heredados, para que realicen algo diferente o en diferente forma Herencia • Esquema jerárquico • Reutilización de código • Definición de clases abstractas que definen un comportamiento genérico, el cual es implementado en las subclases – No se pueden crear objetos de clases abstractas Ejemplo • Definición de la clase Rectangulo • Compilación de la clase • Programa que utilice objetos Rectangulo – Creación de un ejemplar de Rectangulo – Llamadas a métodos del objeto • Ejecución del programa Clase Rectángulo (Estado) ancho posición (x , y) alto Clase Rectángulo (Comportamiento) tamaño posición La clase Rectangulo public class Rectangulo{ int x, y; int ancho, alto; public Rectangulo(){ x = 0; y = 0; ancho = 100; alto = 100; } public void mueve(int x, int y){ this.x = x; this.y = y; } public void cambiaTamano(int ancho, int alto){ this.ancho = ancho; this.alto = alto; } public int calculaArea(){ return ancho*alto; } } Programa public class EjemploRectangulo{ public static void main(String args[]){ Rectangulo r; int area = 0; r = new Rectangulo(); area = r.calculaArea(); System.out.println("Area = "+area); r.cambiaTamano(200,300); area = r.calculaArea(); System.out.println("Area = "+area); } } Rectangulo más completa public class Rectangulo{ int x, y; int ancho, alto; public Rectangulo(){ x = 0; y = 0; ancho = 100; alto = 100; } public Rectangulo(int x, int y){ this.x = x; this.y = y; ancho = 100; alto = 100; } public Rectangulo(int x, int y, int ancho, int alto){ this.x = x; this.y = y; this.ancho = ancho; this.alto = alto; } public void mueve(int x, int y){ this.x = x; this.y = y; } public void cambiaTamano(int ancho, int alto){ this.ancho = ancho; this.alto = alto; } public int calculaArea(){ return ancho*alto; } } Programa public class EjemploRectangulo{ public static void main(String args[]){ Rectangulo r1,r2; int area1, area2; r1 = new Rectangulo(100,100); r2 = new Rectangulo(50,50,100,200); area1 = r1.calculaArea(); area2 = r2.calculaArea(); System.out.println("Area1 = "+ area1 + " , Area2 = " + area2); r1.cambiaTamano(200,300); area1 = r1.calculaArea(); area2 = r2.calculaArea(); System.out.println("Area1 = "+ area1 + " , Area2 = " + area2); } } Mejoras • Modificar el programa del rectángulo para que no utilice las coordenadas como dos enteros • En su lugar definir una clase que sea un punto en el espacio, la cual internamente maneje coordenadas x , y Definición de la clase Punto public class Punto{ public int x = 0; public int y = 0; public Punto(int x, int y){ this.x = x; this.y = y; } } Rectangulo otra vez public class Rectangulo{ Punto posicion; int ancho, alto; public Rectangulo(){ posicion = new Punto(0,0); ancho = 100; alto = 100; } public Rectangulo(Punto p){ posicion = p; ancho = 100; alto = 100; } public Rectangulo(Punto p, int ancho, int alto){ posicion = p; this.ancho = ancho; this.alto = alto; } public void mueve(Punto p){ posicion = p; } public void cambiaTamano(int ancho, int alto){ this.ancho = ancho; this.alto = alto; } public int calculaArea(){ return ancho*alto; } } Lenguaje Java Tipos de datos primitivos Tipo Tamaño Descripción byte short int long float double char boolean 8 bits 16 bits 32 bits 64 bits 32 bits 64 bits 16 bits entero complementos a 2 entero complementos a 2 entero complementos a 2 entero complementos a 2 punto flotante prec. sencilla punto flotante prec. doble Unicode true/false Tipos de datos primitivos • Datos primitivos NO son objetos int x = 56; MiClase x = new MiClase(); x 56 x xyz Variables • Identificador legal con carácteres unicode (65,536 posibles, 34,168 asignados) • letras y dígitos unicode, la primera debe ser letra • No debe ser palabra reservada • Convención: – Primera letra minúscula y cada palabra subsiguiente comienza con mayúscula, sin espacios (variableDeVariasPalabras) Palabras reservadas Operadores • Unitarios – Un operando, prefijo o postfijo • Binarios – Dos operandos, infijo • Ternarios – expresión ? op1 : op2 Operadores aritméticos Operador + * / % + ++ ++ --Uso op1+op2 Descripción Suma Resta Multiplicación División Residuo de op1 / op2 Promueve a int si es byte, short o char Aritméticamente niega op Incrementa a op en 1, se evalua antes del incremento Incrementa a op en 1, se evalua después del incremento Decrementa a op en 1, se evalua antes del decremento Decrementa a op en 1, se evalua después del decremento op1-op2 op1*op2 op1/op2 op1%op2 +op +op op++ ++op op---op Ejemplos class Aritmeticos { public static void main int x = 17, y = 5; System.out.println("x System.out.println("y System.out.println("x System.out.println("x System.out.println("x System.out.println("x System.out.println("x } } (String args[]) { = = + * / % " " y y y y y + + = = = = = x); y); " + " + " + " + " + (x (x (x (x (x + * / % y)); y)); y)); y)); y)); Salida a pantalla x = 17 y=5 x + y = 22 x - y = 12 x * y = 85 x/y=3 x%y=2 Ejemplos class Incrementos { public static void main (String args[]) { int x = 8, y = 13; System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("++x = " + ++x); System.out.println("y++ = " + y++); System.out.println("x = " + x); System.out.println("y = " + y); } } x = y = ++x y++ x = y = 8 13 = 9 = 13 9 14 Salida a pantalla Operadores relacionales • Regresan un valor booleano (true o Operador > < >= <= == != Uso op1>op2 op1=op2 op1<=op2 op1==op2 op1!=op2 false) Descripción Regresa verdadero si op1 es mayor que op2 Regresa verdadero si op1 es menor que op2 Regresa verdadero si op1 es mayor o igual que op2 Regresa verdadero si op1 es menor o igual que op2 Regresa verdadero si op1 es igual a op2 Regresa verdadero si op1 es diferente a op2 Ejemplos class Relacionales { public static void main (String args[]) { int x = 7, y = 11, z = 11; System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("z = " + z); System.out.println("x < y = " + (x < y)); System.out.println("x > z = " + (x > z)); System.out.println("y <= z = " + (y <= z)); System.out.println("x >= y = " + (x >= y)); System.out.println("y == z = " + (y == z)); System.out.println("x != y = " + (x != z)); } } Salida a pantalla x y z x x y x y x = 7 = 11 = 11 < y = true > z = false <= z = true >= y = false == z = true != y = true Operadores condicionales • Regresan un valor booleano (true o Operador && || ! & | ?: int int int int int int a b c d e f = = = = = = false) Uso op1&&op2 op1||op2 Descripción AND lógico, condicionalmente evalua op2 OR lógico, condicionalmente evalua op2 !op Niega lógicamente a op op1&op2 AND lógico, siempre evalua op2 op1|op2 OR lógico, siempre evalua op2 Evalua exp y regresa op1 si es verdadera exp?op1:op2 o regresa op2 si exp es falsa 28; 4; 45; 0; (b == 0) ? 0 : (a / b); (d == 0) ? 0 : (c / d); e=7 f =0 Operadores de bit Operador Uso op1>>op2 op1<>>op2 op1&op2 op1|op2 op1^op2 Descripción >> << >>> & | ^ ~ ~op Recorre los bits de op1 hacia la derecha op2 bits Recorre los bits de op1 hacia la izquierda op2 bits Recorre a la derecha, pero sin signo AND lógico, bit a bit OR lógico, bit a bit XOR lógico, bit a bit Complementa op, bit a bit Ejemplos class Shift { public static void main int x = 7; System.out.println("x System.out.println("x System.out.println("x System.out.println("x } } (String args[]) { = " + x); >> 2 = " + (x >> 2)); << 1 = " + (x << 1)); >>> 1 = " + (x >>> 1)); Salida a pantalla x=7 x >> 2 = 1 x << 1 = 14 x >>> 1 = 3 Operadores de asignación Operador = += -= *= /= %= &= |= ^= <<= >>= >>>= Uso op1=op2 Equivalente a op1+=op2 op1-=op2 op1*=op2 op1/=op2 op1%=op2 op1&=op2 op1|=op2 op1^=op2 op1<<=op2 op1>>=op2 op1>>>=op2 op1 = op1 + op2 op1 = op1 - op2 op1 = op1 * op2 op1 = op1 / op2 op1 = op1 % op2 op1 = op1 & op2 op1 = op1 | op2 op1 = op1 ^ op2 op1 = op1 << op2 op1 = op1 >> op2 op1 = op1 >>> op2 Expresiones • Conjunto de variables, operadores y llamadas a métodos, construido de acuerdo a la sintaxis del lenguaje, y que al evaluarla produce un sólo valor • Los operadores tienen precedencia, la cual se puede modificar por el uso de paréntesis • Las asignaciones se realizan al final • Operadores con igual precedencia se evaluan de izquierda a derecha Precedencia de operadores . ++ * + << < == & ^ | && || ?: [] () -- ! ~ / % >> >>> > <= >= != Estatutos • Decisión – if - else – switch • Ciclos – while – do - while – for if - else if (Condición) Estatuto1; else Estatuto2; if (Condición){ _____; _____; : : }else{ _____; _____; : : } if (Condición) Estatuto1; Ejemplos boolean a,b; : : if (a && b) { x += y * 5; y -= 10; z = (x - 3) / y; } int calificación; char nota; if (calificación >= 90) nota = 'A'; } else if (calificación nota = 'B'; } else if (calificación nota = 'C'; } else if (calificación nota = 'D'; } else { nota = 'F'; } { >= 80) { >= 70) { >= 60) { switch switch (Expresión) { case Constante1: Estatutos1; break; case Constante2: Estatutos2; break; : : default: Estatutos; break; } • • Expresión debe ser char, byte, short o int Las constantes deben de ser del mismo tipo que expresión • break es opcional, si no se utiliza se ejecutan todos los estatutos después del primer case que coincida con la expresión • default maneja todos los casos que no estén contamplados en los case, es opcional • No puede haber dos constantes iguales • Solamente puede existir un default Ejemplo int mes; . . . . . . switch (mes) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: } System.out.println(”Enero"); break; System.out.println(”Febrero"); break; System.out.println(”Marzo"); break; System.out.println(”Abril"); break; System.out.println(”Mayo"); break; System.out.println(”Junio"); break; System.out.println(”Julio"); break; System.out.println(”Agosto"); break; System.out.println(”Septiembre"); break; System.out.println(”Octubre"); break; System.out.println(”Noviembre"); break; System.out.println(”Diciembre"); break; ¿Qué pasa si quitamos un break? while while (condición) estatuto; while (condición){ estatuto1; estatuto2; : : } Condición Estatutos do - while do estatuto; while (condición); Estatutos do{ estatuto1; estatuto2; : : }while (condición); Condición Ejemplos int i = 0; int n = 10; while (in) break; i++; }while(true); i= 0 i= 1 : : i= 11 continue • brinca al final del ciclo, pero evalua la condición para saber si continua iterando int i=0; int n=10; do{ i++; if (i%2!=0) continue; System.out.println(”i= "+i); }while(i Segundo Applet Browsers y Java • Netscape – Shift-reload para cargar las clases de nuevo • IExplorer – Control-reload para cargar las clases de nuevo Métodos de un Applet • init() – Se ejecuta cada vez que se carga el applet (reload?) • start() – Después de init() y cada vez que se regresa a la página • stop() – Cuando se va a otra página o se termina la ejecución del browser • destroy() – Después de stop() cuando se cierra el browser, o la máquina virtual “mata” al Applet Métodos de un Applet • init() – Inicialización de variables y recursos que usará el Applet a través de su vida • start() – Comienzo de la ejecución del Applet, y reinicio en caso de haberse detenido por stop() • stop() – Interrupción de la ejecución, para no consumir CPU (parar animaciones, ciclos) • destroy() – Liberación general de los recursos import java.applet.Applet; import java.awt.Graphics; public class TercerApplet extends Applet { String letrero = ""; public void init() { letrero += "en init() "; } public void start() { letrero += "en start() "; } public void stop() { letrero += "en stop() "; } public void destroy() { letrero += "en destroy() "; } Ejemplo public void paint(Graphics g) { g.drawRect(0, 0, getSize().width - 1, getSize().height - 1); g.drawString(letrero, 5, 15); } } import java.applet.Applet; import java.awt.Graphics; public class CuartoApplet extends Applet { public void init() { System.out.println("en init()"); } public void start() { System.out.println("en start()"); } public void stop() { System.out.println("en stop()"); } public void destroy() { System.out.println("en destroy()"); } } “Debugging” • • • System.out.println() es útil para el rastreo de problemas en un Applet La salida de System.out.println() va a la consola En IExplorer es necesario activarla Práctica • Subir una página con un applet a un servidor y ejecutarlo desde un browser en alguna máquina remota • Sigue las instrucciones del instructor Introducción a AWT (Abstract Window Toolkit) AWT • Nos da acceso a muchos componentes estándar de interfaces gráficas. Botones, Listas, campos de texto, menús, etc. • También define un modelo de eventos para darle funcionamiento a los componentes • El nuevo ambiente gráfico es JFC (Java Foundation Classes, Swing) • Los browsers no traen soporte directo para Swing, se necesita un plug-in de 5 Mbytes aprox. Componentes básicos de AWT TextField Label Choice Label List Button La clase Button Provee el funcionamiento de un botón normal en las diferentes plataformas La clase Button La clase TextField Objeto que permite la edición de una sola línea de texto TextField • getText() – Regresa un string que es el contenido del objeto • setText(String) – Establece el string que contendrá el objeto Administradores de Layout • Sirven para distribuir los objetos en el contexto gráfico • Siguen reglas estrictas para el acomodo de los objetos • Hay que agregar los objetos a contenedores • A los contenedores se les asigna un administrador de Layout • Existe el administrador nulo (null) que sirve para utilizar posicionamiento absoluto Administradores de Layout • Objetos de GUI – Le dan funcionalidad a la aplicación (botones, campos de texto, listas, etc.) • Contenedores – Le dan “hospedaje” físico a los objetos GUI • Administradores – Ordenan los objetos dentro de los contenedores Contenedores Frame Applet Panel Objetos se agregan a contenedores Frame, Panel, Applet Administradores ordenan los objetos dentro del contenedor Administradores de Layout • Los objetos se agregan a los contenedores: – contenedor.add(objeto) • El administrador de layout se aplica a un contenedor – contenedor.setLayout(..) Administradores de Layout • FlowLayout – El default para los applets, acomoda los objetos de izquierda a derecha y agrega renglones a medida que los va necesitando • BorderLayout – Usa cinco áreas predeterminadas, Norte, Sur, Este, Oeste y Centro. El Centro es que usa todo el espacio que sobra después de acomodar las demás áreas • GridLayout – Acomoda los componentes en una cuadrícula, se especifica las dimensiones de la cuadrícula cuando se crea este Layout • CardLayout • GridbagLayout FlowLayout Para agregar componentes se utiliza el método add(Componente) de la clase Container Ejemplo FlowLayout import java.applet.*; import java.awt.*; public class LayoutFlow extends Applet { Button boton1, boton2, boton3; public void init() { boton1 = new Button("Ok"); boton2 = new Button("Cancelar"); boton3 = new Button("Aceptar alguna cosa"); add(boton1); add(boton2); add(boton3); } } Ejemplo FlowLayout import java.applet.*; import java.awt.*; public class LayoutFlow extends Applet { Button boton1, boton2, boton3; public void init() { boton1 = new Button ("Ok, pero ahora más largo a ver que pasa con el Layout"); boton2 = new Button("Cancelar"); boton3 = new Button("Aceptar alguna cosa"); add(boton1); add(boton2); add(boton3); } } Ejemplo FlowLayout import java.applet.*; import java.awt.*; public class LayoutFlow extends Applet { Button boton1, boton2, boton3; public void init() { setLayout(new FlowLayout(FlowLayout.LEFT ,0,0)); boton1 = new Button("Ok"); boton2 = new Button("Cancelar"); boton3 = new Button("Aceptar alguna cosa"); add(boton1); add(boton2); add(boton3); } } BorderLayout • Para agregar componentes a este Layout se usa una variante de add. add(Componente, Posición) • Donde Posición indica las cinco posibles que tiene BorderLayout: North, South, East, West, Center • Posición es una constante String • No se recomienda usar add(Posición, Componente) Ejemplo BorderLayout import java.awt.*; import java.applet.Applet; public class LayoutBorder extends Applet { public void init() { setLayout(new BorderLayout()); add(new Button("Norte"),"North"); add(new Button("Sur"),"South"); add(new Button("Este"),"East"); add(new Button("Oeste"),"West"); add(new Button("Centro"),"Center"); } } Ejemplo BorderLayout import java.awt.*; import java.applet.Applet; public class LayoutBorder extends Applet { public void init() { setLayout(new BorderLayout(20,20)); add(new Button("Norte"),"North"); add(new Button("Sur"),"South"); add(new Button("Este"),"East"); add(new Button("Oeste"),"West"); add(new Button("Centro"),"Center"); } } Creación del BorderLayout, especificando separación de componentes, vertical y horizontal GridLayout • Divide el área gráfica en una cuadrícula rectangular con un número especificado de rectángulos de igual tamaño Ejemplo GridLayout import java.awt.*; import java.applet.Applet; public class LayoutGrid extends Applet { public void init() { setLayout(new GridLayout(3,2)); add(new Button("1")); add(new Button("2")); add(new Button("3")); add(new Button("4")); add(new Button("5")); add(new Button("6")); } } Ejemplo GridLayout import java.awt.*; import java.applet.Applet; public class LayoutGrid extends Applet { public void init() { setLayout(new GridLayout(2,3)); add(new Button("1")); add(new Button("2")); add(new Button("3")); add(new Button("4")); add(new Button("5")); add(new Button("6")); } } Ejemplo GridLayout import java.awt.*; import java.applet.Applet; public class LayoutGrid extends Applet { public void init() { setLayout(new GridLayout(2,3)); add(new Button("1")); add(new Button("2")); add(new Button("3")); add(new Button("4")); } } Si se especifica número de columnas y renglones, el número de columnas se ignora y se ajusta a las que se necesiten Ejemplo GridLayout import java.awt.*; import java.applet.Applet; public class LayoutGrid extends Applet { public void init() { setLayout(new GridLayout(2,3)); add(new Button("1")); add(new Button("2")); add(new Button("3")); add(new Button("4")); add(new Button("5")); add(new Button("6")); add(new Button(”7")); } } Si se especifica número de columnas y renglones, el número de columnas se ignora y se ajusta a las que se necesiten Ejemplo GridLayout import java.awt.*; import java.applet.Applet; public class LayoutGrid extends Applet { public void init() { setLayout(new GridLayout(0,4)); add(new Button("1")); add(new Button("2")); add(new Button("3")); add(new Button("4")); add(new Button("5")); add(new Button("6")); } } El número de columnas tiene sentido solamente cuando se especifica un número de renglones igual a cero TextArea • Región de texto multilínea • De la clase TextComponent hereda la capacidad de establecer y obtener todo el texto contenido o solamente el seleccionado, además de poder establecer el color y font del texto desplegado, color del fondo, hacer el texto editable o no (read only) Constructores de TextArea Algunos métodos de TextArea Métodos heredados de TextComponent • setText(String) • getText() • setEditable(boolean) • select(int,int) • selectAll() Métodos heredados de Component • • • • • • setFont(Font) getFont() setForeground(Color) setBackground(Color) setSize(Dimension) setVisible(boolean) La clase Panel Interfaces adecuadas import java.awt.*; import java.applet.Applet; Ejemplo public class Layouts extends Applet{ Panel botones = new Panel(new GridLayout(8,0,0,10)); Button boton1 = new Button("Insertar"); Button boton2 = new Button("Borrar"); Button boton3 = new Button("Imprimir"); Button boton4 = new Button("Cancelar"); TextArea texto = new TextArea(); public void init(){ setLayout(new BorderLayout(10,0)); botones.add(new Label("Esta es una Demostración")); botones.add(new Label()); botones.add(new Label()); botones.add(new Label()); botones.add(boton1); botones.add(boton2); botones.add(boton3); botones.add(boton4); add(texto,"Center"); add(botones,"East"); } } Práctica • Haz un applet que despliegue la siguiente interfaz Manejo de eventos en AWT Modelo de delegación Fuentes y Escuchadores Objeto Fuente (Source) Evento Objeto Escuchador (Listener) • Las fuentes son objetos que originan o “disparan” eventos. Cada fuente define el conjunto de eventos que puede emitir con: setListener o addListener • Los escuchadores son objetos que implementan interfaces específicas que definen uno o más métodos para la atención de eventos particulares Propagación de eventos Fuente Eventos que se generan Escuchador Evento Escuchadores registrados Métodos para el manejo de eventos • Los objetos fuente cuando disparan un evento llaman al método indicado en los objetos escuchadores que esten registrados. • Al llamar al método correspondiente en el escuchador, también va como parámetro una instancia de la subclase que define el tipo de evento generado Fuente Button Evento ActionEvent class...implements ActionListener{ public void actionPerformed(ActionEvent e){ ....... } } Escuchador ActionListener Ejemplo public class Beep extends Applet{ Button fuente = new Button("Presióname"); EventoAccion escuchador = new EventoAccion(); public void init() { add(fuente); fuente.addActionListener(escuchador); } } class EventoAccion implements ActionListener{ public void actionPerformed(ActionEvent e) { Toolkit.getDefaultToolkit().beep(); } } Crear objeto generador de eventos Crear objeto escuchador de eventos Registrar el escuchador con el fuente Modelo de delegación • Usado en JDK 1.1 y JDK 1.2 (Java 2) • Ya no se usa el modelo de AWT 1.0, modelo basado en herencia • Existen fuentes (sources) que generan o disparan eventos y escuchadores (listeners) • Permite “delegar” el manejo de eventos a objetos escuchadores • El modelo permite manejar y generar eventos Manejo de eventos (sencillo) • Definir el objeto que generará eventos • Definir un manejador de eventos para ese objeto (listener o adapter) • Hacer el enlace entre el objeto y su correspondiente manejador • Un objeto generador puede tener varios manejadores de diferente tipo de eventos • Un manejador puede atender a varios objetos Eventos Escuchador de Eventos Generador de Eventos Evento Escuchador de Eventos Escuchador de Eventos Eventos Generador de Eventos Generador de Eventos Evento Escuchador de Eventos Generador de Eventos add . . . . Listener objeto1.add . . . . Listener (objeto2); Generador de eventos Tipo de eventos a manejar: Acción, mouse, etc. Escuchador (manejador) de eventos • Hace el enlace entre el objeto generador de eventos y el objeto manejador addActionListener ActionListener Ejemplo sencillo import java.applet.Applet; import java.awt.*; import java.awt.event.*; public class Eventos1 extends Applet implements ActionListener { public Button boton = new Button("Presióname"); public TextArea texto = new TextArea("**** Programación en Java ****"); public void init(){ setLayout(new BorderLayout(10,10)); add(boton,"North"); add(texto,"Center"); boton.addActionListener(this); } public void actionPerformed(ActionEvent e){ texto.append("Se tecleó el botón!!!!\n"); } } Ejemplo sencillo Ejemplo import java.applet.Applet; import java.awt.*; import java.awt.event.*; Ejemplo public class Eventos2 extends Applet implements ActionListener { public Button botonArriba = new Button("Arriba"); public Button botonAbajo = new Button("Abajo"); public TextArea texto = new TextArea("**** Programación en Java ****"); public void init(){ setLayout(new BorderLayout(10,10)); add(botonArriba,"North"); add(botonAbajo,"South"); add(texto,"Center"); botonArriba.addActionListener(this); botonAbajo.addActionListener(this); } public void actionPerformed(ActionEvent e){ if (botonArriba.equals(e.getSource())) texto.append("Se tecleó el botón de ARRIBA\n"); else if (botonAbajo.equals(e.getSource())) texto.append("Se tecleó el botón de ABAJO\n"); } } import java.applet.Applet; import java.awt.*; import java.awt.event.*; Ejemplo public class Eventos3 extends Applet implements MouseListener{ public Button boton = new Button("Hazme algo......."); public TextArea texto = new TextArea("**** Programación en Java ****\n"); public void init(){ setLayout(new BorderLayout(10,10)); add(boton,"North"); add(texto,"Center"); boton.addMouseListener(this); } public void mousePressed(MouseEvent event) { texto.append("Se presionó el mouse\n"); } public void mouseClicked(MouseEvent event) { texto.append("Se dió click al mouse\n"); } public void mouseReleased(MouseEvent event) { texto.append("Se soltó el mouse\n"); } public void mouseEntered(MouseEvent event) { texto.append("Entró el mouse\n"); } public void mouseExited(MouseEvent event) { texto.append("Se salió el mouse\n"); } } Ejemplo Manejadores de Eventos • Listeners – Son interfaces – Se tienen que programar todos los métodos definidos • Adapters – Son clases abstractas – Los métodos no hacen nada por omisión – No se necesitan programar todos los métodos Paquete java.awt.event MouseAdapter import java.applet.Applet; import java.awt.*; import java.awt.event.*; Ejemplo public class Eventos4 extends Applet{ public Button boton = new Button("Hazme algo......."); public TextArea texto = new TextArea("**** Programación en Java ****\n"); public void init(){ setLayout(new BorderLayout(10,10)); add(boton,"North"); add(texto,"Center"); ManejaMouse mm = new ManejaMouse(texto); boton.addMouseListener(mm); } } class ManejaMouse extends MouseAdapter{ public TextArea t; public ManejaMouse (TextArea t){ super(); this.t = t; } public void mousePressed(MouseEvent event) { t.append("Se presionó el mouse\n"); } public void mouseReleased(MouseEvent event) { t.append("Se soltó el mouse\n"); } } Choice • Es un estilo de menú “pop-up” • Te despliega una lista de opciones de las cuales puedes seleccionar una • La lista de opciones no está constantemente desplegada como en el caso de List, se despliega al presionar un botón que es parte del choice • El elemento seleccionado es el que queda desplegado Métodos de Choice • Se agrega un item con add(String) o addItem(String) al final de la lista de opciones • Se quita un item de la lista con remove(int) o remove(String) • select(String) y select(int) seleccionan un item de la lista • getItem(int) regresa un String con el item correspondiente al índice dado como parámetro • getItemCount() regresa la cantidad de items que existen en el choice Evento de Choice • Genera un evento ItemEvent cuando se selecciona alguna de sus opciones (item) • Se puede obtener el item seleccionado con getSelectedItem() • También se puede obtener el índice del item seleccionado con getSelectedIndex() • Es necesario implementar ItemListener para capturar la selección de items import java.awt.*; import java.awt.event.*; import java.applet.Applet; Ejemplo public class ChoiceDemo extends Applet implements ItemListener{ Choice choice; Label etiqueta; public void init() { choice = new Choice(); choice.addItem("Uno"); choice.addItem("Dos"); choice.addItem("Tres"); choice.addItem("Cuatro"); choice.addItemListener(this); etiqueta = new Label("Selecciona un elemento"); add(etiqueta); add(choice); } public void itemStateChanged(ItemEvent e) { etiqueta.setText(choice.getSelectedItem()+ " "+ choice.getSelectedIndex()); } } Ejemplo List • Despliega una lista de items seleccionables • Se configura la cantidad de items visibles en una ventana con scroll • Se seleccionan los items en forma similar al choice • Se puede establecer que se soporten selecciones múltiples, varios items seleccionados simultáneamente List • Además de ItemEvent, la lista puede generar ActionEvent • La manera de agregar items es similar a Choice, add(String) y addItem(String), además soporta add(String,int) y addItem(String,int) • La manera de obtener los items seleccionados es similar a Choice con getSelectedIndex() y getSelectedItem(), además soporta getSelectedIndexes() y getSelectedItems() los cuales regresan arreglos import java.awt.*; import java.awt.event.*; import java.applet.Applet; Ejemplo public class ListDemo extends Applet implements ItemListener { List lista; TextArea texto = new TextArea(10,30); public void init() { lista = new List(5); lista.addItem("Uno"); lista.addItem("Dos"); lista.addItem("Tres"); lista.addItem("Cuatro"); lista.addItem("Cinco"); lista.addItem("Seis"); lista.addItem("Siete"); lista.addItemListener(this); add(texto); add(lista); } public void itemStateChanged(ItemEvent e) { texto.append("Se seleccionó "+lista.getSelectedItem()+"\n"); } } Ejemplo Eventos de bajo nivel java.lang.Object | +---java.util.EventObject | +---java.awt.AWTEvent | +---java.awt.event.ComponentEvent | +---java.awt.event.InputEvent | | | +---java.awt.event.KeyEvent | | | +---java.awt.event.MouseEvent | +---java.awt.event.FocusEvent | +---java.awt.event.ContainerEvent | +---java.awt.event.WindowEvent • Eventos que representan interacción directa del usuario • Presionar una tecla, movimiento del ratón, presión y liberación del botón del ratón Eventos de bajo nivel java.awt.event.ComponentEvent cambio de tamaño, movimiento del componente java.awt.event.FocusEvent Componente tomó el foco (gotFocus) o perdió el foco (lostFocus) java.awt.event.KeyEvent tecla presionada o liberada java.awt.event.MouseEvent botón del ratón presionado, liberado, movimiento del ratón, arrastre java.awt.event.ContainerEvent adición y eliminación de componentes de un contenedor java.awt.event.WindowEvent ventana activada, desactivada, abierta, cerrada, minimizada, etc. Eventos semánticos java.lang.Object | +---java.util.EventObject | +---java.awt.AWTEvent | +---java.awt.event.ActionEvent | +---java.awt.event.AdjustmentEvent | +---java.awt.event.ItemEvent | +---java.awt.event.TextEvent • Encapsulan la semántica (el significado) de un componente de interfaz gráfica • No están asociados con ningún componente específico • Button, List, MenuItem disparan eventos de acción (ActionEvent) Eventos semánticos java.awt.event.ActionEvent Ejecutar un comando java.awt.event.AdjustmentEvent Se ajustó un valor java.awt.event.ItemEvent Cambió el estado de un item java.awt.event.TextEvent Cambió el valor de un objeto de texto • Ejemplo: Cuando el usario hace “click” con el ratón sobre un botón, el botón recibe dos (o hasta tres) eventos de bajo nivel, mousePressed y mouseReleased, sin embargo el botón dispara un evento de alto nivel (semántico), el evento de acción (ActionEvent) Jerarquía de los eventos java.lang.Object | +---java.util.EventObject | +---java.awt.AWTEvent | +---java.awt.event.ActionEvent | +---java.awt.event.AdjustmentEvent | +---java.awt.event.ItemEvent | +---java.awt.event.TextEvent | +---java.awt.event.ComponentEvent | +---java.awt.event.InputEvent | | | +---java.awt.event.KeyEvent | | | +---java.awt.event.MouseEvent | +---java.awt.event.FocusEvent | +---java.awt.event.ContainerEvent | +---java.awt.event.WindowEvent Listener (escuchadores) • Son interfaces • Definen métodos para cada evento que puedan generar los diferentes componentes • Se registran con un componente que genera determinados tipos de eventos (add.....Listener) • Existe una relación de uno a uno entre los eventos que genera un componente y los métodos que define una interface Listener • Java trata de obtener un balance en la definición de eventos y sus correspondientes métodos. Suficiente granularidad sin caer en la definición de todos los tipos de eventos Listeners (escuchadores) Listeners de bajo nivel java.awt.event.ComponentListener java.awt.event.ContainerListener java.awt.event.FocusListener java.awt.event.KeyListener java.awt.event.MouseListener java.awt.event.MouseMotionListener java.awt.event.WindowListener Listener semánticos java.awt.event.ActionListener java.awt.event.AdjustmentListener java.awt.event.ItemListener java.awt.event.TextListener ActionListener MouseListener MouseMotionListener • Interfaz separada ya que el arrastre y movimiento del ratón son demasiado comunes y resultaría en demasiadas llamadas innecesarias • Si no registras este tipo de Listener con algún objeto generador de eventos, dicho objeto no disparará los eventos de movimiento y arrastre MouseEvent Variables de MouseEvent Métodos de MouseEvent import import import import java.applet.*; java.awt.*; java.awt.event.*; java.util.*; public class Puntos extends Applet implements MouseListener{ Vector puntos = new Vector(); public void init() { this.addMouseListener(this); } public void mouseClicked(MouseEvent e){ puntos.addElement(e.getPoint()); this.repaint(); } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void paint(Graphics g) { g.setColor(Color.red); Enumeration e = puntos.elements(); while (e.hasMoreElements()) { Point p = (Point) e.nextElement(); g.drawOval(p.x, p.y, 5, 5); } } } Ejemplo Fuente: El applet Escuchador: El applet KeyListener KeyEvent Códigos virtuales de teclas • Para lidiar con la inconsistencias de los diferentes teclados y las diferentes plataformas Asciis de ‘0’ a ‘9’ (0x30 a 0x39) KeyEvent.VK_0 KeyEvent.VK_1 KeyEvent.VK_2 KeyEvent.VK_3 KeyEvent.VK_4 KeyEvent.VK_5 KeyEvent.VK_6 KeyEvent.VK_7 KeyEvent.VK_8 KeyEvent.VK_9 Asciis de ‘A’ a ‘Z’ (0x41 a 0x5A) KeyEvent.VK_A : : : : : : : : KeyEvent.VK_Z Códigos virtuales de teclas KeyEvent.VK_ACCEPT KeyEvent.VK_ADD KeyEvent.VK_ALT KeyEvent.VK_BACK_QUOTE KeyEvent.VK_BACK_SLASH KeyEvent.VK_BACK_SPACE KeyEvent.VK_CANCEL KeyEvent.VK_CAPS_LOCK KeyEvent.VK_CLEAR KeyEvent.VK_CLOSE_BRACKET KeyEvent.VK_COMMA KeyEvent.VK_CONTROL KeyEvent.VK_CONVERT KeyEvent.VK_DECIMAL KeyEvent.VK_DELETE KeyEvent.VK_DIVIDE KeyEvent.VK_DOWN KeyEvent.VK_END KeyEvent.VK_ENTER KeyEvent.VK_EQUALS KeyEvent.VK_ESCAPE KeyEvent.VK_F1 KeyEvent.VK_F2 KeyEvent.VK_F3 KeyEvent.VK_F4 KeyEvent.VK_F5 KeyEvent.VK_F6 KeyEvent.VK_F7 KeyEvent.VK_F8 KeyEvent.VK_F9 KeyEvent.VK_F10 KeyEvent.VK_F11 KeyEvent.VK_F12 KeyEvent.VK_FINAL KeyEvent.VK_HELP KeyEvent.VK_HOME KeyEvent.VK_INSERT KeyEvent.VK_KANA KeyEvent.VK_KANJI KeyEvent.VK_LEFT KeyEvent.VK_META KeyEvent.VK_MODECHANGE KeyEvent.VK_MULTIPLY KeyEvent.VK_NONCONVERT KeyEvent.VK_NUM_LOCK KeyEvent.VK_NUMPAD0 KeyEvent.VK_NUMPAD1 KeyEvent.VK_NUMPAD2 KeyEvent.VK_NUMPAD3 KeyEvent.VK_NUMPAD4 KeyEvent.VK_NUMPAD5 KeyEvent.VK_NUMPAD6 KeyEvent.VK_NUMPAD7 KeyEvent.VK_NUMPAD8 KeyEvent.VK_NUMPAD9 KeyEvent.VK_OPEN_BRACKET KeyEvent.VK_PAGE_DOWN KeyEvent.VK_PAGE_UP KeyEvent.VK_PAUSE KeyEvent.VK_PERIOD KeyEvent.VK_PRINTSCREEN KeyEvent.VK_QUOTE KeyEvent.VK_RIGHT KeyEvent.VK_SCROLL_LOCK KeyEvent.VK_SEMICOLON KeyEvent.VK_SEPARATER KeyEvent.VK_SHIFT KeyEvent.VK_SLASH KeyEvent.VK_SPACE KeyEvent.VK_SUBTRACT KeyEvent.VK_TAB KeyEvent.VK_UNDEFINED KeyEvent.VK_UP Variables y métodos de KeyEvent KeyEvent.KEY_PRESSED Se presionó una tecla KeyEvent.KEY_RELEASED Se soltó una tecla KeyEvent.KEY_TYPED Se presionó y se soltó una tecla public char getKeyChar() Regresa el carácter UNICODE de la tecla presionada public int getKeyCode() Regresa el código de la tecla presionada, no el carácter public static String getKeyText(int keyCode) Convierte a una representación string el código de la tecla presionada tales como END, F4, etc. public long getWhen() Regresa la hora en que sucedió el evento en milisegundos transcurridos desde Enero 1, 1970 Teclas modificadoras Regresan el estado de las teclas modificadoras: public boolean isShiftDown() public boolean isControlDown() public boolean isMetaDown() public boolean isAltDown() public int getModifiers() Regresa el estado de las banderas modificadoras * Pertenecen a la clase InputEvent ALT_MASK BUTTON1_MASK BUTTON2_MASK BUTTON3_MASK CTRL_MASK META_MASK SHIFT_MASK import import import import java.applet.*; java.awt.*; java.awt.event.*; java.util.*; public class PuntosModificados extends Applet implements MouseListener { Vector puntos = new Vector(); Vector colores = new Vector(); public void init() { this.addMouseListener(this); } public void mouseClicked(MouseEvent e) { puntos.addElement(e.getPoint()); int tecla = e.getModifiers(); if ((tecla & InputEvent.SHIFT_MASK) != 0) colores.addElement(Color.red); else colores.addElement(Color.blue); this.repaint(); } Ejemplo public public public public void void void void mousePressed(MouseEvent e) {} mouseReleased(MouseEvent e) {} mouseEntered(MouseEvent e) {} mouseExited(MouseEvent e) {} public void paint(Graphics g) { Enumeration e = puntos.elements(); Enumeration c = colores.elements(); while (e.hasMoreElements()) { Point p = (Point) e.nextElement(); Color color = (Color) c.nextElement(); g.setColor(color); g.fillOval(p.x-5, p.y-5, 10, 10); } } } Adapters (Adaptadores) • Implementan a la mayoría de los Listener • Los métodos de los Listeners implementados no hacen nada • En lugar de implementar un Listener se crea una subclase de un adaptador, de esta manera no se necesita programar todos los métodos del Listener • Reducen escritura de código, programando solamente los métodos necesarios MouseAdapter import java.applet.Applet; import java.awt.*; import java.awt.Toolkit; import java.awt.event.*; public class Beep1 extends Applet{ Button fuente = new Button("Presióname"); ManejaMouse escuchador = new ManejaMouse(); public void init() { add(fuente); fuente.addMouseListener(escuchador); } } class ManejaMouse implements MouseListener{ public void mouseClicked(MouseEvent e){ Toolkit.getDefaultToolkit().beep(); } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} Ejemplo } Ejemplo import java.applet.Applet; import java.awt.*; import java.awt.Toolkit; import java.awt.event.*; public class Beep1 extends Applet{ Button fuente = new Button("Presióname"); ManejaMouse escuchador = new ManejaMouse(); public void init() { add(fuente); fuente.addMouseListener(escuchador); } } class ManejaMouse extends MouseAdapter{ public void mouseClicked(MouseEvent e){ Toolkit.getDefaultToolkit().beep(); } } Consumiendo eventos • Evita el proceso normal de un evento por el componente que lo genera • El evento es despachado a todos los escuchadores • Sólo se aplica a los eventos de bajo nivel de entrada (input events) • public void consume() • Ejemplo: Botón en un ambiente gráfico Ejemplo • TextField que solamente acepte números • Podemos filtrar las letras y otras teclas, pero estás de todas maneras serán procesadas en forma normal por el componente textField (se desplegarán a medida que se vayan tecleando) • Si consumimos alguno de los eventos generados (letras tecleadas), ya no serán procesados por el componente Ejemplo import java.awt.*; import java.awt.event.*; import java.applet.*; public class ConsumeTeclas extends Applet{ TextField texto = new TextField(20); public void init(){ add(new Label("Teclea Sólo números:")); add(texto); texto.addKeyListener(new ManejaTeclas()); } } class ManejaTeclas extends KeyAdapter{ public void keyPressed(KeyEvent e) { int c = e.getKeyCode(); if (ce.VK_9) e.consume(); } } Listeners y Adapters Listener Adapter Métodos Eventos generados por componentes Component AWT Eventos que generan Desarrollo de un objeto con funcionalidad independiente “MiBotón” Requisitos de MiBoton • Funcionalidad independiente – Retroalimentación gráfica al “click” sobre el botón, independiente del contexto donde se ponga • Tamaño variable – Para poder utilizarlo en cualquier contexto gráfico (Layout) • Funcionalidad – Poder asignarle un Listener, para que sirva de algo!!!! MiBotón (1) import java.awt.*; import java.awt.event.*; public class MiBoton1 extends Canvas implements MouseListener{ boolean presionado = false; Color color; public MiBoton1(Color color){ super(); this.color = color; addMouseListener(this); } public void paint(Graphics g){ int diametro; Dimension tamano = new Dimension(getSize()); if (tamano.width < tamano.height) diametro = tamano.width; else diametro = tamano.height; setSize(diametro,diametro); g.setColor(color); if (presionado) g.setColor(color.darker()); g.fillOval(0,0,diametro-1,diametro-1); if (presionado) g.setColor(Color.white); else g.setColor(Color.black); g.drawOval(0,0,diametro-1,diametro-1); g.drawOval(1,1,diametro-3,diametro-3); } public void mousePressed(MouseEvent e){ presionado=true; repaint(); } public void mouseClicked(MouseEvent e){ } public void mouseReleased(MouseEvent e){ presionado=false; repaint(); } public void mouseEntered(MouseEvent e){ } public void mouseExited(MouseEvent e){ } } MiBotón (1) import java.applet.*; import java.awt.event.*; import java.awt.*; public class MisBotones1 extends Applet{ MiBoton1 boton1 = new MiBoton1(Color.red); MiBoton1 boton2 = new MiBoton1(Color.blue); public void init(){ setLayout(new BorderLayout()); add(boton1,"Center"); add(boton2,”North"); } } • Problemas con el tamaño cuando el applet no puede deducir que tamaño asignarle import java.awt.*; import java.awt.event.*; public class MiBoton2 extends Canvas implements MouseListener{ boolean presionado = false; Color color; public MiBoton2(Color color){ super(); this.color = color; addMouseListener(this); } public void paint(Graphics g){ int diametro; Dimension tamano = new Dimension(getSize()); MiBoton (2) diametro = Math.min(tamano.width,tamano.height); setSize(diametro,diametro); g.setColor(color); if (presionado) g.setColor(color.darker()); g.fillOval(0,0,diametro-1,diametro-1); if (presionado) g.setColor(Color.white); else g.setColor(Color.black); g.drawOval(0,0,diametro-1,diametro-1); g.drawOval(1,1,diametro-3,diametro-3); } public Dimension getPreferredSize(){ return new Dimension(50,50); } public void mousePressed(MouseEvent e){ presionado=true; repaint(); } public void mouseClicked(MouseEvent e){ } public void mouseReleased(MouseEvent e){ presionado=false; repaint(); } public void mouseEntered(MouseEvent e){ } public void mouseExited(MouseEvent e){ } } MiBoton (2) import java.applet.*; import java.awt.event.*; import java.awt.*; public class MisBotones2 extends Applet{ MiBoton2 boton1 = new MiBoton2(Color.blue); MiBoton2 boton2 = new MiBoton2(Color.red); public void init(){ setLayout(new BorderLayout()); add(boton1,"Center"); add(boton2,"North"); } } • Problema: el área que responde al ratón cubre “terreno” que está fuera del círculo • Solucionarlo Usando Miboton import java.applet.*; import java.awt.event.*; import java.awt.*; public class MisBotones extends Applet{ MiBoton botonTextoAzul = new MiBoton(Color.blue); MiBoton botonTextoRojo = new MiBoton(Color.red); MiBoton botonTextoVerde = new MiBoton(Color.green); MiBoton botonFondoAzul = new MiBoton(Color.blue); MiBoton botonFondoRojo = new MiBoton(Color.red); MiBoton botonFondoVerde = new MiBoton(Color.green); TextArea texto = new TextArea(); Panel botonesTexto = new Panel(new FlowLayout(FlowLayout.CENTER)); Panel botonesFondo = new Panel(new FlowLayout(FlowLayout.CENTER)); : : : Usando Miboton : : public void init(){ setLayout(new BorderLayout()); botonesTexto.add(botonTextoAzul); botonesTexto.add(botonTextoRojo); botonesTexto.add(botonTextoVerde); botonesFondo.add(botonFondoAzul); botonesFondo.add(botonFondoRojo); botonesFondo.add(botonFondoVerde); add(botonesTexto,"North"); add(texto,"Center"); add(botonesFondo,"South"); ClickRaton c = new ClickRaton(); botonTextoAzul.addMouseListener(c); botonTextoRojo.addMouseListener(c); botonTextoVerde.addMouseListener(c); botonFondoAzul.addMouseListener(c); botonFondoRojo.addMouseListener(c); botonFondoVerde.addMouseListener(c); } : : : Usando Miboton : : : class ClickRaton extends MouseAdapter{ public void mouseClicked(MouseEvent e){ MiBoton b = new MiBoton(Color.black); b = (MiBoton) e.getSource(); if (b.equals(botonTextoAzul)) texto.setForeground(Color.blue); else if (b.equals(botonTextoRojo)) texto.setForeground(Color.red); else if (b.equals(botonTextoVerde)) texto.setForeground(Color.green); else if (b.equals(botonFondoAzul)) texto.setBackground(Color.blue); else if (b.equals(botonFondoRojo)) texto.setBackground(Color.red); else if (b.equals(botonFondoVerde)) texto.setBackground(Color.green); } } } Administradores de diseño CardLayout y GridBagLayout CardLayout • Similar a las cartas en una baraja, de la cual puedes ver una sola a la vez • Se pueden mostrar cada una de las cartas: – Pidiendo la primera o última carta del Layout (en el orden en que fueron agregadas al contenedor) – Pidiendo carta siguiente o anterior en forma secuencial – Especificando una de las cartas con un nombre específico CardLayout • Para agregar componentes se debe usar: – add(componente,nombre) • Métodos de acceso: – – – – – public public public public public void void void void void first(Container parent) next(Container parent) previous(Container parent) last(Container parent) show(Container parent, String name) • Los anteriores son métodos de la clase CardLayout, cuidado! import java.awt.*; import java.awt.event.*; import java.applet.*; public class TarjetaLayout extends Applet implements ActionListener, ItemListener{ Panel p1 = new Panel(); Panel p2 = new Panel(); Panel p3 = new Panel(); Panel c = new Panel(); Panel botones = new Panel(); Button b1 = new Button("Primero"); Button b2 = new Button("Ultimo"); Button b3 = new Button(">>"); Button b4 = new Button("<<"); Choice opcion = new Choice(); CardLayout tarjeta = new CardLayout(); Ejemplo public void init(){ setLayout(new BorderLayout()); opcion.addItem(""); opcion.addItem("Primera"); opcion.addItem("Segunda"); opcion.addItem("Tercera"); botones.add(b1); botones.add(b4); botones.add(b3); botones.add(b2); p1.add(new Label("Este es la primera")); p1.add(new Button("Botón")); p2.add(new Label("Este es la segunda")); p2.add(new TextField(20)); p3.add(new Label("Este es la tercera")); c.setLayout(tarjeta); c.add(p1,"uno"); c.add(p2,"dos"); c.add(p3,"tres"); add(opcion,"North"); add(c,"Center"); add(botones,"South"); b1.addActionListener(this); b2.addActionListener(this); b3.addActionListener(this); b4.addActionListener(this); opcion.addItemListener(this); } public void actionPerformed(ActionEvent e){ if (e.getSource().equals(b3)) tarjeta.next(c); else if (e.getSource().equals(b4)) tarjeta.previous(c); else if (e.getSource().equals(b1)) tarjeta.first(c); else if (e.getSource().equals(b2)) tarjeta.last(c); opcion.select(0); } public void itemStateChanged(ItemEvent e){ switch (opcion.getSelectedIndex()){ case 1: ((CardLayout)c.getLayout()).show(c,"uno"); break; case 2: ((CardLayout)c.getLayout()).show(c,"dos"); break; case 3: ((CardLayout)c.getLayout()).show(c,"tres"); break; } } } Ejemplo GridBagLayout • Despliega componentes en un enrejado de renglones y columnas • A diferencia del GridLayout las celdas no están restringidas a ser de igual tamaño • No necesita que los componentes sean del mismo tamaño • Mantiene un enrejado rectangular dinámico de celdas, en el cual los componentes puede ocupar una o más celdas GridBagConstrains • Cada componente de un GridBagLayout tiene asociada una instancia de esta clase (GridBagConstrains) • Especifica la manera en que será desplegado un componente particular • Tiene varias variables de instancia que especifican como se desplegará un objeto que tenga asociado una instancia de esta clase Variables de GridBagConstrains • gridx, gridy – Especifica la celda de la esquina superior izquierda del componente (gridx=0 y gridy=0 celda de la esquina superior izquierda del Layout). Default es GridBagConstrains.RELATIVE que define que el componente se coloque a la izquierda (gridx) o abajo (gridy) del componente agregado justo antes. • gridwidth, gridheight – Define el número de celdas que ocupa el componente horizontal (gridwidth) y verticalmente (gridheight). El default es 1. GridBagConstrains.REMAINDER (default) indica que el componente es el último de su renglón (gridwidth) o columna (gridheight). GridBagConstrains.RELATIVE indica que el componente es el penúltimo de su renglón (gridwidth) o columna (gridheight). Variables de GridBagConstrains • fill – Para especificar como el componente llenará el área asignada, en caso de que ésta sea de mayor tamaño que el componente. GridBagConstrains.NONE (default), GridBagConstrains.HORIZONTAL (el componente llena su área horizontal, pero no cambia su altura, GridBagConstrains.VERTICAL (llena su área vertical, pero no cambia su ancho), GridBagConstrains.BOTH (llena su área completamente) • insets – Define el espacio mínimo entre componentes • ipadx, ipady – Especifica el relleno interno del componente, es decir cuanto se le añadirá al tamaño mínimo de éste (minumum size), tanto horizontal (ipadx) como horizontalmente (ipady) Variables de GridBagConstrains • anchor – Alineación del componente dentro del su área definida, en caso de el componente sea más pequeño que el área asignada a él. GridBagConstrains.CENTER (default), GridBagConstrains.NORTH, GridBagConstrains..NORTHEAST, GridBagConstrains.EAST, GridBagConstrains.SOUTEAST, GridBagConstrains.SOUTH, GridBagConstrains.SOUTHWEST, GridBagConstrains.WEST, GridBagConstrains.NORTHWEST • weightx, weighty – Especifica como se distribuye el área total del Layout por componente (valor entre 0.0 y 1.0), es importante en caso de que se cambie el tamaño del Layout. Default para ambos es 0.0 import java.awt.*; public class LayoutGridBag1 extends Frame{ Label lApellido = new Label("Apellido: "); Label lNombre = new Label("Nombre: "); TextField tApellido = new TextField(); TextField tNombre = new TextField(); GridBagLayout g = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); Ejemplo public LayoutGridBag1(){ setLayout(g); c.fill = GridBagConstraints.BOTH; c.gridx = 0; c.gridy = 0; c.gridwidth = 1; c.gridheight = 1; c.weightx = 0.0; c.weighty = 0.0; g.setConstraints(lApellido,c); add(lApellido); c.gridy = 1; g.setConstraints(lNombre,c); add(lNombre); c.gridx = 1; c.gridy = 0; c.weightx = 1.0; g.setConstraints(tApellido,c); add(tApellido); c.gridy = 1; g.setConstraints(tNombre,c); add(tNombre); pack(); show(); } public static void main(String args[]){ new LayoutGridBag1(); } Ejemplo Ejemplo (LayoutGridBag2) Label letrero = new Label("Ejemplo 2 de GriBagLayout"); Button boton1 = new Button("Botón 1"); Button boton2 = new Button("Botón 2"); Button boton3 = new Button("Botón 3"); TextField texto = new TextField(); Choice choice = new Choice(); List lista = new List(); TextArea area = new TextArea(); GridBagLayout g = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); setLayout(g); c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.gridwidth = GridBagConstraints.REMAINDER; g.setConstraints(letrero,c); letrero.setAlignment(Label.CENTER); add(letrero); c.gridwidth = 1; c.weightx = 0.0; c.fill = GridBagConstraints.NONE; g.setConstraints(boton1,c); add(boton1); g.setConstraints(boton2,c); add(boton2); c.gridwidth = GridBagConstraints.REMAINDER; g.setConstraints(boton3,c); add(boton3); c.gridwidth = 2; c.gridheight = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.weighty = 1.0; g.setConstraints(area,c); add(area); c.weightx = 0.0; c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = 1; g.setConstraints(lista,c); add(lista); c.weighty = 0.0; c.gridheight = GridBagConstraints.REMAINDER; g.setConstraints(choice,c); add(choice); pack(); show(); Ejemplo (LayoutGridBag2) Ejemplo (LayoutGridBag2) Ejemplo (LayoutGridBag3) Label letrero = new Label("Ejemplo 3 de GriBagLayout"); Button boton1 = new Button("Botón 1"); Button boton2 = new Button("Botón 2"); Button boton3 = new Button("Botón 3"); TextField texto = new TextField(); Choice choice = new Choice(); List lista = new List(); TextArea area = new TextArea(); GridBagLayout g = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); Ejemplo (LayoutGridBag3) setBackground(Color.lightGray); setSize(500,300); letrero.setBackground(Color.blue); letrero.setForeground(Color.white); letrero.setFont(new Font("Serif",Font.BOLD,14)); letrero.setAlignment(Label.CENTER); area.setBackground(Color.red); lista.setBackground(Color.yellow); Ejemplo (LayoutGridBag3) public void estableceDefaults(GridBagConstraints c){ c.gridx = GridBagConstraints.RELATIVE; c.gridy = GridBagConstraints.RELATIVE; c.gridwidth = 1; c.gridheight = 1; c.fill = GridBagConstraints.NONE; c.ipadx = 0; c.ipady = 0; c.anchor = GridBagConstraints.CENTER; c.weightx = 0.0; c.weighty = 0.0; } estableceDefaults(c); c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.gridwidth = GridBagConstraints.REMAINDER; g.setConstraints(letrero,c); add(letrero); estableceDefaults(c); c.weightx = 1.0; g.setConstraints(boton1,c); add(boton1); g.setConstraints(boton2,c); add(boton2); estableceDefaults(c); c.weightx = 0.0; c.gridwidth = GridBagConstraints.REMAINDER; g.setConstraints(boton3,c); add(boton3); estableceDefaults(c); c.gridwidth = 2; c.gridheight = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.weighty = 1.0; g.setConstraints(area,c); add(area); Ejemplo (LayoutGridBag3) estableceDefaults(c); c.weighty = 1.0; c.fill = GridBagConstraints.BOTH; c.gridwidth = GridBagConstraints.REMAINDER; g.setConstraints(lista,c); add(lista); estableceDefaults(c); c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.HORIZONTAL; g.setConstraints(choice,c); add(choice); Ejemplo (LayoutGridBag3) Aplicación con interfaz gráfica Cubriremos las clases Frame, Menu, MenuBar, WindowAdapter Además veremos como se puede ejecutar la aplicación desde Windows sin la necesidad de que se abra un ventana de DOS Frame • Un Frame es una ventana con un título y un borde • Generan los siguientes eventos: WindowOpened, WindowClosing, WindowClosed, WindowIconified, WindowDeiconified, WindowActivated, WindowDeactivated. • Todas las aplicaciones con interfaz gráfica necesitan crear un frame para poder desplegarse • Los applets también pueden abrir frames, estos se abren como ventanas independientes • El Layout por default de un frame es BorderLayout import java.awt.*; import java.awt.event.*; public class Aplicacion extends Frame{ public Aplicacion(){ setTitle("Aplicación"); setSize(300,300); setLocation(100,100); show(); } public static void main(String args[]){ new Aplicacion(); } Aplicación } : : Panel botones = new Panel(new GridLayout(8,0,0,10)); Button boton1 = new Button("Insertar"); Button boton2 = new Button("Borrar"); Button boton3 = new Button("Imprimir"); Button boton4 = new Button("Terminar"); TextArea texto = new TextArea(); : : botones.add(new Label("Opciones")); botones.add(new Label()); botones.add(new Label()); botones.add(new Label()); botones.add(boton1); botones.add(boton2); botones.add(boton3); botones.add(boton4); add(texto,"Center"); add(botones,"East"); : : Aplicación Aplicación public class Aplicacion extends Frame implements ActionListener{ : : boton4.addActionListener(this); : : public void actionPerformed(ActionEvent e){ dispose(); System.exit(0); } : : • dispose() – Destruye el frame, libera los recursos que tiene • System.exit(0) – Termina la ejecución de la máquina virtual, por convención un valor diferente de cero indica condición de error WindowListener WindowAdapter : : ManejaVentana mv = new ManejaVentana(this); addWindowListener(mv); : : class ManejaVentana extends WindowAdapter{ Frame f; public ManejaVentana(Frame f){ this.f = f; } public void windowClosing(WindowEvent e){ f.dispose(); System.exit(0); } Aplicación } Menu y MenuBar • Menús pueden existir sólo en Barras de Menú (MenuBar) • Y las barras de menú pueden existir sólo en frames • Items se agregan a Menu con add() • Menu se agrega a MenuBar con add() • La barra de menú se agrega al Frame con setMenuBar() : : MenuBar barraMenu = new MenuBar(); Menu menu1 = new Menu("Menu 1"); Menu menu2 = new Menu("Menu 2"); : : menu1.add("Opción 1"); menu1.add("Opción 2"); menu1.add("Opción 3"); menu2.add("Opción I"); menu2.add("Opción II"); menu2.add("Opción III"); barraMenu.add(menu1); barraMenu.add(menu2); setMenuBar(barraMenu); Aplicación : : MenuBar barraMenu = new MenuBar(); Menu menu1 = new Menu("Menu 1"); Menu menu2 = new Menu("Menu 2"); MenuItem m11 = new MenuItem("Opción 1"); MenuItem m12 = new MenuItem("Opción 2"); MenuItem m13 = new MenuItem("Opción 3"); MenuItem m21 = new MenuItem("Opción I"); MenuItem m22 = new MenuItem("Opción II"); MenuItem m23 = new MenuItem("Opción III"); Menu m24 = new Menu("Opción IV"); MenuItem m241 = new MenuItem("SubOpción IV"); : : menu1.add(m11); menu1.add(m12); menu1.add(m13); m21.setEnabled(false); menu2.add(m21); m22.setShortcut(new MenuShortcut(KeyEvent.VK_5)); menu2.add(m22); menu2.addSeparator(); menu2.add(m23); m24.add(m241); menu2.add(m24); barraMenu.add(menu1); barraMenu.add(menu2); setMenuBar(barraMenu); : Aplicación Aplicación : MenuItem m13 = new MenuItem("Salir"); : m13.addActionListener(this); : public void actionPerformed(ActionEvent e){ dispose(); System.exit(0); } : Aplicación import java.awt.*; import java.awt.event.*; public class Aplicacion extends Frame implements ActionListener{ Panel botones = new Panel(new GridLayout(8,0,0,10)); Button boton1 = new Button("Insertar"); Button boton2 = new Button("Borrar"); Button boton3 = new Button("Imprimir"); Button boton4 = new Button("Terminar"); TextArea texto = new TextArea(); MenuBar barraMenu = new MenuBar(); Menu menu1 = new Menu("Menu 1"); Menu menu2 = new Menu("Menu 2"); MenuItem m11 = new MenuItem("Opción 1"); MenuItem m12 = new MenuItem("Opción 2"); MenuItem m13 = new MenuItem("Salir"); MenuItem m21 = new MenuItem("Opción I"); MenuItem m22 = new MenuItem("Opción II"); MenuItem m23 = new MenuItem("Opción III"); Menu m24 = new Menu("Opción IV"); MenuItem m241 = new MenuItem("SubOpción IV"); public Aplicacion(){ setTitle("Aplicación"); setSize(300,300); setLocation(100,100); botones.add(new Label("Opciones")); botones.add(new Label()); botones.add(new Label()); botones.add(new Label()); botones.add(boton1); botones.add(boton2); botones.add(boton3); botones.add(boton4); add(texto,"Center"); add(botones,"East"); menu1.add(m11); menu1.add(m12); menu1.add(m13); m21.setEnabled(false); menu2.add(m21); m22.setShortcut(new MenuShortcut(KeyEvent.VK_5)); menu2.add(m22); menu2.addSeparator(); menu2.add(m23); m24.add(m241); menu2.add(m24); barraMenu.add(menu1); barraMenu.add(menu2); setMenuBar(barraMenu); m13.addActionListener(this); boton4.addActionListener(this); ManejaVentana mv = new ManejaVentana(this); addWindowListener(mv); show(); } Aplicación Aplicación public void actionPerformed(ActionEvent e){ dispose(); System.exit(0); } public static void main(String args[]){ System.out.println("Inicio"); new Aplicacion(); System.out.println("Final"); } } class ManejaVentana extends WindowAdapter{ Frame f; public ManejaVentana(Frame f){ this.f = f; } public void windowClosing(WindowEvent e){ f.dispose(); System.exit(0); } } Manejo de Excepciones Excepciones • Una excepción es un evento que sucede durante la ejecución normal de un programa y ocasiona que se cambie el flujo normal de instrucciones • Java maneja excepciones para indicar que ha ocurrido una condición anormal • Los métodos arrojan excepciones Excepciones • Java obliga a utilizar excepciones para evitar caer en errores que ocasionen que el programa termine en forma anormal y/o afecte el funcionamiento del sistema • Java provee un mecanismo para atrapar excepciones, el cual nos da un puerta de escape en caso de que ocurra algún error y poder continuar con la ejecución del programa Excepciones • Nos ahorran código, ya que no tenemos que realizar toda la verificación de una posible acción (ej. abrir un archivo) • Java establece una serie de excepciones que tienen que arrojar ciertos métodos • Podemos programar nuestros métodos para que arrojen excepciones creadas por nosotros import java.io.*; public class NoCompila { private FileReader entrada; public NoCompila(String nombreArchivo) { entrada = new FileReader(nombreArchivo); } } Ejemplo import java.io.*; public class SiCompila { try /catch private FileReader entrada; public SiCompila(String nombreArchivo) { try{ entrada = new FileReader(nombreArchivo); }catch (FileNotFoundException e){} } } • La forma de verificar si es posible realizar alguna instrucción sin problemas, en caso contrario se atrapa la excepción arrojada Ejemplo import java.io.*; public class Excepciones { public static void main (String[] args){ FileReader entrada; String nombreArchivo = args[0]; try{ entrada = new FileReader(nombreArchivo); System.out.println("Archivo abierto sin problemas"); }catch (FileNotFoundException e){ System.out.println("Archivo no existe"); } System.out.println("Programa terminó normalmente"); } } throws • Indica que un método arroja una excepción determinada y ésta debe ser atrapada con catch para poder utilizarlo Excepciones • Se pueden atrapar todas las excepciones particulares de cada método o agrupar varias llamadas a métodos y atrapar las excepciones en bloque • Depende del diseño de tu programa y de la legibilidad de código que quieras Ejemplo import java.io.*; public class Excepcion { public static void main (String[] args){ FileReader entrada; try{ String nombreArchivo = args[0]; String entero = args[1]; entrada = new FileReader(nombreArchivo); System.out.println("Archivo abierto sin problemas"); System.out.println(Integer.parseInt(entero)*2); }catch (FileNotFoundException e){ System.out.println("Archivo no existe"); }catch (NumberFormatException e){ System.out.println("Número no adecuado"); }catch (ArrayIndexOutOfBoundsException e){ System.out.println("Faltan argumentos"); } System.out.println("Programa terminó normalmente"); } } Ejemplo import java.io.*; public class ExcepcionF { public static void main (String[] args){ FileReader entrada; try{ String nombreArchivo = args[0]; String entero = args[1]; entrada = new FileReader(nombreArchivo); System.out.println("Archivo abierto sin problemas"); System.out.println(Integer.parseInt(entero)*2); }catch (FileNotFoundException e){ System.out.println("Archivo no existe"); }catch (NumberFormatException e){ System.out.println("Número no adecuado"); }finally{ System.out.println("Siempre se ejecuta"); } System.out.println("Programa terminó normalmente"); } } finally finally • finally siempre se ejecuta • Nos permite hacer una limpieza de los recursos que un método pudo haber dejado abiertos o en uso por la finalización abrupta debido a una excepción • Eso nos evita el tener que duplicar código en cada catch para hacer la limpieza Programación de Hilos (Threads) Hilos (Threads) • Contexto de ejecución, proceso liviano (lightweight) • Un flujo secuencial de instrucciones dentro de un programa Hilo Programa Multiprocesos vs Multihilos • Multiproceso: – Dos o más programas (procesos) independientes ejecutándose en forma “paralela” – Cada proceso tiene su propio espacio de memoria, su propio conjunto de variables, su propia pila, etc. – El control lo tiene el sistema operativo • Multihilo: – Dos o más “tareas” ejecutándose en forma “paralela” dentro de un programa – Comparten los recursos del programa – El control lo tiene el programa Programa Multihilo Recursos variables, pila, archivos, sockets, etc. Hilos Hilos Multihilos en Java • Java tiene un soporte natural para multihilos • main, Garbage Collection, actualizaciones de pantalla; todos corren en su propio hilo • Al contrario de multiproceso en el cual cada programa es independiente, en multihilo el programador tiene la responsabilidad de que los hilos se ejecuten en forma adecuada, ya que todos comparten los recursos del programa, y se tiene que poner especial atención en no caer en problemas como dead-lock y starvation ¿Por qué usar hilos? • Hacer un mejor uso de los recursos – Se pueden ejecutar tareas en el fondo (background) mientras se espera por entrada del usuario • Evitar bloqueo del programa – Ejecutar tareas mientras se está leyendo de disco o se espera por una conexión de red • Programas más adecuados – Desplegar barra de progreso mientras se realiza alguna tarea tardada • Programación más elegante y “fácil” – Más estructuración en la programación • “Imprescindible” para animaciones El método run() • Método de la clase Thread, es el que realiza el trabajo, el que se llama para que arranque un hilo su ejecución • Esté método es el que se tiene que redefinir (override) para que tu hilo haga algo • El método run en la clase Thread no hace nada • Cuando un objeto tiene en ejecución el método run(), ese hilo está compitiendo con los demás hilos activos por recursos del sistema (CPU) • Cuando un objeto termina la ejecución de su método run(), el hilo se muere Dos maneras de crear un hilo de ejecución • Extender la clase Thread, reprogramando el método run()que está vacio – La manera natural de crear hilos • Implementar la interfaz Runnable, programando el método run() – En caso de que los objetos que se quieren ejecutar en un hilo pertenezcan a una clase que extiende a otra La clase Thread Comentarios preliminares • El arranque de hilos se realiza en dos pasos: – Crear una instancia de la clase Thread – Llamar al método run() del objeto creado • La llamada al método run() no se hace directamente, sino que se llama al método start() del objeto, esto causa que la máquina virtual llame a run() • El método sleep(long x) de la clase Thread, ocasiona que el hilo deje de competir por los recursos durante x milisegundos, después de ese tiempo, comienza a pelear por recursos otra vez • Al llamar a start, automáticamente hay dos hilos corriendo, el que se arrancó con start() y el que ejecutó la llamada Extendiendo la clase Thread public class Hilos1{ public static void main(String[] args){ Hilo1 h1 = new Hilo1("Uno"); Hilo1 h2 = new Hilo1("Dos"); h1.start(); h2.start(); } } class Hilo1 extends Thread{ String s; public Hilo1(String s){ this.s = s; } public void run(){ for(int i=0; i<10; i++){ System.out.println(s+" "+i); try{ sleep(Math.round(Math.random()*1000)); }catch(InterruptedException e){} } } } Implementando Runnable public class Hilos2{ public static void main(String[] args){ Hilo1 h1 = new Hilo1("Uno"); Hilo1 h2 = new Hilo1("Dos"); Thread t1 = new Thread(h1); Thread t2 = new Thread(h2); t1.start(); t2.start(); } } class Hilo1 implements Runnable{ String s; public Hilo1(String s){ this.s = s; } public void run(){ for(int i=0; i<10; i++){ System.out.println(s+" "+i); try{ Thread.sleep(Math.round(Math.random()*1000)); }catch(InterruptedException e){} } } } Estados de un hilo • Hilo nuevo – Hilo recién creado • Ejecutable – Compitiendo por CPU • Detenido – No compitiendo por CPU • Muerto Estados de un hilo New Thread() start() yield() - sleep(x) - wait() - bloqueado en I/O - suspend() Nuevo - El método run() terminó su ejecución - stop() Ejecutable Detenido - Transcurrieron x msegs - notify() o notifyAll() - se completó I/O - resume() Muerto Estados de un hilo • new Tread(...) – Creado, pero no todavía no comienza ejecución • start() – crea los recursos necesarios para su ejecución, lo deja listo para que la máquina virtual lo ponga a correr llamando al método run(), compite por los recursos del sistema • Bloqueado por I/O, sleep() o wait() – La máquina virtual puede seleccionar otro hilo para ejecución, para salir de este estado la acción debe de corresponder a la acción que lo bloqueó • Muerto – Terminó run(), una vez muerto un hilo no puede volver a ejecución import java.awt.*; import java.applet.*; import java.awt.event.*; public class Hilos3 extends Applet implements ActionListener{ Ejemplo Button boton1 = new Button boton2 = new Button boton3 = new TextField cuenta1 = TextField cuenta2 = TextField cuenta3 = Cuenta t1, t2, t3; Button("Para el 1"); Button("Para el 2"); Button("Para el 3"); new TextField("0"); new TextField("0"); new TextField("0"); public void init(){ setLayout(new GridLayout(2,3)); add(cuenta1); add(cuenta2); add(cuenta3); add(boton1); add(boton2); add(boton3); boton1.addActionListener(this); boton2.addActionListener(this); boton3.addActionListener(this); } public void start(){ t1 = new Cuenta(500,cuenta1); t2 = new Cuenta(1000,cuenta2); t3 = new Cuenta(2000,cuenta3); t1.start(); t2.start(); t3.start(); } public void stop(){ t1.contando = false; t2.contando = false; t3.contando = false; } public void actionPerformed(ActionEvent e){ if (e.getSource().equals(boton1)) t1.contando = false; else if (e.getSource().equals(boton2)) t2.contando = false; else if (e.getSource().equals(boton3)) t3.contando = false; } } Ejemplo class Cuenta extends Thread{ long deltaT; int cuenta=0; TextField caja; boolean contando = true; public Cuenta(long deltaT, TextField caja){ this.deltaT = deltaT; this.caja = caja; } public void run(){ while(contando){ cuenta ++; caja.setText(Integer.toString(cuenta)); try{ sleep(deltaT); } catch (InterruptedException e){} } caja.setText("Ya se murió"); } } Ejemplo Prioridades • Todos los hilos tienen una prioridad relativa a otros hilos • La máquina virtual selecciona al hilo de mayor prioridad en estado ejecutable y lo pone a correr • El hilo que está en ejecución hasta: – llama a yield() – Pasa a estado no ejecutable (parado) – otro hilo de mayor prioridad pasa a estado ejecutable • • • • Un hilo hereda su prioridad del hilo que lo crea La prioridad de un hilo se puede modificar con setPriority(int) Las constantes disponibles MIN_PRIORITY, NORM_PRIORITY, MAX_PRIORITY Si un hilo de alta prioridad se pone en ejecución y no tiene nada de I/O puede acaparar todo el CPU (hilos egoistas, selfish threads) • Es conveniente que el hilo ejecute yield() o sleep() a intervalos regulares para dar la oportunidad de que otros hilos puedan correr • yield() sólo cede el CPU a hilos de igual prioridad Constructores Sincronización de hilos • Es necesario sincronizar el acceso a recursos compartidos para evitar inconsistencias en los resultados • Si dos hilos acceden a un mismo recurso, el orden de ejecución es impredecible, depende de la máquina virtual y otros factores del sistema (carga, ejecución de otros hilos, etc) • Java implementa un mecanismo de monitores, si un objeto es identificado con synchronized se le asocia un candado (lock) • Un monitor permite el acceso serializado y no simultáneo a un objeto synchronized • Hilos que quieran acceder a un objeto sincronizado se ponen en fila de espera hasta que el objeto quede desocupado (unlock) • Sólo un hilo puede estar dentro de un objeto sincronizado • Se recomienda utilizar synchronized a nivel método, pero puede sincronizar cualquier sección de código (sección crítica) • Cada objeto tiene un solo candado, si un hilo entra a un método sincronizado, el objeto pone el candado a todos los métodos sincronizados, es decir ningún otro hilo puede ejecutar ningún método sincronizado del objeto, hasta que el hilo poseedor del candado lo libere • La manera de liberar el candado en un objeto es cuando se termina la ejecución del un método sincronizado • No vale la pena sincronizar asignaciones de algunos datos primitivos porque son atómicas • Excesiva sincronización tiene un impacto relevante en el rendimiento Ejemplo Contador contador Incrementa Imprime Decrementa Imprime Suma Resta public class NoSincronizado{ public static void main(String args[]){ Contador c = new Contador(); Suma s = new Suma(c); Resta r = new Resta(c); s.start(); r.start(); } } class Contador{ public int contador = 0; public void sumaUno(){ contador++; System.out.print("Suma: "); System.out.println(contador); } public void restaUno(){ contador--; System.out.print("Resta: "); System.out.println(contador); } Ejemplo class Suma extends Thread{ Contador c; public Suma(Contador c){ this.c = c; } public void run(){ for(int i=0;i<10;i++) c.sumaUno(); } } class Resta extends Thread{ Contador c; public Resta(Contador c){ this.c = c; } public void run(){ for(int i=0;i<10;i++) c.restaUno(); } } } Ejemplo public class Sincronizado{ public static void main(String args[]){ Contador c = new Contador(); Suma s = new Suma(c); Resta r = new Resta(c); s.start(); r.start(); } } Ejemplo class Suma extends Thread{ Contador c; public Suma(Contador c){ this.c = c; } public void run(){ for(int i=0;i<10;i++) c.sumaUno(); } } class Resta extends Thread{ Contador c; public Resta(Contador c){ this.c = c; } public void run(){ for(int i=0;i<10;i++) c.restaUno(); } } class Contador{ public int contador = 0; synchronized void sumaUno(){ contador++; System.out.print("Suma: "); System.out.println(contador); } synchronized void restaUno(){ contador--; System.out.print("Resta: "); System.out.println(contador); } } Ejemplo wait() y notify() • Son miembros de la clase java.lang.Object • Se llaman desde métodos o bloques sincronizados • wait() hace que un hilo ceda su candado sobre un objeto y para su ejecución • notify() elige un hilo que este esperando (en wait) y lo despierta • Si hay varios hilos esperando se despertará al de prioridad más alta • Si hay varios hilos de igual prioridad esperando no se garantiza cual es que será despertado • Los hilos se ponen en fila de espera para accesar un objeto con monitor si: – tratan de llamar un método sincronizado mientras otro hilo está usando el objeto – llaman explícitamente a wait() dentro de un método sincronizado • notifyAll() despierta a todos los hilos y compiten por el CPU Recomendaciones • No usar stop(), suspend() o resume() • Cuidado con la sincronización excesiva • Usar notifyAll() en lugar de notify() • Reducir las prioridades de los hilos de tarea en el fondo o animaciones Manejo de Gráficas Imágenes y Animación La clase Canvas • La clase Canvas debe ser extendida, es decir debe ser superclase de alguna clase que programes, ya que no hace nada por si sola • Es una manera de que puedas implementar tu propio componente, dándole el funcionamiento que desees (un ejemplo más adelante) • También es útil como área de dibujo y para desplegar imágenes • Cuando se utiliza Canvas hay que tener mucho cuidado con programar los métodos minimumSize() y preferredSize(), para que reflejan el tamaño que deseas en tu objeto tipo Canvas, porque corres el peligro de que tu canvas tome un tamaño muy pequeño o definitivamente sea invisible • Lo anterior depende de que Layout utilices dentro de tu contenedor para asignarle espacio a tu objeto Canvas Coordenadas de un componente (0,0) x Componente y (ancho-1,alto-1) width height minimumSize() y preferredSize() • Cuando un layout trata de desplegar sus componentes ejecuta estos métodos en todos los objetos que tiene para acomodarlos adecuadamente • Importante especificar para Canvas ya que no tienen un tamaño definido cuando son creados • Regresan un objeto tipo Dimension repaint() • Para indicarle a un componente que se debe de redibujar • La llamada a este método ocasiona que AWT ejecute el método update() del componente, el cual a su vez llama a paint() repaint() • public void repaint() – Petición a AWT que ejecute el método update() (paint()) del componente lo más pronto posible • public void repaint(long time) – Petición a AWT que ejecute el método update() (paint()) del componente time milisegundos más tarde • public void repaint(int x, int y, int width, int height) – Petición a AWT que ejecute el método update() (paint()) del componente lo más pronto posible, pero que rdibuje sólo la porción especificada por el área rectangular • public void repaint(long time, int x, int y, int width, int height) – Petición a AWT que ejecute el método update() (paint()) del componente time milisegundos más tarde, pero que rdibuje sólo la porción especificada por el área rectangular Moviendo una imagen • Necesitamos un Canvas para hacer todo el dibujo (el cuadro azul y la bola roja) • Necesitamos un ciclo para que redibuje todo el Canvas con la bola en diferente posición cada vez (incrementando la coordenada horizontal) • El ciclo puede ir dentro del paint(), pero eso haría que nuestro objeto consumiera todo el CPU, además de que una vez que se llamara a paint() jamás se saldría y nuestro applet no podría hacer otra cosa. Moviendo una imagen • Entonces es conveniente que el ciclo de pintado sea un hilo, de esta manera nuestro objeto podría estar en un applet con otros objetos sin consumir todos los recursos • Es adecuado que la prioridad del hilo sea la más baja ya que generalmente una animación NO ES lo más importante dentro de una applet o aplicación • Además tenemos que hacer una verificación de las coordenadas para hacer algo cuando la bola llega al extremo izquierdo (que se regrese o aparezca del lado izquierdo nuevamente) Moviendo una imagen • Haremos que aparezca del lado izquierdo • Además nuestro applet tendrá que comportarse adecuadamente, es decir debe de jugar alegremente y sin pelearse mucho con los otros niños (applets e hilos) • Lo anterior incluye parar su ejecución cuando ya no este visible y continuar su movimiento cuando el usuario revisita nuestra página • Controlar el movimiento con los métodos start() y stop() del applet • Asi es que adelante................. class CuadroConBola1 extends Canvas implements Runnable{ Color colorCuadro,colorBola; int posicion = 0; boolean vivo = true; boolean moviendo = true; boolean derecha = true; int diametroBola; Dimension tamano = new Dimension(); Ejemplo public CuadroConBola1(Color color1,Color color2){ super(); colorCuadro = color1; colorBola = color2; } public void run(){ Thread.currentThread().setPriority(Thread.MIN_PRIORITY); while (vivo){ if (moviendo){ posicion +=5; if (posicion>tamano.width) posicion = 0; repaint(); } try{ Thread.sleep(50); } catch(InterruptedException e){} } } Que el applet muera en algún momento Que detenga al máximo el consumo de recursos cuando no está visible Ejemplo public void paint(Graphics g){ tamano = getSize(); El tamaño no es fijo, depende diametroBola = tamano.height/2; g.setColor(colorCuadro); del tamaño del contexto gráfico g.fillRect(0,0,tamano.width,tamano.height); donde insertemos nuestra figura g.setColor(colorBola); g.fillOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); g.setColor(Color.black); g.drawOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); g.drawOval(posicion+1,tamano.height/4+1,diametroBola-3,diametroBola-3); } } import java.awt.event.*; public class BolaMovil1 extends Applet{ CuadroConBola1 x; Thread t; public void init(){ setLayout(new BorderLayout()); x = new CuadroConBola1(Color.yellow,Color.red); t = new Thread(x,"bola1"); add(x,"Center"); t.start(); } public void start(){ x.moviendo = true; } public void stop(){ x.moviendo = false; } public void destroy(){ x.vivo = false; } Ejemplo Para que tome un tamaño, dado que un Canvas no tiene un tamaño por default } Problema • El problema es inmediatamente visible y es un molesto parpadeo, esto ocurre por la forma en que AWT maneja el dibujo de componentes. • Cada vez que AWT detecta que un componente necesita redibujarse por una llamada a repaint() del componente, AWT llama a update() de ese componente • Y update() borra el fondo del componente antes de llamar a paint() que es la rutina que normalmente tu reprogramas para dibujar algo Proceso de repaint() objeto.repaint() Aviso a AWT que el objeto se redibuje AWT lo pone en la lista de repintado update() Borra el fondo del objeto (mismo color del background) y llama al método paint() del objeto objeto.paint() AWT llama al método update() objeto Solución • Reprogramar el método update() para que no borre el fondo y dibuje directamente lo que queremos, es decir hacer en update() lo que normalmente hacemos en paint() • El método paint() de todas maneras se necesita porque AWT lo llama directamente cuando necesita actualizar los objetos por el despliegue de ventanas import java.awt.*; import java.applet.*; import java.awt.event.*; public class BolaMovil2 extends Applet{ CuadroConBola2 x; Thread t; public void init(){ setLayout(new BorderLayout()); x = new CuadroConBola2(Color.blue,Color.red); t = new Thread(x,"bola1"); add(x,"Center"); t.start(); } public void start(){ x.moviendo = true; } public void stop(){ x.moviendo = false; } public void destroy(){ x.vivo = false; } } Ejemplo Ejemplo public void paint(Graphics g){ update(g); } public void update(Graphics g){ tamano = getSize(); diametroBola = tamano.height/2; g.setColor(colorCuadro); g.fillRect(0,0,tamano.width,tamano.height); g.setColor(colorBola); g.fillOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); g.setColor(Color.black); g.drawOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); g.drawOval(posicion+1,tamano.height/4+1,diametroBola-3,diametroBola-3); } Problemita • Ya se eliminó el parpadeo del rectángulo grande, pero todavía vemos parpadeo en el círculo, esto inicialmente ya no lo podemos evitar ya que reprogramamos el update(), el parpadeo del círculo se debe a que se limpia el círculo por el dibujo del rectángulo, es el mismo problema que teníamos con el update() original pero ahora nosotros somos los que borramos el fondo del círculo Solución • Una técnica que se utiliza mucho en el manejo de gráficas es conocidad como “Double Buffering” • La idea es manejar un área de memoria intermedia para hacer toda la manipulación gráfica fuera de pantalla, y una vez que este completa vaciar esa área a pantalla • Nos tardamos lo mismo en dibujar todo, pero el despliegue es mucho más rápido ya que es movimiento de memoria a memoria Double Buffering Buffer intermedio Pantalla hacer dibujo fuera de pantalla class CuadroConBola3 extends Canvas implements Runnable{ : : Dimension offTamano; Image offImagen; Graphics offGraphics; Ejemplo Declaración de nuevas variables: Tamaño del buffer Imagen que guardará el buffer Contexto gráfico del buffer public void update(Graphics g){ tamano = getSize(); if ( (offGraphics == null) ||(tamano.width != offTamano.width) || (tamano.height != offTamano.height) ) { offTamano = tamano; offImagen = createImage(tamano.width, tamano.height); offGraphics = offImagen.getGraphics(); } diametroBola = offTamano.height/2; offGraphics.setColor(colorCuadro); offGraphics.fillRect(0,0,tamano.width,tamano.height); offGraphics.setColor(colorBola); offGraphics.fillOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); offGraphics.setColor(Color.black); offGraphics.drawOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); offGraphics.drawOval(posicion+1,tamano.height/4+1,diametroBola-3,diametroBola-3); g.drawImage(offImagen,0,0,this); } } class CuadroConBola3 extends Canvas implements Runnable{ : : Dimension offTamano; Image offImagen; Graphics offGraphics; Ejemplo Averiguar si tamaño ha cambiado o si el buffer todavía no ha sido creado public void update(Graphics g){ tamano = getSize(); if ( (offGraphics == null) ||(tamano.width != offTamano.width) || (tamano.height != offTamano.height) ) { offTamano = tamano; offImagen = createImage(tamano.width, tamano.height); offGraphics = offImagen.getGraphics(); } diametroBola = offTamano.height/2; offGraphics.setColor(colorCuadro); offGraphics.fillRect(0,0,tamano.width,tamano.height); offGraphics.setColor(colorBola); offGraphics.fillOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); offGraphics.setColor(Color.black); offGraphics.drawOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); offGraphics.drawOval(posicion+1,tamano.height/4+1,diametroBola-3,diametroBola-3); g.drawImage(offImagen,0,0,this); } } class CuadroConBola3 extends Canvas implements Runnable{ : : Dimension offTamano; Image offImagen; Graphics offGraphics; Ejemplo Dibujar imagen fuera de pantalla public void update(Graphics g){ tamano = getSize(); if ( (offGraphics == null) ||(tamano.width != offTamano.width) || (tamano.height != offTamano.height) ) { offTamano = tamano; offImagen = createImage(tamano.width, tamano.height); offGraphics = offImagen.getGraphics(); } diametroBola = offTamano.height/2; offGraphics.setColor(colorCuadro); offGraphics.fillRect(0,0,tamano.width,tamano.height); offGraphics.setColor(colorBola); offGraphics.fillOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); offGraphics.setColor(Color.black); offGraphics.drawOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); offGraphics.drawOval(posicion+1,tamano.height/4+1,diametroBola-3,diametroBola-3); g.drawImage(offImagen,0,0,this); } } class CuadroConBola3 extends Canvas implements Runnable{ : : Dimension offTamano; Image offImagen; Graphics offGraphics; Ejemplo public void update(Graphics g){ tamano = getSize(); if ( (offGraphics == null) ||(tamano.width != offTamano.width) || (tamano.height != offTamano.height) ) { offTamano = tamano; offImagen = createImage(tamano.width, tamano.height); offGraphics = offImagen.getGraphics(); } Vaciar imagen del buffer a pantalla diametroBola = offTamano.height/2; offGraphics.setColor(colorCuadro); offGraphics.fillRect(0,0,tamano.width,tamano.height); offGraphics.setColor(colorBola); offGraphics.fillOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); offGraphics.setColor(Color.black); offGraphics.drawOval(posicion,tamano.height/4,diametroBola-1,diametroBola-1); offGraphics.drawOval(posicion+1,tamano.height/4+1,diametroBola-3,diametroBola-3); g.drawImage(offImagen,0,0,this); } } Cargando imágenes • Dos métodos de la clase Applet: – Image getImage(URL url) – Image getImage(URL url, String name) • Dos métodos de la clase Toolkit: – Image getImage(URL url) – Image getImage(String filename) Desplegando imágenes boolean drawImage(Image img, int x, int y, ImageObserver observer) boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) Image img : La imagen a dibujar int x, int y : Coordenadas de la esquina superior izquierda int width, int height : El ancho y el alto (en pixels) de la imagen Color bgcolor : Color del fondo ImageObserver observer : El objeto que desplegará la imagen, para la mayoría de los casos basta especificar this Ejemplo import java.awt.*; import java.applet.Applet; public class DespliegaImagen extends Applet { Image imagen; public void init() { imagen = getImage(getCodeBase(), "mundo.gif"); } public void paint(Graphics g) { g.drawImage(imagen, 0, 0, this); g.drawImage(imagen, 90, 200, 200, 100, this); } } Animación • Desplegar secuencialmente una serie de imágenes • Con un reatrdo preestablecido entre imagen e imagen • Es conveniente que el despliegue se encuentre en un hilo import java.awt.*; import java.applet.Applet; public class Animacion extends Applet implements Runnable { int cuadro = -1; Thread hilo; Dimension offTamano; Image offImagen; Graphics offGraphics; Image[] imagenes; Ejemplo public void init() { imagenes = new Image[10]; for (int i = 1; i <= 10; i++) { imagenes[i-1] = getImage(getCodeBase(),"circum"+i+".gif"); } } public void start() { if (hilo == null) { hilo = new Thread(this); } hilo.start(); } public void stop() { hilo = null; offGraphics = null; offImagen = null; } Ejemplo public void run() { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); while (Thread.currentThread() == hilo) { cuadro++; repaint(); try { Thread.sleep(200); } catch (InterruptedException e) { break; } } } Ejemplo public void paint(Graphics g) { update(g); } public void update(Graphics g) { Dimension d = getSize(); if ( (offGraphics == null) || (d.width != offTamano.width) || (d.height != offTamano.height) ) { offTamano = d; offImagen = createImage(d.width, d.height); offGraphics = offImagen.getGraphics(); } offGraphics.setColor(getBackground()); offGraphics.fillRect(0, 0, d.width, d.height); offGraphics.setColor(Color.black); offGraphics.drawImage(imagenes[cuadro % 10], 0, 0, this); g.drawImage(offImagen, 0, 0, this); } } Problemas • Si pones atención al comienzo de la animación se ve un efecto donde las imágenes no se despliegan completas al principio, esto se debe a que las imágenes se van cargando en el momento del despliegue • La carga de imágenes se realiza en un hilo que comienza a ejecutarse en forma independiente, dejando que el programa continue con su ejecución Problemas • El problema es muho más grave cuando estás bajando las imágenes en la red, ya que el tiempo de transferencia se incrementa tremendamente • Esto puede ocasionar que intentes desplegar imágenes que todavía no lleguen o imágenes incompletas, y a pesar de que no marca errores y el programa sigue funcionando, el efecto visual no es el que pretendes obtener Solución • La solución es usar la clase MediaTracker que sirve para rastrear la carga de archivos (en nuestro caso, imágenes) desde la red • MediaTracker te permite verificar que todas las imágenes esten cargadas antes de comenzar la animación • En caso de que no esten todas las imágenes puedes desplegar un letrero de espera MediaTracker Métodos importantes import java.awt.*; import java.applet.Applet; public class Animacion1 extends Applet implements Runnable { int cuadro = -1; Thread hilo; Dimension offTamano; Image offImagen; Graphics offGraphics; Image[] imagenes; MediaTracker rastreador; Ejemplo public void init() { imagenes = new Image[10]; rastreador = new MediaTracker(this); for (int i = 1; i <= 10; i++) { imagenes[i-1] = getImage(getCodeBase(),"circum"+i+".gif"); rastreador.addImage(imagenes[i-1],0); } } public void start() { if (hilo == null) { hilo = new Thread(this); } hilo.start(); } public void stop() { hilo = null; offGraphics = null; offImagen = null; } Ejemplo public void run() { try{ rastreador.waitForAll(); }catch (InterruptedException e){} Thread.currentThread().setPriority(Thread.MIN_PRIORITY); while (Thread.currentThread() == hilo) { cuadro++; repaint(); try { Thread.sleep(200); } catch (InterruptedException e) { break; } } } Ejemplo public void paint(Graphics g) { update(g); } public void update(Graphics g) { Dimension d = getSize(); if (!rastreador.checkAll()){ g.clearRect(0,0,d.width, d.height); g.drawString("Imagenes cargando . . . .",0,d.height/2); } if ( (offGraphics == null) || (d.width != offTamano.width) || (d.height != offTamano.height) ) { offTamano = d; offImagen = createImage(d.width, d.height); offGraphics = offImagen.getGraphics(); } offGraphics.setColor(getBackground()); offGraphics.fillRect(0, 0, d.width, d.height); offGraphics.setColor(Color.black); offGraphics.drawImage(imagenes[cuadro % 10], 0, 0, this); g.drawImage(offImagen, 0, 0, this); } } Introducción a Swing Introducción a Swing • Es el heredero de AWT • Incrementa considerablemente la capacidad (funcional y cosmética) de los componentes • javax.swing es el paquete que contiene las nuevas clases • La transición no es muy difícil, la filosofía sigue siendo la misma, sobretodo en la manipulación de eventos Componentes Swing • Los componentes de Swing son livianos (lightweigt) • Están construidos completamente en Java, ya no dependen de un "peer" nativo, es decir son completamente independientes de la plataforma • Ya no están limitados al mínimo común denominador de los objetos en las diferentes plataformas • Se puede especificar la forma gráfica que tomará tu programa o applet ("look and feel") • Puedes agregar o cambiar la apariencia y funcionalidad de cualquier componente sin mayores problemas Algunas características adicionales • Todos los nuevas clases comienzan con J, JButton, JLabel, JFrame, etc. • Los botones y etiquetas pueden tener imágenes y texto • Cada componente puede tener un "tooltip" que se activa cuando el ratón se posiciona sobre el objeto un tiempo determinado • AWT y Swing se pueden mezclar en un programa sin problemas, sólo hay que tener en cuenta que los objetos AWT son pesados (heavyweight), y estos se desplegarán sobre cualquier objeto Swing import java.awt.*; import java.awt.event.*; import javax.swing.*; Ejemplo public class EjemploSwing1 extends JFrame{ JButton b1 = new JButton("Correo",new ImageIcon("correo.gif")); JButton b2 = new JButton("Música",new ImageIcon("musica.gif")); JButton b3 = new JButton("Duerme",new ImageIcon("duerme.gif")); public EjemploSwing1() { b2.setHorizontalTextPosition(JButton.LEFT); b3.setHorizontalTextPosition(JButton.CENTER); b1.setToolTipText("Este es el botón 1"); getContentPane().setLayout(new FlowLayout()); getContentPane().add(b1); getContentPane().add(b2); getContentPane().add(b3); pack(); show(); } public static void main(String s[]) { new EjemploSwing1(); } } import java.awt.*; import java.awt.event.*; import javax.swing.*; public class EjemploSwing2 extends Frame implements ActionListener{ JButton botonMetal; JButton botonMotif; JButton botonWindows; public EjemploSwing2() { setLayout(new FlowLayout()); botonMetal = new JButton("Metal"); botonMotif = new JButton("Motif"); botonWindows = new JButton("Windows"); botonMetal.addActionListener(this); botonMotif.addActionListener(this); botonWindows.addActionListener(this); Ejemplo Clase anónima add(botonMetal); add(botonMotif); add(botonWindows); pack(); show(); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0);}}); } Ejemplo public void actionPerformed(ActionEvent e) { String lf; if (e.getSource().equals(botonWindows)) lf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; else if (e.getSource().equals(botonMetal)) lf = "javax.swing.plaf.metal.MetalLookAndFeel"; else lf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; try{ UIManager.setLookAndFeel(lf); SwingUtilities.updateComponentTreeUI(this); pack(); }catch(Exception ex){} } public static void main(String s[]) { new EjemploSwing2(); } } Ejemplo import java.awt.*; import java.awt.event.*; import javax.swing.*; public class EjemploSwing3 extends JFrame implements ActionListener{ JLabel figura; JRadioButton r1 = new JRadioButton("Mariposa"); JRadioButton r2 = new JRadioButton("Pollo"); JRadioButton r3 = new JRadioButton("Canino"); JRadioButton r4 = new JRadioButton("Rana"); JRadioButton r5 = new JRadioButton("Tortuga"); JPanel botones = new JPanel(); Ejemplo public EjemploSwing3() { r1.setActionCommand("Mariposa"); r1.setMnemonic(KeyEvent.VK_M); r1.setSelected(true); r2.setActionCommand("Pollo"); r2.setMnemonic(KeyEvent.VK_P); r3.setActionCommand("Canino"); r3.setMnemonic(KeyEvent.VK_C); r4.setActionCommand("Rana"); r4.setMnemonic(KeyEvent.VK_R); r5.setActionCommand("Tortuga"); r5.setMnemonic(KeyEvent.VK_T); ButtonGroup grupo = new ButtonGroup(); grupo.add(r1); : grupo.add(r5); botones.setLayout(new GridLayout(0,1)); botones.add(r1); : botones.add(r5); r1.addActionListener(this); : r5.addActionListener(this); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0);}}); Ejemplo figura = new JLabel(new ImageIcon("Mariposa.gif")); figura.setPreferredSize(new Dimension(200,200)); getContentPane().setLayout(new BorderLayout()); getContentPane().add(botones,BorderLayout.EAST); getContentPane().add(figura, BorderLayout.CENTER); public void actionPerformed(ActionEvent e){ figura.setIcon(new ImageIcon(e.getActionCommand()+".gif")); } Ejemplo import import import import java.awt.*; java.awt.event.*; javax.swing.*; javax.swing.event.*; Ejemplo public class EjemploSwing4 extends JFrame implements ChangeListener{ JLabel figura; JSlider figuras = new JSlider(JSlider.HORIZONTAL,1,10,1); public EjemploSwing4() { figura = new JLabel("Figura 1",new ImageIcon("circum1.gif"),JLabel.CENTER); figura.setVerticalTextPosition(JLabel.BOTTOM); figura.setHorizontalTextPosition(JLabel.CENTER); figura.setPreferredSize(new Dimension(200,200)); figuras.setMinorTickSpacing(1); figuras.setMajorTickSpacing(3); figuras.setPaintTicks(true); figuras.setPaintLabels(true); figuras.setSnapToTicks(true); figuras.addChangeListener(this); getContentPane().setLayout(new BorderLayout()); getContentPane().add(figuras,BorderLayout.SOUTH); getContentPane().add(figura, BorderLayout.CENTER); Ejemplo try{ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); SwingUtilities.updateComponentTreeUI(this); }catch(Exception ex){} pack(); show(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0);}}); } public void stateChanged(ChangeEvent e){ figura.setIcon(new ImageIcon("circum" + String.valueOf(figuras.getValue())+".gif")); figura.setText("figura "+ String.valueOf(figuras.getValue())); } public static void main(String s[]) { new EjemploSwing4(); } } Ejemplo Flujos Streams y Readers/Writers Flujo • Es una secuencia de bytes (carácteres) que se mueve desde una fuente hacia un destino a través de una trayectoria de comunicación Fuente Destino Operación normal de flujos Fuente Lectura Flujo Programa Programa Escritura Destino • La fuente/destino puede ser memoria, un archivo, un socket, etc. Lectura/Escritura de flujos Abrir flujo Abrir flujo Leer mientras exista información Escrbir mientras exista información Cerrar flujo Cerrar flujo Ejemplo import java.io.*; public class LeeArchivo1 { public static void main(String[] args) throws IOException { FileInputStream leeArchivo = new FileInputStream(args[0]); int caracter; while ((caracter = leeArchivo.read()) != -1) System.out.print((char) caracter); leeArchivo.close(); } } Ejemplo A3 5C 23 DD 4A 2D 21 8F BC A3 34 65 B2 CC leeArchivo.read() import java.io.*; public class LeeArchivo1 { public static void main(String[] args) throws IOException { FileInputStream leeArchivo = new FileInputStream(args[0]); int caracter; while ((caracter = leeArchivo.read()) != -1) System.out.print((char) caracter); leeArchivo.close(); } } Jerarquía de flujos • La mayoría de las clases de flujos se derivan de InputStream y OutputStream • Esto permite utilizar clases que son más adecuadas a una tarea particular, como en el ejemplo anterior, en lugar de utilizar un flujo genérico y nosotros adecuarlo por programación • InputStream y OutputStream nos dan algunos métodos genéricos para lectura y escritura de bytes. Las subclases nos dan los métodos particulares que son más apropiados dependiendo de la fuente o destino InputStream Object InputStream (abstract) FileInputStream PipedInputStream FilterInputStream (abstract) DataInputStream BufferedInputStream LineNumberInputStream PushbackInputStream ByteArrayInputStream SequenceInputStream StringBufferInputStream OutputStream Object OutputStream (abstract) FileOutputStream PipedOutputStream FilterOutputStream (abstract) DataOutputStream BufferedOutputStream PrintStream ByteArrayOutputStream Métodos de InputStream read() • public int read() throws IOException – Lee un byte del flujo de entrada y lo regresa – Regresa -1 si se alcanza el final del flujo – Se bloquea (espera) hasta que existan datos disponibles – Arroja la excepción IOException si ocurre un error durante la lectura – Normalmente reprogramado por las subclases read(byte[]) • public int read(byte[] b) throws IOException – Lee una secuencia de bytes del flujo de entrada y los pone en el arreglo especificado – Regresa la cantidad de bytes leidos – Regresa -1 si es que se alcanzó el final del flujo de entrada – Se bloquea hasta que existan datos disponibles – Arroja la excepción IOException si ocurre un error durante la lectura read(byte[],int,int) • public int read(byte[] b,int des,int lon) throws IOException – Lee una secuencia de lon bytes y los pone en el arreglo b a partir del índice des – Regresa el número de bytes leidos – Regresa -1 si es que se alcanzó el final del flujo de entrada – Se bloquea hasta que encuentre datos disponibles – Arroja la excepción IOException si ocurre un error durante la lectura skip(long) • public long skip(long n) throws IOException – Se brinca (y descarta) un número de bytes especificado por n – Regresa el número de bytes que realmente se descartaron – Regresa -1 si se alcanzó el final del flujo de entrada – Arroja la excepción IOException si ocurre un error durante el salto available() • public int available() throws IOException – Regresa el número de bytes que se pueden leer del flujo de entrada sin que la operación de lectura bloquee la secuencia del programa – Se utiliza para "ver", sin leer, cuantos datos hay disponibles – En algunos sistemas el resultado arrojado no es confiable – Arroja la excepción IOException si ocurre un error durante la operación close() • public void close() throws IOException – Cierra el flujo de entrada y libera todos los recursos asociados (asignados por el sistema operativo) con el flujo – Siempre es conveniente cerrar los flujos para asegurarse que el procesamiento del flujo por parte del sistema termine correctamente – Arroja la excepción IOException si ocurre un error durante la operación mark(int) • public synchronized void mark(int readlimit) – Marca la posición actual en el flujo de entrada, para posteriormente regresar a ella en caso necesario – Regresa el número de bytes que se pueden leer después de la marca antes de que la marca sea invalidada por la capacidad del buffer – boolean markSupported() indica si el flujo de entrada permite marcas – void reset() reposiciona al flujo en la última posición marcada Métodos de OutputStream write(...) • public void write(int b) throws IOException – Escribe un byte al flujo de salida • public void write(byte[] b) throws IOException – Escribe una secuencia de bytes al flujo de salida • public void write(byte [] b,int des,int lon) throws IOException – Escribe lon bytes del arreglo b a partir de des • Se bloquean hasta que el o los datos sean escritos • Arrojan IOException en caso de error durante la escritura flush() • public void flush() throws IOException – Ocasiona que todo dato que esté en el buffer sea escrito inmediatamente al flujo de salida – Se tiene que reprogramar en las subclases porque en OutputStream no hace nada close() • public void close() throws IOException – Cierra el flujo de salida y libera los recursos asociados por el sistema Clases de flujos • FileInputStream – Subclase de InputStream que lee datos de un archivo especificado por nombre, o por un objeto de tipo File o Filedescriptor, para leer archivos es mejor utilizar DataInputStream que es de tipo FilterInputStream, la cual permite leer líneas de texto y datos primitivos de Java de una manera más adecuada. Se puede crear un DataInputStream especificando el InputStream que será filtrado Clases de flujos... • FileOutputStream – Subclase de OutputStream que escribe datos a un archivo especificado por nombre, o por un objeto de tipo File o Filedescriptor, para escribir archivos es mejor utilizar DataOutputStream o PrintOutputStream • PipedInputStream y PipedOutputStream – Util para la comunicación entre hilos (threads). Un PipedInputStream se debe conectar a un objeto PipedOutputStream Clases de flujos... • ByteArrayInputStream y ByteArrayOutputStream – Para leer o escribir datos de un arreglo como si viniera de un archivo o socket, los datos del arreglo se pueden obtener con toByteArray() o toString(), el método reset() deshecha los datos que están guardados en el arreglo y posiciona el apuntador al comienzo • SequenceInputStream – Nos da un medio de concatenar datos de dos o más flujos de entrada, los datos son leidos en el orden en el cual se especifican los flujos Clases de flujos... • StringBufferInputStream – Los datos vienen de un string especificado – Util cuando se quiere leer datos de memoria como si viniera de una archivo o socket – Similar a ByteArrayInputStream Clases de flujos filtrados • Se derivan de FilterInputStream y FilterOutputStream, las cuales son clases abstractas • Estas clases definen la interfaz para flujos filtrados, los cuales procesan los datos a medida que son leidos o escritos Clases de flujos filtrados... • DataInputStream – Nos permite leer líneas de texto y datos primitivos de Java de una manera fácil – Es la clase más utilizada para leer datos de un archivo – Agrupa bytes leidos de un flujo y los interpreta como datos primitivos de Java • BufferedInputStream – Incrementa la eficiencia de lectura, leyendo mayores cantidades de información y guardándola en un buffer interno Clases de flujos filtrados... • LineNumberInputStream – Mantiene un registro de las líneas de datos que se leen. El método setLineNumber() establece la numeración de la línea actual y numera las líneas subsecuentes a partir del número inicial • PushBackInputStream – Da la capacidad de regresar un byte leido al flujo original, el cual será leido con la siguiente llamada a read() Clases de flujos filtrados... • BufferedOutputStream – Permite aumentar la eficiencia de la escritura a un flujo utilizando un buffer interno intermedio el cual se vacía al flujo cuando el buffer se llena o se llama al método flush() • PrintStream – Agrega funcionalidad a otro flujo de salida dando la posibilidad de escribir representaciones de los diferentes tipos de datos de Java. A pesar de su nombre no es imprescindible que la salida sea a impresora Clases de flujos filtrados... • DataOutputStream – Nos da la facilidad de convertir los diferentes tipos de datos primitivos de Java en secuencias de carácteres con formato específico, para posteriormente sean enviados a algún flujo de salida DataInputStream DataInputStream DataInputStream • El problema es que este método no convierte bytes a carácteres (unicode) DataOutputStream DataOutputStream Ejemplo import java.io.*; public class LeeArchivo2 { public static void main(String[] args) throws IOException { FileInputStream leeArchivo = new FileInputStream(args[0]); DataInputStream leeFiltrado = new DataInputStream(leeArchivo); String linea; while ((linea = leeFiltrado.readLine()) != null) System.out.println(linea); leeArchivo.close(); leeFiltrado.close(); } } método desaprobado import java.io.*; public class LeeArchivo2 { public static void main(String[] args) throws IOException { FileInputStream leeArchivo = new FileInputStream(args[0]); DataInputStream leeFiltrado = new DataInputStream(leeArchivo); String linea; while ((linea = leeFiltrado.readLine()) != null) System.out.println(linea); leeArchivo.close(); leeFiltrado.close(); } } leeFiltrado.readLine() “Hola que tal” A3 34 65 CC 21 10110011 10011110 1100 Readers y Writers • JDK 1.1 nos da dos tipos diferentes de flujos (streams): – Orientados a byte (8 bits, Ascii) – Orientados a caracter (16 bits, Unicode) • Los dos tipos de flujos se organizan en dos jerarquías, una que consiste en clases de flujos orientados a byte y la otra en clases de flujos orientados a caracter Readers y Writers • Las dos jeraquías son funcionalmente casi idénticas y contienen clases y subclases equivalentes difiriendo solamente en la parte final (sufijo) del nombre • Las orientadas a byte terminan en InputStream u OutputStream • las orientadas a caracter terminan en Reader o Writer Flujos de entrada Flujos de salida Ejemplo import java.io.*; public class LeeArchivo3 { public static void main(String[] args) throws IOException { FileReader leeArchivo = new FileReader(args[0]); BufferedReader leeFiltrado = new BufferedReader(leeArchivo); String linea; while ((linea = leeFiltrado.readLine()) != null) System.out.println(linea); leeArchivo.close(); leeFiltrado.close(); } } Otras clases de java.io • File – Nos ayuda a especificar nombres de archivos y directorios, además nos da métodos para averiguar información acerca de un archivo como su path completo, o si tiene permisos de escritura, etc. • FileDescriptor – El equivalente a una manija de bajo nivel para un archivo o socket java.awt.FileDialog • Despliega una ventana del sistema para que el usuario seleccione un archivo • Debe de pertenecer a un Frame • Es una ventana modal, es decir cuando se le da show() bloquea el resto de la aplicación hasta que el usuario seleccione un archivo o cancele la operación FileDialog FileDialog • show() – Hace la ventana de FileDialog visible y bloquea la ejecución de la aplicación hasta que se seleccione un archivo • setMode(int) – Establece si la ventana de FileDialog es para leer un archivo (LOAD) o para escribir un archivo (SAVE) FileDialog • getFile() – Regresa como String el archivo seleccionado • getDirectory() – Regresa como String el directorio al cual pertenece el archivo seleccionado • En caso de no haber seleccionado ningún archivo ambos regresan null public class Archivo1 extends Frame implements ActionListener{ static Archivo1 f; Button boton = new Button("Abrir"); TextArea despliega = new TextArea(); FileDialog dialogo = new FileDialog(this); Image figura; String nombreArchivo, nombreDirectorio; File archivo; Ejemplo public Archivo1(){ super(); setTitle("Archivero"); setSize(200,200); setLocation(300,300); figura = Toolkit.getDefaultToolkit().getImage("canino.gif"); setIconImage(figura); add(despliega,"Center"); add(boton,"South"); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ f.dispose(); System.exit(0); }}); boton.addActionListener(this); pack(); show(); } public void actionPerformed(ActionEvent e){ Button b = (Button) e.getSource(); if(boton.getLabel()=="Abrir"){ dialogo.setMode(FileDialog.LOAD); dialogo.show(); nombreArchivo = dialogo.getFile(); nombreDirectorio = dialogo.getDirectory(); if (nombreDirectorio!=null && nombreArchivo!= null){ archivo = new File(nombreDirectorio,nombreArchivo); despliegaArchivo(archivo); boton.setLabel("Guardar"); } }else{ dialogo.setMode(dialogo.SAVE); dialogo.setFile(nombreArchivo); dialogo.setDirectory(nombreDirectorio); dialogo.show(); nombreArchivo = dialogo.getFile(); nombreDirectorio = dialogo.getDirectory(); if (nombreDirectorio!=null && nombreArchivo!= null){ archivo = new File(nombreDirectorio,nombreArchivo); guardaArchivo(archivo); } boton.setLabel("Abrir"); } } Ejemplo Ejemplo public void despliegaArchivo(File f){ FileReader archivo; BufferedReader filtrado; despliega.setText(""); try{ archivo = new FileReader(f); filtrado = new BufferedReader(archivo); String linea; while ((linea = filtrado.readLine()) != null) despliega.append(linea+"\n"); archivo.close(); filtrado.close(); }catch(FileNotFoundException e){ despliega.append(e.getMessage()); }catch(IOException e){ despliega.append(e.getMessage()); } } Ejemplo public void guardaArchivo(File f){ FileWriter archivo; BufferedWriter filtrado; String contenido="nada"; try{ archivo = new FileWriter(f); filtrado = new BufferedWriter(archivo); contenido = despliega.getText(); filtrado.write(contenido,0,contenido.length()); filtrado.flush(); archivo.close(); filtrado.close(); }catch(FileNotFoundException e){ despliega.append(e.getMessage()); }catch(IOException e){ despliega.append(e.getMessage()); } despliega.setText(""); } Ejemplo Métodos de File public class Archivo2 extends Frame implements ActionListener{ Ejemplo public void despliegaPropiedades(File f){ despliega.setText("Propiedades del Archivo: "+f.getName()+"\n"); despliega.append("canRead()>> "+String.valueOf(f.canRead())+"\n"); despliega.append("canWrite()>> "+String.valueOf(f.canWrite())+"\n"); despliega.append("exists()>> "+String.valueOf(f.exists())+"\n"); despliega.append("getAbsolutePath()>> "+f.getAbsolutePath()+"\n"); despliega.append("getPath()>> "+f.getPath()+"\n"); despliega.append("length()>> "+String.valueOf(f.length())+"\n"); } Entendiendo System.out.println(...) System.out.println() System.out.println() PrintStream PrintStream System.out.println() • out variable de la clase System del paquete lang • out variable de tipo PrintStream • La clase PrintStream tiene una serie de métodos print y println para poder escribir una representación legible para cada tipo de dato primitivo en Java • No arroja excepciones PrintStream desaprobado • PrintStream ya está desaprobado (deprecated) • Es recomendable utilizar PrintWriter • Asi se tiene el soporte para escribir carácteres Unicode • Los métodos de PrintStream eliminan la parte alta de los carácteres para transformarlos en código Ascii de 8 bits Leyendo del teclado • Utilizaremos InputStreamReader para poder leer Unicode • InputStreamReader transforma los bytes leidos en carácteres Unicode • Envolveremos al InputStreamReader en un BufferedReader por eficiencia import java.io.*; public class Teclado { public static void main(String[] args){ String linea=""; InputStreamReader entrada = new InputStreamReader(System.in); BufferedReader teclado = new BufferedReader(entrada); System.out.println("Teclea líneas de texto"); System.out.println("Teclea q y para terminar"); try{ while(linea.compareTo("q")!=0){ linea = teclado.readLine(); System.out.println(">> "+linea); } }catch(IOException e){ System.out.println(e.getMessage()); } System.out.println("Fin del Programa"); try{ teclado.close(); entrada.close(); }catch(IOException e){ System.out.println(e.getMessage()); } } } Ejemplo Redes en Java Introducción • Además del manejo implícito de redes que tiene (carga de applets, clases, imágenes, etc.), Java tiene la posibilidad de manejar la comunicación por medio de redes usando el modelo de referencia TCP/IP • Esta comunicación se realiza utilizando sockets, los cuales son la parte fundamental del manejo de redes con TCP/IP • Es un conjunto de protocolos para comunicaciones de redes, son los que le dan vida a Internet y por consiguiente al Web TCP/IP vs OSI Aplicación Presentación Sesión Transporte Red Enlace Física Aplicación TCP/IP Acceso a la red Física HTTP, Telnet, FTP, SMTP, SNMP, etc (Aplicaciones usuario) TCP/IP TCP IP UDP Acceso a la red • TCP: • UDP: • IP: Transmission Control Protocol User Datagram Protocol Internet Protocol TCP • Protocolo orientado a conexión que maneja un canal de comunicación confiable entre dos computadoras • Garantiza que los mensajes llegarán al destino en forma correcta y ordenada • Verificación de errores, reconocimientos (ACK), retransmisión, secuenciación de paquetes • HTTP, FTP, Telnet UDP • Protocolo orientado a no-conexión que envía paquetes de datos independientes (datagramas), sin garantía de la llegada o del orden de los paquetes • No incurre en el gasto extra de mantener una conexión y hacer la verificación de cada paquete por medio de ACKs y timeouts • Diseñado para aplicaciones donde la pérdida parcial de datos no es importante Direcciones IP y puertos • Cuando enviamos información en Internet necesitamos identificar la máquina destino y el proceso que queremos maneje los datos enviados • Una dirección IP identifica una máquina en Internet, son de 32 bits: 131.178.14.14, 192.9.48.9 • Puertos identifican a un proceso dentro de una máquina son números de 16 bits 192.9.48.9 Direcciones IP y puertos Paquete Internet Aplicación Servidor WEB Servidor FTP : Miprograma : Puerto 80 21 : 5999 : Dir IP, puerto, datos 131.178.14.14 Direcciones IP y puertos Prog1 Prog2 Datos Puerto1 Puerto2 PuertoN ProgN Sistema Operativo #Puerto Datos Paquete Dir IP #Puerto Datos Sockets • Un socket es un extremo de un enlace de comunicación bidireccional • A un socket se le asocia un número de puerto, para que el sistema identifique a que aplicación mandar algún paquete • También se le asocia una dirección IP para que un paquete mandado por el socket pueda viajar por la red hacia un destino • Las aplicaciones escriben y leen de sockets 131.178.2.25 Puerto 5000 Socket Sockets Socket Puerto 6000 131.178.2.25, 5000,"Hola" 131.178.14.14 Petición de conexión 131.178.2.25 Puerto 5000 131.178.2.25, 5000, Connection Request Puerto 6000 131.178.14.14 Petición de conexión 131.178.2.25 Puerto 5000 131.178.2.25, 5000, Connection Request Puerto 6000 131.178.14.14 Establecimiento de la conexión 131.178.2.25 Puerto 5000 Puerto 6000 131.178.14.14 Establecimiento de la conexión 131.178.2.25 Puerto 7867 Puerto 5000 55.78.34.56 Puerto 6000 131.178.14.14 192.9.48.9 UDP Internet 34.56.89.54, 5000,"Hola" 131.178.14.14 La clase InetAddress • Representa un dirección de IP • No tiene constructor • Para crear un ejemplar de esta clase es necesario llamar a los métodos: – getLocalHost() – getByName(String) – getAllByName(String) Métodos de InetAddress • public static InetAddress getLocalHost() – Regresa la dirección IP de la máquina local • public static InetAddress getByName(String host) – Regresa la dirección IP de la máquina indicada en el parámetro, puedes ser el nombre (“javax.mty.itesm.mx”) o la dirección especificada como string (“131.178.14.228”) • public static InetAddress[] getAllByName(String host) – Regresa todas las direcciones IP asignadas a la máquina indicada como parámetro Métodos de InetAddress • public String getHostName() – Regresa el nombre de la máquina con esta dirección de IP • public String getHostAddress() – Regresa la dirección de IP en formato tradicional (131.178.14.14) • public byte[] getAddress() – Regresa la dirección de IP como un arreglo de bytes. El byte más significativo de la dirección está en el subíndice 0 Ejemplo import java.net.*; public class PruebaInetAddress{ public static void main(String args[]){ String argumento; InetAddress direccion=null; try{ argumento = args[0]; }catch (ArrayIndexOutOfBoundsException e){ argumento = null; } try{ if (argumento!=null) direccion = InetAddress.getByName(args[0]); else direccion = InetAddress.getLocalHost(); }catch (UnknownHostException e){ System.out.println(e.getMessage()); System.exit(0); } System.out.println(direccion.getHostAddress()); System.out.println(direccion.getHostName()); System.out.println(direccion.toString()); byte[] dir = direccion.getAddress(); for (int i=0;i"+recibido); aMandar = new String(recibido.toUpperCase()); buffer = new byte[80]; buffer = aMandar.getBytes(); puertoCliente = paquete.getPort(); paquete = new DatagramPacket(buffer,buffer.length, dirCliente, puertoCliente); yo.send(paquete); } //yo.close(); DatagramSocket yo = null; InetAddress dir = null; DatagramPacket paquete; byte[] buffer = new byte[80]; String recibido, tecleado=" "; BufferedReader delTeclado = new BufferedReader (new InputStreamReader(System.in));; dir = InetAddress.getByName(args[0]); yo = new DatagramSocket(); while(tecleado.length()!=0){ System.out.print("Teclea un mensaje: "); tecleado = delTeclado.readLine(); buffer = tecleado.getBytes(); paquete = new DatagramPacket(buffer, buffer.length, dir, 5000); yo.send(paquete); buffer = new byte[80]; paquete = new DatagramPacket(buffer, buffer.length); yo.receive(paquete); recibido = new String(paquete.getData()); System.out.println(">> "+recibido); } yo.close(); Ejemplo ClienteD1 Multicasting • Es enviar el mismo paquete a varios destinatarios simultáneamente • Sólo se puede hacer con datagramas, de hecho MulticastSocket extiende a DatagramSocket • un paquete multicast se envía a un grupo de direcciones IP clase D : – 224.0.0.1 - 239.255.255.255 • MulticastSocket tiene métodos para unirse y abandonar grupos Ejemplo ServidorMul public static void main(String[] comandos) throws IOException { DatagramSocket yo = new DatagramSocket(); while (true) { byte[] buf = new byte[256]; String aMandar = new String(new Date().toString()); buf = aMandar.getBytes(); InetAddress group = InetAddress.getByName("230.0.0.1"); DatagramPacket paquete = new DatagramPacket(buf, buf.length, group, 5000); yo.send(paquete); System.out.println("Ya mandé "+aMandar); long ahora = System.currentTimeMillis(); while(ahora+1000>System.currentTimeMillis()); } // yo.close(); } Ejemplo ClienteMul public static void main(String[] args) throws IOException { MulticastSocket yo = new MulticastSocket(5000); InetAddress dir = InetAddress.getByName("230.0.0.1"); yo.joinGroup(dir); DatagramPacket paquete; while (true) { byte[] buf = new byte[256]; paquete = new DatagramPacket(buf, buf.length); yo.receive(paquete); String recibido = new String(paquete.getData()); System.out.println("Recibido " + recibido); } // yo.leaveGroup(address); // yo.close(); } Transferencia de objetos • Los flujos (streams y readers/writers) nos permiten mandar objetos por medio de la red sin problemas • Capacidad de mandar estructuras de datos complejas • Capacidad de mandar un objeto para procesamiento en una máquina más potente • ServidorM3.java y Cliente3.java Acceso a Bases de Datos con JDBC JDBC • Es un API de Java para ejecutar estatutos de SQL (Structured Query Language) • Aunque no es un acrónimo, sino una marca registrada, es común darle el significado de Java DataBase Connectivity • Programando con JDBC se puede acceder a casi cualquier Base de Datos comercial por medio de comandos SQL JDBC • Lo más importante es que no necesitamos un programa diferente para cada tipo de Base de Datos que manejemos • Un mismo programa puede accesar la misma estructura en Bases de Datos comerciales diferentes • Extiende la universalidad de Java a Bases de Datos además de las plataformas ODBC • Open DataBase Connectivity • Es la respuesta de Microsoft al mismo problema, acceso a diferentes Bases de Datos con una misma API • Se puede usar ODBC directamente desde Java pero: está programada en C y necesita llamar a métodos nativos, problemas de seguridad y transportabilidad además de otros factores Puente JDBC-ODBC • Se puede usar el puente para que los programas sigan siendo 100% Java • El acceso a la Base de Datos se hace por medio de ODBC • El programador sólo desarrolla en Java y accede a las Bases de Datos por medio del API JDBC, no tiene necesidad de aprender a manejar ODBC, sólo necesita configurarlo Modelo de 2 capas Aplicación o Applet Java Servidor BD Driver JDBC Protocolo propietario de la Base de Datos Modelo de 3 capas Interfaz Gráfica "Bussiness Logic" Applet o Página html Servidor Java Driver JDBC o Servlet Servidor BD Llamadas RMI, CORBA, HTML Protocolo propietario de la Base de Datos Drivers • (Tipo 1) Puente JDBC-ODBC y driver ODBC – La aplicación necesita cargar el código nativo del driver ODBC • (Tipo 2) API nativo con acceso a Java – Convierte llamadas JDBC a llamadas nativas de las Bases de Datos • (Tipo 3) Protocolo de red 100% Java – Convierte llamadas JDBC en llamadas a un protocolo de red independiente el cual es traducido en el servidor a llamadas nativas de la Base de Datos • (Tipo 4) Protocolo nativo 100% Java – Convierte directamente las llamadas JDBC a llamadas nativas de la Base de Datos Pasos previos • Tener instalado JDK con JDBC – JDK ya viene con JDBC, puedes conseguir ejemplos en: http://www.javasoft.com/products/jdbc/book.html • Instalar el driver en la máquina – Nosotros usaremos el puente JDBC-ODBC, asi es que tendremos que configurar ODBC • Instalar el manejador de la Base de Datos – En caso necesario instalar la aplicación, SQL Server, Oracle, Foxpro, DBase, etc., nosotros usaremos Access Configuración de ODBC • En el panel de control seleccionar ODBC Configuración de ODBC • Ya tenemos en disco una base de datos llamada "curso1.mdb" • Seleccionar agregar • Selecionar el tipo de driver que queremos agregar, en nuestro caso será "Microsoft Access Driver (*.mdb) • Presionar Terminar Configuración de ODBC • Asignar un nombre (data source name) para hacer referencia a ella desde Java Configuración de ODBC • En la opción avanzado se puede asignar usuario y password para el acceso de la base de datos Configuración de ODBC • Después presionar seleccionar para ubicar la base de datos en el disco o en la red Ejemplos • Para los siguientes ejemplos tendremos una base de datos ya existente (la que acabamos de configurar) curso1.mdb, el "data source name" también es curso1 pero no es necesario que coincidan • curso1 tiene una tabla que se llama lista, la cual es una lista de alumnos con nombre y matrícula y las calificaciones de tres parciales Tabla lista de curso1 Pasos de un programa • Cargar driver – Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); – La instrucción anterior crea un ejemplar del driver y lo registra con el DriverManager en una sola instrucción • Establecer una conexión a la base de datos – Connection conexion = DriverManager.getConnection ("jdbc:odbc:curso1","jdbc","jdbc"); • Crear un estatuto asociado a la conexión para poder hacer accesos a la base de datos – Statement estatuto = conexion.createStatement(); Consulta a una tabla • La consulta a una tabla se hace por medio del estatuto: – executeQuery("query en SQL") • Donde el query típicamente es un estatuto SELECT de SQL • El query es mandado en forma de String y regresa un objeto de la clase ResultSet que guarda todos los registros obtenidos con el query – ResultSet rs = estatuto.executeQuery("SELECT..."); • rs tiene un apuntador que inicialmente apunta antes del primer registro del grupo obtenido, la forma de avanzar en los registros dentro del grupo es con el método next() del ResultSet que regresa un valor booleano indicando si es que todavía quedan más registros en el ResutSet Consulta a una tabla • La forma de obtener los valores particulares de cada campo en un registro es con los métodos get...() de ResultSet donde la particular versión de get depende del tipo de dato y el parámetro es el nombre del campo o el número de la columna del campo en el registro del grupo obtenido (resultSet) con el estatuto: – getString("nombre"), getInt("EX2"), getBoolean(3), etc. import java.sql.*; public class BaseDeDatos1{ public static void main(String[] args){ try{ Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); }catch(ClassNotFoundException e){ System.out.println(e.getMessage()); } try{ Connection conexion = DriverManager.getConnection("jdbc:odbc:curso1"); Statement estatuto = conexion.createStatement(); ResultSet rs = estatuto.executeQuery("select * FROM lista"); while(rs.next()){ String matricula = rs.getString("MATRICULA"); String nombre = rs.getString("NOMBRE"); int ex1 = rs.getInt("EX1"); int ex2 = rs.getInt("EX2"); int ex3 = rs.getInt("EX3"); System.out.println(matricula+" "+nombre+" "+ex1+" "+ex2+" "+ex3); } estatuto.close(); conexion.close(); }catch(SQLException e){ System.out.println(e.getMessage()); } } } Ejemplo Ejemplo Ejemplo BaseDeDatos2.java Connection conexion = DriverManager.getConnection("jdbc:odbc:curso1","jdbc","jdbc"); Statement estatuto = conexion.createStatement(); ResultSet rs = estatuto.executeQuery("select MATRICULA,NOMBRE "+ "from lista where NOMBRE>'b' and NOMBRE<'f' "+ "order by NOMBRE DESC"); while(rs.next()){ String matricula = rs.getString("MATRICULA"); String nombre = rs.getString(2); System.out.println(matricula+" "+nombre); } Modificación de una tabla • La modificación de tablas se realiza con el estatuto executeUpdate • estatuto.executeUpdate("comando SQL"); • Los comandos típicos SQL para actualización de tablas son – UPDATE – INSERT INTO – DELETE FROM Ejemplo BaseDeDatos3.java estatuto.executeUpdate("update lista set EX1 = EX1 + 10,EX2 = EX2 + 5"); estatuto.executeUpdate("update lista set EX1=100,EX2=100,EX3=100 "+ "where NOMBRE>'a' AND NOMBRE<'b'"); estatuto.executeUpdate("delete from lista where MATRICULA>'7'"); estatuto.executeUpdate("insert into lista values('49052','Pablo Díaz',"+ "100,100,100)"); estatuto.executeUpdate("insert into lista (MATRICULA,NOMBRE,EX3) "+ "values ('123456','Tonto',50)"); Ejemplo Ejemplo BaseDeDatos4.java Statement estatuto = conexion.createStatement(); Statement estatuto1 = conexion.createStatement(); //estatuto.executeUpdate("create table final (MATRICULA text(6), NOTA number)"); //estatuto.executeUpdate("create table final (MATRICULA varchar(6), NOTA int)"); estatuto.executeUpdate("create table final (MATRICULA varchar(6), NOTA double)"); ResultSet rs = estatuto.executeQuery("select * FROM lista"); while(rs.next()){ String matricula = rs.getString("MATRICULA"); int ex1 = rs.getInt("EX1"); int ex2 = rs.getInt("EX2"); int ex3 = rs.getInt("EX3"); double nota = (double)(ex1+ex2+ex3)/3; estatuto1.executeUpdate("insert into final values("+matricula+"," +String.valueOf(nota)+")"); } rs = estatuto.executeQuery("select * FROM final"); while(rs.next()){ String mat = rs.getString("MATRICULA"); double not = rs.getDouble("NOTA"); System.out.println(mat+" "+Math.round(not)); } Ejemplo PreparedStatement • Es una manera de pasar parámetros a estatutos de query y update • Se usa para tener estatutos preparados que se utilizan con frecuencia y que posiblemente ya estén compilados en el servidor de BdeD. Eficiencia! • Los parámetros se especifican con ? y mantienen un orden (índice) que se va incrementando a medida que usas los ? • El valor de los parámetros se especifica con las funciones set...(índice, valor), donde la versión de set depende del tipo de dato que asignarás al parámetro • El estatuto se llama sin el típico parámetro String Ejemplo BaseDeDatos5.java PreparedStatement estatuto = conexion.prepareStatement("select * from final "+ "where NOTA > ? and NOTA < ?"); estatuto.setDouble(1,70); estatuto.setDouble(2,80); ResultSet rs = estatuto.executeQuery(); while(rs.next()){ String matricula = rs.getString("MATRICULA"); double nota = rs.getDouble("NOTA"); System.out.println(matricula+" "+nota); } Acceso a dos o más tablas • Normalmente se diseñan varias tablas en una base de datos con campos en común para poder accesar la información en forma más eficiente • En nuestro caso tenemos dos tablas que tiene el campo matrícula • Cuando se hace un acceso a dos o más tablas se necesita especificar a que tabla pertenece cada campo. Tabla.campo • Esto sólo se necesita para campos que tengan el mismo nombre en las diferentes tablas Ejemplo BaseDeDatos6.java ResultSet rs = estatuto.executeQuery("select lista.NOMBRE from lista, "+ "final where final.NOTA>70 and final.NOTA<80 "+ "and lista.MATRICULA = final.MATRICULA"); while(rs.next()){ String nombre = rs.getString("NOMBRE"); System.out.println(nombre); } Stored Procedures • Un stored procedure es un grupo de estatutos SQL que ejecutan una tarea particular y se toman como una unidad (es como una rutina en SQL) • La mayoría de los manejadores de Bases de Datos tiene la capacidad de programar stored procedures, pero la sintaxis varía de una a otra, además de otras particularidades Stored Procedures • Es conveniente que los programes en la Base de Datos que uses y los llames desde Java, a pesar de que los puedes crear en Java • El llamado a un stored procedure es: – CallableStatement estatuto=conexion.prepareCall("{call SP}"); – ResultSet rs = estatuto.executeQuery(); • Para crearlos desde Java: – Statement estatuto = con.createStatement(); – estatuto.executeUpdate("create procedure as SP . . . . ); Servlets Servlets • • • • Es Java en el servidor Applets en browsers, Servlets en el servidor Aplicar todas las ventajas de Java Apoya la idea de ejecutar el trabajo en el servidor (back end) y dejar el cliente como interfaz (front end) • Soporte directo para desarrollar páginas de Web "dinámicas" javax.servlet.* • Es una extensión de java (por eso la x), es decir no pertence al núcleo de APIs • A pesar de que los servlets no son especificamente para servidores de Web, es en el Web donde han recibido la mayor atención inicial • javax.servlet.http.HttpServlet Servlets vs CGIs • Common gateway Interface • Estándar para desarrollar el lado del servidor en aplicaciones de Web (generalmente programados en Perl) • Ventajas de servlets – familiaridad: es Java! – transportabilidad: la mayoría de los vendedores de servidores soportan servlets – seguridad: por Java – eficiencia: El servidor arranca un proceso nuevo por cada petición a un CGI javax.servlet.Servlet • Interfaz genérica para servlets • service(): es el motor de un servlet, atiende peticiones, recibe dos parámetros (objetos del tipo ServletRequest y ServletResponse), el primero encapsula la petición de un cliente y el segundo la respuesta que se regresa • init(): Método para inicializar al servlet, acepta un parámetro de tipo ServletConfig • destroy(): Donde se hace la limpieza del servlet • getServletConfig(): regresa el objeto tipo ServletConfig que se pasa a init() • getServletInfo(): regresa un String con información que se programa previamente Ejemplo import javax.servlet.http.*; import javax.servlet.*; import java.io.*; public class Servlet0 extends HttpServlet{ protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException{ String s = “”; s += "\n"; s += "\n"; s += "Primer Servlet\n"; s += "\n"; s += "

Hola que tal!

\n"; s += ""; resp.setContentType("text/html"); resp.setContentLength(s.length()); resp.getOutputStream().print(s); } } Ejemplo Breve Introducción a HTML “Minimal survival Kit” HTML • • • • HyperText Markup Language Lenguaje de Marcación de Hipertexto Hiper  Superior Markup  Marcar Es un lenguaje para: – FORMATEO – VISUALIZACIÓN • No es un lenguaje de Programación HTML • Este es un ejemplo de HTML Este es un ejemplo de HTML HTML • Existen etiquetas y elementos • Etiquetas indican la función y/o formato de los elementos • ..... • Palabra subrayada Palabra subrayada Estructura de una página en HTML Encabezado (HEAD) • Contiene información acerca del documento (página) – Título (.....). Debe de existir – Autor, palabras clave, lenguaje, etc. – Información que no se considera contenido – Encabezados HTTP Documento (BODY) • Es el contenido del documento que se despliega en el navegador. • Es la parte que se despliega en el navegador o explorador. • Contiene etiquetas para formato, visualización y enlaces. Anidación de etiquetas • Para producir múltiples efectos en un elemento • Tanto la etiqueta inicial como final deben de quedar anidadas – Hola que tal!Hola que tal! Atributos de etiquetas – Son parte de las etiquetas – Pueden ser opcionales – Extienden o modifican la acción de una etiqueta – .......... – ..... Una página HTML Ejemplo de HTML

Ejemplos

Esta es nuestra primera prueba con HTML. La iremos cambiando para ver que impacto tienen las diferentes etiquetas de este lenguaje.

Hiperenlaces • Etiqueta “Anchor” con atributo href – texto Visita Yahoo Visita Yahoo Servlet0.java import javax.servlet.http.*; import javax.servlet.*; import java.io.*; public class Servlet0 extends HttpServlet { protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException{ StringBuffer buffer = new StringBuffer(); buffer.append("\n"); buffer.append("\n"); buffer.append("Primer Servlet\n"); buffer.append("\n"); buffer.append("

Hola que tal!

\n"); buffer.append(""); resp.setContentType("text/html"); resp.setContentLength(buffer.length()); resp.getOutputStream().print(buffer.toString()); } } Servidor de Web con "Servlet Engine" Funcionamiento "Servlet engine" R E Q R E S P service(req,resp) : : ServletX Browser Preparación • Agregar servlet.jar al classpath para poder compilar servlets – Copiar el archivo al directorio: /dir_java/jre/lib/ext • Bajar servlet.jar del sitio de SUN o utilizar el que venga con la maquinaria de Servlets • Instalar un servidor de Web • Instalar una maquinaria de servlets • TOMCAT tiene ambos Tomcat 5 • Subproyecto de Jakarta, el cual es un proyecto de Apache (ASF). www.apache.org • El proyecto Jakarta se encarga de crear y mantener soluciones “open source” para Java en el servidor • Tomcat es excelente maquinaria de servlets y JSPs, actualizada y de buen rendimiento • Si viene de Apache......... • Ant, Cocoon, Struts, Axis.......... Instalación de Tomcat 5 • • • • • • • • • • Necesita j2sdk Bajar Tomcat del sitio http://jakarta.apache.org Establecer JAVA_HOME (variable de ambiente) Activar “servlet reloading” (para desarrollo) Puerto 8080 (default) o el 80? Habilitar “invoker servlet” Cambiar la memoria de DOS (Win98) Establecer CATALINA_HOME (opcional) Arrancar Tomcat (standalone) o servicio Probar ejemplos (http://localhost:8080) Creación de un Servlet • Compilar el archivo del servlet (ServletX.java) • Poner el código obtenido (ServletX.class) en el directorio correspondiente (classes) de la aplicación de Web – miAplicacionDeWeb/WEB-INF/classes • Llamar al servlet – http://máquina/miAplicacionDeWeb/servlet/ServletX Servlets HTTP • Son los más usados hasta el momento • Para la creación de páginas de Web dinámicas • Dos maneras de llamar a un servlet (o a cualquier recurso) – POST – GET • service(req, resp) analiza la petición y la enruta al método apropiado (doPost o doGet) GET y POST • GET – Es el default para todas las conexiones – Pasa los parámetros dentro del URL – Hay que reprogramar doGet(req,resp) • POST – Sólo disponible en formas (form) – Pasa los parámetros independiente del URL ("escondidos") – Hay que reprogramar doPost(req,resp) Introducción a formularios en HTML Formularios (Forms) • ¿Qué son? Contenedores de información. • ¿Cuál es su objetivo? Proporcionan interactividad a las páginas de hipertexto. • ¿Para qué se usan? – Recolectar (registrar) información. – Generar respuestas exclusivas (“customized”) – Construir páginas “al vuelo” (“on the fly”) Formularios (Forms) Etiqueta
• El contendedor ...
se utiliza para encasillar elementos dentro de un formulario. • Una forma tiene propiedades: – ACTION, METHOD • y elementos: – TEXT, BUTTON, CHECKBOX, etc Elementos en un formulario • Botón – NAME=“string” – VALUE=“string” • Conjunto de opciones – CHECKED – NAME=“string” – VALUE=“text” Elementos en un formulario • Archivo – ACCEPT=“MIME type” – NAME=“string” – VALUE=“string” • Oculto – NAME=“string” – VALUE=“string” Elementos en un formulario • Texto – – – – – – – – MAXLENGTH=número NAME=“string” VALUE=“string” SIZE=número • Password MAXLENGTH=número NAME=“string” VALUE=“string” SIZE=número Elementos en un formulario • Conjunto de selección – CHECKED – NAME=“string” – VALUE=“string” • Borrardo de datos – VALUE=“RESET” ... u otro texto a discresión del desarrollador. Elementos en un formulario • Envío de datos • Área de texto – – – – – VALUE=“SUBMIT”... u otro texto a discresión del desarrollador. COLS=número ROWS=número NAME=“string” VALUE=“string” Elementos en un formulario • SELECT – MULTIPLE – NAME=“string” – SIZE=número • OPTION – SELECTED – VALUE=“string” ¿Cómo se envía la información? • Encodificada por parejas con el formato ... nombre=valor&nombre=valor& nombre=valor ... separadas por el caracter ‘&’. • Los caracters especiales se traducen al formato %HH (códigos ASCII en HEX) y el espacio en blanco se convierte al signo ‘+’ • Existen dos métodos para enviar la información ... GET y POST. Método GET • En este formato la información se envía junto con el URL HTTP://maquina/directorio/servlet/MiServlet ?texto1=algo&texto2=otro&texto3=más • Es el método menos seguro ya que muestra la información transferida al usuario. Método POST • En este formato la información se envía junto con el URL HTTP://maquina/directorio/servlet/MiServlet • Es el método más seguro ya que la información transferida nunca se muestra. Propiedad ACTION • Indica el URL de programa en el servidor (servlet) que se debe ejectuar para procesar los datos de una forma. • Además del URL del programa especifica el método a utilizar para el envio: GET o POST Servlet1.html Servlets: Ejemplo 1

Lod dos tipos de llamadas a un Servlet

"Form"

Esta forma usa el método POST, el default es GET

"Hyperlink"

El enlace usa el método GET

Servlet1 Servlet1.java import javax.servlet.http.*; import javax.servlet.*; import java.io.*; public class Servlet1 extends HttpServlet{ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException{ Analizar petición (req) Generar respuesta (resp) } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException{ Analizar petición (req) Generar respuesta (resp) } } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException{ StringBuffer buffer = new StringBuffer(); buffer.append("\n"); buffer.append("\n"); buffer.append("Resultado con POST\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("

Servlet atendió POST

\n"); buffer.append("

Hola que tal!!!!\n"); buffer.append("\n"); buffer.append(""); resp.setContentType("text/html"); resp.setContentLength(buffer.length()); resp.getOutputStream().print(buffer.toString()); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException{ StringBuffer buffer = new StringBuffer(); buffer.append("\n"); buffer.append("\n"); buffer.append("Resultado con GET\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("

Servlet atendió GET

\n"); buffer.append("

Hola que tal!!!!\n"); buffer.append("\n"); buffer.append(""); resp.setContentType("text/html"); resp.setContentLength(buffer.length()); resp.getOutputStream().print(buffer.toString()); } Analizando parámetros • Los nombres de los parámetros y sus valores se transmiten como strings • Se obtienen con el método getParameter() del objeto de tipo HttpServletRequest • valor = req.getParameter("nombre"); String Servlet2.html

Lod dos tipos de llamadas a un Servlet

Esta forma usa el método POST, el default es GET


Esta forma usa el método GET, el default

Servlet2.html Servlet2.java protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException{ String caja1 = req.getParameter("caja1"); String caja2 = req.getParameter("caja2"); caja1=caja1.toUpperCase(); caja2=caja2.toLowerCase(); StringBuffer buffer = new StringBuffer(); buffer.append("\n"); buffer.append("\n"); buffer.append("Resultado con POST\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("

Servlet 2 atendió POST

\n"); buffer.append("

Me mandaron:\n"); buffer.append("

"+caja1+"\n"); buffer.append("

"+caja2+"\n"); buffer.append("\n"); buffer.append(""); resp.setContentType("text/html"); resp.setContentLength(buffer.length()); resp.getOutputStream().print(buffer.toString()); } Servlet2 http://131.178.14.14:8080/curso/servlet/Servlet2 Servlet2.java protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException{ String caja1 = req.getParameter("caja1"); String caja2 = req.getParameter("caja2"); caja1=caja1.toLowerCase(); caja2=caja2.toUpperCase(); StringBuffer buffer = new StringBuffer(); buffer.append("\n"); buffer.append("\n"); buffer.append("Resultado con GET\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("

Servlet 2 atendió GET

\n"); buffer.append("

Me mandaron:\n"); buffer.append("

"+caja1+"\n"); buffer.append("

"+caja2+"\n"); buffer.append("\n"); buffer.append(""); resp.setContentType("text/html"); resp.setContentLength(buffer.length()); resp.getOutputStream().print(buffer.toString()); } Servlet2 http://131.178.14.14:8080/curso/servlet/Servlet2?caja1=CuRsO&caja2=JaVa Ejemplo práctico • Aplicación de Base de datos de 3 capas • El cliente es un browser – Alta disponibilidad – Adecuada interfaz gráfica – No hay necesidad de distribuir la aplicación • El servidor es un servlet – Java – Se puede cambiar en cualquier momento – No hay necesidad de configurar ODBC en el cliente Modelo de 3 capas Consulta Respuesta Query Respuesta Cliente Servidor Front End Bussiness Logic Servidor de Base de Datos Ventajas del modelo de 3 capas • El cliente puede ser liviano • El cliente puede ser universal • La lógica para las consultas y su procesamiento se ejecuta en un servidor de más potencia • La lógica y el procesamiento de las consultas puede cambiar sin alterar al cliente • No se necesita driver en el cliente Ejemplo • • • • Proceso de inscripción y consulta de alumnos Base de datos que almacena a los alumnos La inscripción se realiza en un browser! El servlet maneja las peticiones y regresa las respuestas en forma de una página de Web • En cualquier momento se puede cambiar el "look and feel" de la página de inscripción y los clientes siguen ejecutándose desde un browser Ejemplo • Inscripcion.html – Página de Web que es el front end de la inscripción • Inscripcion.class – Servlet que procesa la inscripción dando de alta al alumno en una Base de Datos, regresa una página de Web con el resultado de la inscripción • Despliega.class – Servlet que hace la consulta de todos los alumnos inscritos y regresa una página de Web con todos los alumnos desplegados • Cursojava.mdb – Base de datos con los datos de los alumnos, contiene la tabla Alumnos Inscripcion.html Inscripcion.html

Apellidos:

Nombres:

Correo:

Ver a los demás inscritos Inscripcion.java import import import import javax.servlet.http.*; javax.servlet.*; java.io.*; java.sql.*; public class Inscripcion extends HttpServlet{ private Connection conexion; private String baseDeDatos ="jdbc:odbc:cursojava"; private PreparedStatement inscribeAlumno; public void init(ServletConfig config) throws ServletException{ super.init(config); try{ Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); conexion = DriverManager.getConnection(baseDeDatos,"",""); inscribeAlumno = conexion.prepareStatement("INSERT INTO alumnos "+ "(apellidos, nombres, puesto, correo) values (?,?,?,?)"); }catch(Exception e){} } Inscripcion.java doPost(...) protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException{ Alumno inscrito = new Alumno(req); try{ inscribeAlumno.setString(1,inscrito.getApellidos()); inscribeAlumno.setString(2,inscrito.getNombres()); inscribeAlumno.setString(3,inscrito.getPuesto()); inscribeAlumno.setString(4,inscrito.getCorreo()); inscribeAlumno.executeUpdate(); }catch(Exception e){} Inscripcion.java doPost(...) StringBuffer buffer = new StringBuffer(); buffer.append("\n"); buffer.append("\n"); buffer.append("Aviso de Inscripción\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("

"+inscrito.getNombres()+" "+ inscrito.getApellidos()+"

\n"); buffer.append("

Ya estás inscrito\n"); buffer.append("

Quieres ver a los otros?\n"); buffer.append("\n"); buffer.append(""); resp.setContentType("text/html"); resp.setContentLength(buffer.length()); PrintWriter salida = new PrintWriter(resp.getOutputStream()); salida.println(buffer.toString()); salida.close(); } class Alumno{ String nombres; String apellidos; String puesto; String correo; La clase Alumno public Alumno(HttpServletRequest req){ apellidos = req.getParameter("apellidos"); if (apellidos.equals("")) apellidos = "sin appellidos"; nombres = req.getParameter("nombres"); if (nombres.equals("")) nombres = "sin nombres"; puesto = req.getParameter("puesto"); if (puesto.equals("")) puesto = "sin puesto"; correo = req.getParameter("correo"); if (correo.equals("")) correo = "sin correo"; } public Alumno(String apellidos, String nombres, String puesto, String correo){ this.apellidos = apellidos; this.nombres = nombres; this.puesto = puesto; this.correo = correo; } La clase Alumno public void setNombres(String nombres){ this.nombres = nombres; } public void setApellidos(String apellidos){ this.apellidos = apellidos; } public void setPuesto(String puesto){ this.puesto = puesto; } public void setCorreo(String correo){ this.correo = correo; } public String getNombres(){ return nombres; } public String getApellidos(){ return apellidos; } public String getPuesto(){ return puesto; } public String getCorreo(){ return correo; } Ejemplo Despliega.java import import import import javax.servlet.http.*; javax.servlet.*; java.io.*; java.sql.*; public class Despliega extends HttpServlet{ private Connection conexion; private String baseDeDatos ="jdbc:odbc:cursojava"; private Statement estatuto; public void init(ServletConfig config) throws ServletException{ super.init(config); try{ Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); conexion = DriverManager.getConnection(baseDeDatos,"",""); estatuto = conexion.createStatement(); }catch(Exception e){} } Despliega.java protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException{ Alumno inscrito; ResultSet rs=null; StringBuffer buffer = new StringBuffer(); buffer.append("\n"); buffer.append("\n"); buffer.append("Curso de Java\n"); buffer.append("\n"); buffer.append("

\n"); buffer.append("

Lista de Alumnos

\n"); buffer.append("

\n"); buffer.append("

\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); Despliega.java try{ rs = estatuto.executeQuery("SELECT * FROM alumnos ORDER BY apellidos"); int cont = 1; while(rs.next()){ inscrito = new Alumno(rs); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); cont++; } }catch(SQLException e){} buffer.append("
NombrePuestoCorreo
"+String.valueOf(cont)+""+inscrito.getApellidos()+", "+ inscrito.getNombres()+""+inscrito.getPuesto()+" "+inscrito.getCorreo()+"
\n"); buffer.append("\n"); buffer.append(""); resp.setContentType("text/html"); resp.setContentLength(buffer.length()); PrintWriter salida = new PrintWriter(resp.getOutputStream()); salida.println(buffer.toString()); salida.close(); La clase Alumno public Alumno(ResultSet rs){ try{ apellidos = rs.getString("apellidos"); nombres = rs.getString("nombres"); correo = rs.getString("correo"); puesto = rs.getString("puesto"); }catch(SQLException e){} } La clase Despliega public void destroy(){ try{ conexion.close(); }catch(SQLException e){} } Página que regresa Despliega.class Cuidado!!!!!!! Variables init() service() service() service() service() destroy() Cuidado!!!!!!! • En init se abre una conexión a la base de datos y se crea un estatuto • Cuando hay peticiones simultáneas, éstas comparten la conexión y el estatuto • Esto lo hicimos por cuestiones de eficiencia, ya que crear conexiones consume recursos • Pero . . . . . . Posibles soluciones • Sincronizar el acceso a la Base de Datos • Implementar la interfaz SingleThreadModel – Un solo service() en ejecución en cualquier momento • Crear una conexión por cada petición – No poner código “sensible” en init() ni destroy() – La Base de Datos debe ser capaz de manejar múltiples conexiones • Dejar que el manejador de la Base de Datos haga uso de sus capacidades de “pool” de conexiones......... Si las tiene Cookies Las famosas galletitas Galletas • Cookies • Información que se guarda en la máquina del cliente en un archivo de texto • En su forma más sencilla: – Nombre=valor • También se puede especificar la fecha de expiración y algunos otros datos ¿Por qué? • HTTP es un protocolo que no mantiene estados (Stateless) • Cada petición es servida en forma independiente por el servidor • Incluso dentro de una misma página • Las “cookies” nos permiten mantener un estado con un cliente específico Ejemplos • • • • Contador de visitas Login y password Gustos (hábitos de navegación) Carrito de compras ¿Buenas o malas? • • • • • Muy útiles Puro texto No ejecución No virus Publicación de mis hábitos y costumbres de navegación • Se pueden desactivar Uso de cookies • Se usan para guardar datos en el cliente • Todavía están en proceso de estandarización • javax.servlet.http.Cookie Métodos importantes • getCookies() – Método de HttpServletRequest – Regresa un arreglo de tipo Cookie con las cookies que existen en el cliente • getName() y getValue() – De la clase Cookie – Regresan el nombre y el valor de una cookie • setMaxAge(int expiry) y getMaxAge(int expiry) – Establecen y regresan el tiempo de duración de una cookie en segundos. expiry = 0 la cookie se borra, expiry < 0 durante la sesión del navegador • addCookie(Cookie) – Método de HttpServletResponse – Agrega una cookie en el cliente al cual va la respuesta InscripcionC.java public class InscripcionC extends HttpServlet{ String paginaInscripcion; String paginaReinscripcion; public void init(ServletConfig config) throws ServletException{ super.init(config); paginaInscripcion = leeArchivo("f:\\www\\curso\\InscripcionCN.html"); paginaReinscripcion = leeArchivo("f:\\www\\curso\\InscripcionCR.html"); } private String leeArchivo(String archivo){ StringBuffer pagina = new StringBuffer(); try{ FileReader leeArchivo = new FileReader(archivo); BufferedReader leeFiltrado = new BufferedReader(leeArchivo); String linea; while ((linea = leeFiltrado.readLine()) != null) pagina.append(linea+"\n"); leeArchivo.close(); leeFiltrado.close(); }catch(FileNotFoundException e){ }catch(IOException e){ } return pagina.toString(); } InscripcionC.java protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException{ String pagina=paginaInscripcion; Cookie[] cookies = req.getCookies(); try{ for(int i=0; i < cookies.length; i++) { if (cookies[i].getName().equals("galletita") && cookies[i].getValue().equals("galletita")){ pagina = paginaReinscripcion; break; } } }catch(Exception e){ } Cookie galletita = new Cookie("galletita","galletita"); galletita.setMaxAge(-1); resp.addCookie(galletita); resp.setContentType("text/html"); resp.setContentLength(pagina.length()); PrintWriter salida = new PrintWriter(resp.getOutputStream()); salida.println(pagina); salida.close(); } public class Identifica extends HttpServlet{ Enumeration nombres; String parametro; String valor; Identifica.java protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException{ String escrito = req.getParameter("escrito"); StringBuffer buffer = new StringBuffer(); buffer.append("\n"); buffer.append("\n"); buffer.append("Resultado con POST\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("

Variables de Ambiente

\n"); nombres = req.getHeaderNames(); while (nombres.hasMoreElements()) { parametro = (String)nombres.nextElement(); buffer.append(parametro + " = "); valor = req.getHeader(parametro); buffer.append(valor); buffer.append("
"); } buffer.append("\n"); buffer.append(""); resp.setContentType("text/html"); resp.setContentLength(buffer.length()); resp.getOutputStream().print(buffer.toString()); } Documentación de Servlets • Se baja del sitio de SUN, del mismo lugar donde bajamos las clases de servlets • Algunos métodos adicionales de la clase Cookie • Métodos para obtener parámetros (encabezados) de HttpServletRequest Manejo de Sesiones • HTTP es un protocolo que no mantiene estado (stateless) • Cada conexión es completamente independiente de la anterior • Un problema para manejar peticiones en diferentes páginas de un mismo cliente Soluciones al problema • Cookies – La mejor solución pero el usuario las puede deshabilitar • Reescritura del URL (URL rewritting) – Cada página debe ser generada en forma dinámica • Campos ocultos – Cualquier persona puede ver el código... Sesiones en Servlets • Servlets maneja la clase HTTPSession • Es una abstracción poderosa que nos permite despreocuparnos de los detalles del manejo de estado • Primero intenta utilizar cookies y si no se puede usa la reescritura de URL • Todo es transparente al programador Objeto Session • HttpSession sesion = request.getSession(true) • Es tan usado que en caso de no exista una sesión asociada con el cliente crea una en forma atutomática Valores asociados a una sesión • getAttribute(nombre) – Antes se usaba getValue(...) (deprecated) – Regresa un Object  hay que hacer casting • SetAttribute(nombre, valor) – Antes se usaba putValue(...) (deprecated) Ejemplos • Veremos dos ejemplos: – Vista de páginas sólo a usuarios autorizados (Página de Login) – Carrito de compras sencillo JSPs Java Server Pages Páginas de Web con contenido DINÁMICO! JSPs Separa el contenido (generado por programadores) y la presentación (producida por diseñadores) Desarrollo en Web Servlets • Programa en Java produce una página en HTML Java Html Página de Web JSPs • Página en Html con “scripts” de Java Html Java Página de Web import import import import java.io.*; javax.servlet.*; javax.servlet.http.*; java.util.*; public class Fecha extends HttpServlet { public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ ServletOutputStream out = res.getOutputStream(); res.setContentType("text/html"); out.println(""); out.println(" Servlet de Fecha "); out.println(""); out.println("

La fecha es: "+ new Date().toString() +"

"); out.println(""); out.println(""); out.close(); } } <%@ page language import = %> JSP <BODY> <H1> La fecha es: </BODY> </HTML> = "java" "java.util.*" de Fecha <%= new Date().toString() %> JSPs Java/Html P R O G R A M A D O R A D I S E Ñ A D O R Páginas de Web • • • • • HTML (Estáticas) CGI (Perl, Php, C) Servlets (java) ASPs (vbscript) JSPs (Java) JSPs • Código de Java embebido en página HTML • HTML con etiquetas adicionales especícificas para JSPs • Tres tipos de etiquetas – Elementos de código (scripting) – Elementos de acción – Elementos directivos Etiquetas de Scripting • Comentarios – <%-- .... --%> – • Declaraciones – <%! ..... %> • Expresiones – <%= ..... %> • Scriptles – <% ..... %> Comentarios • ] --> • Genera un comentario que se envía al cliente y se puede visualizar en el código fuente de HTML <%@ page language = "java“ %> Jsp1.jsp

Página generada con JSP

Comentarios • <%-- Comentario --> • Comentario que no se envía al cliente (escondido) • Para documentar la página JSP Jsp2.jsp <%-- Este comentario no aparecerá en el cliente --%>

Página generada con JSP

Declaraciones • <%! Declaraciones %> • Para declarar variables o métodos válidos en el lenguaje, para ser utilizados dentro de la página • Debe de contener por lo menos un estatuto de declaración válido • Cada estatuto debe terminar con ; • Se deben declarar las variables y métodos antes de ser usados en la página • Se pueden usar variables y métodos de los paquetes importados con la directiva Page, sin necesidas de declararlos explícitamente <%! Int i, j; String s; Date fecha = new Date(); %> Expresiones • <%= expresión %> • Expresión válida en el lenguaje de script (Java) • La expresión se evalua, se convierte a String y se inserta en la página, en el lugar donde aparece • No debe de terminar con ; <%@ page language = "java" import = "java.util.*" %> <%! Date fecha = new Date(); %> Jsp3.jsp Hoy es <%= fecha.toString() %> Scriptlets • <% estatutos %> • Puede contener estatutos, declaración de variables o métodos • Se pueden usar los objetos implícitos de JSP – request, response, out, . . . . . • Se ejecutan en el momento de la petición de la página, al igual que las expresiones • Las declaraciones se ejecutan una sola vez, al momento de cargar la página por primera vez . . . . . . Scriptlets <%@ page language = "java" import = "java.util.*" %> <%! int accesos = 0; String tipo; %> Jsp4.jsp <% accesos++; if ((accesos%2) != 0) tipo = "impar"; else tipo = "par"; %>
La página se ha cargado <%= accesos %>
Que quiere decir un número <%= tipo %> de veces
<% out.print(""); out.print(new Date().toString()); out.println(""); %>
Fin de la página Declaración de métodos • Los métodos se declaran dentro de una etiqueta de declaración (<%! ...... %>) • Se pueden usar en toda la página <%@ page language = "java" %> <%! int accesos = 0; String tipo; public String tipo(int n){ if ((n%2) != 0) return "impar"; else return "par"; } %> Jsp5.jsp <% accesos++; %>
La página se ha cargado <%= accesos %> veces
Que quiere decir un número <%= tipo(accesos) %> de veces La directiva Page <%@ page [ language [ extends [ import [ session [ buffer [ autoFlush [ isThreadSafe [ info [ errorPage [ contentType [ isErrorPage %> = = = = = = = = = = “java” ] “package.clase” ] “{package.class | package.*},...] “true|false” ] “none|8kb|sizeKb” ] “true|false” ] “true|false” ] “text” ] “relativeURL” ] “mimeType [;charset=charSet]”| “text/html ; charset = ISO-8859-1” ] = “true|false” ] Objetos implícitos • • • • • • • • request response out session application config pageContext page Jsp6.html

Formulario

Esta forma llamará a una JSP y regreserá el primer dato en minúsculas y el segundo en mayúsculas

Dato1:
Dato2:

request <%@ page language="java" %> Jsp6.jsp <% String s1 = request.getParameter("caja1"); String s2 = request.getParameter("caja2"); %>
Dato1: <%= s1.toLowerCase() %>
Dato2: <%= s2.toUpperCase() %> request JDBC con JSPs Despliega.jsp <%@ page languaje = "java" import = "java.sql.*" errorPage = "Error.jsp" %> <%! Connection conexion; Statement estatuto; ResultSet rs; String nombres, apellidos, puesto, correo; int cont; %> <% Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); conexion = DriverManager.getConnection("jdbc:odbc:cursojava"); %>

Lista de Alumnos

JDBC con JSPs <% estatuto = conexion.createStatement(); rs = estatuto.executeQuery("SELECT * FROM alumnos ORDER by apellidos"); cont = 0; while(rs.next()){ cont++; nombres = rs.getString("nombres"); apellidos = rs.getString("apellidos"); puesto = rs.getString("puesto"); correo = rs.getString("correo"); %> <% } rs.close(); estatuto.close(); conexion.close(); %>
Nombre Puesto Correo
<%= cont %> <%= nombres +" "+ apellidos %> <%= puesto %> > <%= correo %>
<% estatuto = conexion.createStatement(); rs = estatuto.executeQuery("SELECT * FROM alumnos ORDER by apellidos"); cont = 0; while(rs.next()){ cont++; nombres = rs.getString("nombres"); apellidos = rs.getString("apellidos"); puesto = rs.getString("puesto"); correo = rs.getString("correo"); %> <% } rs.close(); estatuto.close(); conexion.close(); %>
Nombre Puesto Correo
<%= cont %> <%= nombres +" "+ apellidos %> <%= puesto %> > <%= correo %>
Una JSP es un Servlet! GET Archivo.jsp Página HTML Una JSP es un Servlet! • Verificar fecha en archivo – Generar código java – Compilar y generar .class Archivo.jsp • Ejecutar y generar HTML Página HTML Archivo.class Archivo.java jspInit() y jspDestroy() <%! Connection conexion; Statement estatuto; ResultSet rs; String nombres, apellidos, puesto, correo; int cont; public void jspInit(){ try{ Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); conexion = DriverManager.getConnection("jdbc:odbc:cursojava"); }catch(ClassNotFoundException e1){ System.err.println("Error en la clase"); }catch(SQLException e2){ System.err.println("Error en SQL"); } } public void jspDestroy(){ try{ conexion.close(); }catch(SQLException e2){} } %> Rendimiento • Impacto inicial – Generación del .class • Servlet en memoria • Código generado – Puede ser más eficiente que el producido por el programador – out.print  out.write • Producción!!!!!!!!!! – Más rápida y adecuada JavaBeans • Son componentes • Clases que eventualmente se convertirán en objetos • Siguen ciertas reglas un poco más estrictas que las clases normales • Nacieron como componentes gráficos para IDEs JavaBeans • Si se usan bien realmente nos dan la separación entre diseño y contenido que tanto se necesita • No hay que olvidar que en última instancia un bean es una clase, de la cual se pueden crear objetos JavaBeans, ¿dónde van? • Son clases que deben de estar accesibles por medio del classpath del contenedor de JSPs • La manera más fácil es ponerlos en el directorio classes, que está en el directorio WEB-INF de la aplicación de Web • Los ejemplos que están en la literatura usan paquetes para agrupar los beans, y estos deben de seguir la estructura jerárquica correspondiente Reglas • Debe de tener un constructor sin parámetros • No debe de tener variables de ejemplar públicas • Las variables (propiedades) del bean se deben de obtener o modificar por medio de métodos llamados getXxx y setXxx Ejemplo import java.util.*; import java.text.*; public class FechasBean{ private Locale local = new Locale("es","MX"); public FechasBean(){} public String getFechaLarga(){ DateFormat f = DateFormat.getDateInstance(DateFormat.FULL, local); return f.format(new Date()); } public String getHoraCorta(){ DateFormat f = DateFormat.getTimeInstance(DateFormat.SHORT, local); return f.format(new Date()); } } Fecha.jsp <%@ page language = "java" %>

La fecha de es:

La hora es:

Alcance de un bean • “Tiempo” de vida dado por scope • page – Se crea cada vez que se carga la página (Fecha3.jsp) • session – Dura toda la sesión de peticiones (requests) (Fecha3a.jsp) • application – Para compartir los beans con otros servlets y jsps con sesiones diferentes (Fecha4.jsp) Un mejor Despliega DespliegaConBean.jsp <%@ page %>

Lista de Alumnos

Fin de la lista

language = "java" errorPage = "Error.jsp" DespliegaBean.java import java.util.*; import java.sql.*; public class DespliegaBean{ private Connection conexion; private String baseDeDatos ="jdbc:odbc:cursojava"; private Statement estatuto; private ResultSet rs; public DespliegaBean(){ try{ Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); }catch(ClassNotFoundException e){} } DespliegaBean.java synchronized public String getParticipantes(){ Alumno inscrito; StringBuffer buffer = new StringBuffer(500); buffer.append("
\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); DespliegaBean.java try{ conexion = DriverManager.getConnection(baseDeDatos,"",""); estatuto = conexion.createStatement(); rs = estatuto.executeQuery("SELECT * FROM alumnos ORDER BY apellidos"); int cont = 1; while(rs.next()){ inscrito = new Alumno(rs); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); buffer.append("\n"); cont++; } rs.close(); estatuto.close(); conexion.close(); }catch(SQLException e){} buffer.append("
NombrePuestoCorreo
"+String.valueOf(cont)+""+inscrito.getApellidos()+", "+ nscrito.getNombres()+""+inscrito.getPuesto()+" "+inscrito.getCorreo()+"
"); return buffer.toString(); Manejo de Sesiones • A veces el usuario inhibe las cookies • Tenemos que tener métodos alternos para manejar estado del cliente • Existen métodos ya probados: – URLrewriting y campos escondidos • URLrewriting es tremendamente tedioso Manejo de sesiones • Java implementó una clase que maneja sesiones • Inicialmente trata de usar cookies y si no puede lo hace a través de URLrewriting • Pero es completamente transparente • Ver ejemplos Modelos I y II • Son modelos para el desarrollo de aplicaciones en Web • Inicialmente nos vemos tentados a utilizar solamente JSPs (por su facilidad) • Pero acabamos con código muy difícil de mantener, nuestros JSPs se hacen cada vez más complicados Modelo 1 Petición JSP Respuesta Base De Datos JavaBean Modelo 2 Petición servlet Base De Datos Respuesta JSP JavaBean Ejemplo de la red • Ananalizaremos un ejemplo de la revista JavaWorld • Nos dará un diferente enfoque al desarrollo de estas aplicaciones • Además manejaremos sesiones http://javax.mty.itesm.mx/puce