컴퓨터/웹 : JS

[Node.js](개인 프로젝트) 사진-페이지 연동

도도새 도 2023. 4. 6. 18:15

사진 연동

 

 드디어 학교 졸업과제를 끝냈다. 이로서 다시 본 프로젝트로 복귀하게 되었다.

 

 사실 오늘 정리하는 내용은 졸업과제 시작 전 한 내용이지만 개강과 졸업과제가 겹쳐서 포스팅할 생각을 못하고 있었다. 오늘은 이 내용을 재정리하며 내 프로젝트 진행 상황을 재확인하고, 다시 프로젝트에 돌입하고자 한다.

 

 

db에 사진 연동

 

 이전 포스팅에서 Cloudinary를 이용해 사진 업로드 기능을 구현 한 바 있다. multer를 사용해 받았고, req.files에 그 값들이 담긴다. 이 담긴 값에는 url도 남기는데, 단순히 이 url들을 db에 삽입해주기만 하면 사진과 연동이 된다.

, 아래 코드를 추가하였다.

  const images = req .files .map (f =>({url :f .path , filename :f .filename }));

  const cafe = new Cafe ({

   images :images ,

   name :cafeData .name ,

   menu :menu ,

   description :cafeData .description ,

   purpose :cafeData .purpose ,

   location :cafeData .location ,

   latitude :cafeData .latitude ,

   longitude :cafeData .longitude ,

   repreMenu :repreMenu

  });

그런데 결과 사진을 보니 크기가 제각각인게 마음에 들지 않았다. 이미지 사이즈 관련해서 sharp모듈이 있기는 하지만, 전처리해서 이미지 크기를 바꾸어 저장할 생각은 없기에 css를 건드려보기로 한다.

 

html을 아래와 같이 작성했다(ejs이다)

 

           <div style ="text-align: left;">

             <img src ="<%= cafe.images[0].url %>" style ="width: 200px; height: 200px; object-fit: contain;">

           </div >

divimg요소를 감싼 후 왼쪽 정렬하고, img는 몽고DB의 첫 번쨰 이미지 url을 받아온다. 크기는 200px, 200px로 설정한 후, object-fit 속성을 contain으로 설정하였다.

*object-fit 속성

 

이미지, 비디오 등의 요소 내용의 크기와 표시 영역 크기가 다를 때(img태그와 img소스 내용 크기가 다를 때) 어떻게 이미지를 조절할지 지정한다.

fill : 내용을 표시 영역에 꽉 채운다. 비율이 왜곡 될 수 있다.

contain : 내용을 표시 영역에 최대한 맞춘다. 가로 세로 비율을 유지하며, 내용이 표시 영역보다 작으면 확대한다.

cover : 내용을 표시 영역에 최대한 맞춘다. 가로 세로 비율을 유지하며, 내용이 영역보다 클 경우 일부가 잘린다.

none : 크기 조절하지 않는다. 내용이 표시 영역을 벗어나면 잘린다.

scale-down : ‘none’‘contain’ 중 작은 것을 선택한다.

결과

그 결고 업로드한 썸네일이 화면에 나타나게 되었다.

 

React part

 

이제 할 작업은 React페이지의 카루셀의 크기 조절 및 이미지 삽입, 그리고 댓글의 이미지 삽입 기능 추가이다.

 

아직 구현해보지 않은 지금으로서 의문은 axios로 이미지 url을 보내게 될 텐데, 받는 쪽에서 upload미들웨어로 어떻게 값을 보낼 것인가.

 

 

우선 카루셀에 이미지 띄우는 코드는 쉽게 완성하였다.

  const  Carousel_list = [];

  for (let img of probs .images ){

   Carousel_list .push (

    <Carousel.Item style ={{height :'25rem', width :'25rem'}}>

     <img

      className ="d-block w-100"

      src ={img .url }

      style ={{objectFit :'contain', width :'100%', height :'100%'}}

     />

    </Carousel.Item >

   )

  }

 

카루셀 자식 요소를 배열로 만들어 배열에 넣은 후 {}로 넣어주면 끝이다! 여기서도 크기 조절을 위해 object-fit 속성을 contain으로 해주었다.

 

이제 유저가 댓글을 달 때 이미지를 넣도록 해주는 작업을 할 것이다. 언제나 그랬듯 여전히 깊게 리액트를 다뤄 본 적이 없으므로 모호하다.

 

 

일반적으로 서버-서버엔진에서는 inputmulti로 설정하여 사진을 보내도록 한다. 아래와 같은 형태이다.

         <form action ="/cafe"method ="POST"enctype ="multipart/form-data">

 현재로서 서버로 axiospost를 하는 것은 구현이 되어있는 상태이다. 즉 클라이언트 측에서 사용자로부터 이미지 url만 받아올 수 있으면 넘기는 객체에 url값만 추가하면 해결되는 문제이다.

 

이 문제는 아래와 같이 해결하였다.

  const handleFileUpload = (event ) =>{

   const uploadedFile = event .target .files [0 ];

   console .log ("업로드딘 파일", uploadedFile );

  }

              <div class ="input-group mb-3 mt-3">

               <input type ="file"class ="form-control"id ="inputGroupFile02"  onChange ={handleFileUpload }/>

               <label class ="input-group-text"for ="inputGroupFile02">사진 </label >

              </div >

그런데 읽어온 파일의 형식이 전혀 알 수가 없었다. 이전에 multer를 사용했는데, 클라이언트측에서도 multer사용이 가능할까?

 

multer의 조건은 멀티파트/fomr-data형식의 요청이다. 클라이언트 측에서는 FormData객체를 사용하면 이게 가능하다고 한다.

 

이를 이용해서 기존 코드를 약간 수정하고자 한다.

   const formData = new FormData ();

 

   await axios .post (`http://localhost:8080/cafe/user/review/create/${id }`, data )

 

그러니 서버 측에서 keyphotosimgFile객체를 잘 인식하고 업로드 처리를 해주었다. keyname처럼 이용이 가능한 듯 하다.

app .post ('/cafe/user/review/create/:id', upload .single ('photos'), async (req , res ) => {

upload.single에서 정상적으로 받아서 클라우디너리에 저장해 주었다.

 

이렇게 업로드 처리가 완료되었다. 이제 이걸 db에 할당하고, 띄우는 코드를 작성해야한다. 단순히 req.fileurl을 저장하는 식으로 구현하면 충분할 것이다.

 

  const tempComment = { 

   image :req .file .url ,

   user :userID ,

   content :comment ,

   purpose :atmos ,

   rating :{

    taste :tasteRate ,

    atmosphere :atmosRate ,

    price :priceRate

   }

  }

  cafe .comment .push (tempComment );

  await cafe .save ()

이것만으로 DB저장은 끝이다. 이제 다시 React에서 정보를 받아오는 부분을 건드려야한다.

 

이미 이전에 Data를 받아와 댓글로 띄우는 작업을 한 바있는데, 이때 모델의 모든 데이터를 넘기도록 하였다. , 이번에 업데이트 된 내용도 (아마) 같이 넘겨져 있을 것이다. 이 부분의 객체 값을 확인하고 내부로 접근해서 url을 사용하면 끝이다....라고 생각했는데 넘겨받은 값에 image가 없다. DB를 확인해봐야한다.

 

에러 발생

우선적으로 코드를 보니 req.file.url이 아닌 req.file.path로 접근해야한다!! 이를 해결했음에도 url이 저장되지 않는다.

 

스키마를 살펴보니 내가 잘못 설정했다는 것을 알아차렸다.

  comment : [{

   image :{

    url :String ,

   },

여기서 url:String이 아니라 type:String으로 해야한다. 맨날 하는 간단하고 어이없는 실수다.

 

이제 React에서 콘솔을 찍어보면,

이렇게 이 image값을 img태그 url에 넣음으로서 사진을 띄우는 작업을 완료하게 되었다!!!

 

결론

 

지금까지 후기 페이지는 이렇게 만들어졌다. 본래는 대댓글까지 구현할 계획이었으나, 생각보다 해야할 작업이 많아서 나중으로 미루거나 하지 않기로 했다. 지금 제일 막히는 부분은 구현보다도 기획이다. 남은 페이지를 무엇으로 채울지 정말 고민이다.

 

 

+ 사진을 올리도록 했더니 댓글을 쓴 후 컴포넌트가 리랜더링 되지 않는 오류가 발생하였다. 이부분도 추후 고쳐야한다.

지금 생각으로써는 이 부분은 데이터를 모두 받아오는 데 완료하면 useState를 건드려서 페이지가 다시 랜더링 되도록 하면 좋을 것 같다. 어쨌든 post이후 get이 다시 실행되기만 하면 해결 될 문제이다.