jueves, 27 de septiembre de 2007

Conectar Java con MySQL

Hoy vamos a ver como podemos crear un aplicativo en java que se conecte a una base de datos MySQL y nos cargue unos datos en una interfaz gráfica sencilla.



Para este ejercicio se ha creado una base de datos llamada clase que tiene tres tablas: estudiante, asignatura y nota; para la creación de estas tablas ejecutamos este script de la base de datos.

CREATE DATABASE `clase`;

CREATE TABLE `asignatura` (
`asi_codigo` varchar(6) NOT NULL,
`asi_nombre` varchar(60) NOT NULL,
PRIMARY KEY (`asi_codigo`)
);

INSERT INTO `asignatura` VALUES('201502','Algebra'),
('201501','Matemáticas'),
('301502','Programación orientada a objetos'),
('301501','Programación básica');

CREATE TABLE `estudiante` (
`est_codigo` varchar(11) NOT NULL,
`est_nombre` varchar(100) NOT NULL,
PRIMARY KEY (`est_codigo`)
);

INSERT INTO `estudiante` VALUES ('2007202004','Alvarez Juan Jose'),
('2007202003','Espitia Maldonado Ana Julieth'),
('2007202002','Mendez Maria'),
('2007202001','Diaz Perez Juan Diego'),
('2007202007','Olguin Ricaute Manuel'),
('2007202006','Miranda Perez Juan'),
('2007202005','Triana Maria');

CREATE TABLE `nota` (
`est_codigo` varchar(11) NOT NULL,
`asi_codigo` varchar(6) NOT NULL,
`nota` double NOT NULL,
PRIMARY KEY (`est_codigo`,`asi_codigo`)
);

INSERT INTO `nota` VALUES('2007202001','201502',5),
('2007202002','201502',4.3),
('2007202003','201502',2.3),
('2007202004','201502',3.3),
('2007202001','201501',4),
('2007202002','201501',2.8),
('2007202003','201501',1.5),
('2007202004','201501',4.3),
('2007202001','301502',2.2),

('2007202002','301502',4.5),
('2007202003','301502',1.9),
('2007202004','301502',4.3),
('2007202001','301501',4.9),
('2007202002','301501',5),
('2007202003','301501',4.3),
('2007202004','301501',4);


Una ves que tenemos la base de datos creada, creamos un nuevo proyecto en eclipse, una ves creado el proyecto hacemos click derecho con el ratón sobre el nombre del proyecto y seleccionamos la opción de propiedades, en esta ventana seleccionamos la opción de "Java Build Path" y en esta la pestaña "Libraries", dentro de esta hacemos click sobre el botón "Add External Jars..." y buscamos el mysql-conector-java que podemos descargar de la pagina de MySQL, y hacemos click en aceptar.

Este .jar es el que nos va permitir conectarnos con mysql y hacer consultas a la base de datos.

Después de haber asociado el conectorJ al proyecto creamos dos paquetes para separar el acceso a datos con la interfaz gráfica de usuario, en mi caso he llamados a estos paquetes así:

  • co.madesoft.db para el acceso a datos
  • co.madesoft.gui para la interfaz gráfica de usuario
en el primero creamos las siguientes clases:

DbConnection para la conexion con la base de datos


package co.madesoft.db;

import java.sql.*;
/**
* Clase que permite conectar con la base de datos
* @author alejo
*/
public class DbConnection {
static String bd = "clase";
static String login = "root";
static String password = "";
static String url = "jdbc:mysql://localhost/"+bd;

Connection conn = null;

/** Constructor de DbConnection */
public DbConnection() {
try{
//obtenemos el driver de para mysql
Class.forName("com.mysql.jdbc.Driver");
//obtenemos la conexión
conn = DriverManager.getConnection(url,login,password);
if (conn!=null){
System.out.println("Conección a base de datos "+bd+" OK");
}
}catch(SQLException e){
System.out.println(e);
}catch(ClassNotFoundException e){
System.out.println(e);
}
}
/**Permite retornar la conexión*/
public Connection getConnection(){
return conn;
}

public void desconectar(){
conn = null;
}

}



DbEstudiante para la manipulación de la tabla estudiante


package co.madesoft.db;

import java.sql.*;

public class DbEstudiante {
DbConnection cn;

/** Constructor de DbUser */
public DbEstudiante() {
cn = new DbConnection();
}

/** Obtiene las notas de un estudiante por su codigo */
public Object[][] getNotasByEstudiante(String cod){
int registros = 0;

try{
Statement stm = cn.getConnection().createStatement();
PreparedStatement pstm = cn.getConnection().prepareStatement("SELECT count(1) as cont" +
" FROM asignatura a " +
" inner join nota n on a.asi_codigo = n.asi_codigo" +
" where n.est_codigo = ? ");

pstm.setString(1, cod);
ResultSet res = pstm.executeQuery();

res.next();
registros = res.getInt("cont");
res.close();
}catch(SQLException e){
System.out.println(e);
}

Object [][] data = new Object[registros][5];
try{
Statement stm = cn.getConnection().createStatement();
PreparedStatement pstm = cn.getConnection().prepareStatement("SELECT n.asi_codigo, " +
" a.asi_nombre, " +
" n.nota " +
" FROM asignatura a " +
" inner join nota n on a.asi_codigo = n.asi_codigo " +
" where n.est_codigo = ? order by n.asi_codigo ");

pstm.setString(1, cod);
ResultSet res = pstm.executeQuery();
int i = 0;
while(res.next()){
String asiCodigo = res.getString("asi_codigo");
String asiNombre = res.getString("asi_nombre");
Double asiNota = res.getDouble("nota");

data[i][0] = asiCodigo;
data[i][1] = asiNombre;
data[i][2] = asiNota;
i++;
}
res.close();
}catch(SQLException e){
System.out.println(e);
}
return data;
}
/** trae todos los estudiantes */
public Object[][] getEstudiantes(){
int registros = 0;
try{
Statement stm = cn.getConnection().createStatement();
PreparedStatement pstm = cn.getConnection().prepareStatement("SELECT count(1) as cont" +
" FROM estudiante ");

ResultSet res = pstm.executeQuery();
res.next();
registros = res.getInt("cont");
res.close();
}catch(SQLException e){
System.out.println(e);
}

Object [][] data = new Object[registros][5];
try{
Statement stm = cn.getConnection().createStatement();
PreparedStatement pstm = cn.getConnection().prepareStatement("SELECT est_codigo, " +
" est_nombre " +
" FROM estudiante " +
" ORDER BY est_codigo ");


ResultSet res = pstm.executeQuery();
int i = 0;
while(res.next()){
String estCodigo = res.getString("est_codigo");
String estNombre = res.getString("est_nombre");

data[i][0] = estCodigo;
data[i][1] = estNombre;
i++;
}
res.close();
}catch(SQLException e){
System.out.println(e);
}
return data;
}
}


En el segundo paquete creamos tan solo la clase que define la interfaz gráfica que nos muestra los datos retornados por los métodos de la clase anterior. Esta clase implemeta aparte de los elementos que se manejan comunmente en una intrefaz de usuario los siguientes elementos: JScrollPane, DefaultTableModel, JTable para los cuales se puede verificar el codigo y entender su uso o consultar cualquier tuorial de swing .


package co.madesoft.gui;

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;

import co.madesoft.db.*;

public class GuiEstudiante implements ActionListener {

JFrame frame;
JScrollPane spEstudiantes,spNotas;
DefaultTableModel dtmEstudiantes,dtmNotas;
JTable jtbEstudiantes,jtbNotas;
JPanel pnlEstudiantes;
JLabel lblCodigo,lblNombre;
JTextField txtCodigo,txtNombre;
Object[][] dtEstudiantes;
Object[][] dtNotas;
DbEstudiante us = new DbEstudiante();

int fila = -1;
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
GuiEstudiante g = new GuiEstudiante();
}

public GuiEstudiante(){
frame = new JFrame("Notas de estudiantes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

dtEstudiantes = us.getEstudiantes();

String[] columNames = {"codigo","nombres"};
dtmEstudiantes= new DefaultTableModel(dtEstudiantes, columNames);

String[] columNamesNotas = {"codigo","asignatura","nota"};
dtmNotas = new DefaultTableModel(dtNotas,columNamesNotas);

jtbEstudiantes = new JTable(dtmEstudiantes);
jtbEstudiantes.setPreferredScrollableViewportSize(new Dimension(500, 120));

jtbNotas = new JTable(dtmNotas);
jtbNotas.setPreferredScrollableViewportSize(new Dimension(500,80));

spEstudiantes = new JScrollPane(jtbEstudiantes);
spNotas = new JScrollPane(jtbNotas);

lblCodigo = new JLabel("Codigo");
lblNombre = new JLabel("Nombre");

txtCodigo = new JTextField(10);
txtNombre = new JTextField(10);

pnlEstudiantes = new JPanel(new GridLayout(2,2));
pnlEstudiantes.add(lblCodigo);
pnlEstudiantes.add(txtCodigo);
pnlEstudiantes.add(lblNombre);
pnlEstudiantes.add(txtNombre);

jtbEstudiantes.addMouseListener(new MouseAdapter(){

public void mouseClicked(MouseEvent e){
fila = jtbEstudiantes.rowAtPoint(e.getPoint());
int columna = jtbEstudiantes.columnAtPoint(e.getPoint());
if ((fila > -1) && (columna > -1)){
txtCodigo.setText(String.valueOf(jtbEstudiantes.getValueAt(fila,0)));
txtNombre.setText(String.valueOf(jtbEstudiantes.getValueAt(fila,1)));

dtNotas = us.getNotasByEstudiante(String.valueOf(jtbEstudiantes.getValueAt(fila,0)));
int contRows = dtmNotas.getRowCount();
for(int i=0;i<contRows;i++){
dtmNotas.removeRow(0);
}
for(int i=0;i<dtNotas.length;i++){
Object[] newRow={dtNotas[i][0],dtNotas[i][1],dtNotas[i][2]};
dtmNotas.addRow(newRow);
}
}
}
});

frame.getContentPane().add(spEstudiantes,BorderLayout.NORTH);
frame.getContentPane().add(pnlEstudiantes,BorderLayout.CENTER);
frame.getContentPane().add(spNotas,BorderLayout.SOUTH);

frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(frame.getParent());
frame.setVisible(true);
}

public void limpiarCampos(){
txtCodigo.setText("");
txtNombre.setText("");
}

public void actionPerformed(ActionEvent e){
int resultado = -1;
}
}



Ya solo nos resta compilar y ejecutar y tendremos corriendo nuestro aplicativo que nos muestra una lista de estudiantes en una tabla y las notas de cada uno de ellos en otra segun seleccionemos un estudiante de la primera tabla.

miércoles, 12 de septiembre de 2007

Programación de un timer en java

Como se puede programar una tarea repetitiva y automática en un aplicativo tipo Swing de java?, esta pregunta me la plantearon los alumnos de programación orientada a objetos, mi respuesta un Timer. Pero veamos como se hace esto.


La idea es generar una aplicación con una etiqueta que usaremos como display del contador y tres botones con las acciones de iniciar, parar y reset.


El contador se mantendrá contando una ves pulsemos el botón Iniciar y solo se detendrá al pulsar el botón Parar; si pulsamos el botón Reset su contador debe regresar a cero.


Para este fin utilizaremos la clase Timer de java.util, entonces nuestros imports quedaran de la siguiente manera:

import java.awt.*;

import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;


Para poder manejar una tarea de manera automática y repetitiva debemos sobre-escribir el método run de la clase TimerTask; para esto crearemos una clase interna que llamaremos RemindTask y nuestro método run quedara como sigue:


class RemindTask extends TimerTask {
public void run() {
segundos++;
lblTime.setText(String.valueOf(segundos));
if(frozen){
System.out.println("Terminamos la ejecucion del timer");
timer.cancel();
}
}
}


Este método lo único que hace es incrementar una variable segundos y cargar este valor en el display de nuestro contador. Recuerden que dijimos que era una clase interna, así que se debe declarar dentro del cuerpo de la clase de la interfaz gráfica con lo que el código total queda de la siguiente manera:


public class AppContadorSwing implements ActionListener{
JFrame frame;
JPanel panel;
JButton btnIniciar,btnParar,btnReset;
JLabel lblTime;
Timer timer;
int segundos;
//manejar el valor del contador
boolean frozen;
//manejar el estado del contador

public AppContadorSwing() {
frame = new JFrame("Contador Swing");
panel = new JPanel(new GridLayout(1,3));
btnIniciar = new JButton("Iniciar");
btnIniciar.addActionListener(this);
btnParar = new JButton("Parar");
btnParar.addActionListener(this);
btnReset = new JButton("Reset");
btnReset.addActionListener(this);
lblTime = new JLabel("0",SwingConstants.CENTER);

panel.add(btnIniciar);
panel.add(btnParar);
panel.add(btnReset);

frame.getContentPane().add(lblTime, BorderLayout.NORTH);
frame.getContentPane().add(panel, BorderLayout.SOUTH);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.pack();
frame.setVisible(true);

frozen = true;
//iniciamos el estado en congelado
segundos = 0;
}

//clase interna que sobre-escribe el metodo run de TimerTask

class RemindTask extends TimerTask {
public void run() {
segundos++;
lblTime.setText(String.valueOf(segundos));
if(frozen){
System.out.println("Terminamos la ejecucion del timer");
timer.cancel();
//detenemos el timer
}
}
}

public void actionPerformed(ActionEvent a) {
System.out.println(a.getActionCommand());
if(a.getActionCommand().equals("Iniciar")){
frozen = false;
timer = new Timer();
//le asignamos una tarea al timer
timer.schedule(new RemindTask(),0, 1*100);
}
if(a.getActionCommand().equals("Parar")){
frozen = true;
}
if(a.getActionCommand().equals("Reset")){
frozen = true;
segundos = 0;
lblTime.setText(String.valueOf(segundos));
}
}

public static void main(String[] args){
JFrame.setDefaultLookAndFeelDecorated(true);
AppContadorSwing c = new AppContadorSwing();
}
}


En color verde van los comentarios que afectan la ejecución del timer como tal, el resto del código se refiere a la interfaz gráfica, que no es tema de esta guía.

martes, 11 de septiembre de 2007

Introducción

Este blog lo creo con el fin de tener un sitio de consulta para mis alumnos del curso de programación orientada a objetos y demás personas interesadas en la materia, espero que sea de utilidad a quienes lo consulten.

Agradezco de antemano sugerencias acerca de sus contenidos

Conceptos Básicos de POO

Se puede hablar de Programación Orientada a Objetos cuando se reúnen las características de: abstracción, encapsulación, herencia y polimorfismo; y los conceptos básicos que las forman: objetos, mensajes, clases, instancias y métodos.

Conceptos Básicos:
  • Un objeto es una encapsulación abstracta de información, junto con los métodos o procedimientos para manipularla. Un objeto contiene operaciones que definen su comportamiento y variables que definen su estado entre las llamadas a las operaciones.
  • Una clase equivale a la generalización o abstracción de un tipo específico de objetos.
  • Un mensaje representa una acción a tomar por un determinado objeto.
  • Una instancia es la concrección de una clase.
  • Un método consiste en la implementación en una clase de un protocolo de respuesta a los mensajes dirigidos a los objetos de la misma. La respuesta a tales mensajes puede incluir el envío por el método de mensajes al propio objeto y aun a otros, también como el cambio del estado interno del objeto.

Características:

La abstracción: Consiste en la generalización conceptual de un determinado conjunto de objetos y de sus atributos y propiedades, dejando en un segundo término los detalles concretos de cada objeto. ¿Qué se consigue con la abstracción? Bueno, básicamente pasar del plano material (cosas que se tocan) al plano mental (cosas que se piensan).

La encapsulación: Se refiere a la capacidad de agrupar y condensar en un entorno con límites bien-definidos distintos elementos. Cuando hablemos de encapsulación en general siempre nos referiremos, pues, a encapsulación abstracta. De manera informal, primero generalizamos (la abstracción) y luego decimos: la generalización está bien, pero dentro de un cierto orden: hay que poner límites (la encapsulación), y dentro de esos límites vamos a meter, a saco, todo lo relacionado con lo abstraído: no sólo datos, sino también métodos, comportamientos, etc.

Por un lado es una abstracción pues, de acuerdo con la definición establecida anteriormente, es en ésta donde se definen las propiedades y atributos genéricos de determinados objetos con características comunes (recordemos el ejemplo de la sala de cine). La Clase es, por otro lado, una encapsulación porque constituye una cápsula o saco que encierra y amalgama de forma clara tanto los datos de que constan los objetos como los procedimientos que permiten manipularlos. Las Clases se constituyen, así, en abstracciones encapsuladas.

La herencia: Se aplica sobre las clases. O sea, de alguna forma las clases pueden tener descendencia, y ésta heredará algunas características de las clases "padres". Si disponemos las clases con un formato de árbol genealógico, tenderemos lo que se denomina una estructura jerarquizada de clases.

La OOP promueve en gran medida que las relaciones entre objetos se basen en construcciones jerárquicas. Esto es, las clases pueden heredar diferencialmente de otras clases (denominadas "superclases") determinadas características, mientras que, a la vez, pueden definir las suyas propias. Tales clases pasan, así, a denominarse "subclases" de aquéllas.

La herencia se implementa mediante un mecanismo que se denomina derivación de clases: las superclases pasan a llamarse clases base, mientras que las subclases se constituyen en clases derivadas. El mecanismo de herencia está fuertemente entroncado con la reutilización del código en OOP. Una clase derivada posibilita, el fácil uso de código ya creado en cualquiera de las clases base ya existentes.

El concepto de herencia constituye un estrato básico del paradigma de objetos, pero esto no significa que todas las relaciones entre clases en OOP deban ajustarse siempre a este modelo jerárquico. Es necesario establecer si la pretendida relación entre objetos es de pertenencia o de derivación. En una relación típica de pertenencia un objeto contiene al otro

Polimorfismo: Esta propiedad, como su mismo nombre sugiere múltiples formas, se refiere a la posibilidad de acceder a un variado rango de funciones distintas a través del mismo interfaz. O sea, que, en la práctica, un mismo identificador puede tener distintas formas (distintos cuerpos de función, distintos comportamientos) dependiendo, en general, del contexto en el que se halle inserto.

El polimorfismo se puede establecer mediante la sobrecarga de identificadores y operadores, la ligadura dinámica y las funciones virtuales. El término sobrecarga se refiere al uso del mismo identificador u operador en distintos contextos y con distintos significados.

La sobrecarga de funciones conduce a que un mismo nombre pueda representar distintas funciones con distinto tipo y número de argumentos. En el ámbito de la OOP, la sobrecarga de funciones equivale a que un mismo mensaje puede ser enviado a objetos de diferentes clases de forma que cada objeto respondería al mensaje apropiadamente.

La sobrecarga de operadores permite, por otro lado, el desarrollo de un código más coherente, como especialización de la sobrecarga de funciones, posibilitando la re-definición (para tipos de datos definidos-por-el-usuario) de las operaciones realizadas por éstos (+, -, *, >, etc.). Esto es, ocurre lo mismo que en la sobrecarga de funciones, pero aquí, en vez de identificadores de funciones, tenemos operadores.

Gracias a la ligadura dinámica, pueden invocarse operaciones en objetos obviando el tipo actual del éstos hasta el momento de la ejecución del código.


Otros Conceptos
  • Agregación: Composición de un objeto por otros. Es una relación más débil que la que existe entre el atributo y el objeto al cual pertenece, y más fuerte que una asociación.
  • Concurrencia: Propiedad que distingue un objeto activo de otro inactivo.
  • Persistencia: Es la propiedad de un objeto cuya existencia trasciende el tiempo y/o el espacio (ej. el objeto continua existiendo luego de que su creador deja de existir / la ubicación de un objeto se mueve a un espacio de direcciones diferente de aquella donde fue creada).
  • Visibilidad: capacidad de restringir el acceso a atributos y servicios de un objeto. Particularmente importante en el diseño e implementación. (ej.: público / protegido / privado)