본문 바로가기

WEB

React에서 파일 다운로드 구현

728x90



React를 사용하여 버튼을 누르면 특정 파일이 다운로드 되는 방법에 대해 설명하고자 합니다. 
일단 파일은 이전 글(node.js 에서 Excel로 데이터 저장)에서 사용한 엑셀 파일을 사용하겠습니다. 

 

먼저 누를 버튼을 생성하겠습니다. React 관련 디자인들이 있는 MUI CORE 사이트의 버튼을 쓰겠습니다. 

해당 사이트의 버튼을 쓰기위해 일단 필요한 패키지를 다운받습니다.

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material

 

그리고 아래 코드를 이용해서 플로팅 버튼을 만듭니다.

import React from "react";
import Fab from '@mui/material/Fab';
import Box from '@mui/material/Box';
import Addicon from '@mui/icons-material/Add';
const FloatingBtn = () =>{
    return (
        <Box
            sx={{
                position: 'fixed', //fixed를 통한 위치 고정 (스크롤 시에도 고정됨)
                // 절대 위치 설정 (화면 가운데 배치)
                top: '50%',
                left: '50%',
            }}
        >
            <Fab variant="extended" color="primary">
                <Addicon sx={{ mr: 1 }} />
                Excel 다운로드
            </Fab>
        </Box>
    );
}

export default FloatingBtn

위와같은 버튼이 만들어졌습니다. 이제 버튼을 누를 때 엑셀 파일이 만들어지게 해야합니다. 

 

(엑셀 파일 저장 요청) => 엑셀 파일 만들기 => 파일명 전달 => (해당 파일 다운로드 요청) => 파일전달 => (다운로드)

 

위 구조로 코드를 짜는데 () 부분은 프론트엔드, 나머지는 백엔드에서 진행하는 코드로 짜겠습니다. 

 

일단 프론트 엔드에서의 코드는 다음과 같습니다. 

import React from 'react';
import Fab from '@mui/material/Fab';
import Box from '@mui/material/Box';
import Addicon from '@mui/icons-material/Add';
import axios from 'axios'
import Filesaver from 'file-saver'

const FloatingBtn = () =>{

    const downloadFile = (filename) => {
        axios.get(`http://127.0.0.1:4000/download/${filename}`, {
            responseType: 'blob'
        }).then((response) => {
            Filesaver.saveAs(new Blob([response.data]), filename);
        }).catch((error) => {
            console.error('Error downloading file:', error);
        });
    };

    const Send_download = () => {
        axios.post("http://127.0.0.1:4000/save-file")
            .then((res) => {
                console.log('Server response:', res.data);
                // 파일 이름 전달 받기
                const { filename } = res.data;
                // 다운로드 요청을 보냅니다.
                console.log('Filename received:', filename);
                downloadFile(filename);
            })
            .catch((error) => {
                console.error('Error:', error);
            });
    };


    return (
        <Box
            sx={{
                position: 'fixed', //fixed를 통한 위치 고정 (스크롤 시에도 고정됨)
                // 절대 위치 설정 (화면 가운데 배치)
                top: '50%',
                left: '50%',
            }}
        >
            <Fab variant="extended" color="primary" onClick={Send_download}>
                <Addicon sx={{ mr: 1 }} />
                Excel 다운로드
            </Fab>
        </Box>
    );
}

export default FloatingBtn

 

axios를 사용하여 백엔드에 save 요청과 돌아온 파일 이름을 사용하여 다운로드를 요청합니다. 
그 후 다운로드 파일이 오면 해당 파일을 blob을 사용하여 클라이언트에서 다운받을 수 있게 합니다.

 

백엔드 코드는 아래와 같습니다.

const fs = require('fs');
const ExcelJS = require('exceljs');
const express = require('express');
const cors = require('cors');

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

const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet('Data');

// 엑셀 파일 생성 함수 선언
async function saveToExcel() {
    const filename = "data.xlsx";
    
    // 파일 중복 생성을 막기 위한 조건문 
    if (!fs.existsSync(filename))
    {
        const mergeRange = 'A1:D1';
        // 셀 병합 시도 전에 병합 여부를 확인합니다

        sheet.mergeCells(mergeRange);

        // 데이터 삽입
        sheet.getCell('A1').value = `Date: ${new Date().toLocaleString()}`;

        // 날짜와 시간 셀의 정렬 설정 (가운데 정렬 & 굵은 글씨)
        sheet.getCell('A1').alignment = { horizontal: 'center' };
        sheet.getCell('A1').font = { bold: true };

        try {
            // data.xlsx 이름의 엑셀파일 생성
            await workbook.xlsx.writeFile(filename);
            return filename;
        } catch (err) {
            console.error("Can't create Excel file:", err);
            throw err; // 에러를 호출 측으로 전파합니다
        }
    }
    else
    {
        return filename;
    }

}

// 엑셀 저장 요청 확인 시 엑셀 저장 및 파일명 전달
app.post('/save-file', async (req, res) => {
    try {
        const fileName = await saveToExcel();
        res.status(200).json({ filename: fileName }); // json파일에 파일이름 전달
    } catch (err) {
        console.error('Error in /save-file route:', err);
        res.status(500).send('Error collecting or saving data.');
    }
});

// 다운로드 요청 시 엑셀파일 전달
app.get('/download/:filename', (req, res) => {
    const filename = req.params.filename;

    if (fs.existsSync(filename)) {
        res.download(filename, (err) => {
            if (err) {
                console.error('Error downloading file:', err);
                res.status(500).send('Error downloading file');
            }
        });
    } else {
        console.error('File does not exist:', filename);
        res.status(404).send('File not found');
    }
});

// 포트 4000번을 사용한 서버 구축
app.listen(4000, () => {
    console.log('Server is running on port 4000');
});

 

cors를 적용하지 않으면 브라우저 오류가 발생해서 cors() 를 사용해서 모든 접속을 허용했습니다. 

결과적으로 아래와 같이 버튼 클릭시 엑셀파일을 잘 다운로드 합니다

'WEB' 카테고리의 다른 글

Node.js 오류 시에도 서버 끄지 않기  (0) 2024.10.10
Node.js에서 SMS 보내기(COOLSMS사용)  (0) 2024.09.21
node.js 에서 Excel로 데이터 저장  (0) 2024.08.17
.env 환경변수 설정  (0) 2024.08.16
React 정보를 Unity로 보내기  (0) 2024.05.08