Golang 및 React를 사용한 이미지 업로드

Golang은 효율성과 동시성 분야에서 블록버스터급 서버 측 언어입니다. Nodejs 개발자라면 확실히 웹 API 서비스를 구축하기 위해 express js를 접하게 될 것입니다. Gofiber는 golang을 위한 익스프레스 프레임워크와 정확히 같으며 의심할 여지 없이 Fasthttp 및 golang의 효율성으로 호황을 누리고 있습니다.

이 블로그 게시물에서는 gofiber를 사용하여 간단한 이미지 업로드 서버를 만들고 프론트엔드용 reactjs를 사용하여 파일에서 이미지를 선택하고 서버에 업로드합니다.

우리는 서버에 대한 http 요청에 axios를 사용할 것이며 인증을 구현하고 많은 api 요청을 처리할 때 정말 좋습니다. 그것은 반응에서 API를 다룰 때 삶을 쉽게 만드는 많은 기능을 가지고 있습니다.

우리는 더 나은 SEO에 직접적인 영향을 미치는 접근성에서 버튼, 이미지 및 레이아웃과 같은 재료를 디자인하기 위해 chakra ui를 사용할 것입니다.

우리가 사용할 라이브러리 및 도구


  • 고랑
  • 고파이버
  • reactjs
  • 액시오스
  • 차크라 ui

  • 백엔드 설정



    새 디렉토리를 만들고 입력하십시오.

    mkdir go-react-image-upload
    
    cd go-react-image-upload
    
    
    server 내부에 새 디렉토리go-react-image-upload를 생성하고 입력합니다.

    mkdir server 
    
    cd server
    
    

    이동 환경 설정

    go mod init github.com/harshmangalam
    
    

    백엔드에 필요한 패키지 설치

    go get  github.com/gofiber/fiber/v2
    
    go get github.com/google/uuid
    
    
    

    uuid는 고유 ID를 생성하여 이미지 이름을 쉽게 지정하고 두 이미지의 이름이 동일하지 않도록 합니다.
    main.go 안에 새로운 go 파일server을 만들고 코드 작성을 시작합니다.

    package main
    
    import (
        "fmt"
        "log"
        "os"
        "strings"
    
        "github.com/gofiber/fiber/v2"
        "github.com/gofiber/fiber/v2/middleware/cors"
        "github.com/google/uuid"
    )
    
    func main() {
        // create new fiber instance  and use across whole app
        app := fiber.New()
    
        // middleware to allow all clients to communicate using http and allow cors
        app.Use(cors.New())
    
        // serve  images from images directory prefixed with /images
        // i.e http://localhost:4000/images/someimage.webp
    
        app.Static("/images", "./images")
    
        // handle image uploading using post request
    
        app.Post("/", handleFileupload)
    
        // delete uploaded image by providing unique image name
    
        app.Delete("/:imageName", handleDeleteImage)
    
        // start dev server on port 4000
    
        log.Fatal(app.Listen(":4000"))
    }
    
    
    
    func handleFileupload(c *fiber.Ctx) error {
    
        // parse incomming image file
    
        file, err := c.FormFile("image")
    
        if err != nil {
            log.Println("image upload error --> ", err)
            return c.JSON(fiber.Map{"status": 500, "message": "Server error", "data": nil})
    
        }
    
        // generate new uuid for image name 
        uniqueId := uuid.New()
    
        // remove "- from imageName"
    
        filename := strings.Replace(uniqueId.String(), "-", "", -1)
    
        // extract image extension from original file filename
    
        fileExt := strings.Split(file.Filename, ".")[1]
    
        // generate image from filename and extension
        image := fmt.Sprintf("%s.%s", filename, fileExt)
    
        // save image to ./images dir 
        err = c.SaveFile(file, fmt.Sprintf("./images/%s", image))
    
        if err != nil {
            log.Println("image save error --> ", err)
            return c.JSON(fiber.Map{"status": 500, "message": "Server error", "data": nil})
        }
    
        // generate image url to serve to client using CDN
    
        imageUrl := fmt.Sprintf("http://localhost:4000/images/%s", image)
    
        // create meta data and send to client
    
        data := map[string]interface{}{
    
            "imageName": image,
            "imageUrl":  imageUrl,
            "header":    file.Header,
            "size":      file.Size,
        }
    
        return c.JSON(fiber.Map{"status": 201, "message": "Image uploaded successfully", "data": data})
    }
    
    
    func handleDeleteImage(c *fiber.Ctx) error {
        // extract image name from params
        imageName := c.Params("imageName")
    
        // delete image from ./images
        err := os.Remove(fmt.Sprintf("./images/%s", imageName))
        if err != nil {
            log.Println(err)
            return c.JSON(fiber.Map{"status": 500, "message": "Server Error", "data": nil})
        }
    
        return c.JSON(fiber.Map{"status": 201, "message": "Image deleted successfully", "data": nil})
    }
    
    
    
    
    main.go에서 server 실행

    go run main.go
    
    

    이제 서버가 가동되어 Postman을 사용하여 테스트할 수 있습니다.


    프런트엔드 설정


    server 디렉토리에서 외부로 이동하여 reactjs를 사용하여 create-react-app 프로젝트를 생성합니다.

    
    npx create-react-app reactjs
    
    cd reactjs
    
    

    종속성 설치

    npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4 axios
    
    
    index.js
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    
    
    ReactDOM.render(
    
      <App />
      ,
      document.getElementById('root')
    );
    
    
    

    설정App.js
    import { Box, ChakraProvider, Container } from "@chakra-ui/react";
    import Axios from "axios";
    import Upload from "./components/Upload";
    
    Axios.defaults.baseURL = "http://localhost:4000";
    
    function App() {
      return (
        <ChakraProvider>
          <Box
            minH="100vh"
            w="100%"
            bg="gray.200"
            display="flex"
            alignItems="center"
            justifyContent="center"
          >
            <Container maxWidth="container.xl">
              <Upload />
            </Container>
          </Box>
        </ChakraProvider>
      );
    }
    
    export default App;
    
    
    
    

    새 후크 만들기useUpload 후크 인hooks 폴더
    hooks/useUpload.js
    
    
    import { useState } from "react";
    import axios from "axios";
    import { useToast } from "@chakra-ui/react";
    
    const useUpload = () => {
      const [image, setImage] = useState(null);
      const [loading, setLoading] = useState(false);
    
      const [uploadedImage, setUploadedImage] = useState(null);
    
      const toast = useToast();
    
      const handleChangeImage = (e) => {
        setImage(e.target.files[0]);
      };
    
      const handleUploadImage = async () => {
        try {
          setLoading(true);
          const formData = new FormData();
          formData.append("image", image);
          const res = await axios.post("/", formData);
          if (res.data.data) {
            console.log(res.data);
            setUploadedImage(res.data.data);
            toast({
              title: "Image Uploaded",
              description: res.data.message,
              status: "success",
              duration: 4000,
              isClosable: true,
            });
          }
        } catch (error) {
          console.log(error);
        } finally {
          setImage(null);
          setLoading(false);
        }
      };
    
      const handleRemoveImage = async () => {
        try {
          setLoading(true);
    
          const res = await axios.delete(`/${uploadedImage.imageName}`);
          if (res.data) {
            console.log(res.data);
            setUploadedImage(null);
            toast({
              title: "Image Deleted",
              description: res.data.message,
              status: "success",
              duration: 4000,
              isClosable: true,
            });
          }
        } catch (error) {
          console.log(error);
        } finally {
          setLoading(false);
        }
      };
      return {
        image,
        uploadedImage,
        loading,
        handleChangeImage,
        handleUploadImage,
        handleRemoveImage,
      };
    };
    
    export default useUpload;
    
    
    
    
    
    Upload.js 폴더 안에 components 생성
    components/Upload.js
    
    
    import { Button, Heading, VStack, Image, HStack, Tag } from "@chakra-ui/react";
    import React from "react";
    import { useRef } from "react";
    import useUpload from "../hooks/useUpload";
    
    function Upload() {
      const imageRef = useRef(null);
      const {
        loading,
        image,
    
        handleRemoveImage,
        handleChangeImage,
        handleUploadImage,
        uploadedImage,
      } = useUpload();
      return (
        <>
          <input
            style={{ display: "none" }}
            type="file"
            accept="image/*"
            ref={imageRef}
            onChange={handleChangeImage}
          />
          <VStack>
            <Heading>Image uploading using Golang and Reactjs</Heading>
            <Button
              onClick={() => imageRef.current.click()}
              colorScheme="blue"
              size="lg"
            >
              Select Image
            </Button>
          </VStack>
    
          {image && (
            <VStack my="4">
              <Image
                src={URL.createObjectURL(image)}
                width="300px"
                height="300px"
                alt="selected image..."
              />
              <Button
                onClick={handleUploadImage}
                variant="outline"
                colorScheme="green"
                isLoading={loading}
              >
                Upload
              </Button>
            </VStack>
          )}
    
          {uploadedImage && (
            <VStack my="4">
              <Image
                src={uploadedImage.imageUrl}
                width="300px"
                height="300px"
                alt={uploadedImage.imageName}
              />
    
              <HStack>
                <Tag variant="outline" colorScheme="blackAlpha">
                  ~ {Math.floor(uploadedImage.size / 1024)} Kb
                </Tag>
                <Button
                  variant="solid"
                  colorScheme="red"
                  onClick={handleRemoveImage}
                  isLoading={loading}
                >
                  Delete
                </Button>
              </HStack>
            </VStack>
          )}
        </>
      );
    }
    
    export default Upload;
    
    
    
    










    Github 레포


    백엔드




    거친 망 갈람 / golang-반응-이미지-업로드-서버






    프런트엔드




    거친 망 갈람 / golang-반응-이미지-업로드-클라이언트






    Create React App 시작하기


    이 프로젝트는 Create React App으로 부트스트랩되었습니다.

    사용 가능한 스크립트


    프로젝트 디렉토리에서 다음을 실행할 수 있습니다.

    npm 시작


    개발 모드에서 앱을 실행합니다.
    브라우저에서 보려면 http://localhost:3000을 여십시오.
    수정하면 페이지가 다시 로드됩니다.
    또한 콘솔에 린트 오류가 표시됩니다.

    npm 테스트


    대화형 감시 모드에서 테스트 러너를 시작합니다.
    자세한 내용은 running tests 섹션을 참조하십시오.

    npm 실행 빌드


    프로덕션용 앱을 build 폴더에 빌드합니다.
    프로덕션 모드에서 React를 올바르게 번들로 묶고 최상의 성능을 위해 빌드를 최적화합니다.
    빌드가 축소되고 파일 이름에 해시가 포함됩니다.
    앱을 배포할 준비가 되었습니다!
    자세한 내용은 deployment 섹션을 참조하십시오.

    npm 실행 꺼내기


    참고: 이것은 단방향 작업입니다. 한 번 eject , 돌아갈 수 없습니다!
    만약 너라면…

    View on GitHub

    좋은 웹페이지 즐겨찾기