Implementar un ABM y listado de una tabla MySQL utilizando el framework Express como base para la aplicación web.
Ya vimos en un concepto anterior la instalación del MySQL y la creación de la base de datos aquí.
c:\ejerciciosnodejs> express ejercicio23 --view=hbs
Estamos llamando al programa 'express' y le pasamos dos parámetros, el primero indica el nombre de nuestro proyecto y el segundo el sistema de plantillas que utilizaremos para generar nuestras páginas dinámicas (handlebars)
Ya tenemos creado la carpeta ejercicio23 y dentro de esta los archivos y subcarpetas básicos:
ejercicio23 app.js package.json bin www public images javascripts stylesheets router index.js users.js views error.hbs index.hbs layout.hbs
Instalamos todas las dependencias de módulos:
c:\ejerciciosnodejs\ejercicio23>npm install
Cuando llamamos a 'npm install' sin ningún otro parámetro lo que hace es buscar el archivo 'package.json' y proceder a instalar todos los módulos especificados en la propiedad 'dependencies'.
Ahora ya tenemos creado la carpeta 'node_modules' con las 7 carpetas que coinciden con las dependencias especificadas en el archivo json:
body-parser cookie-parser debug express hbs morgan serve-favicon
Recordemos que hasta ahora hemos creado un esqueleto funcional de una aplicación Node.js utilizando el framework Express y lo podemos ejecutar:
Podemos ejecutar nuestra aplicación mínima creada con el 'express-generador':
c:\ejerciciosnodejs\ejercicio23>node ./bin/www
Y ya podemos solicitar al servidor la página raíz del sitio:
Recordemos que otra forma de iniciar a nuestro proyecto en Node.js cuando definimos el archivo package.json:
En lugar de escribir:
c:\ejerciciosnodejs\ejercicio23>node ./bin/www
Escribimos:
c:\ejerciciosnodejs\ejercicio23>npm start
En el archivo json hay una propiedad start donde definimos el archivo que inicia nuestra aplicación:
"scripts": { "start": "node ./bin/www" },
Instalamos el módulo para comunicarnos con MySQL desde la línea de comandos:
c:\ejerciciosnodejs\ejercicio23>npm install mysql2
Luego de esto ya tenemos instalado en la carpeta node_modules el paquete mysql2:
{ "name": "ejercicio23", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "cookie-parser": "~1.4.4", "debug": "~2.6.9", "express": "~4.16.1", "hbs": "~4.0.4", "http-errors": "~1.6.3", "morgan": "~1.9.1", "mysql2": "^3.9.2" } }
Entramos en la carpeta routes y abrimos y modificamos el archivo index.js por el siguiente código:
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index'); }); module.exports = router;
Lo único que modificamos es la llamada a render borrando el segundo parámetro.
Ahora abrimos el archivo index.hbs de la carpeta views y creamos el HTML con un menú de opciones de nuestro programa:
<a href="/articulos/creartabla">Creacion de una tabla 'articulos' con MySQL</a></p> <a href="/articulos/alta">alta de articulos</a></p> <a href="/articulos/listado">Listado completo de articulos</a></p> <a href="/articulos/consulta">Consulta de un articulo por codigo</a></p> <a href="/articulos/modificacion">Modificacion de un articulo</a></p>
Si ejecutamos la aplicación ya podemos ver nuestro menú de opciones:
Agregaremos a nuestro archivo app.js una nueva ruta que se encargará todo lo relacionado con el tema de artículos:
var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users'); var articulos = require('./routes/articulos'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'hbs'); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', indexRouter); app.use('/users', usersRouter); app.use('/articulos',articulos); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
Las dos líneas que agregamos son el requerimiento del paquete articulos:
var articulos = require('./routes/articulos');
Y el enlace con la aplicación Express:
app.use('/articulos',articulos);
En la carpeta routes crearemos un módulo para iniciar la conexión con la base de datos y poder recuperar una referencia a la misma.
bd.js
var mysql = require('mysql2') var conexion = mysql.createConnection({ host: 'localhost', user: 'root', password: '', database: 'base1' }) conexion.connect(function (error) { if (error) console.log('Problemas de conexion con mysql') else console.log('se inicio conexion') }) module.exports = conexion
Procedemos ahora a crear el módulo 'articulos.js' en la carpeta 'routes' donde dispondremos la lógica para implementar el ABM.
articulos.js
var express = require('express') var router = express.Router() var bd = require('./bd') //Creación de la tabla router.get('/creartabla', function (req, res, next) { bd.query('drop table if exists articulos', function (error, resultado) { if (error) { console.log(error) return } }) bd.query('create table articulos (' + 'codigo int primary key auto_increment,' + 'descripcion varchar(50),' + 'precio float' + ')', function (error, resultado) { if (error) { console.log(error) return } }) res.render('mensajearticulos', { mensaje: 'La tabla se creo correctamente.' }) }) //Alta de registros router.get('/alta', function (req, res, next) { res.render('altaarticulos') }) router.post('/alta', function (req, res, next) { const registro = { descripcion: req.body.descripcion, precio: req.body.precio } bd.query('insert into articulos set ?', registro, function (error, resultado) { if (error) { console.log(error) return } }) res.render('mensajearticulos', { mensaje: 'La carga se efectuo correctamente' }) }) //Listado de registros router.get('/listado', function (req, res, next) { bd.query('select codigo,descripcion,precio from articulos', function (error, filas) { if (error) { console.log('error en el listado') return } res.render('listararticulos', { articulos: filas }) }) }) //Consulta router.get('/consulta', function (req, res, next) { res.render('consultaarticulos') }) router.post('/consulta', function (req, res, next) { bd.query('select descripcion,precio from articulos where codigo=?', req.body.codigo, function (error, filas) { if (error) { console.log('error en la consulta') return } if (filas.length > 0) { res.render('listadoconsulta', { articulos: filas }) } else { res.render('mensajearticulos', { mensaje: 'No existe el codigo de articulo ingresado' }) } }) }) //Modificacion router.get('/modificacion', function (req, res, next) { res.render('consultamodificacion') }) router.post('/modificar', function (req, res, next) { bd.query('select descripcion,precio,codigo from articulos where codigo=?', req.body.codigo, function (error, filas) { if (error) { console.log('error en la consulta') return } if (filas.length > 0) { res.render('formulariomodifica', { articulos: filas }) } else { res.render('mensajearticulos', { mensaje: 'No existe el codigo de articulo ingresado' }) } }) }) router.post('/confirmarmodifica', function (req, res, next) { const registro = { descripcion: req.body.descripcion, precio: req.body.precio } bd.query('UPDATE articulos SET ? WHERE ?', [registro, { codigo: req.body.codigo }], function (error, filas) { if (error) { console.log('error en la consulta') console.log(error) return } res.render('mensajearticulos', { mensaje: 'El articulo fue modificado' }) }) }) module.exports = router
Lo primero que hacemos es requerir el paquete bd que se encuentra en la misma carpeta (tanto el archivo articulos.js y bd.js se ubican en la carpeta routes):
var bd = require('./bd')
Para implementar la creación de la tabla tenemos que en el menú de opciones el primer enlace pasa la ruta '/articulos/creartabla':
<a href="/articulos/creartabla">Creacion de una tabla 'articulos' con MySQL</a></p>
Luego esta ruta la capturamos mediante el método get del objeto routes y solo indicamos '/creartabla' ya que en el archivo app.js indicamos app.use('/articulos',articulos)
//Creación de la tabla router.get('/creartabla', function (req, res, next) { bd.query('drop table if exists articulos', function (error, resultado) { if (error) { console.log(error) return } }) bd.query('create table articulos (' + 'codigo int primary key auto_increment,' + 'descripcion varchar(50),' + 'precio float' + ')', function (error, resultado) { if (error) { console.log(error) return } }) res.render('mensajearticulos', { mensaje: 'La tabla se creo correctamente.' }) })
Dentro del callback del método get procedemos a llamar al método query del objeto bd y efectuamos el borrado de la tabla articulos si ya existe y posteriormente la creamos con tres campos.
Finalmente pedimos que se muestre la plantilla 'mensajearticulos' y le pasamos como parámetro un objeto literal con un atributo llamado mensaje. El archivo mensajearticulos.hbs se almacena en la carpeta views y su contenido es:
<p>{{mensaje}}</p> <a href="/">Retornar</a>
Es decir mostramos el contenido del mensaje en un hipervínculo a la raiz del sitio web.
Si probamos de ejecutar la primer opción de nuestro menú tendremos como resultado la creación de la tabla (no olvidar de iniciar de arrancar el MySQL y crear la base de datos 'base1'):
Para implementar el alta en la tabla articulos se inicia cuando presionamos la segunda opción de nuestro menú:
<a href="/articulos/alta">alta de articulos</a></p>
Y desde el archivo articulos.js procedemos a capturar dicha ruta:
//Alta de registros router.get('/alta', function (req, res, next) { res.render('altaarticulos') })
En el método get procedemos a mostrar el contenido del archivo 'altaarticulos.hbs' que se encuentra como ya sabemos en la carpeta views y su contenido es:
<form method="post" action="/articulos/alta"> Ingrese descripcion del articulo: <input type="descripcion" name="descripcion" size="50"> <br> Ingrese el precio del articulo: <input type="text" name="precio" size="10"> <br> <input type="submit" value="Agregar"> </form>
Desde el navegador podemos observar el formulario de carga:
Cuando se presiona el botón submit procedemos a capturar dicha ruta en el archivo articulos.js donde procedemos a cargar los datos en la tabla de la base de datos:
router.post('/alta', function (req, res, next) { const registro = { descripcion: req.body.descripcion, precio: req.body.precio } bd.query('insert into articulos set ?', registro, function (error, resultado) { if (error) { console.log(error) return } }) res.render('mensajearticulos', { mensaje: 'La carga se efectuo correctamente' }) })
Podemos observar que llamamos nuevamente a la plantilla 'mensajearticulos' pero con un mensaje distinto a la creación de la tabla que vimos en el paso anterior.
Para implementar el listado completo de la tabla articulos se llama desde nuestro menú:
<a href="/articulos/listado">Listado completo de articulos</a></p>
Y en el archivo 'articulos.js' procedemos a capturar dicha ruta en el método:
//Listado de registros router.get('/listado', function (req, res, next) { bd.query('select codigo,descripcion,precio from articulos', function (error, filas) { if (error) { console.log('error en el listado') return } res.render('listararticulos', { articulos: filas }) }) })
Mediante un select recuperamos todas las filas de la tabla 'articulos' y llamamos al método sender pasando como segundo parámetro un objeto literal con un atributo que contiene todas las filas recuperadas.
En el archivo listaarticulos.hbs procedemos a mostrar los datos pasados en el objeto literal:
<table border="1"> <tr> <td>Codigo</td><td>Descripcion</td><td>Precio</td> </tr> {{#each articulos}} <tr> <td>{{codigo}} </td> <td>{{descripcion}}</td> <td>{{precio}}</td> </tr> {{/each}} </table> <a href="/">Retornar</a>
En el navegador podemos observar como se muestra la tabla de datos luego de procesarse la plantilla:
Para implementar la consulta de un articulo por su código llamamos desde nuestro menú:
<a href="/articulos/consulta">Consulta de un articulo por codigo</a></p>
Y en el archivo articulos.js capturamos la ruta y devolvemos la plantilla 'consultaarticulos':
//Consulta router.get('/consulta', function (req, res, next) { res.render('consultaarticulos') })
La plantilla consultaarticulos.hbs:
<form method="post" action="/articulos/consulta"> Ingrese codigo del articulo a consultar: <input type="text" name="codigo" size="5"> <br> <input type="submit" value="consultar"> </form>
En el navegador podemos ver:
Y luego que se presiona el botón submit capturamos la ruta en el método donde procedemos a buscar el código de articulo ingresado:
router.post('/consulta', function (req, res, next) { bd.query('select descripcion,precio from articulos where codigo=?', req.body.codigo, function (error, filas) { if (error) { console.log('error en la consulta') return } if (filas.length > 0) { res.render('listadoconsulta', { articulos: filas }) } else { res.render('mensajearticulos', { mensaje: 'No existe el codigo de articulo ingresado' }) } }) })
En el caso que exista el código de articulo ingresado procedemos a generar la plantilla 'listadoconsulta.hbs' y pasar un objeto literal para que se muestre los datos:
{{#each articulos}} <p>Descripcion:{{descripcion}}<br> Precio:{{precio}}</p> {{/each}} <a href="/">Retornar</a>
En el navegador podemos ver en el caso que exista el código:
Si no existe el código de artículo mostramos la plantilla 'mensajearticulos.hbs' pasando el mensaje respectivo.
Finalmente para implementar la modificación de un articulo llamamos desde nuestro menú:
<a href="/articulos/modificacion">Modificacion de un articulo</a></p>
Y en el archivo articulos.js capturamos la ruta y devolvemos la plantilla 'consultamodificacion':
//Modificacion router.get('/modificacion', function (req, res, next) { res.render('consultamodificacion') })
La plantilla consultamodificacion.hbs es:
<form method="post" action="/articulos/modificar"> Ingrese codigo del articulo a modificar: <input type="text" name="codigo" size="5"> <br> <input type="submit" value="buscar"> </form>
En el navegador podemos ver:
Cuando se presiona el botón submit se captura la ruta y procedemos a consultar el código y cargar la plantilla formulariomodifica.hbs:
router.post('/modificar', function (req, res, next) { bd.query('select descripcion,precio,codigo from articulos where codigo=?', req.body.codigo, function (error, filas) { if (error) { console.log('error en la consulta') return } if (filas.length > 0) { res.render('formulariomodifica', { articulos: filas }) } else { res.render('mensajearticulos', { mensaje: 'No existe el codigo de articulo ingresado' }) } }) })
La plantilla formulariomodifica.hbs muestra la descripción y precio actual del artículo y almacena en un campo hidden el código de artículo que estamos modificando:
{{#each articulos}} <form method="post" action="/articulos/confirmarmodifica"> Ingrese nueva descripcion del articulo: <input type="descripcion" name="descripcion" size="50" value="{{descripcion}}"> <br> Ingrese nuevo precio del articulo: <input type="text" name="precio" size="10" value="{{precio}}"> <input type="hidden" name="codigo" size="10" value="{{codigo}}"> <br> <input type="submit" value="Modificar"> </form> {{/each}}
En el navegador podemos ver:
Cuando se presiona el botón 'submit' procedemos a capturar la ruta mediante el método:
router.post('/confirmarmodifica', function (req, res, next) { const registro = { descripcion: req.body.descripcion, precio: req.body.precio } bd.query('UPDATE articulos SET ? WHERE ?', [registro, { codigo: req.body.codigo }], function (error, filas) { if (error) { console.log('error en la consulta') console.log(error) return } res.render('mensajearticulos', { mensaje: 'El articulo fue modificado' }) }) })
En este algoritmo procedemos a modificar una fila de la tabla artículos y mostrar un mensaje que la modificación fue hecha.
Este proyecto lo puede descargar en un zip con todos los archivos desde este enlace : ejercicio23