백엔드/express.js

이미지 업로드 - multer

syleemomo 2024. 5. 16. 17:34
728x90

https://medium.com/@hassaanistic/image-handeling-using-multer-in-react-d7fea28e8dc6

 

 

multer 를 이용하여 이미지를 업로드하는 방법은 두가지가 있다. 첫번째는 이미지를 서버로 전송하면 특정폴더에 저장하고, 폴더에 저장된 이미지 데이터를 DB에 저장하고, 브라우저로 이미지 데이터를 보낸다. 두번째는 이미지를 서버로 전송하면 특정폴더에 저장하고, 폴더에 저장된 이미지 경로를 브라우저로 전송하고, 브라우저에서 해당경로의 파일 데이터를 읽는 방식이다. 즉, 브라우저로 이미지 데이터를 보내느냐, 이미지 경로를 보내느냐의 차이다. 또는 서버쪽에서 이미지 데이터를 조회하느냐 프론트쪽에서 이미지 데이터를 조회하느냐의 차이다.

 

아래 코드는 두번째 방법을 사용한다. 두번째 방법의 단점은 이미지 리스트를 보여줘야 할때 예를 들어 이미지가 1000개이면 서버접속을 1000번 해야된다. 물론 상세페이지에서 하나의 이미지를 보여주는건 가능하다. 하지만 첫번째 방법으로 하면 이미지 데이터의 리스트를 한번의 서버접속으로 조회할 수 있다.

 

Creating image model

const mongoose = require('mongoose');

const imageSchema = new mongoose.Schema({
  name: String,
  contentType: String,
  imageUrl: String, // Store the image URL here ->// we can fetch the image from databse using this 
  // Add any other fields you need for your image
});


module.exports = mongoose.model('Image', imageSchema);

 

Creating Middleware

const multer = require('multer');

const storage = multer.diskStorage({
    destination: (req, file, callback) => {
      callback(null, ("./uploads") );  // ->("./uploads")  this is the destination where files will save in the HArdDisk Storage 
    },
    filename: (req, file, callback) => {
      callback(null, file.originalname);
    },
  });

//   const upload = multer({ storage :storage }); OR
  const upload = multer({ storage });

  module.exports = upload;
  
// memoryStorage() vs diskStorage() ? : {    
// const storage = multer.memoryStorage(); // It open the image in the Ram temporarily --> Not save permanently -> good for croping , editing , and making change in the  file Function without saving the copy permanently 
//we use memoryStorage if we don't need to save the image permanently and for future use
//In our case we have to use the disk storage to save the images permanently for the future use
//}

 

Server Room

const express = require('express');
const db = require("./config/connectToDatabase")
const app = express();
const PORT = process.env.PORT ;
const imageRouter =  require("./routes/imageRoutes");
var cors = require('cors') //For connecting Backend with frontend

app.use(express.json());
app.use(cors());

app.get('/', (req,res )=>{
    res.send("Hello MEDIUM");
});


app.use('/api/images',imageRouter);


app.listen(PORT , (req, res) => {
    console.log(`Running at http://localhost:${PORT}`);
});

 

Routes file

const express = require('express');
const router = express.Router();
const upload = require('../middlewares/multerStorage'); // Import the multer middleware
const {postingImage ,singleImage } = require('../controller/imageController'); // Import the image controller


router.post('/upload', upload.single('image'), postingImage); // Call the imageController.uploadImage function
router.route('/:id').get(singleImage)

module.exports = router;

 

Control Room for Image APIs

const Image = require("../models/imageModel");
const path = require("path"); //for single specific Image
const fs = require('fs'); //for single specific Image



// @Posting  Image using POST 
// http://localhost:5000/api/images/upload
const postingImage = async (req, res) => {
  try {
    // Create an Image model instance.
    const image = new Image({
      name: req.file.originalname,
      contentType: req.file.mimetype,
      imageId: req.file.id,
    });

    // Save the Image model instance to the database.
    const savedImage = await image.save();

    // Set the imageUrl based on your server URL and the image ID
    savedImage.imageUrl = `http://localhost:5000/api/images/${savedImage._id}`;
    //this is for getting the image from the database

    // Save the updated Image model
    await savedImage.save();

    res.json(savedImage);
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: 'Image upload failed' });
  }
}



// @Getting Specific Image using GET
// http://localhost:5000/api/images/:id
const singleImage = async (req, res) => {
  try {
    const image = await Image.findById(req.params.id); //req -> local:Url 
    // await console.log(image.name)
    if (!image) {
      return res.status(404).json({ error: 'Image not found' });
    }

    // Construct the path to the image file in the uploads folder based on _id
    // const imagePath = path.join(__dirname, 'uploads', `${req.user._id}-${image.name}`); //"will use when add authentication"
    // const imagePath = path.join(__dirname, 'uploads', `${image.name}`);  //this is disgusting `${}`
    const imagePath = path.join(__dirname, '..', 'uploads', image.name);
    // console.log(imagePath);

    // Check if the file exists
    if (!fs.existsSync(imagePath)) {
      return res.status(404).json({ error: 'Image file not found' });
    }

    // Send the image file as a response
    res.sendFile(imagePath);
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: 'Failed to retrieve image' });
  }
}



module.exports = { postingImage, singleImage,};

 

FrontEnd part

import React, { useEffect, useState } from "react";
import {Buttons} from "@chakra-ui/react";

export default function Profile() {
  const [fileInput, setFileInput] = useState(null);
  const [selectedImageForDisplay, setselectedImageForDisplay] = useState(null);

  useEffect(() => {

    // Check if there's a saved image URL in localStorage and set it
    const savedImageURL = localStorage.getItem("selectedImageForDisplay");
    if (savedImageURL) {
      setselectedImageForDisplay(savedImageURL);
    }
  }, []);

  const onChangeHandle = (e) => {
    setFileInput(e.target.files[0]);
  };

  const handleImageUpload = () => {
    if (fileInput) {
      const formData = new FormData();
      formData.append("image", fileInput);

      fetch("http://localhost:5000/api/images/upload", {
        method: "POST",
        body: formData,
        headers: {
          'Authorization': `Bearer ${localStorage.getItem("token")}`,
        }
      })
        .then((response) => {
          if (response.ok) {
            return response.json();
          }
          throw new Error("Image upload failed.");
        })
        .then((data) => {
          fetchAndDisplayImage(data.imageUrl);
        })
        .catch((error) => {
          console.error("Error uploading image:", error);
        });
    }
  };

  const fetchAndDisplayImage = (imageUrl) => {
    fetch(imageUrl, {
      method: "GET",
      headers: {
        'Authorization': `Bearer ${localStorage.getItem("token")}`,
      }
    })
      .then((response) => {
        if (response.ok) {
          return response.blob();
        }
        throw new Error("Failed to fetch the image.");
      })
      .then((blob) => {
        const url = URL.createObjectURL(blob);
        setselectedImageForDisplay(url);

        // Save the image URL in localStorage
        localStorage.setItem("selectedImageForDisplay", url);
      })
      .catch((error) => {
        console.error("Error fetching image:", error);
      });
  };

  return (
 
     <div>
        <input
          type="file"
          accept="image/*"
          onChange={onChangeHandle}
        />
        <Button
          bg={"purple.300"}
          onClick={handleImageUpload}
          style={{ margin: "20px" }}
        >
          Upload Image
        </Button>
        {selectedImageForDisplay && (
          <div style={{ width: "200px", height: "200px" }}>
            <img
              src={selectedImageForDisplay}
              alt="Selected"
              style={{ width: "100%", height: "100%" }}
            />
          </div>
        )}
      </div>

    
  );
}
728x90