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