728x90
반응형

1. 셀레니움을 설치한다.

$ sudo pip3 install selenium

 

2. 라우터에 다음 내용을 추가해준다.

/chwideukapp/views.py

from time import sleep
from rest_framework.views import APIView
from rest_framework.response import Response
from selenium import webdriver

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument("--single-process")
chrome_options.add_argument("--disable-dev-shm-usage")
path = '/usr/bin/chromedriver'
driver = webdriver.Chrome(path, chrome_options=chrome_options)


class ChwideukRouter(APIView):
    def get(self, request):
        return Response({'success': True})

    def post(self, request):
        driver.get("https://typo.tistory.com/")

        print("+" * 100)
        print(driver.title)   # 크롤링한 페이지의 title 정보
        print(driver.current_url)  # 현재 크롤링된 페이지의 url
        print("-" * 100)

        title = driver.title
        url = driver.current_url

        driver.close()
        return Response({'title': title, 'url': url})

 

옵션을 추가한 이유는 아래와 같은 에러가 떠서 그렇습니다.

unknown error: DevToolsActivePort file doesn't exist

 

3. 서버를 실행하고 postman으로 요청을 보내보자.

postman

 

역시 개발이란 코딩도 힘든데 환경 세팅하는게 더 힘들다.. 수많은 삽질을 한 결과 드디어 기본 틀을 작성하게 되었다.

이 뒤부턴 driver로 원하는 페이지로 이동해서 원하는 데이터를 수집하는게 끝이라 여기서 django rest framework 기초 프로젝트는 종료하겠다. 아래는 selenium 사용에 있어 필요한 메소드를 잘 정리해놓은 블로그이다.

 

https://pythondocs.net/selenium/%EC%85%80%EB%A0%88%EB%8B%88%EC%9B%80-%ED%81%AC%EB%A1%A4%EB%9F%AC-%EA%B8%B0%EB%B3%B8-%EC%82%AC%EC%9A%A9%EB%B2%95/

 

셀레니움 크롤러 기본 사용법 - 뻥뚫리는 파이썬 코드 모음

셀레니움 전반에 관하여 간략하게 정리한다. 이 문서는 셀레니움 버전 3 기준이다. 최근 4버전이 출시되었으나 사용방법이 약간 다르니 이 부분을 확인하길 바란다. 사용 방법이나 예시는 따로

pythondocs.net

 

 

728x90
반응형
728x90
반응형

1. 프로젝트를 만든다.

$ django-admin startproject apiServer

 

2. settings.py 파일에 rest_framework 를 추가해준다.

settings.py

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
]

 

3. 새 마이그레이션을 생성하고 슈퍼유저를 생성해준다.

$ python3 manage.py makemigrations
$ python3 manage.py migrate
$ python3 manage.py createsuperuser

 

4. 앱을 하나 만들어준다. ( 이름은 상관없습니다. )

$ python3 manage.py startapp chwideukapp

 

5. apiServer 폴더 안 settings.py 에 만든 앱을 추가해준다.

/apiServer/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'chwideukapp'
]

 

6. 새로 만든 앱의 models.py 파일을 수정해준다.

 

/chwideukapp/models.py

from django.db import models


class ChwideukModel(models.Model):
    title = models.CharField(max_length=70, default='')
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

 

7. 새 마이그레이션을 생성한다.

$ python3 manage.py makemigrations
$ python3 manage.py migrate

 

8. serializers.py 파일을 만든다.

/chwideukapp/serializers.py

from rest_framework import serializers
from .models import ChwideukModel


class ChwideukSerializer(serializers.ModelSerializer):
    class Meta:
        model = ChwideukModel
        fields = ['title']

 

9. views.py 파일을 수정해준다. 

from rest_framework.views import APIView
from rest_framework.response import Response


class ChwideukRouter(APIView):
    def get(self, request):
        return Response({'success': True})

    def post(self, request):
        return Response({'success': False})

 

10. apiServer 폴더의 urls.py에 방금 만든 라우터를 추가해준다.

from django.contrib import admin
from django.urls import include, path

from chwideukapp.views import ChwideukRouter


urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/chwideuk/', ChwideukRouter.as_view())
]

 

11. 서버를 시작하고 postman으로 실험해보았다. ( 서버 포트는 8000, 로컬 포트는 8001 입니다 )

 

이제 API 서버와 라우터는 만들었으니 다음 포스트에서는 Selenium을 사용해보겠다.

728x90
반응형
728x90
반응형

웹 크롤러의 종류는 많다고 한다. 나는 그 중 동적 클롤러인 Selenium을 택했다.

정적 크롤링은 말 그대로 정적인 페이지에서 사용 가능하며 동적 크롤링은 로그인 등 동적으로 데이터가 바뀌는 사이트에 적합하다.

 

전 포스트에서 REST API 를 만들 땐 맥북에 파이참으로 만들었지만 이번엔 AWS에 서버를 만들고 VSCode 로 원격접속해서 

다시 처음부터 만들어보기로 했다.

 

아래는 무료 서버를 진짜 빠르고 간단하게 만드는 방법 

 

AWS LightSail(1) - 인스턴스 생성하기

정말 빠르게 AWS LightSail로 인스턴스를 만들어보자. Lightsail에 관하여 https://lightsail.aws.amazon.com/ls/docs/ko_kr/all 1. aws 사이트에 회원가입, 로그인을 하고 Lightsail 서버를 찾아서 들어간다. 2...

typo.tistory.com

 

Selenium은 크롬 브라우저 기반으로 실행되기 때문에 크롬과 크롬 드라이버가 필요하다. 

1. 필요한 패키지를 설치한다.

$ sudo apt-get update
$ sudo apt-get install -y unzip xvfb libxi6 libgconf-2-4

 

자바를 8버전 이상으로 설치한다.

$ sudo apt-get install default-jdk

 

2. 크롬을 설치한다.

$ sudo curl -sS -o - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add
$ sudo echo "deb [arch=amd64]  http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list
$ sudo apt-get -y update
$ sudo apt-get -y install google-chrome-stable

 

 

3. 내 크롬의 버전을 확인하고 아래 사이트에 들어가서 크롬드라이버의 버전을 확인한다.

$ google-chrome --version

 

 

ChromeDriver - WebDriver for Chrome - Downloads

Current Releases If you are using Chrome version 104, please download ChromeDriver 104.0.5112.20 If you are using Chrome version 103, please download ChromeDriver 103.0.5060.53 If you are using Chrome version 102, please download ChromeDriver 102.0.5005.61

chromedriver.chromium.org

 

4. 맨 앞 숫자가 크롬 버전과 같은지 확인한 후 크롬 드라이버를 설치하고 압축을 해제한다.

$ wget https://chromedriver.storage.googleapis.com/[버전입력]/chromedriver_linux64.zip
$ unzip chromedriver_linux64.zip

 

5. 시스템 구성을 위해 크롬 드라이버를 이동 및 권한을 부여해준다.

$ sudo mv chromedriver /usr/bin/chromedriver
$ sudo chown root:root /usr/bin/chromedriver
$ sudo chmod +x /usr/bin/chromedriver

 

6. Selenium 서버를 설치 후 실행한다.

$ wget https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.0.jar
$ xvfb-run java -Dwebdriver.chrome.driver=/usr/bin/chromedriver -jar selenium-server-standalone-3.141.0.jar

 

7. 파이썬을 설치한다. 

$ sudo apt-get install python3

 

8. 파이썬 가상환경을 위해 패키지를 설치 후 가상환경을 만들어준다.

$ apt-get install python3-venv
$ python3 -m venv example

 

9. 장고와 djangorestframework를 설치한다.

$ apt install python3-pip
$ pip3 install django
$ pip3 install djangorestframework markdown

 

 

728x90
반응형
728x90
반응형

파이썬 웹 크롤러가 종류가 많다고 한다. 나는 그 중에 Scrapy를 선택했다.

자세한 내용은 아래 사이트에 들어가보면 볼 수 있다.

 

https://docs.scrapy.org/en/latest/#

 

Scrapy 2.6 documentation — Scrapy 2.6.1 documentation

© Copyright 2008–2022, Scrapy developers. Revision 23537a0f. Last updated on May 26, 2022.

docs.scrapy.org

 

1. 먼저 scrapy 를 설치한다.

$ pip install scrapy

 

2. 스크래피 프로젝트를 생성한다.

$ scrapy startproject scrapy_project

 

3. spiders 폴더 안에 파이썬 파일을 만들어준다.

scrapy_project/scrapy_project/spiders/example.py

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://www.example.com/'
    ]

    def parse(self, response):
        url = response.url
        title = response.css('h1::text').get()
        print(f'URL is: {url}')
        print(f'Title is: {title}')

 

4. spider 폴더 경로로 이동하여 아래 명령어를 실행해보자.

$ scrapy runspider example.py

 

5. 결과를 확인한다.

 

6. 추가로 settings.py 파일에 아래 내용을 추가하면 좋다.

CONCURRENT_REQUESTS = 1    
DOWNLOAD_DELAY = 0.25  # 250ms 기다림 
HTTPCACHE_ENABLED = True  # cache 기능 사용
728x90
반응형
728x90
반응형

이번엔 우리가 새로운 라우터를 만들어보자. 아래 명령어 한 줄로 손쉽게 앱을 하나 만들 수 있다.

$ python manage.py startapp api_server

 

 

1. 먼저 Model을 수정해준다.

/api_server/models.py

from django.db import models


class APIServer(models.Model):
    title = models.CharField(max_length=70, default='')
    link = models.URLField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

 

2 pythonProject 폴더 안 settings.py에 api_server 앱을 추가해준다.

/pythonProject/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'api_server'
]

 

3. 새 마이그레이션을 생성한다.

$ python manage.py makemigrations
$ python manage.py migrate

 

4. Serializer 세팅을 위해 아래와같이 파일을 만든다.

/api_server/serializer.py

from rest_framework import serializers
from .models import APIServer


class APIServerSerializer(serializers.ModelSerializer):
    class Meta:
        model = APIServer
        fields = ['title']
Serializer 는 queryset 과 model instance 같은 것들을 쉽게  JSON 또는 XML 의 데이터 형태로 렌더링 할 수 있게 해줍니다. 우리는 APIServer 모델을 serialize 해줘야 하기 때문에 ModelSerializer를 사용합니다.

 

5. views 파일을 수정해준다.

/api_server/views.py

from rest_framework import viewsets
from .serializers import APIServerSerializer
from .models import APIServer


class APIServerRouter(viewsets.ModelViewSet):
    queryset = APIServer.objects.all()
    serializer_class = APIServerSerializer

 

rest_framework 의 viewset 을 사용하면 CRUD 로직을 짜지 않아도 사용 가능하게 해준다.

 

6. pythonProject 폴더의 urls.py 파일을 수정해준다.

/pythonProject/urls.py

from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from api_server.views import APIServerRouter

router = routers.DefaultRouter()
router.register('apiserver', APIServerRouter)

urlpatterns = [
    path('admin/', admin.site.urls),

    path('', include(router.urls)),

    path('api-auth/', include('rest_framework.urls'))
]

 

7. 서버를 시작해 8000번 포트를 켜보자.

 

8. /apiserver 경로로 들어가보면 GET 과 POST 메소드를 GUI로 사용할 수 있다.

(GET, POST, GET/[id], PUT/[id], DELETE/[id])

728x90
반응형
728x90
반응형

자세한 내용은 아래 사이트에서 확인할 수 있다.

https://www.django-rest-framework.org/

 

Home - Django REST framework

 

www.django-rest-framework.org

 

1. 필요한 패키지를 설치한다.

$ pip install djangorestframework markdown

 

2. settings.py 파일과 urls.py 파일을 수정해준다.

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
]

 

urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),

    path('api-auth/', include('rest_framework.urls'))
]

 

3. 다시 파이썬을 실행해주고 아래 주소로 가보자.

 

/api-auth/ 로 가보면 djangorestframework 에서 지원해주는 login, logout 기능이 있다는 것을 확인할 수 있다.

이번엔 login 경로까지 가보자.

 

 

이렇게 화면이 뜨는 것을 볼 수 있다.

 

/admin 경로로 들어가면 아래와 같은 화면이 뜨는 것도 볼 수 있는데

아래 명령어로 슈퍼유저를 생성 후 비밀번호를 설정 한 후에 들어갈 수 있다.

$ python manage.py createsuperuser

 

혹시나 비밀번호를 잊어버린 경우 비밀번호를 초기화 해주자

$ python manage.py cangepassword admin

 

다시 admin으로 들어가서 로그인을 해보면

이렇게 성공적으로 로그인된 화면을 볼 수 있다.

728x90
반응형
728x90
반응형

웹 스크래핑 전용 api 서버를 만들고 싶어졌다.

자바스크립트보다는 파이썬이 웹 스크래핑에 유용하다 하여 Django 서버를 만들게 되었다.

 

웹 크롤링과 웹 스크래핑의 차이점은?
웹 크롤링과 웹 스크래핑은 모두 정보를 추출해온다는 데서는 공통점을 지닙니다.
하지만 '타켓 웹 페이지의 유무'와 '중복 제거(deduplication)의 실행 여부'에서 차이가 납니다.
웹 크롤링은 특정 웹 페이지를 목표로 하지 않습니다. 일단 탐색부터 하고, 정보를 가져오죠. '선탐색 후추출'입니다. 반면 웹 스크래핑을 할 때는 목표로 하는 특정 웹페이지가 있습니다.우리가 원하는 정보를 어디서 가져올지 타겟이 분명하고, 그 타겟에서 정보를 가져오죠. 그래서 '선결정 후추출'입니다.
또, 웹 크롤링에서는 중복 제거가 필수적입니다. 중복되거나 불필요한 정보를 가져와서 분류를 더 어렵게 할 필요는 없으니까요. 도서관의 책이 개별적으로 구분되는 색인이 있는 것처럼 웹 크롤링도 수집한 웹 페이지가 중복되지 않도록 서로 다른 색인을 남깁니다. 그래서 웹 크롤링을 웹 인덱싱(web indexing)이라고도 부릅니다.
반면 웹 스크래핑에서는 중복 제거가 필수는 아닙니다. 중복된 정보를 가지고 있을 필요는 없지만, 그렇다고 꼭 필수적으로 하는 일도 아니죠.

 

1. 파이썬을 설치한다.

https://www.python.org/downloads/ 

 

Download Python

The official home of the Python Programming Language

www.python.org

 

2. 파이썬 개발 환경을 위해 파이참을 설치한다.

https://www.jetbrains.com/ko-kr/pycharm/download/#section=mac

 

다운로드 PyCharm: JetBrains가 만든 전문 개발자용 Python IDE

 

www.jetbrains.com

 

3. 파이참에 New Project 를 클릭해서 프로젝트를 만들어준다.

 

4. 터미널에서 django를 설치한다.

$ pip install django

 

5. django-admin 명령어로 django 프로젝트를 만들어준다.

$ django-admin startproject apiServer .

 

6. 아래 명령어로 서버를 실행해본다.

$ python manage.py runserver

 

8000 포트에 서버가 작동하고 있는 것을 확인할 수 있다. 아래 url을 눌러보면

 

 

이렇게 잘 뜨는 것을 확인할 수 있다.

728x90
반응형
728x90
반응형

이번 포스트는 winston으로 만든 모듈을 라우터에 미들웨어로 사용하는 법을 익히겠다.

 

1. ./middleware/index.js 파일을 만든다

 

2. index.js 파일에서 looging 모듈을 export 해준다.

exports.logging = (req, res, next) => {

    try {
        logger.info('');
    }
    catch (Err) {
		logger.error(Err);
    }
}

 

여기서 어떤 내용을 로그에 담아 모아둘지 생각해야한다. 나같은 경우는

 

Error

  • error 로그는 각 라우터에서 확인

Info

  • 어떤 라우터에 접근했는지 
  • 토큰을 verify 하여 토큰에 대한 정보 ( 로그인 데이터 )
  • 메소드 별로 body 나 params, 또는 query (Request Data)

이렇게 할 생각이다. 코드로 구현해보면

 

./middleware/index.js

const { logger } = require('../config/winston');

const jwt = require("jsonwebtoken");
const secretObj = require("../config/jwt");

exports.logging = (req, res, next) => {
    var logStr = {}
    try {
        // 접속 경로
        logStr.url = req.originalUrl;
        console.log("cookies : ", req.cookies)

        const verify = jwt.verify(
            '쿠키 안의 토큰 위치',
            secretObj.secret,
            { expiresIn: '86400000' }
        )

        // 쿠키 안의 토큰 (로그인 정보)
        logStr.loginData = verify.isLogined // 토큰의 정보


        // 메소드
        logStr.method = req.method;

        switch (req.method) {
            case 'GET':
                logStr.query = req.query;
                break;
            case 'POST':
                logStr.body = req.body;
                break;
            case 'PATCH':
                logStr.body = req.body;
                break;
            case 'DELETE':
                logStr.query = req.query;
                break;
        }

        logger.info(JSON.stringify(logStr))

        next();
    }
    catch (Err) {
        logger.error(Err)
        res.send({ success: false });
    }
}

 

 

3. 로깅이 필요한 라우터 파일에 logger 를 import 해주고 미들웨어로 심어준다.

const { logging } = require('../middleware/index');

...

router.post("/list", logging, function (req, res, next) {

...

})

 

4. 파일을 열어 확인해보면 정상적으로 log Data 가 찍힌 것을 볼 수 있다.

 


원하는 색깔을 넣고 싶을 경우 다음과 같이 하면 된다.

const winston = require('winston');
const winstonDaily = require('winston-daily-rotate-file');

const logDir = 'logs';  // logs 디렉토리 하위에 로그 파일 저장
const { combine, timestamp, printf, colorize } = winston.format;

// Define log format
const logFormat = printf(info => {
    return `${info.timestamp} ${info.level}: ${info.message}`;
});

const colors = {
    error: 'red',
    warn: 'yellow',
    info: 'green',
    http: 'magenta',
    debug: 'blue'
}

winston.addColors(colors)


/*
 * Log Level
 * error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
 */
const logger = winston.createLogger({
    format: combine(
        colorize({ all: true }),
        timestamp({
            format: 'YYYY-MM-DD HH:mm:ss',
        }),
        logFormat,
    ),
    transports: [
        // info 레벨 로그를 저장할 파일 설정
        new winstonDaily({
            level: 'info',
            datePattern: 'YYYY-MM-DD',
            dirname: logDir,
            filename: `%DATE%.log`,
            maxFiles: 30,  // 30일치 로그 파일 저장
            zippedArchive: true,
        }),
        // error 레벨 로그를 저장할 파일 설정
        new winstonDaily({
            level: 'error',
            datePattern: 'YYYY-MM-DD',
            dirname: logDir + '/error',  // error.log 파일은 /logs/error 하위에 저장 
            filename: `%DATE%.error.log`,
            maxFiles: 30,
            zippedArchive: true,
        }),
    ],
});

// Production 환경이 아닌 경우(dev 등) 
if (process.env.NODE_ENV !== 'production') {
    logger.add(new winston.transports.Console({
        format: winston.format.combine(
            winston.format.colorize(),  // 색깔 넣어서 출력
            winston.format.simple(),  // `${info.level}: ${info.message} JSON.stringify({ ...rest })` 포맷으로 출력
        )
    }));
}

module.exports = { logger };
728x90
반응형
728x90
반응형

프로젝트를 진행하다보면 로깅의 필요성을 절실히 깨닫게 된다. 

예를 들어 어떤 정보가 오고 갔는지, 에러가 떠서 프로그램이 멈췄을 경우 어떤 에러가 발생했었는지 등 활용 방안은 여러가지가 있다.

 

바로 시작해보자.

 

1. 필요한 npm 패키지를 설치한다.

$ npm install winston winston-daily-rotate-file --save

 

2. winston logger config 파일 작성

./config/winston.js

import winston from 'winston';
import winstonDaily from 'winston-daily-rotate-file';

const logDir = 'logs';  // logs 디렉토리 하위에 로그 파일 저장
const { combine, timestamp, printf } = winston.format;

// Define log format
const logFormat = printf(info => {
  return `${info.timestamp} ${info.level}: ${info.message}`;
});

/*
 * Log Level
 * error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
 */
const logger = winston.createLogger({
  format: combine(
    timestamp({
      format: 'YYYY-MM-DD HH:mm:ss',
    }),
    logFormat,
  ),
  transports: [
    // info 레벨 로그를 저장할 파일 설정
    new winstonDaily({
      level: 'info',
      datePattern: 'YYYY-MM-DD',
      dirname: logDir,
      filename: `%DATE%.log`,
      maxFiles: 30,  // 30일치 로그 파일 저장
      zippedArchive: true, 
    }),
    // error 레벨 로그를 저장할 파일 설정
    new winstonDaily({
      level: 'error',
      datePattern: 'YYYY-MM-DD',
      dirname: logDir + '/error',  // error.log 파일은 /logs/error 하위에 저장 
      filename: `%DATE%.error.log`,
      maxFiles: 30,
      zippedArchive: true,
    }),
  ],
});

// Production 환경이 아닌 경우(dev 등) 
if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),  // 색깔 넣어서 출력
      winston.format.simple(),  // `${info.level}: ${info.message} JSON.stringify({ ...rest })` 포맷으로 출력
    )
  }));
}

export { logger };
// module.exports = { logger };

 

로그 레벨에 따라서 저장하는 파일 위치와 파일 명을 설정할 수도 있다.

error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6

 

3. log관리가 필요한 라우터에 import 하고 logger를 사용한다.

import express from 'express';
import { logger } from './config/winston';

const app = express().Application;

app.listen(3000, () => {
  logger.info('Server listening on port 3000');
});

app.get('/', (req, res) => {
  logger.info('GET /');
  res.sendStatus(200);
});

app.get('/error', (req, res) => {
  logger.error('Error message');
  res.sendStatus(500);
});

 

4. 파일이 제대로 생기는지 확인해본다.

728x90
반응형
728x90
반응형

DB에서 데이터를 가져와 fileState 에 담아주었다면, fileState 의 file_location에 S3 파일 저장위치가 담겨있을 것이다.

( fileReducer 참고)

 

리스트 항목을 클릭했을 때 file_location이 있는 상태면 다운로드를 할 수 있게끔 구현해보자.

1. 이전 코드에 추가해준다.

<WrapperDiv
    kindOf={`input`}
>
    <TextField
        label={`사업자등록증`}
        type='file'
        color='primary'
        size='small'
        InputLabelProps={{
            shrink: true,
        }}
        name={`file_object`}
        onChange={(e: any) => {
            let reader = new FileReader();
            let file = e.target.files[0];
            reader.onloadend = () => {
                fileDispatch({ name: e.target.name, value: file });
                fileDispatch({ name: 'file_url', value: reader.result });
            };
            reader.readAsDataURL(file);
        }}
    />
</WrapperDiv>
{fileState.file_url !== '' &&
    <WrapperDiv>
        <img style={{ width: "100%", height: "100%" }} src={fileState.file_url} />
    </WrapperDiv>
}
{(!fileState.file_url && fileState.file_location !== '') &&
    <GridBoxDiv
        gtc={`1fr 1fr`}
        gap={`10px`}
        ai={`center`}
        kindOf={`input`}
    >
        <TextField
            label={`사업자등록증 파일`}
            type='text'
            color='primary'
            size='small'
            InputLabelProps={{
                shrink: true,
            }}
            value={'image.png'}
            disabled={true}
        />
        <Button
            width={`100%`}
            height={`35px`}
            padding={`0`}
            margin={`0`}
            type={`button`}
            kindOf={`greyButton`}
            hoverGrey={true}
            id={fileState.file_location}
            onClick={download}
        >
            download
        </Button>

    </GridBoxDiv>
}

 

리스트 항목을 클릭했을 때 file_url은 없는 상태(undefined)일 것이고 ( DB에 없는 내용이기 때문 ) file_location은 s3 저장위치를

나타낼 것이다.

 

2. 다운로드 버튼을 만들었고 이제 버튼 이벤트를 추가해준다.

    const download = (e: any) => {
        console.log(e.target.id);
        fetch(e.target.id, {
            method: "GET",
            headers: {}
        })
            .then(response => {
                response.arrayBuffer().then(function (buffer) {
                    const url = window.URL.createObjectURL(new Blob([buffer]));
                    const link = document.createElement("a");
                    link.href = url;
                    link.setAttribute("download", "image.png"); //or any other extension
                    document.body.appendChild(link);
                    link.click();
                });
            })
            .catch(err => {
                console.log(err);
            });
    }

 

url 데이터가 있을 때 클릭하면 다운로드를 할 수 있게 해주는 함수이다. 파일의 이름도 지정해줄 수 있다.

여기까지 내용을 정리해보면

 

  1. input type file 을 이용해 클라이언트 State 안에 file 내용을 저장하고, formData 로 만들어 백엔드에 전송한다.
  2. 백엔드에선 multer 로 file을 인식한 뒤 s3.upload 메소드로 파일을 저장해준다. 저장이 성공하면 DB에 key값이랑 location을 저장한다 (file은 인코딩 해아함 )
  3. 클라이언트에서 이미 등록된 사진을 확인할 경우 먼저 DB에 해당 key에 부합하는 데이터가 있는지 확인 후 있으면 location을 가져온다.
  4. location을 Reducer에서 s3 파일 위치로 만들어 state에 담아준다.
  5. url download 함수와 버튼을 만들어 다운로드 가능하게끔 만들어준다.

 

@@ 혹시 큰 용량의 파일이 업로드가 413에러가 뜰 때 nginx가 설치되어있다면 /etc/nginx/nginx.conf 파일에 

http {
    client_max_body_size 5M;

    ...
}

이 구문을 추가해주자.

728x90
반응형

+ Recent posts