sábado, 1 de septiembre de 2012

Introduccion JavaEE


Hoy vamos a ver una rebanada de lo que es JavaEE, esta API es la que nos ayuda a desarrollar aplicaciones basadas en la web, en mi opinion es codigo escrito en Java que se encuentra publicado en un servidor.

Para realizar el objetivo de esta entrada es necesario contar con los siguientes:
  1. Un contenedor de servlets(Tomcat o Jetty) o un servidor de aplicaciones(GlassFish, JBoss, WebLogic, ...). La diferencia entre uno y otro, es que el un servidor es mucho mas robusto, estan diseñados para soportar la especifiacion de JavaEE y el contenedor unicamente nos sirve para correr JSPs y Servlets, de hecho los servidores tienen un contenedor dentro de ellos.(Para el ejemplo esta entrada es suficiente un contenedor, en mi caso elegi Tomcat por facilidad)
  2. La base de datos del ejemplo pasado con al menos un registro
  3. Un archivo .jar con las clases de los ejemplos anteriores
  4. Conocimientos basicos en HTML

Primero configuremos nuestro Eclipse para que trabaje directamente con Tomcat, hacemos esto en File > New > Other... en la ventana que se nos muestra vamos a lo opcion Server


En la siguiente ventana seleccionamos nuestra version de Tomcat que hayamos descargado y damos click en "Next"

Ahora seleccionamos la carpeta donde se encuentra Tomcat:


En seguida damos click en "Finish", con esto ya esta configurado el contenedor. Ahora vamos a crear el proyecto, para variar las cosas vamos a File > New > Other...

Buscamos la opcion Web, y ahi seleccionamos Dynamic Web Project


En la siguiente ventana escribimos el nombre del proyecto y clickeamos en "Finish"


Ahora debemos agregar a nuestro Class path el archivo jar que contiene las clases que creamos anteriormente.

Una vez hecho esto vamos a crear nuestro primer JSP(que de JSP no tiene nada =)), vamos a la carpeta que dice WebContent damos click derecho y seleccionamos New > JSP File, de ahi el procedimiento es muy similar como cuando creamos una clase


Un JSP es una pagina que contiene HTML y Java, el HTML nos sirve para darle forma y estructura a nuestra pagina, Java por otra parte nos ayuda a generar el contenido dinamico de nuestra aplicacion. El codigo java se escribe entre los simbolos <% %> en medio de ellos es valido escribir el codigo Java que necesitemos.

Para nuestro primer JSP vamos a tener el siguiente codigo:

  <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Bienvenido</title>
  </head>
  <body>
   <form action="actionServlet" method="post">
    <h1>Tu nombre</h1>
    <input type = "text" name="user" />
    <input type="submit" value="Click Me">
   </form>
  </body>
  </html>

En el atributo action del formulario escribimos el nombre del servlet que va a atender nuestra peticion. Siendo asi creemos el servlet, para hacerlo vamos a la parte de Java Resources con ayuda del poderoso click derecho creamos un nuevo servlet.

Los servlets son las clases que nos van a ayudar a atender todas las peticiones web que se realicen a nuestra aplicacion, hay ciertas cosas a tener en cuenta acerca de estas clases:

  • doGet(). es el metodo que se encarga de escuchar las peticiones que se hagan atraves de un GET al servidor, esto es cuando pasamos los valores que queremos procesar atraves de la URL:
    url?param1=val1&param2=val2&...
  • doPost(). atiende todas las peticiones que se hacen atreves del POST al servidor, estas permiten un mayor envio de informacion y seguridad.
  • @WebServlet(). esta anotacion nos va a ayudar a definir el nombre con el que se va a publicar nuestro servlet.

El codigo que vamos a utilizar es el siguiente:
package com.unapagina.web;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import sociedad.Persona;

import com.unapagina.negocio.Controller;


@WebServlet("/actionServlet")
public class ActionServlet extends HttpServlet {
 private static final long serialVersionUID = 1L;

 public ActionServlet() {
  super();
 }

 
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  doPost(request,response);
 }

 
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  Persona usuario;
  HttpSession sesion;
  sesion = request.getSession();
  String usr = request.getParameter("user").trim();
  if((usuario = Login.autenticar(usr)) != null){
   sesion.setAttribute("user", usuario);
   getServletContext().getRequestDispatcher("/hola.jsp").forward(request, response);
  }else
   getServletContext().getRequestDispatcher("/error.jsp").forward(request, response);
 }

}

El objeto HttpSession nos ayuda a manejar la sesion de nuestro usuario en la aplicacion, podemos registrar objetos en la sesion y posteriormente manipularlos en otra parte de la aplicacion. Utilizando el metodo getSession() del objeto HttpServletRequest obtenemos la sesion asociada a el si esta existe, de lo contrario se crea una nueva.

En este ejemplo haremos login en nuestra aplicacion validando unicamente el nombre de usuario en nuestra base de datos, para ello utilizaremos el metodo autenticar(), el cual se auxilia del metodo PersonaPersist.busqEspecifica()[es necesario modificar levemente este metodo para que se ajuste a la nueva estructura de la BD] si el usuario es valido lo registraremos como un objeto de la sesion con el metodo setAttribute() que recibe como parametros el nombre del objeto y el objeto que sera almacenado en sesion. Posteriormente navegamos a la pagina hola.jsp usamos el metodo getServletContext().getRequestDispatcher().forward() debido a que se trata de un recurso que esta dentro de nuestra misma aplicacion, de tal manera que tengamos que regresar el control al navegador y esta haga un nuevo POST al servidor preguntado por hola.jsp, optimizando los tiempos de respuesta.

Les dejo el codigo del metodo autenticar()

public static Persona autenticar(String user){
  Persona usr = null;

  Connection con = ConexionDB.conectar("127.0.0.1/sociedad?useServerPrepStmts=true", "root", "");

  try {
   usr = PersonaPersist.busqEspecifica(con, user);
  } catch (SQLException e) {
   e.printStackTrace();
  }

  return usr;

}

El ultimo paso sera crear nuestra pagina hola.jsp en la cual vamos a mostrarle al usuario su informacion personal que ya tenemos almacenada, vamos a utilizar las etiquetas de JSP <%= %> al utilizar las etiquetas de esta forma el JSP escribira en el HTML el valor que le pasemos entre las mismas. Para importar la clase Persona utilizamos las directivas de pagina las cuales se definen entre los tags <%@ page %>, es aqui donde definimos los pauqetes que vamos a utilizar, el juego de caracteres, etc. Siendo asi nuestro codigo debe lucir como el siguiente:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import = "sociedad.Persona" %>
<% Persona usuario = (Persona) session.getAttribute("user"); %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hola</title>
</head>
<body>
 <h1>Bienvenido <%= usuario.getNombre() %></h1>
 <table>
  <tr>
   <td>Peso:</td>
   <td><%= usuario.getPeso() %> kg</td>
  </tr>
  <tr>
   <td>Edad:</td>
   <td><%= usuario.getEdad() %> a&ntilde;os</td>
  </tr>
  <tr>
   <td>Sexo:</td>
   <td><%= usuario.isMujer() ? "Mujer" : "Hombre" %></td>
  </tr>
  <tr>
   <td>ID:</td>
   <td><%= usuario.getIdPersona() %></td>
  </tr>
 </table>
</body>
</html>


Como vemos lo primero que hacemos es obtener el objeto que almacenamos en la sesion con el metodo session.getAttribute() al cual le hacemos un cast a nuestra clase, esto debido a que en la sesion se guardan objetos del tipo Object, finalmente unicamente imprimimos su informacion personal utilizando los metodos get de la clase persona.

Al final obtendremos algo como esto:



Recuerden que aun falta escribir la pagina error.jsp en caso de que no sea un usuario valido, ya que si no la escribimos nos mandara error cuando lo estemos probando.

Saludos!!!

sábado, 11 de agosto de 2012

Ultima Clase

Al fin y despues de tanto tiempo lo prometido los codigos de la ultima clase.

Para poder trabajar correctamente los codigos es necesario que tengamos en nuestra base de datos dos tablas, una para almacenar a personas y otra para alamacenar futbolistas. Estas entidades estan represenatdas por nuestras clases Persona y Futbolista, asi que deben de contener los atributos que queramos almacenar de las instancias de estos objetos.

La tabla persona puede definirse como:

+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| nombre    | varchar(80) | YES  |     | NULL    |       |
| peso      | float       | YES  |     | NULL    |       |
| edad      | int(11)     | YES  |     | NULL    |       |
| sexo      | tinyint(1)  | YES  |     | NULL    |       |
| idpersona | varchar(8)  | NO   | PRI |         |       |
+-----------+-------------+------+-----+---------+-------+


Y la tabla futbolista como:

+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| equipo    | varchar(50) | NO   | PRI |         |       |
| posicion  | varchar(50) | NO   | PRI |         |       |
| idpersona | varchar(8)  | NO   | PRI |         |       |
+-----------+-------------+------+-----+---------+-------+


Bien ahora ya que tenemos nuestras tablas creadas, vamos a escribir las clases que se van a encargar de ir a escribir, leer, actualizar y borrar.

Empecemos por crear la clase que se encargara de hablar con la entidad persona, se llamara PersonaPersist y la colocamos en el paquete sociedad.datos, para indicar que se trata de una clase que interactuara con la BD.

  package sociedad.datos;

  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import sociedad.Persona;

  public class PersonaPersist {
 
   public static void persist(Connection con, Persona p) throws SQLException{
    String st = "INSERT INTO persona(nombre,peso,edad,sexo,idpersona) VALUES(?,?,?,?,?)";
    PreparedStatement pst;
    
    pst = con.prepareStatement(st);
    pst.setString(1, p.getNombre());
    pst.setFloat(2, p.getPeso());
    pst.setInt(3, p.getEdad());
    pst.setBoolean(4, p.isMujer());
    pst.setString(5, p.getIdPersona());
    pst.executeUpdate();
    
   }
  }


Con el metodo persist() vamos a guardar una persona en la base de datos.

En la variable st tenemos la sentencia SQL que ejecutara el GBD(Gestor de Base de Datos) como vemos la hemos escrito usando la forma:

INSERT INTO tabla(atr1, atr2, ...) VALUES (val1, val2, ...)

para hacer esto mas ententible a todas las personas que lean nuestro codigo(esto me incluye a mi y a ti que estas leyendo) y hemos utilizado un caracter ? donde van los valores que deseamos almacenar.

Con la linea con.prepareStatement(st); le decimos al GBD que compile la sentencia SQL almacenada en el string st, con esto se logra una ejecucion mas rapida del SQL de nuestros modulos y ademas establece los valores permitidos para cada campo que vamos a guardar.

Cuando escribimos pst.setString(1, p.getNombre()); estamos indicando que el PreparedStatement va a settear un string en el parametro 1 y que vale lo que tenga el atributo nombre de la persona p. Hacemos esto tantas veces como signos ? hallamos puesto en nuestro query, utilizando el metodo set adecuado(setFolat(), setInt(), ...).

Finalmente el metodo pst.executeUpdate(); va a mandar ejecutar el query para almacenar a nuestra persona en la BD.

En este punto te pregunto

¿aun armas querys concatenando strings?

De responder NO, te felicito utilizas buenas practicas de programacion
Si me dices que SI, no te preocupes todos lo hemos hecho alguna vez nadie nace sabiendo, es malo utilizar concatenacion para armar cadenas SQL debido a que existen muchos personajes con los conocimientos suficientes de SQL Injection para tirar nuestro sistema y llevarse la informacion que almacenemos en el repositorio de datos. Haciendo uso de PreparedStaments les dificultamos esta tarea ya que estos validan que el valor que enviemos al GBD concuerde con lo que este espera recibir.

...para tu tren, ¿que es eso de throws SQLException?

Eso mis amigos quiere decir que el metodo puede fallar, si has leido bien nuestro metodo puede fallar, como todo en esta vida no podemos decir que algo se comportara de la misma manera siempre, nuestro metodo puede fallar por que no encuentre la tabla, no este disponible la base de datos, halla mucho retraso en la red, etc.

Con throws le decimos a la JVM, si llego a fallar, por favor dile a quien me mando ejecutar porque falle; sabemos que el metodo puede no terminar satisfactoriamente lanzamos el error porque a persist() unicamente le interesa escribir en la BD el no sabe que hacer con los errores, la clase que invoque el metodo sera la que se encargue de tratar el error de manera correcta.

Listo ya podemos guardar personas ahora necesitamos guardar futbolistas, sencillo creemos una clase que haga eso

  package sociedad.datos;

  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import sociedad.atleta.Futbolista;
  import sociedad.atleta.util.PosicionFutbol;

  public class FutbolistaPersist {

   public static void persist(Connection con, Futbolista f) throws SQLException{
    String st = "INSERT INTO futbolista(equipo,posicion,idpersona) VALUES(?,?,?)";
    PreparedStatement pst;
    
    pst = con.prepareStatement(st);
    for(PosicionFutbol pos : f.getPosicion()){
     pst.setString(1, f.getEquipo());
     pst.setString(2, pos.toString());
     pst.setString(3, f.getIdPersona());
     pst.executeUpdate();
    }
   }
  }


Ya esta hemos creado la clase que se va a comunicar con la BD para guardar la informacion de los futbolistas.

Ahora les presento a la nueva clase ConexionDB le he agregado metodos para utilizar transacciones en nuestras idas a la base de datos, esto para garantizar la integridad de los datos

  package sociedad.datos;

  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.SQLException;

  public class ConexionDB {
   
   public static Connection conectar(String url, String usr, String pass){
    try {
     Class.forName("com.mysql.jdbc.Driver");
     return DriverManager.getConnection("jdbc:mysql://" + url, usr, pass);
    } catch (ClassNotFoundException | SQLException e) {
     e.printStackTrace();
    }
    return null;
   }
   
   public static Connection conectar(String url, String usr, String pass, boolean autoCommit){
    Connection con = conectar(url, usr, pass);
    
    try {
     con.setAutoCommit(autoCommit);
    } catch (SQLException e) {
     e.printStackTrace();
    }
    
    return con;
   }
   
   public static void cerrarConexion(Connection cx){
    if(cx != null)
     try {
      cx.close();
     } catch (SQLException e) {
      e.printStackTrace();
     }
   }
   
   public static void rollbackTransaction(Connection cx){
    try {
     cx.rollback();
    } catch (SQLException e) {
     e.printStackTrace();
    }
   }
   
   public static void commitTransaction(Connection cx){
    try {
     cx.commit();
    } catch (SQLException e) {
     e.printStackTrace();
    }
   }
   
  }


Donde:
  • conectar(String, String, String, boolean) nos va a servir para crear una conexion a la base de datos indicandole si queremos o no que los cambios en la BD se confirmen inmediatamente despues de ejecutar una sentencia, atraves del parametro boolean.
  • rollbackTransaction() va a ayudar a cancelar la transaccion que acabemos de ejecutar en caso de que algo halla salido mal.
  • commitTransaction() sera el encargado de confirmar la transaccion cuando todo se ejecute OK.

Tenemos las clases que nos van a ayudar con la BD, ahora solo nos falta la clase que las va a invocar y sabe que hacer en caso de que ocurra un error, en este ejemplo he propuesto la clase RegSocl.

  package sociedad.proceso;

  import java.sql.Connection;
  import java.sql.SQLException;
  import sociedad.Persona;
  import sociedad.atleta.Futbolista;
  import sociedad.datos.ConexionDB;
  import sociedad.datos.FutbolistaPersist;
  import sociedad.datos.PersonaPersist;

  public class RegSocl {
   public static void guardaPersona(Persona persona){
    Connection con;
    
    con = ConexionDB.conectar("127.0.0.1/sociedad?useServerPrepStmts=true", "root", "");
    try {
     PersonaPersist.persist(con,persona);
    } catch (SQLException e) {
     e.printStackTrace();
    }finally{
     ConexionDB.cerrarConexion(con);
    }
   }
   
   public static void guardaFutbolista(Futbolista futbolista){
    Connection con;
    
    if(futbolista.getPosicion() != null){
     con = ConexionDB.conectar("127.0.0.1/sociedad?useServerPrepStmts=true", "root", "", false);
     
     try {
      PersonaPersist.persist(con, futbolista);
      FutbolistaPersist.persist(con, futbolista);
     } catch (SQLException e) {
      ConexionDB.rollbackTransaction(con);
      e.printStackTrace();
      System.out.println("No se pudo guardar en BD");
     }
     ConexionDB.commitTransaction(con);
    }
   }
  }


Con guardaPersona() invocamos nuestro metodo PersonaPersist.persist() dentro de un bloque try...catch debido a que como bien dijimos antes nuestro codigo puede fallar, haciendo esto podemos atrapar la excepcion y tratarla de la mejor manera posible, para este ejemplo unicamente imprimimos el error.

La sintaxis completa del bloque try...catch es:

  try{
   ...
   codigo que puede fallar
   ...
  }catch(Exception e){
   ...
   codigo en caso de que haya ocurrido un error
   ...
  }finally{
   ...
   codigo que siempre debe ejecutarse con o sin errores
   ...
  }


El metodo guardaFutbolista() llamara a nuestro metodo para guardar personas(para almacenar su informacion de persona) y posteriormente el de futbolistas(para guardar su informacion de futbolista), en caso de que un error ocurriera hace rollback a la transaccion descartando los cambios si todo sale bien hace commit y se guarda la informacion de nuestro futbolista.

A probar nuestro codigo, creemos una clase main con el codigo necesario para guardar personas y futbolistas en nuestra BD, pero esa labor es para usted estimado lector.

Les dejo el codigo completo aqui para que lo revisen incluye lo poquito que vimos de swing tambien para los que comentaron acerca de conceptos basicos en Java les dejo este libro y este otro es de cajon.

Espero el curso halla sido de su agrado
No olviden comentar
¡¡Saludos a todos!!
Nos leemos en la siguiente entrada

miércoles, 25 de julio de 2012

Codigo Base de Datos


En esta entrada pondre el codigo que utilizaremos la clase del sabado para conectarnos a la base de datos(BD), para que esta clase pueda compilarse y ejecutarse correctamente es indispensable que tengamos en conector de Java con MySQL el cual lo pueden encontrar aqui.
Ya que lo bajemos es necesario agregarlo al classpath, que es decirle a la JVM donde va a buscar las clases que no conozca. Para hacer esto en eclipse damos click derecho en nuestro proyecto y en el menu vamos a Build Path>Configure Build Path...


Ahora en la ventana que se nos abre, damos click en Add External JARs... y buscamos el conector que hemos descargado, dentro del archivo que bajemos viene un archivo .jar ese es el que se agra al classpath.


Ya que hemos configurado nuestro classpath, vamos a crear la clase que nos ayudara a conectarnos a la BD en el paquete sociedad.datos
package sociedad.datos;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConexionDB {

  public static Connection conectar(String url, String usr, String pass){
   try {
    Class.forName("com.mysql.jdbc.Driver");
    return DriverManager.getConnection("jdbc:mysql://" + url, usr, pass);
   } catch (ClassNotFoundException | SQLException e) {
    e.printStackTrace();
   }
   return null;
  }

  public static void cerrarConexion(Connection cx){
   if(cx != null)
    try {
    cx.close();
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }

}

Listo con esta clase podremos abrir una conexion a la BD con el metodo conectar() y cerrar la conexion con el metodo cerrarConexion().
Para probar que todo esta jalando bien podemos utilizar el siguiente codigo:
package main;

import java.sql.Connection;
import sociedad.datos.ConexionDB;

public class Main {

 public static void main(String[] args) {

    Connection conx = ConexionDB.conectar( "127.0.0.1/sociedad" , "root" , "" );
    System.out.println(conx);
    ConexionDB.cerrarConexion(conx);
  }

}

Los parametros que le pasamos al metodo conectar son
  1. host/basededatos.donde se encuentra el servidor de BD y a que base nos vamos a conectar
  2. user.el usuario de la base de datos
  3. password.la contraseña del servidor de BD
Listo si ejecutamos el codigo y todo esta bien nos debe de imprimir una cadena como la siguiente:

No se olviden de instalar su MySQL

Saludos!!!

miércoles, 18 de julio de 2012

Codigos Fuera de Clase

Los siguientes codigos son para darle un poco mas de complejidad a los que hemos estado viendo en el curso, leeanlos, cualquier duda manden un correo, dejen un comentario, una mentada lo que sea.

Empecemos por definir un concepto nuevo, las clases abstractas, tienen la caracteristica principal de que no pueden ser instanciadas, es decir, no podemos crear un objeto del tipo de una clase abstracta. Ademas las clases contienen metodos abstractos, los cuales son metodos que unicamente estan definidos pero su cuerpo esta vacio y debe ser implementado en las clases que heredan.

Estas clases nos sirven para modelar de manera mas eficiente el comportamiento de las clases que heredan de ella.

¿pero para que me sirve una clase que no puede ser instanciada?

Tomemos el ejemplo que hemos venido trabajando, podemos decir que una Persona es un Ser, pero no sabemos concretamente que es un ser solo conocemos sus atributos y metodos; no podemos crear un Ser asi como asi, este debe ser una persona, un animal, alf o lo que sea, por lo tanto todos los que se digan seres deben tener atibutos y metodos en comun.

Siendo asi definimos la clase Ser dentro del paquete universo de la siguiente manera:

  package universo;

  public abstract class Ser {
   private int vida = (int) (Math.random() * 10 + 1);

   protected void vivir(){
    vida--;
   }
  
   protected int getVida(){
    return this.vida;
   }

   protected abstract void respirar();
  }


Para indicarle a la JVM que se trata de una clase abstracta debemos de utilizar la palabra abstract en la declaracion de la clase. De igual manera agregamos la palabara abstract en la firma del metodo para indicar que este es abstracto y por lo tanto debe estar vacio.

Ahora debemos de cambiar la definicion de la clase Persona para que herede de Ser

  package sociedad;

  import universo.Ser;

  public class Persona extends Ser {
   private String nombre;
   private float peso;
   private int edad;
   private boolean mujer;// true: mujer, false: hombre
   private Thread viviendo = new Thread(){
    @Override
    public void run(){
     while(getVida() > 0 ){
      vivir();
      System.out.println(nombre + ": Tengo " + getVida() + " de vida");
      try {
       Thread.sleep(2500);
      } catch (InterruptedException e) {
       e.printStackTrace();
      }
     }
     System.out.println("RIP " + nombre);
    }
   };

  //...aqui va todo el codigo que hemos hecho

   public Persona(){
    this.nombre = "pepito";
    viviendo.start();
   }

   @Override
   public void respirar() {
    System.out.println("estoy respirando");
   }
  }
<

Observamos algunos cambios en la clase.

  1. En su declaracion decimos que hereda de Ser
  2. Agregamos un nuevo atributo del tipo Thread llamado viviendo, este nos sera muy util para utilizar el metodo vivir de la clase padre.
  3. Hemos cambiado el constructod por defecto para que invoque a viviendo.start()
  4. Finalmente implementamos el metodo abstracto respirar() -sin mucha imaginacion cuando lo hice ¬¬

espera, espera, ¿que es eso de Thread?

Un thread o hilo, es una fraccion de codigo que se ejecuta de manera paralela al flujo principal del programa, en este caso lo utilizamos para invocar al metodo vivir mientras realizamos otras tareas con nuestra clase Persona.

La implementacion de un hilo en esta clase fue express solamente la puse para ilustrar un poco los hilos, ya que eston son bastante complejos y nos llevaria un rato aprenderlos.

En el codigo

  private Thread viviendo = new Thread(){
   @Override
   public void run(){
    while(getVida() > 0 ){
       vivir();
         System.out.println(nombre + ": Tengo " + getVida() + " de vida");
       try {
         Thread.sleep(2500);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println("RIP " + nombre);
   }
  };


lo que hicimos fue crear un nuevo hilo de ejecucion cada vez que se instancie la clase, todos los hilos deben de sobreescribir el metodo run().

Con el metodo sleep() le decimos al hilo que detenga su ejecucion durante un tiempo en milisegundos, este metodo lanza una excepcion en caso de que no pueda mandar a dormir al hilo.

  public Persona(){
   this.nombre = "pepito";
   viviendo.start();
  }


Cuando invocamos el metodo start() es la señal para que el hilo comience a trabajar.

Ya hemos terminado con la clase Persona, bien ahora lo que sigue; en Java existe un concepto llamado interface, las cuales son un conjunto de metodos abstractos y constantes que tiene una relacion entre si.

En Java solo se puede heredar de una clase y se pueden implementar N interfaces

Ahora definimos una interface dentro del paquete sociedad.atleta.util

  package sociedad.atleta.util;

  public interface Atleta {

   Atleta competir(Atleta oponente);

   void entrenar();
  }


La interface solo tiene dos metodos competir() y entrenar(), los cuales deben ser implementados en todas las clases que implemente la interface, nosotros vamos a implementarla en la clase Futbolista de la siguiente forma:

  package sociedad.atleta;

  import java.util.ArrayList;
  import sociedad.Persona;
  import sociedad.atleta.util.Atleta;
  import sociedad.atleta.util.PosicionFutbol;

  public class Futbolista extends Persona implements Atleta {
   private String equipo;
   private ArrayList posicion;
   private int poder;
   
   public int getPoder() {
    return poder;
   }
   
   public void setPoder(int poder) {
    this.poder = poder;
   }
   
  //...todo lo demas

   @Override
   public Atleta competir(Atleta oponente) {
    if(this.getPoder() > ((Futbolista)(oponente)).getPoder())
     return this;
    else
     return oponente;
   }
  
   @Override
   public void entrenar() {
    this.poder++;
   }
  }


Con la palabra implements indicamos que la clase va a implementar los metodos de la interface.

Los cambios en la clase son:

  • Agregamos el atributo poder, para indicar el nivel de destreza del jugador
  • Implementamos el metodo competir(), el cual unicamente compara el atributo poder del objeto que se pasa por parametro contra el valor que tiene el objeto this y regresa el que tenga mayor poder.
  • Implementamos el metodo entrenar(), que aumenta el poder de cada objeto.

Finalmente hechemos a andar este cacharro, en nuestra clase principal:

package main;

  import sociedad.atleta.Futbolista;
  import sociedad.atleta.util.PosicionFutbol;

  public class Main {
   public static void main(String[] args) {
    Futbolista jorge = new Futbolista("Jorge Campos","Pumas");
    jorge.setEdad(34);
    jorge.addPosicion(PosicionFutbol.PORTERO);
    jorge.addPosicion(PosicionFutbol.DELANTERO);
    System.out.println(jorge.saludar());
    
    jorge.entrenar();
    
    Futbolista temo = new Futbolista("El Cuau","America");
    
    Futbolista ganador = (Futbolista) (jorge.competir(temo));
    System.out.println("\tEl ganador es " + ganador.getNombre());
   }
  }


Despues de compilar y ejecutar nos arrojara algo como esto en la terminal, dependiendo de cuanto entrene y cuanta vida tenga nuestro jugador



Saludos!!!

No se olviden de instalar el plugin WindowBuilder Pro, para ver GUIs en Java el proximo sabado

miércoles, 11 de julio de 2012

Primeros Codigos


En esta entrada al fin publicare los códigos que hemos venido escribiendo en los cursos de los sábados, con una breve explicación.

Primero debemos crear un nuevo proyecto en Eclipse

 

Ahí se nos mostrara un asistente donde nos pedirá información básica para crear el proyecto.

Luego crearemos la clase Persona dentro del paquete sociedad, la clase persona contendrá los siguientes atributos y métodos:

package sociedad;

public class Persona {
       private String nombre;
       private float peso;
       private int edad;
       private boolean mujer;// true: mujer, false: hombre
      
       public String getNombre() {
             return nombre;
       }
      
       public float getPeso() {
             return peso;
       }
      
       public int getEdad() {
             return edad;
       }
      
       public boolean isMujer() {
             return mujer;
       }
      
       public void setNombre(String nombre) {
             this.nombre = nombre;
       }
      
       public void setPeso(float peso) {
             this.peso = peso;
       }
      
       public void setEdad(int edad) {
             this.edad = edad;
       }
      
       public void setMujer(boolean sexo) {
             this.mujer = sexo;
       }

       public Persona(){
             this.nombre = "pepito";
       }
      
       public Persona(String nombre){
             this.nombre =  nombre;
       }
      
       protected String saludar(){
             return "Hola mi nombre es " + nombre + " tengo " + edad + " años y soy " + (isMujer() ? "mujer" : "hombre");
       }
}



Ya tenemos nuestra primer clase, como podemos leer en el código los atributos de la clase son privados, es decir que únicamente la clase puede accesar a ellos; para cada atributo corresponden un par de métodos públicos, uno para establecer el valor y otro para devolverlo, esto se conoce como encapsulamiento, es decir, únicamente la clase puede acceder a sus atributos directamente las demás clases tienen que hacerlo atraves de los métodos destinados para ello.

Existe una convención para la definición de estos:

Los métodos que sirven para establecer el valor de un atributo(llamados setters), por convención se escriben de la siguiente manera:

public void setAtributo(tipo atributo){
…   
this.atributo = atributo;
}


Donde:
  • public(modificador acceso): para que las demás clases puedan invocar al método
  • void(tipo de dato de retorno): es el tipo de dato que nos va a regresar el método, en este caso el método no nos regresa nada
  • setAtributo(nombre del método): el nombre de los setters por convención se escribe como set seguido del nombre del atributo que va a modificar con la primera letra en mayúscula
  • tipo atributo(parametro): el valor que se va a establecer en el atributo


Los métodos que nos ayudan a obtener el valor de un atributo(métodos getters), son declarados de la siguiente manera:

public tipo getAtributo(){
return this.atributo;
}



La diferencia entre estos es básicamente:

Los setters no nos regresan ningún valor y reciben como parámetro el valor que se va a establecer en el atributo.
Los getters nos regresan el valor de un atributo y no reciben parámetros.


 ¿¿que pasa con el método isMujer()??

Este es un caso especial cuando se trata de tipos de datos booleanos, para ser mas claros en lo que estamos haciendo cambia un poco la manera de nombrar los getters , el método get lo nombramos como isMujer(), para hacer notar que si el método nos regresa true se trata de una mujer y false si se trata de un hombre.

Ya tenemos la clase persona, pero una persona puede tener distintos roles en la sociedad uno de ellos podría ser un futbolista el cual es una persona, ya que tiene los mismos atributos y métodos, además tiene características y tareas especializadas de acuerdo a su profesión.

Ahora crearemos la clase Futbolista dentro del paquete sociedad.atleta, la cual esta definida como:


package sociedad.atleta;

import java.util.ArrayList;
import sociedad.Persona;
import sociedad.atleta.util.PosicionFutbol;

public class Futbolista extends Persona {
       private String equipo;
       private ArrayList<PosicionFutbol> posicion;
      
       public String getEquipo() {
             return equipo;
       }
      
       public ArrayList<PosicionFutbol> getPosicion() {
             return posicion;
       }
      
       public void setEquipo(String equipo) {
             this.equipo = equipo;
       }
      
       public void setPosicion(ArrayList<PosicionFutbol> posicion) {
             this.posicion = posicion;
       }
      
       public void addPosicion(PosicionFutbol posicion){
             if(this.posicion == null)
                    this.posicion = new ArrayList<PosicionFutbol>();
             this.posicion.add(posicion);
       }
      
       public Futbolista(){}
      
       public Futbolista(String nombre, String equipo){
             setNombre(nombre);
             this.equipo =  equipo;
       }
      
       @Override
       public String saludar(){
             String saludo =  "Soy " + getNombre() + " juego en el " + equipo + ", y soy ";
             for(PosicionFutbol p : posicion)
                    saludo += p + ",";
             return super.saludar() + "\n" + saludo;
       }
}


Para indicar que Futbolista es una Persona y hereda todos sus atributos y métodos public y protected, utilizamos la palabra extends seguida del nombre de la clase de la cual hereda.

Tanto Futbolista como Persona tienen el método saludar, pero se comportan de manera diferente esto se conoce como polimorfismo, ya que cambia el comportamiento del método dependiendo de la clase que lo invoque.
Para ser mas claro e indicar que estamos sobreescribiendo el método usamos la anotación @Override, de esta manera podemos identificar mas rápidamente los métodos que han sido sobreescritos.

Si deseáramos invocar al método de la clase Persona utilizamos super, que nos sirve para invocar métodos y constructores de la clase padre, se utiliza de la siguiente manera:


super.metodo(); //cuando se trata de un método
//cuando se trata de constructores
super();
super(param1, …);



También notamos que la clase Futbolista tiene un atributo posicion que es un arreglo que almacena datos tipo PosicionFutbol el cual es un enum.

¿qué es un enum?

Es un conjunto de constantes que se relación entre si, en nuestro caso serán las posiciones que puede desempeñar un jugador: defensa, delantero, portero, medio.

Definimos esta enum en el paquete sociedad.atleta.util de la siguiente manera:


package sociedad.atleta.util;

public enum PosicionFutbol{
       DELANTERO, DEFENSA, PORTERO, MEDIO
}


Las posiciones se escriben en mayúsculas ya que por convención las constantes se escriben asi. De esta manera podemos acceder a ellas de la siguiente forma:

PosicionFutbol.DELANTERO;
PosicionFutbol.DEFENSA;

Para ver en acción las clases que hemos escrito crearemos una clase que contenga el método main, por conveniencia y de manera que podamos abstraer mas nuestro código creamos una clase en otro paquete que contenga el método main y desde ahí es donde instaciamos nuestras clases.


Una sugerencia de esta clase es la siguiente:


package main;

import sociedad.atleta.Futbolista;
import sociedad.atleta.util.PosicionFutbol;

public class Main {

       public static void main(String[] args) {
             Futbolista jorge = new Futbolista("Jorge Campos","Pumas");
             jorge.setEdad(34);
             jorge.addPosicion(PosicionFutbol.PORTERO);
             jorge.addPosicion(PosicionFutbol.DELANTERO);
             System.out.println(jorge.saludar());
       }

}


Donde instanciamos una clase del tipo futbolista e invocamos sus métodos setEdad(), addPosicion() y saludar()

Después de ejecutar el código en la consola nos debe de aparecer esto:

 

Al final la estructura de directorios que tendremos será la siguiente:

 

Eso ha sido todo en esta entrada, son los códigos que hemos realizado hasta el momento con algunas modificaciones.

Saludos!!!