Tutorial - Como crear una galería de imágenes / fotos con Nodejs - MongoDB y alojarlas en un servicio en la nube llamado Cloudinary

Tecnología
  
Programación Web
  
Nodejs
  
Javascript
  
Bootstrap
  
Express Js
  
Desarrollo Web
    07 Febrero, 2021   Regresar el blog
Compartir:

En el día de hoy te voy a ensenar a crear una aplicación web de Galería de imágenes / Fotos, usando Nodejs, Mongodb y otras tecnologías de Javascript como handlebars, Express entre otras más. Además almacenaremos nuestras imágenes en un servicio de la nube llamado Cloudinary.

Empezaremos creando una carpeta en nuestro escritorio /galeria-node y activando la consola de nuestro editor de código favorito, e instalaremos las siguientes dependencias:

npm init --yes

npm i express mongoose express-handlebars morgan multer cloudinary fs-extra dotenv cross-env

npm i --save-dev @babel/node @babel/core @babel/cli @babel/preset-env nodemon 

Creamos un archivo llamado .babelrc con lo siguiente:

{
    "presets" : [
        "@babel/env"
    ]
}

configuramos el archivo package.json con lo siguiente:

"dev": "nodemon src/index.js --exec babel-node",
    "build":"babel src --out-dir build",
    "start": "node build/index.js"

A continuación crearemos la estructura del proyecto:

dentro de la carpeta src/ crearemos esta estructura
models/
views/
routes/
index.js 
app.js 
database.js 

Para este tutorial almacenaremos nuestras imágenes en un proveedor externo llamado https://cloudinary.com/ para ello nos registraremos en su pagina web, una vez registrados en el dashboard tendremos a nuestra disposición el nombre de usuario, la api key y la api secret necesario para usar el servicio


Crearemos un archivo .env que contendrá nuestras variables privadas

.env
MONGODB_URI=mongodb://localhost/galeria_imagenes_db
PORT=3000
CLOUDINARY_CLOUD_NAME=tu_nombre_usuario_cloudinary
CLOUDINARY_API_KEY=tu_api_key_cloudinary
CLOUDINARY_API_SECRET=tu_secret_cloudinary

Crearemos nuestro servidor e inicializaremos express, el motor de plantillas handlebars y algunos middlewares para dejarlo listo para nuestro tutorial

index.js
import 'dotenv/config'
import app from './app'
app.listen(app.get('PORT'), () => {
    console.log('Server on port:',app.get('PORT'))
    console.log('Environment:', process.env.NODE_ENV)
})

app.js
import express from 'express'
import exphbs from 'express-handlebars'
import path from 'path'
import morgan from 'morgan'
import multer from 'multer'
import routes from './routes'
import './database'
const app = express()
// Initializations
app.set('PORT', process.env.PORT || 3000)
app.set('views', path.join(__dirname,'views'))
app.engine('.hbs', exphbs({
    defaultLayout : 'main',
    layoutsDir: path.join(app.get('views'),'layouts'),
    partialsDir: path.join(app.get('views'),'partials'),
    extname: '.hbs'
}))
app.set('view engine','.hbs')
// Middlewares
app.use(morgan('dev'))
app.use(express.json())
app.use(express.urlencoded({extended:false}))
const storage = multer.diskStorage({
    destination:path.join(__dirname,'public/uploads'),
    filename: (req, file, cb) => {
        cb(null, new Date().getTime() + path.extname(file.originalname))
    }
})
app.use(multer({storage}).single('image'))
app.use(routes)
export default app

Ahora procederemos a conectarnos con la base de datos:

database.js
import mongoose from 'mongoose'
mongoose.connect(process.env.MONGODB_URI, {
    useNewUrlParser:true,
    useUnifiedTopology: true
})
.then( db => console.log('DB is connected') )
.catch ( err => console.log(err) )

Crearemos nuestro modelo de datos llamado Image dentro de la carpeta models:

models/Image.js
import {Schema, model} from 'mongoose'
const Image = new Schema({
    title: String, 
    description: String,
    imageURL: String,
    public_id: String
})
export default model('Image', Image)

Crearemos una nuestras rutas necesarias para el tutorial

routes/index.js
import {Router} from 'express'
import fs from 'fs-extra'
import Image from '../models/Image'
const router = Router()
import cloudinary from 'cloudinary'
cloudinary.config({
    cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
    api_key: process.env.CLOUDINARY_API_KEY,
    api_secret: process.env.CLOUDINARY_API_SECRET
})
router.get('/', async (req,res) => {
    const images = await Image.find().lean()
    res.render('images',{images})
})
router.get('/images/add', async (req,res) => {
    const images = await Image.find().lean()
    res.render('images_form',{images})
})
router.post('/images/add', async (req,res) => {
    const {title, description} = req.body
    const result = await cloudinary.v2.uploader.upload(req.file.path)
    const newImage = new Image({
        title,
        description,
        imageURL: result.url,
        public_id: result.public_id
    })
    await newImage.save()
    //remove the image from local
    await fs.remove(req.file.path)
    res.redirect('/')
})
router.get('/images/delete/:id', async (req, res) => {
    const image = await Image.findByIdAndRemove(req.params.id)
    await cloudinary.v2.uploader.destroy(image.public_id)
    res.redirect('/images/add')
})
export default router

Crearemos una carpeta llamada views que contendra a su vez layouts/ y partials/ dentro de layouts/ crearemos un archivo llamado main.hbs

views/layouts/main.hbs
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tutorial - Como crear una galería de imágenes / fotos>n Nodejs - MongoDB y alojarlas en un servicio en la
        nube llamado Cloudinary </title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/flatly/bootstrap.min.css">
    <link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css" />
</head>
<body>
    {{> navigation }}
    <div class="container p-2">
        {{{ body }}}
    </div>
    <script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
    <script>
        var swiper = new Swiper('.swiper-container', {
      effect: 'coverflow',
      grabCursor: true,
      centeredSlides: true,
      slidesPerView: 'auto',
      coverflowEffect: {
        rotate: 50,
        stretch: 0,
        depth: 100,
        modifier: 1,
        slideShadows: true,
      },
      pagination: {
        el: '.swiper-pagination',
      },
    });
    </script>
<body>
</html>

views/partials/navigation.hbs
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid container">
    <a class="navbar-brand" href="/">Photo Gallery <i>from</i> <code class="text-danger">Jfdesousa7</code></a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <b class="navbar-toggler-icon"></b>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="/images/add">Add Image +</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

views/images.hbs
<style>
   body {
      background: #fff;
      font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
      font-size: 14px;
      color: #000;
      margin: 0;
      padding: 0;
   }
   .swiper-container {
      width: 100%;
      padding-top: 50px;
      padding-bottom: 50px;
   }
   .swiper-slide {
      background-position: center;
      background-size: cover;
      width: 300px;
      height: 400px;
   }
</style>
<h3>My Images</h3>

<div class="swiper-container">
   <div class="swiper-wrapper">
      {{#each images}}
      <img src="{{imageURL}}" class="swiper-slide" />
      {{/each}}
   </div>
   
   <div class="swiper-pagination"></div>
</div>

views/images_form.hbs
<div class="row ">
    <div class="col-4">
        <div class="card">
            <div class="card-body">
                <form action="/images/add" method="POST" enctype="multipart/form-data"> 
                    <div class="mb-3">
                    <input type="text" required class='form-control' name="title" placeholder="Title" autofocus>
                </div>
                <div class="mb-3">
                    <textarea rows="3" required name="description" class="form-control" placeholder="Image description"></textarea>
                </div>
                <div class="mb-3">
                    <div class="custom-file">
                        <input type="file" required name="image" class="custom-file-input" id="inputFile" />
                        <label for="inputFile" class="custom-file-label">Choose File</label>
                    </div>
                </div>
                <button class="btn btn-primary btn-block">Upload Photo</button>
                </form>
            </div>
        </div>
    </div>
        <div class="col-8">
            <table class="table">
                <thead>
                    <th>Title</th>
                    <th>Description</th>
                    <th>Actions</th>
                </thead>
                <tbody>
                        {{#each images}}
                            <tr>
                                <td>{{title}}</td>
                                <td>{{description}}</td>
                                <td><a href="{{imageURL}}" target="_blank" class="btn btn-xs btn-info">View</a></td>
                                <td><a href="/images/delete/{{_id}}" class="btn btn-xs btn-danger">Delete</a></td>
                            </tr>
                        {{/each}}
                </tbody>
            </table>
        </div>
</div>

Para la galería del home usaremos una librería llamada Swiper https://swiperjs.com/get-started


Adjunto Imágenes del resultado final








Y con esa amigos llegamos al final del tutorial, espero que lo hayan disfrutado y hasta la próxima!


Visita mi sitio web oficial

tupaginaonline.net

223 vistas
Compartir:


Autor
Jose Fuentes

- Web Developer -

 


0 COMENTARIO(S)
Contesta
Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *
Comentario *
Nombre *
Correo electrónico *
Sitio web

Articulos Relacionados
Articulos recientes

Desarrollos en venta

$ usd dólar 600