En post pasados [Ejemplo práctico de MVC java Swing con Netbeans, 3 en raya java con MVC y Netbeans , MVC: Modelo, Vista y Controlador en PHP], se vio una introducción y algunos ejemplos sobre el modelo MVC (Model, View, Controller). En esta ocasión, no volveremos repetir en que consiste tal patrón, sino realizaremos un ejemplo práctico, creo yo, es la mejor forma de aprender y familiarizarse con este modelo para el desarrollo de software.
No hacemos uso de ningún framework, al contrario, todo el proyecto se desarrolla sin ellos, para asi entender de lleno como es que trabaja el modelo MVC .
Necesitamos
Nivel: Intermedio
Duración: 3o minutos
Comencemos.
1.- Lo primero que necesitamos es una base de datos, créala con el nombre de tu preferencia. Para este ejemplo se utiliza solamente una tabla – Nombre: Producto – cuya estructura es la siguiente:
CREATE TABLE producto ( p_id varchar(6) NOT NULL, p_nombre varchar(21) NOT NULL, p_precio float NOT NULL default '0', p_cantidad int(20) NOT NULL default '0', PRIMARY KEY (p_id) )
Insertamos unos cuantos datos:
INSERT INTO producto VALUES ('P9-U7J', 'Producto 1', 100, 0); INSERT INTO producto VALUES ('KO-8HY', 'Producto 2', 56.9, 0); INSERT INTO producto VALUES ('UJ-9KK', 'Producto 3', 120.5, 0); INSERT INTO producto VALUES ('KK-77G', 'Producto 4', 23.4, 0); INSERT INTO producto VALUES ('KJ-886', 'Producto 5', 88, 0); INSERT INTO producto VALUES ('PP-99P', 'Producto 6', 78.9, 0); INSERT INTO producto VALUES ('GH-77U', 'Producto 7', 99.9, 0);
2.- Abre Netbeans y crea un nuevo proyecto de escritorio y dale un nombre, por ejemplo «AProductoMVC». Netbeans te crea la siguiente estructura de archivos:
AProductoMVC -Paquete de fuentes -- aproductomvc ----Main.Java -Paquete de fuentes -Bibliotecas -Bibliotecas de pruebas
3.- Lo que haremos ahora sera crear nuestra estructura MVC.
En el paquete donde se encuentra el Main.java, clic derecho -> Reestructurar -> Cambiar nombre. Coloca como nuevo nombre «controlador» y clic en «reestrcututar».
Crea dos nuevos paquetes más, «modelo» y «vista».
En el paquete controlador, agrega una nueva clase llamada «controlador.java».
En el paquete modelo, agrega dos clases que son, «database.java» y «modelo.java».
En el paquete vista, añade un JFrame que se llamara «interfaz.java».
Como cambiamos el nombre a nuestro paquete donde estaba el Main.al ejecutar nos saldrá un error «java.lang.NoClassDefFoundError: aproductomvc/Main», esto nos dice que no encuentra el Main. Para darle solución, clic derecho sobre el proyecto -> Propiedades. Busca la categoría «Ejecutar» y en la opción del Main Class , dale clic en examinar y selecciona «controlador.main» , para terminar clic en «aceptar».
4.- Como hacemos uso de una base de datos, debemos añadir al proyecto el Driver MySQL JDBC en su última versión.
Hasta ahora debemos tener lo siguiente:
5.- LA VISTA: Nuestro proyecto consta de tan solo un JFrame con el siguiente diseño:
Estamos utilizando «jformattedtextfield» para tratar los datos, las mascaras son las siguientes:
__id_producto : AA-AAA
__nombre: *********************
__precio: #0.00
__cantidad: #0
IMPORTANTE: Netbeans crea por defecto estos controles con la propiedad PRIVATE, esto no nos sirve, debemos cambiarlo, selecciona un control (por ejemplo: __id_producto ), dale clic derecho y busca «propiedades», en la pestaña «Codigo», cambia la propiedad «modificadores de variable: private», por PUBLIC. Repite esta acción para todos los controles.
6. EL MODELO: aquí colocamos la representación de nuestro sistema, puede ser una sola clase o varias clases dependiendo del tamaño de nuestro proyecto. En este tutorial, se utilizan dos clases podrían ser más o menos depende del programador.
Clase «database«, nos conectara a MySQL y retornara la conexión.
package modelo; import java.sql.*; /** * @web https://www.jc-mouse.net * @author Mouse */ public class database { /* DATOS PARA LA CONEXION */ /** base de datos por defecto es test*/ private String db = "dbtest"; /** usuario */ private String user = "root"; /** contraseña de MySql*/ private String password = ""; /** Cadena de conexion */ private String url = "jdbc:mysql://localhost/"+db; /** variable para trabajar con la conexion a la base de datos */ private Connection conn = null; /** Constructor de clase */ public database(){ this.url = "jdbc:mysql://localhost/"+this.db; try{ //obtenemos el driver de para mysql Class.forName("com.mysql.jdbc.Driver"); //obtenemos la conexión conn = DriverManager.getConnection( this.url, this.user , this.password ); }catch(SQLException e){ System.err.println( e.getMessage() ); }catch(ClassNotFoundException e){ System.err.println( e.getMessage() ); } } public Connection getConexion() { return this.conn; } }
Clase modelo.java , aquí es donde se procesa la información y retorna un resultado.
package modelo; import java.sql.*; import javax.swing.table.DefaultTableModel; /** * @web https://www.jc-mouse.net * @author Mouse */ public class modelo extends database{ /** Constructor de clase */ public modelo (){} /** Obtiene registros de la tabla PRODUCTO y los devuelve en un DefaultTableModel*/ public DefaultTableModel getTablaProducto() { DefaultTableModel tablemodel = new DefaultTableModel(); int registros = 0; String[] columNames = {"ID","Nomnbre","Precio","Cantidad"}; //obtenemos la cantidad de registros existentes en la tabla y se almacena en la variable "registros" //para formar la matriz de datos try{ PreparedStatement pstm = this.getConexion().prepareStatement( "SELECT count(*) as total FROM producto"); ResultSet res = pstm.executeQuery(); res.next(); registros = res.getInt("total"); res.close(); }catch(SQLException e){ System.err.println( e.getMessage() ); } //se crea una matriz con tantas filas y columnas que necesite Object[][] data = new String[registros][5]; try{ //realizamos la consulta sql y llenamos los datos en la matriz "Object[][] data" PreparedStatement pstm = this.getConexion().prepareStatement("SELECT * FROM producto"); ResultSet res = pstm.executeQuery(); int i=0; while(res.next()){ data[i][0] = res.getString( "p_id" ); data[i][1] = res.getString( "p_nombre" ); data[i][2] = res.getString( "p_precio" ); data[i][3] = res.getString( "p_cantidad" ); i++; } res.close(); //se añade la matriz de datos en el DefaultTableModel tablemodel.setDataVector(data, columNames ); }catch(SQLException e){ System.err.println( e.getMessage() ); } return tablemodel; } /** Registra un nuevo producto */ public boolean NuevoProducto(String id, String nombre , String precio, String cantidad) { if( valida_datos(id, nombre, precio, cantidad) ) { //se reemplaza "," por "." precio = precio.replace(",", "."); //Se arma la consulta String q=" INSERT INTO producto ( p_id , p_nombre , p_precio, p_cantidad ) " + "VALUES ( '" + id + "','" + nombre + "', '" + precio + "'," + cantidad + " ) "; //se ejecuta la consulta try { PreparedStatement pstm = this.getConexion().prepareStatement(q); pstm.execute(); pstm.close(); return true; }catch(SQLException e){ System.err.println( e.getMessage() ); } return false; } else return false; } /** Elimina un registro dado su ID -> Llave primaria */ public boolean EliminarProducto( String id ) { boolean res=false; //se arma la consulta String q = " DELETE FROM producto WHERE p_id='" + id + "' " ; //se ejecuta la consulta try { PreparedStatement pstm = this.getConexion().prepareStatement(q); pstm.execute(); pstm.close(); res=true; }catch(SQLException e){ System.err.println( e.getMessage() ); } return res; } /** Metodo privado para validar datos */ private boolean valida_datos(String id, String nombre , String precio, String cantidad) { if( id.equals(" - ") ) return false; else if( nombre.length() > 0 && precio.length()>0 && cantidad.length() >0) { return true; } else return false; } }
7.- EL CONTROLADOR: es el encargado de captutar los eventos producidos por el usuario procesarlos enviando los datos al modelo y retornar la información en la vista.
package controlador; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JOptionPane; import javax.swing.table.DefaultTableModel; //se importa modelo e interfaz import modelo.modelo; import vista.interfaz; /** * @web https://www.jc-mouse.net * @author Mouse */ public class controlador implements ActionListener,MouseListener{ /** instancia a nuestra interfaz de usuario*/ interfaz vista ; /** instancia a nuestro modelo */ modelo modelo = new modelo(); /** Se declaran en un ENUM las acciones que se realizan desde la * interfaz de usuario VISTA y posterior ejecución desde el controlador */ public enum AccionMVC { __VER_PRODUCTOS, __AGREGAR_PRODUCTO, __ELIMINAR_PRODUCTO } /** Constrcutor de clase * @param vista Instancia de clase interfaz */ public controlador( interfaz vista ) { this.vista = vista; } /** Inicia el skin y las diferentes variables que se utilizan */ public void iniciar() { // Skin tipo WINDOWS try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); SwingUtilities.updateComponentTreeUI(vista); vista.setVisible(true); } catch (UnsupportedLookAndFeelException ex) {} catch (ClassNotFoundException ex) {} catch (InstantiationException ex) {} catch (IllegalAccessException ex) {} //declara una acción y añade un escucha al evento producido por el componente this.vista.__VER_PRODUCTOS.setActionCommand( "__VER_PRODUCTOS" ); this.vista.__VER_PRODUCTOS.addActionListener(this); //declara una acción y añade un escucha al evento producido por el componente this.vista.__AGREGAR_PRODUCTO.setActionCommand( "__AGREGAR_PRODUCTO" ); this.vista.__AGREGAR_PRODUCTO.addActionListener(this); //declara una acción y añade un escucha al evento producido por el componente this.vista.__ELIMINAR_PRODUCTO.setActionCommand( "__ELIMINAR_PRODUCTO" ); this.vista.__ELIMINAR_PRODUCTO.addActionListener(this); //añade e inicia el jtable con un DefaultTableModel vacio this.vista.__tabla_producto.addMouseListener(this); this.vista.__tabla_producto.setModel( new DefaultTableModel() ); } //Eventos que suceden por el mouse public void mouseClicked(MouseEvent e) { if( e.getButton()== 1)//boton izquierdo { int fila = this.vista.__tabla_producto.rowAtPoint(e.getPoint()); if (fila > -1){ this.vista.__id_producto.setText( String.valueOf( this.vista.__tabla_producto.getValueAt(fila, 0) )); this.vista.__nombre.setText( String.valueOf( this.vista.__tabla_producto.getValueAt(fila, 1) )); this.vista.__precio.setText( String.valueOf( this.vista.__tabla_producto.getValueAt(fila, 2) )); this.vista.__cantidad.setText( String.valueOf( this.vista.__tabla_producto.getValueAt(fila, 3) )); } } } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) { } //Control de eventos de los controles que tienen definido un "ActionCommand" public void actionPerformed(ActionEvent e) { switch ( AccionMVC.valueOf( e.getActionCommand() ) ) { case __VER_PRODUCTOS: //obtiene del modelo los registros en un DefaultTableModel y lo asigna en la vista this.vista.__tabla_producto.setModel( this.modelo.getTablaProducto() ); break; case __AGREGAR_PRODUCTO: //añade un nuevo registro if ( this.modelo.NuevoProducto( this.vista.__id_producto.getText(), this.vista.__nombre.getText() , this.vista.__precio.getText(), this.vista.__cantidad.getText() ) ) { this.vista.__tabla_producto.setModel( this.modelo.getTablaProducto() ); JOptionPane.showMessageDialog(vista,"Exito: Nuevo registro agregado."); this.vista.__id_producto.setText(""); this.vista.__nombre.setText("") ; this.vista.__precio.setText("0"); this.vista.__cantidad.setText("0") ; } else //ocurrio un error JOptionPane.showMessageDialog(vista,"Error: Los datos son incorrectos."); break; case __ELIMINAR_PRODUCTO: if ( this.modelo.EliminarProducto( this.vista.__id_producto.getText() ) ) { this.vista.__tabla_producto.setModel( this.modelo.getTablaProducto() ); JOptionPane.showMessageDialog(vista,"Exito: Registro eliminado."); this.vista.__id_producto.setText(""); this.vista.__nombre.setText("") ; this.vista.__precio.setText("0"); this.vista.__cantidad.setText("0") ; } break; } } }
8.- Para terminar el código para el Main.java, el encargado de arrancar toda la aplicación.
package controlador; import vista.interfaz; /** * @web https://www.jc-mouse.net/ * @author Mouse */ public class Main { public static void main(String[] args) { //ejecuta el controlador y este la vista new controlador( new interfaz() ).iniciar() ; } }
Proyecto en ejecución
Descarga el proyecto en netbeans 6.9 AQUI
Una procedimiento almacenado es un conjunto de sentencias de SQL que se pueden almacenar en el servidor, de esta forma n[...]
En este tutorial se explica una forma de crear CD autoejecutable para programas hechos en java asi como para instalar la[...]
El error: Instalaba SQL Server 2008 R2 en español en Windows con el idioma «Español (Bolivia)»y de repente me salio este[...]
Mensajes ocultos utilizando el método de Inserción en el bit menos significativo (Least Significant Bit Insertion) El mé[...]
En este post implementaremos el código necesario para multiplicar matrices con el lenguaje Kotlin, pero para realizar es[...]
En este tutorial crearemos el botón de Google+ Google Circles para una interfaz de escritorio 🙂 si no sabes lo que son e[...]