๊ทธ๋™์•ˆ 17ํŽธ์„ ๊ฑฐ์ณ์„œ ์›น ๊ฐœ๋ฐœ React&Python์œผ๋กœ ์›น๊ฐœ๋ฐœ(๋งํฌ์„œ๋น„์Šค)๋ฅผ ๊ฐœ๋ฐœ ํ–ˆ์œผ๋ฉฐ, 

ํ˜ผ์ž ํ”„๋ก ํŠธ/๋ฐฑ์—”๋“œ๋ฅผ ํ•˜๋‹ค ๋ณด๋ฉด ๋ณต์žกํ•จ์„ ๋Š๋ผ๋ฉฐ, ์ˆ˜์ •์ž‘์—…์ด ์ด๋ฃจ์–ด์ง€๋ฉด ๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—”๋“œ ์—ฌ๋Ÿฌ ์†Œ์Šค๋“ค์„ ๊ฑฐ์ณ์„œ ๊ด€๋ จ ๋‚ด์šฉ์„ ๋ฐ˜์˜ํ•ด์•ผ ํ•˜๋Š” ์–ด๋ ค์›€์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, ๋ฐ˜๋ณต์ ์ธ ๊ฐœ๋ฐœ ๊ณผ์ •์„ ํ†ตํ•ด์„œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์‹ค๋ ฅ์„ ๋†’์ผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

 

์ตœ๋Œ€ํ•œ STEP BY STEP๋กœ ์†Œ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ์„ค๋ช…ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์œผ๋‚˜,

๋” ๋ณต์žกํ•ด ์กŒ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์ง€๋งŒ, ์ผ๋‹จ ์ฐจ๊ทผ์ฐจ๊ทผ ๋”ฐ๋ผํ•ด๋ณด๋ฉด ์ข‹์„ ๋“ฏ ํ•˜๋‹ค.

 

๋˜ํ•œ ๋ณธ ์†Œ์Šค๋ฅผ ๊ณต๊ฐœํ•˜๋ฉด์„œ ์—ฌ๋Ÿฌ๋ถ„๊ณผ ํ•จ๊ป˜ WIN-WIN์ด ๋  ์ˆ˜ ์žˆ์„ ๊ฑฐ๋ผ๊ณ  ๋ฏฟ์œผ๋ฉฐ, ์ˆ˜์ •๊ณผ ๋ฐœ์ „์„ ํ•ด ๊ฐ€๋ฉด์„œ ์—ฌ๋Ÿฌ๋ถ„๋“ค ๋งŒ์˜ ๋ ˆํผ๋Ÿฐ์Šค ์†Œ์Šค๊ฐ€ ๋˜๊ธธ ๋ฐ”๋ž€๋‹ค.

 

๋ˆ„๊ตฌ๋‚˜ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ์†Œ์Šค์ด๋ฉฐ, ๋‹จ์ง€ ํ•œ๋ฒˆ๋„ ์ „์ฒด์ ์ธ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ๋ชปํ•œ๋ถ„๋“ค์„ ์œ„ํ•œ ๊ฒƒ์ด๋ฏ€๋กœ, ์™„๋ฒฝํ•œ ์†Œ์Šค ๋‚ด์šฉ์ด ์•„๋‹˜์„ ๋‹ค์‹œ ํ•œ๋ฒˆ ๋ง์”€๋“œ๋ฆฌ๋ฉฐ, ์ œ 1ํŽธ์„ ๋งˆ์น˜๊ณ ์ž ํ•œ๋‹ค.

 

 ๋งํฌ์„œ๋น„์Šค git : https://github.com/firstvalue1/LINKSERVICE.git

 

GitHub - firstvalue1/LINKSERVICE

Contribute to firstvalue1/LINKSERVICE development by creating an account on GitHub.

github.com

๋ณด์‹œ๋‹ค ์ˆ˜์ •์ด๋‚˜, ์˜๊ฒฌ ์žˆ์œผ์‹œ๋ฉด git์— ๋‚จ๊ฒจ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

 

 

๋‹ค์Œ์€ ๋งํฌ์„œ๋น„์Šค๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์ถ”๊ฐ€์ ์ธ ๊ธฐ๋Šฅ๋“ค์„ ๊ณ„์† ๊ฒŒ์‹œ ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

 

#12. React์—์„œ Drag & Drop์„ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ

 

#12. React์—์„œ Drag & Drop์„ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ

๋งํฌ์„œ๋น„์Šค ๋“ฑ๋กํ™”๋ฉด์—์„œ Input Value์„ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•˜๋‹ค. ๊ทธ๋Ÿผ ์ด๋ฏธ์ง€ ๋“ฑ๋ก์„ ์œ„ํ•œ Drag&Drop ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๋ฅผ ์ œ์ž‘ํ•ด๋ณด์ž. #11. Reactํ™”๋ฉด์—์„œ ๊ฐ ํ•ญ๋ชฉ์˜ Input Value์„ ๊ฐ€์ ธ์˜ค๊ธฐ #11. Reactํ™”๋ฉด์—์„œ

firstvalue.tistory.com

 

React์—์„œ ๋“ฑ๋กํ™”๋ฉด์—์„œ ์ด๋ฏธ์ง€๋ฅผ Drag&Drop ํ• ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„์„ ํ–ˆ๋‹ค.

๊ทธ๋Ÿผ ์ด์   ๋“ฑ๋กํ™”๋ฉด์˜ ๋งˆ๋ฌด๋ฆฌ๋กœ ์ €์žฅ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋ณด์ž.

 

 

1.1.  ์ด๋ฏธ์ง€ ์ €์žฅ๊ธฐ๋Šฅ ์ œ์ž‘

์ด๋ฏธ์ง€ ์ €์žฅ๊ธฐ๋Šฅ(linkSevice.uploadImage) ์€ ์•„์ง API ์ œ์ž‘ ๋ฐ Service์„ ์–ธ์„ ํ•˜์ง€ ์•Š์•˜๋‹ค.

     โ˜ž ์„ค๋ช…์ฐจ์›์—์„œ ์„œ๋ฒ„๋‹จ์— API์ œ์ž‘ ์‹œ ์ œ์™ธ ํ–ˆ๋‹ค. ์•ž๋‹จ์—์„œ ๋ญ” ์ง€ ๋ชจ๋ฅธ ์ƒํƒœ์—์„œ ์†Œ์Šค๋ฅผ ๋ฏธ๋ฆฌ ์ œ์ž‘ํ•˜์ง€ ์•Š๊ณ ,

          ์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•ด ์ง€๊ธˆ ๋‚ด์šฉ์„ ๋ฐ˜์˜ํ–ˆ๋‹ค.

 

๋งํฌ์ •๋ณด๋ฅผ DB์— ์ €์žฅ ์‹œ ์šฐ๋ฆฌ๋Š” ๋ฏธ๋ฆฌ /api/link/create API ์„ ์‚ฌ์ „์— ์ œ์ž‘ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ, ์‹ค์ œ ํ™”๋ฉด์—์„œ DB ์ €์žฅ ์‹œ 2๊ฐ€์ง€๊ฐ€ ๋” ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•œ๋‹ค.

 

์ฒซ์งธ, ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ž์ฒด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ธฐ๋Šฅ

๋‘˜์งธ, ์ด๋ฏธ์ง€ ํŒŒ์ผ๋ช…(URL)์„ ๋งํฌ์ •๋ณด DB์— ์ €์žฅํ•˜๋Š” ๊ธฐ๋Šฅ

 

โŽŸโŽœ์ด๋ฏธ์ง€ ์ €์žฅ ๊ธฐ๋Šฅ

 

์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๋Š” ๋ณดํ†ต DB์— ์ง์ ‘ ๋„ฃ๋Š” ๋ฐฉ๋ฒ•๊ณผ ์„œ๋ฒ„์— ์ด๋ฏธ์ง€๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์žฅ๋‹จ์ ์€ ์žˆ์œผ๋‚˜, ์ด๋ฏธ์ง€๋ฅผ DB์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์€ ํ–ฅํ›„ ์ด๋ฏธ์ง€ ํ˜ธ์ถœ ์‹œ ์†๋„์™€ DB์šฉ๋Ÿ‰๊ณผ ์œ ์ง€๋ณด์ˆ˜์— ๋ถˆํŽธํ•จ์ด ์žˆ์–ด, ๋ณ„๋„ ์„œ๋ฒ„์— ๋ณด๊ด€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•œ๋‹ค.

 

๊ธฐ์—…์˜ ๊ฐœ๋ฐœ์€ CDN์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋ณ„๋„ ๋ณด๊ด€ ๋ฐฉ์‹์„ ์ถ”์ฒœํ•œ๋‹ค.

์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์ œ์ž‘ํ•˜๋ฉด์„œ, ๋‹ค์‹œํ•œ๋ฒˆ ์„œ๋ฒ„๋‹จ๊ณผ ํด๋ผ์ด์–ธํŠธ๋‹จ์˜ API์ œ์ž‘ ๊ด€๋ จํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด์ž.

 

1)   ์„œ๋ฒ„ RESTful API์ œ์ž‘

- ์ด๋ฏธ์ง€ ๋ณด๊ด€ ํด๋” ์ง€์ • ( config.py )

- ์ด๋ฏธ์ง€ ์—…๋กœ๋“œํ›„ ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ด๋ฆ„๊ณผ URL์„ DB์— ๋ณด๊ด€

- ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ / ์‚ญ์ œ CLASS ์ œ์ž‘

- API ์„ ์–ธ

 

2) ํด๋ผ์ด์–ธํŠธ API ํ˜ธ์ถœ

   - API config์— ์„œ๋ฒ„๋‹จ API ํ˜ธ์ถœ url๊ด€๋ฆฌ ( api.config.js )

- ์„œ๋น„์Šค์— API ํ˜ธ์ถœ const ์ง€์ • ( service.js )

 

โŽŸโŽœ์„œ๋ฒ„๋‹จ API ์ œ์ž‘

 

โŒ˜ config.py ( ์œ„์น˜: linkservice/server/config/config.py )

--------------------------------------------------------------------------------------------------

์•ž์—์„œ config.py์— ๊ฐœ๋ฐœ๊ณ„(Development)์™€ ์šด์˜๊ณ„(Production) ์ด๋ฏธ์ง€ ์ €์žฅ ์œ„์น˜๋ฅผ ์ง€์ • ํ–ˆ์—ˆ๋‹ค.

#์ด๋ฏธ์ง€ ์œ„์น˜ ์„ค์ •
    image_folder = os.path.normpath(os.path.join(dir, os.pardir)) + '/client/public/images/'
    COVER_IMAGE_FORDER = image_folder
    IMAGE_FORDER = image_folder
    IMAGE_URL = 'http://127.0.0.1:3000/images/'

image_folder๋Š” ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์˜ ๋ถ€๋ชจ ๋””๋ ‰ํ† ๋ฆฌ ( /linkservice) ์„ ํ™•์ธํ•ด์„œ /client/public/images ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

( ํ•ด๋‹น ํด๋”์— images ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์ž )

โ˜ž NAS๋‚˜ CDN ์ €์žฅ ์‹œ image_folder์— ์œ„์น˜๋ฅผ ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค.
โ˜ž COVER_IMAGE_FORDER
๋Š” ํ–ฅํ›„ ์ปค๋ฒ„ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€/๋ณ€๊ฒฝ ํ•  ์˜ˆ์ •์ด๋ผ ๋ฏธ๋ฆฌ ์„ค์ •ํ–ˆ๋‹ค.

 

โŒ˜ links_model.py ( ์œ„์น˜: linkservice/server/models/links_model.py )

--------------------------------------------------------------------------------------------------

 

๊ธฐ์กด์— links_model.py์— 2๊ฐ€์ง€๊ฐ€ ์ถ”๊ฐ€์ ์œผ๋กœ ํ•„์š”ํ•˜๋‹ค.

์ด๋ฏธ์ง€ ์—…๋กœ๋“œํ›„ ๋งํฌ์ •๋ณด์— ์ด๋ฏธ์ง€ ์ด๋ฆ„์„ ๋งคํ•‘ ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ ์ด๋ฏธ์ง€ ์ด๋ฆ„์„ ์ €์žฅํ•˜๋Š” method์™€ ํ˜„์žฌ DB์˜  id ์‹œํ€€์Šค ๊ฐ’์„ ์•Œ์•„๋‚ด๋Š” method๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 

id์˜ ํ˜„์žฌ ์‹œํ€€์Šค๋ฅผ ์•Œ์•„์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ์ €์žฅ์ˆœ์„œ๋ฅผ ์ž˜ ์ƒ๊ฐํ•˜๋ฉด ํ•„์š”์„ฑ์ด ๋ณด์ธ๋‹ค.

์ด๋ฏธ์ง€๊ฐ€ ๋จผ์ € ์ €์žฅ ๋˜๋ฉด id์„ ์•Œ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, 1)๋งํฌ์ •๋ณด(์ด๋ฆ„,ํƒœ๊ทธ ๋“ฑ)๊ฐ€ ๋จผ์ € ์ €์žฅ๋˜์–ด ์‹œํ€€์Šค์ธ id๊ฐ’์ด ์ƒ์„ฑํ•œ ๋‹ค์Œ 2)์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค.

from sqlalchemy.sql import text

query์— raw string ํ˜•ํƒœ์˜ SQL๋ฌธ์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ sqlalchemy.sql.text ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์šฐ์„  sqlalchemy.sql.text ์„ import ํ•˜๊ณ , ์•„๋ž˜ ์†Œ์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

# ๋งํฌ ์ด๋ฏธ์ง€ ์ •๋ณด๋ฅผ DB์— ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ
# id์™€ ํŒŒ์ผ์ด๋ฆ„ ํ˜น์€ ์ด๋ฏธ์ง€ ๋งํฌ๋ฅผ ํŒŒ๋ผ๋ฉ”ํƒ€๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌ
    @classmethod
    def update_filename(self, id, filename):
        try:
            query = "update links set imageurl = :v2 where id = :v1"
            db.session.execute(text(query), {'v1':id, 'v2':filename})
        except:
            db.session.rollback()
            print('update_filename : ์˜ค๋ฅ˜๋ฐœ์ƒ')
            print(query)
        finally:
            db.session.commit()
            db.session.close()

# ๋งํฌ์ •๋ณด๊ฐ€ ์ €์žฅ๋œ ํ˜„์žฌ ์‹œํ€€์Šค id ๊ฐ’์„ ์•Œ์•„๋‚ธ๋‹ค. 
	@classmethod
	def currval_id(self):
		result = db.session.query(func.max(self.id)).scalar()
		return result

โŒ˜ image.py ( ์œ„์น˜: linkservice/server/src/image.py )

-------------------------------------------------------------------------------------------------

์ด๋ฏธ์ง€ ๊ด€๋ จ Resource์„ ์ œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ image.py์„ ํ•˜๋‚˜ ์ƒ์„ฑํ•œ๋‹ค.

image.py์—์„œ๋Š” ์ธ๋„ค์ผ ์ •๋„์˜ ์ด๋ฏธ์ง€๋งŒ ์žˆ์œผ๋ฉด ๋˜๋ฏ€๋กœ, 1) ์ด๋ฏธ์ง€๋ฅผ resizing์„ ํ•˜๊ณ , 2)์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ํด๋”์— ์ €์žฅํ•œ ๋‹ค์Œ, 3) ๋งํฌ์ •๋ณด DB์— ์ด๋ฏธ์ง€ ํŒŒ์ผ๋ช…(URL)์„ ๋งคํ•‘ ์‹œํ‚จ๋‹ค.

โ˜ž DB์— ์ €์žฅ๋˜๋Š” ์ด๋ฏธ์ง€ ํŒŒ์ผ๋ช…์€ ์‹ค์ œ CDNํ˜น์€ NAS ์˜ URLํ˜•ํƒœ๋กœ ์ €์žฅ๋œ๋‹ค.

   config.py์˜ IMAGE_URL ๊ฐ’์„ ์ฐธ๊ณ ํ•˜๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

from flask_restful import Resource
from flask import jsonify, request, current_app
from PIL import Image, ImageOps
from models.links_model import LinkModel

"""
UPLOAD  IMAGE /api/link/image 
"""
class ImageUpload(Resource):
    def post(self):
        f = request.files['image']
        folder = current_app.config.get('IMAGE_FORDER')
        img_url = current_app.config.get('IMAGE_URL')

        img = Image.open(f)
        
        # ์ด๋ฏธ์ง€๋ฅผ ๊ฐ•์ œ์ ์œผ๋กœ Resizingํ•œ๋‹ค.
        # Resizing์„ ์•ˆํ•ด๋„ ์ข‹์œผ๋‚˜, ํŒŒ์ผ ์šฉ๋Ÿ‰์„ ์ค„์ด๊ณ ์ž ๋ฐ˜์˜
        img_resize = img.resize((50,50), Image.LANCZOS)
        img_resize = ImageOps.exif_transpose(img_resize)
        img_resize = img_resize.convert('RGB')

        id = LinkModel.currval_id()
        file_name = str(id) + '_' + str(date_function.today()) + '.' + f.filename.rsplit('.', 1)[1].lower()
        img_resize.save(folder + file_name)
		LinkModel.update_filename(id, img_url + file_name)

        return '์ด๋ฏธ์ง€๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค..'

ํ”„๋ก ํŠธ์—”๋“œ์—์„œ formData๋กœ ๋ณด๋‚ธ image์„ request.files๋กœ ๋ฐ›์•„ Python์˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ pillow(PIL) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ Resizingํ•œ๋‹ค.

 

๋˜ํ•œ ํŒŒ์ผ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•œ๋‹ค. ์ด์œ ๋Š” ํ•œ๊ธ€ ํ˜น์€ ๊ฐ™์€ ํŒŒ์ผ ์ด๋ฆ„์ด ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ์— ๋Œ€๋ถ€๋ถ„ ์‚ฌ์ดํŠธ๋ฅผ ๋ณด๋ฉด ๋ช…๋ช…๊ทœ์น™(Naming rule)์— ๋งž๊ฒŒ ๋ณ€๊ฒฝํ•˜์—ฌ ์ž์ฒด ๋ณด๊ด€ํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” ํŒŒ์ผ๋ช… Naming rule์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๊ธฐ๋กœ ํ•˜์ž. ( ๊ฐ์ž ์ •ํ•ด๋„ ๋ฌด๋ฐฉ ํ•œ๋‹ค.)

   โ–บ ID_๋‚ ์งœ.ํ™•์žฅ์ž

 

        ๐Ÿ“Œ DB์— ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ €์žฅ ์‹œ image_url + file_name์ž„์„ ์ƒ๊ธฐํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.

 

๋˜ํ•œ, ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋งํฌ์ •๋ณด๊ฐ€ ์ˆ˜์ •/์‚ญ์ œ ์‹œ ๊ธฐ์กด ์ด๋ฏธ์ง€๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ์ž‘์—…๋„ ํ•„์š”ํ•จ์œผ๋กœ ๋ฏธ๋ฆฌ ์ž‘์„ฑํ•œ๋‹ค.

"""
CHANGE  IMAGE /api/link/image/<int:id>
"""
class ImageChange(Resource):
    def put(self, id):
        f = request.files['image']
        folder = current_app.config.get('IMAGE_FORDER')
        img_url = current_app.config.get('IMAGE_URL')

        img = Image.open(f)
        # ์ด๋ฏธ์ง€๋ฅผ ๊ฐ•์ œ์ ์œผ๋กœ Resizingํ•œ๋‹ค.
        # Resizing์„ ์•ˆํ•ด๋„ ์ข‹์œผ๋‚˜, ํŒŒ์ผ ์šฉ๋Ÿ‰์„ ์ค„์ด๊ณ ์ž ๋ฐ˜์˜
        img_resize = img.resize((50,50), Image.LANCZOS)
        img_resize = ImageOps.exif_transpose(img_resize)
        img_resize = img_resize.convert('RGB')

        file_name = str(id) + '_' + str(date_function.today()) + '.' + f.filename.rsplit('.', 1)[1].lower()
        img_resize.save(folder + file_name)

        LinkModel.update_filename(id, img_url + file_name)

        return '์ด๋ฏธ์ง€๊ฐ€ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค..'

ImageUpload() ์™€ ImageChange() ์˜ ์ฐจ์ด์ ์€ id ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š๋ƒ ์•„๋‹ˆ๋ฉด currval_id๊ฐ€์ง€๊ณ  ์ƒ์„ฑํ•˜๋Š๋ƒ ์ฐจ์ด๋‹ค.

์†Œ์Šค๋ฅผ ํ•˜๋‚˜๋กœ ๋ณ‘ํ•ฉํ•ด๋„ ๋ ์ง€ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ง์ ‘ ํ•ด๋ณด์‹œ๋ฉด ์ข‹์„ ๋“ฏ ํ•˜๋‹ค.

 

โŒ˜ server.py ( ์œ„์น˜: linkservice/server/server.py )

--------------------------------------------------------------------------------------------------

API์— ImageUpload Resource์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

server.py์— ImageUpload์„ importํ•˜๊ณ ,

from src.image import ImageUpload

api resource์— ์ถ”๊ฐ€ํ•œ๋‹ค.

api.add_resource(ImageUpload, '/api/link/image')
api.add_resource(ImageChange, '/api/link/image/<int:id>')

 

โŽŸโŽœํด๋ผ์ด์–ธํŠธ๋‹จ(ํ”„๋ก ํŠธ ์—”๋“œ) API ํ˜ธ์ถœ

 

โŒ˜ api.config.js ( ์œ„์น˜: linkservice/client/src/component/api/api.config.js )

-------------------------------------------------------------------------------------------------

์„œ๋น„์Šค๋ช… API์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

api.config.js

โŒ˜ service.js ( ์œ„์น˜: linkservice/client/src/component/service/service.js )

-------------------------------------------------------------------------------------------------

linkService์—์„œ API์„ ํ˜ธ์ถœํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

service.js

๋ชจ๋‘ ์ž‘์„ฑ๋˜๋ฉด, ์ด์   ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์ž

http://localhost:3000/create ๋กœ ์ ‘์† ํ›„ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด๋ณด๊ณ  ๋“ฑ๋ก ํ•œ๋‹ค.

 

์ •์ƒ์ ์œผ๋กœ ๋“ฑ๋ก๋˜์—ˆ๋‹ค๋ฉด ์ดˆ๊ธฐํ™”๋ฉด์—์„œ ํ™•์ธํ•ด๋ณด์ž.

http://locahost:3000

 

 

 

๊ด€๋ฆฌ์ž๋ชจ๋“œ ํ™”๋ฉด์„ ๋งŒ๋“ค์–ด ๋“ฑ๋ก/ํŽธ์ง‘/์‚ญ์ œ/์ˆœ์„œ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ Prototype UI์„ ๊ตฌ์„ฑํ•ด ๋ณด์ž.

#8. ํ”„๋ก ํŠธ์—”๋“œ ํ™”๋ฉด๊ฐœ๋ฐœ (component ์ œ์ž‘)

 

#8. ํ”„๋ก ํŠธ์—”๋“œ ํ™”๋ฉด๊ฐœ๋ฐœ (component ์ œ์ž‘)

#7. ํ”„๋ก ํŠธ์—”๋“œ ํ™”๋ฉด ๊ฐœ๋ฐœ #7. ํ”„๋ก ํŠธ์—”๋“œ ํ™”๋ฉด ๊ฐœ๋ฐœ 1. React๋กœ ํ™”๋ฉด ๊ฐœ๋ฐœ ์ž, ์ด์ œ๋ถ€ํ„ฐ REACT๋กœ ํ™”๋ฉด์„ ๊ฐœ๋ฐœ ํ•ด๋ณด์ž. ์•ž์—์„œ ์‚ฌ์ „ ์ค€๋น„์‹œ ํ”„๋กœ์ ํŠธ ํด๋”์ธ linkservice์•„๋ž˜์— npx create-react-app ์œผ๋กœ ์ด๋ฏธ c

firstvalue.tistory.com

 

๋ฐ์ดํ„ฐ๊นŒ์ง€ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์œผ๋‹ˆ, ์ด์   ๋””์ž์ธ์„ ํ•ด๋ณด์ž.

 

โŒ˜ links.css ( ์œ„์น˜: linkservice/client/src/css/links.css)

โŒ˜ links.jsx ( ์œ„์น˜: linkservice/client/src/component/links.jsx)

---------------------------------------------------------------------------------------------------------

CSS์„ ์œ„ํ•œ ํด๋”๋ฅผ ๋งŒ๋“ค๊ณ  links.cssํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

๋ชจ๋“  CSS๋Š” links.css์— ๋„ฃ์–ด๋‘์—ˆ๋‹ค.

 

link.css์— ์šฐ์„  link-container์™€ link-wrapper์˜์—ญ์„ ๋งŒ๋“ค์–ด์ฃผ๊ณ ,

.link-container {
    margin-bottom: 6px;
    cursor: move;
}
.link-wrapper {
    padding: 12px;
box-shadow: 0em 0em 0.1em #000000;
    border-radius: 10px;
}

link-show ์˜์—ญ์—๋Š” link image์™€ link name์ด ๋ณด์—ฌ์ฃผ๋„๋ก ํ•œ๋‹ค.

.link-show {
    display: flex;
    align-items: center;
}
.link-img {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    object-fit: cover;
}
.link-title {
    flex-direction: column;
    margin-left: 10px;
min-width: 200px;
    width: 70%;
    font-weight: 600;
}

 

โŒ˜ links.jsx์—์„œ CSS์„ importํ•˜๊ณ  CSS๋“ค์„ ์ ์šฉํ•ด๋ณธ๋‹ค.

links.jsx์— links.css importํ•œ๋‹ค.
div className์„ ์ ์šฉํ•œ๋‹ค.

โŽฎ๊ฒฐ๊ณผํ™”๋ฉด

 

๋งํฌ์ •๋ณด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋“ฑ๋กํ•ด์„œ ํ™•์ธํ•ด ๋ณธ๋‹ค.

JSON ๋ฐ์ดํ„ฐ ์ค‘ ํ™œ์šฉํ•˜์ง€ ์•Š๋Š” ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€์ ์œผ๋กœ ํ™”๋ฉด์— ์ ์šฉํ•ด๋ณด์ž.

 

โŽฎ๋งํฌ์ •๋ณด ๊ฑธ๊ธฐ

 

link-show ๋ถ€๋ถ„์— onClick์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

์ด์   ํด๋ฆญํ•˜๋ฉด linkurlํ•ญ๋ชฉ์˜ ์ •๋ณด์— ๋”ฐ๋ผ ํŽ˜์ด์ง€ ์ด๋™์ด ๋œ๋‹ค.

 

 

โŽฎํƒœ๊ทธ์ •๋ณด ํ‘œ์‹œ

 

link-wrapper ๋ถ€๋ถ„์— tag ํ‘œ์‹œ๋ฅผ ํ•ด๋ณด์ž.

ํƒœ๊ทธ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‚˜, ์—ฌ๊ธฐ์„œ๋Š” ์ตœ๋Œ€ 3๊ฐœ๊นŒ์ง€๋งŒ ์ž…๋ ฅ์ด ๊ฐ€๋Šฅ(ํ™”๋ฉด ์ œ์•ฝ์‚ฌํ•ญ) ํ•˜๊ณ ,

ํƒœ๊ทธ์˜ ๊ตฌ๋ถ„์ž๋Š” / ๋กœ ํ•ด์„œ ๊ตฌ๋ถ„ํ•œ๋‹ค. (์˜ˆ,  ํƒœ๊ทธ1/ํƒœ๊ทธ2/ํƒœ๊ทธ3 )

 

ํƒœ๊ทธ์˜ ๋‚ด์šฉ์„ ํ‘œ์‹œํ•ด์ค€๋‹ค.

ํƒœ๊ทธ ํ‘œ์‹œ๋ฅผ ์œ„ํ•œ html ์ถ”๊ฐ€

ํƒœ๊ทธ ๊ด€๋ จ css์„ ์ถ”๊ฐ€ํ•œ๋‹ค

.tag-container {
    display: flex;
    flex-wrap: nowrap;
}
.tag-row {
    flex-basis: 90px;
}
.tag-button {   
    flex-basis: 21%;
    height: 20px;
    border-radius: 6px;
    margin-right: 15px;
    text-align: center;
    font-size: 4px;
    color: rgb(218, 213, 213);
}
.tag-blue {
    background-color: rgb(82, 65, 234); 
}

ํƒœ๊ทธ ํ‘œ์‹œ

๋งˆ์ง€๋ง‰ ํƒœ๊ทธ๋Š” ์ œ์ฃผ๋„/๊ทค/ํ• ์ธ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถ„ํ• ์„ ํ•ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์—ฌ๋Ÿฌ ๊ฐœ ํƒœ๊ทธ๋„ ๊ฐ๊ฐ ์ƒ‰์ƒ์„ ๋‹ค๋ฅด๊ฒŒ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด ๋ณด์ž.

 

tag button ์ƒ‰์ƒ์„ ๋‹ค๋ฅด๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ classList์— ๋‹ค๋ฅธ ์ƒ‰์ƒ์„ ๋‹ด์•„ ์ ์šฉํ•ด๋ณด์ž.

 

์ฐธ๊ณ ๋กœ, ์กฐ๊ธˆ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœchild component์ธ TagList(Props)์„ ๋งŒ๋“ค์–ด ๋ Œ๋”๋ง์„ ํ•˜๋Š” ๋ฐฉ์‹๋„ ์žˆ๋‹ค.

child component ์ธ TagList(Props)

์œ„ ์†Œ์Šค์—์„œ ๋ˆ„๋ฝ๋œ ๊ฒŒ ํ•˜๋‚˜ ์žˆ๋‹ค.

๋ฐ”๋กœ tag ๊ฐ’์ด ์—†์„ ๊ฒฝ์šฐ๋„ ๋นˆ ํ•ญ๋ชฉ์— tag-orange css๊ฐ€ ์ ์šฉ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค.

ํƒœ๊ทธ๊ฐ€ ์—†์„๊ฒฝ์šฐ ๋นˆ์นธ์œผ๋กœ ํ‘œ์‹œ๋œ๋‹ค.

 

๊ทธ๋ž˜์„œ tag๊ฐ’์ด ์žˆ์„ ๊ฒฝ์šฐ๋งŒ ๋ Œ๋”๋ง ๋˜๋„๋ก ์กฐ๊ฑด์„ ํ•˜๋‚˜ ๋” ์ค˜์„œ ํ•ด๊ฒฐํ•œ๋‹ค.

!tag ์„ or ์กฐ๊ฑด์œผ๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค.

!tag || tag.split('/').map( (tag, index)=>

๋ฌผ๋ก  child function์ธ TagList(Props)์„ ์•ˆํ•˜๊ณ ,

LinkMain()์—์„œ ๋ฐ”๋กœ ๋ Œ๋”๋ง์„ ํ•ด๋„ ๋ฌด๋ฐฉํ•œ๋‹ค. ์•„๋ž˜ ๊ฐ™์€ ์‹์œผ๋กœ ํ•ด๋„ ๊ฒฐ๊ณผ๋Š” ๊ฐ™์œผ๋‹ˆ ์†Œ์Šค ์ฐธ๊ณ ๋งŒ ํ•˜๊ธธ ๋ฐ”๋ž€๋‹ค.

 

๊ฐœ๋ฐœ ์†Œ์Šค ๋ฐฉ์‹์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ์‹์ด๋‹ค. ๋ญ๊ฐ€ ์˜ณ๋‹ค, ๊ทธ๋ฅด๋‹ค ์„ ํŒ๋‹จํ•˜๋Š” ๊ฒƒ์€ ๋งž์ง€ ์•Š๋‹ค. ๋‹จ, ์ข€๋” ๊ฐ€๋…์„ฑ๊ณผ Performance, ์œ ์ง€๋ณด์ˆ˜ ๋“ฑ์„ ๊ณ ๋ คํ•˜์—ฌ ํšŒ์‚ฌ๊ธฐ์ค€ ํ˜น์€ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ํ˜‘์—…ํ•ด์„œ ์ฝ”๋”ฉ ๊ธฐ์ค€์— ๋งž์ถฐ์„œ ๊ฐœ๋ฐœํ•˜๋ฉด ๋œ๋‹ค.

 

์ด์  , ์ƒ‰์ƒ๊ด€๋ จ css๋ฅผ ์ถ”๊ฐ€ํ•˜์ž.

.tag-orange {
    background-color: rgb(200, 173, 108);
}
.tag-grin {
    background-color: rgb(18, 161, 139); 
}

 

์‹ค์ œ ๋ณต์žกํ•˜๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ „์ฒด์ ์œผ๋กœ ํฌ๋งท๋งŒ ์ดํ•ดํ•œ๋‹ค๋ฉด ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š”๋ฐ ๋งŽ์€ ๋„์›€์ด ๋  ๊ฒƒ์œผ๋กœ ์ƒ๊ฐ๋œ๋‹ค.

 

ํ•˜์ง€๋งŒ, ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ์–ด๋ ค์› ๋˜ ๊ธฐ์–ต์ด ์žˆ์–ด์„œ ์ด์ œ๋ถ€ํ„ฐ

TO-DO ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด ํ•˜๋‚˜์”ฉ ์™„์„ฑํ•ด๋ณด์ž.

( ํ™”๋ฉด์„ค๊ณ„๋ฅผ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ฐธ๊ณ ํ•˜๊ธธ ๋ฐ”๋ž€๋‹ค.)

 


๋‹ค์ŒํŽธ์—๋Š” ๋งํฌ์„œ๋น„์Šค์˜ ๋“ฑ๋กํ™”๋ฉด์„ ์ œ์ž‘ํ•ด๋ณด์ž.

1.1. ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ ๋ฐ ํ™˜๊ฒฝ์„ค์ •

ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ๋Š” ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ๋ฅผ ๋‚˜๋ˆ„๊ณ ์ž client / server๋กœ ๊ตฌ๋ถ„ ํ•œ๋‹ค.

โŽฎํ”„๋กœ์ ํŠธ ํด๋” : linkserver/

       |-------- client ( React ๊ตฌ์กฐ)

       |-------- server ( Python๊ตฌ์กฐ )

 

โŽฎํ”„๋กœ์ ํŠธ ํด๋”๋ฅผ ๋งŒ๋“ค๊ณ   Client ํ™˜๊ฒฝ๊ณผ Server ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•ด ๋ณด๊ฒ ๋‹ค.

ํ„ฐ๋ฏธ๋„์„ ์—ด์–ด์„œ,

     > mkdir linkservice

     > cd linkservice

 

โŽฎํ”„๋กœ์ ํŠธ ํด๋”์—์„œ react ํ™˜๊ฒฝ์œผ๋กœ client ํด๋” ์ƒ์„ฑ

     > npx create-react-app client

โŽฎํ”„๋กœ์ ํŠธ ํด๋”์—์„œ python๊ฐ€์ƒํ™˜๊ฒฝ์œผ๋กœ serverํด๋” ์ƒ์„ฑ

     > python3 -m venv server

 โŽฎํ”„๋กœ์ ํŠธ ํด๋”์ธ linkservice ์•„๋ž˜์— client์™€ serverํ™˜๊ฒฝ์ด ๊ตฌ์ถ•๋˜์—ˆ๋‹ค. 

 

 ๋‹ค์ŒํŽธ์—๋Š”  Python Flask๋กœ API ์ œ์ž‘์„ ํ•ด๋ณด์ž.

1.    ๊ฐœ๋ฐœ ์ค€๋น„

1.1. ์‚ฌ์ „ ์ค€๋น„ ์ž‘์—…

๋ฐฑ์—”๋“œ(BACK-END) : Python, Flask, SQLAlchemy์„ ํ†ตํ•ด RESTful API์ œ์ž‘,

ํ”„๋ก ํŠธ์—”๋“œ(FRONT-END) : React, Bootstrap, material ui ์„ ์‚ฌ์šฉํ•˜์—ฌ page ์ œ์ž‘

๋ฐ์ดํƒ€๋ฒ ์ด์Šค(DB) : PostgreSQL

  

1.2. ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ

์„ค์น˜๋ฐฉ๋ฒ•์€ ๋ณ„๋„ ์„ค๋ช…ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ํ•„์š”์‹œ ๊ฒ€์ƒ‰ํ•˜์‹œ๋ฉด ๋งŽ์€ ์ž๋ฃŒ๋“ค์ด ๋‚˜์™€ ์žˆ๋‹ค.

 

๐Ÿ‘€ ๋ฐฑ์—”๋“œ(BACK-END)

· Python3.6.X ( ์šด์˜์ฒด์ œ์— ๋งž๊ฒŒ ์„ค์น˜ )

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ : https://www.python.org/downloads/

 

· POSTMAN

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ: https://www.getpostman.com/products

 

· PostgreSQL ์ตœ์‹ ๋ฒ„์ „( ์šด์˜์ฒด์ œ์— ๋งž๊ฒŒ ์„ค์น˜ )

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads

 

· DBeaver Community ๋ฒ„์ „( ์šด์˜์ฒด์ œ์— ๋งž๊ฒŒ ์„ค์น˜ )

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ: https://dbeaver.io/download/

๏ƒ  DBeaver๋Š” DBํˆด์ด๋ฏ€๋กœ ๋‹ค๋ฅธ DBํˆด์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ๋ณ„๋„ ์„ค์น˜ ์•ˆ ํ•ด๋„ ๋œ๋‹ค.

 

๐Ÿ‘€ ํ”„๋ก ํŠธ์—”๋“œ(FRONT-END)

· Node.js ์™€ NPM

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ : https://nodejs.org/ko/download/

· NPX ์„ค์น˜ : ๋ช…๋ น ํ”„๋กฌํ”„ํŠธ์—์„œ ์‹คํ–‰> npm install npx -g

· Yarn ์„ค์น˜ : ๋ช…๋ น ํ”„๋กฌํ”„ํŠธ์—์„œ ์‹คํ–‰> npm install yarn -g

1.    ๊ฐœ๋ฐœ ๊ฐœ์š”

 

IT๊ธฐ์—…์„ ํ‡ด์‚ฌ ํ›„ ๊ฐœ๋ฐœ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด์„œ ์–ด๋–ค ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐฐ์šธ๊นŒ ๊ณ ๋ฏผํ•˜๋ฉด์„œ ์˜ˆ์ „์— ์ž ๊น ๊ณต๋ถ€ํ–ˆ๋˜ Angularjs์„ ๋‹ค์‹œ ํ•ด๋ณผ๊นŒ ํ–ˆ์œผ๋‚˜, ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐฐ์šฐ๊ธฐ๋กœ ๋งˆ์Œ ๋จน์œผ๋ฉด์„œReact์™€ Python ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ–ˆ๋‹ค.

 

๋‹ค๋‹ˆ๋˜ ํšŒ์‚ฌ๋Š” JAVA์˜ ์œ„์ฃผ์˜ MSA, ์ž์ฒด ํ”„๋ ˆ์ž„์›Œํฌ ์†”๋ฅ˜์…˜๋“ฑ ์‚ฌ์šฉํ•˜์—ฌ, ์ตœ์‹  ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐฐ์šธ ์‹œ๊ฐ„๋„ ์—†์—ˆ๊ณ , ๊ณผ์žฅ๊ธ‰ ์ดํ›„ ๋ถ€ํ„ฐ๋Š” ๊ฐœ๋ฐœ๋ณด๋‹ค๋Š” BA ์—ญํ• ๋งŒ ํ•˜๋‹ค ๋ณด๋‹ˆ, ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ƒˆ๋กญ๊ฒŒ ๊ณต๋ถ€ํ•˜๋Š”๊ฒƒ์ด ์–ด๋ ค์›€์ด ์žˆ์—ˆ๋‹ค.

 

๋ณธ ๋‚ด์šฉ์€ ์•ฝ 2๋‹ฌ๊ฐ„ React์™€ Python์„ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ๊ตฌ์ถ•ํ•œ ๋‚ด์šฉ์˜ ์†Œ์Šค๋ฅผ ๊ฐœ๋ฐœ ๋‹จ๊ณ„๋ถ€ํ„ฐ ํ•˜๋‚˜ํ•˜๋‚˜ ๋”ฐ๋ผ ํ• ์ˆ˜ ์žˆ๋„๋ก ๊ณต์œ ํ•˜์—ฌ ๋งŽ์€ ๋ถ„๋“ค๊ณผ ๋‚˜๋ˆ„๊ณ ์ž ํ•œ๋‹ค.

 

๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋‹ค๋ณด๋‹ˆ, ์ดˆ๋ณด ํ˜น์€ ์ฒซ ํ”„๋กœ์ ํŠธ ์‹ ์ž…์€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ ๋‹ค.

์†Œ์Šค ์œ„์ฃผ์˜ ๋‚ด์šฉ์ด๋ฏ€๋กœ, ์†Œ์Šค๋‚ด์— ์ฃผ์„์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ๋‹ค๊ณ  ํ–ˆ์œผ๋‚˜, ๋งŽ์ด ๋ถ€์กฑํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ, ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋…์€ ์•Œ๊ณ  ์žˆ๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ์ง„ํ–‰๋˜๋ฏ€๋กœ, ํ•„์š”์‹œ ๊ฒ€์ƒ‰์„ ํ†ตํ•ด ์ถ”๊ฐ€์ ์œผ๋กœ ๊ณต๋ถ€๋ฅผ ํ•˜์‹œ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

 

๊ฐœ๋ฐœํ•  ๋•Œ ๊ฐœ๋…์ ์ธ ์„ค๋ช…๋งŒ ํ•˜๋Š” ์ž๋ฃŒ๊ฐ€ ๋งŽ์•„, ์‹ค์ œ ์šด์˜๋˜๋Š” ์ฐธ๊ณ ์†Œ์Šค๋ฅผ ์ฐพ๊ธฐ๊ฐ€ ์–ด๋ ค์šด ๊ฒฝํ—˜์ด ์žˆ์—ˆ๊ณ , ์ด๋Ÿฐ ๊ฒฝํ—˜์„ ์ดˆ๋ณด ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ ์กฐ๊ธˆ์ด๋‚˜๋งˆ ๋„์›€์„ ์ฃผ๊ณ ์ž ๋ชจ๋“  ์†Œ์Šค๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š”๊ฒƒ์„ ๋”ฐ๋ผํ•˜๋ฉด์„œ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ์ตํžˆ๊ธฐ ๋ฐ”๋ผ๋Š” ๋งˆ์Œ์— ์•ž์œผ๋กœ ๊ณ„์† ์—ฌ๊ธฐ์— ๊ธฐ๋ก์„ ๋‚จ๊ธฐ๋ฉด์„œ ์ง„ํ–‰ํ•  ์˜ˆ์ •์ด๋‹ค.

 

   โ€ป ์ตœ์ข… ์†Œ์Šค๋Š” ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„  or ์ค‘๊ฐ„๋‹จ๊ณ„์— git์œผ๋กœ ๊ณต์œ ํ•  ์˜ˆ์ •์ด๋‹ค.

 

1.1. ๋ฌด์—‡์„ ๋งŒ๋“ค ๊ฒƒ์ธ๊ฐ€?

๊ฐœ๋ฐœ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด์„œ ๋ฌด์ž‘์ • ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค ์–ด๋–ค ๊ฒƒ์„ ๋งŒ๋“ค์ง€ ๋ชฉํ‘œ๋ฅผ ์ •ํ•ด์„œ ๊ณต๋ถ€๋ฅผ ํ•˜๋ฉด ์ข‹์„ ๋“ฏ ํ•˜๋‹ค.

 

์š”์ฆ˜์€ ๋งŽ์€ ์ธํ”Œ๋ฃจ์–ธ์Šค๋‚˜ ์œ ํˆฌ๋ฒ„ ๋“ฑ ํฌ๋ฆฌ์—์ดํ„ฐ ๋ถ„๋“ค์ด ๋‹ค์–‘ํ•œ ์ฝ˜ํ…์ธ ๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋ฉ€ํ‹ฐ๋งํฌ ์‚ฌ์ดํŠธ๋“ค์ด ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.

๋ฉ€ํ‹ฐ ๋งํฌ ์„œ๋น„์Šค๋Š” ์ธ์Šคํƒ€๊ทธ๋žจ, ๋ธ”๋กœ๊ทธ, ๋งˆ์ผ“ ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋งํฌ๋ฅผ ํ•œ๊ณณ์— ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค

 

     ์˜ˆ) ๋งํฌํŠธ๋ฆฌ(Linktree), ์ธํฌํฌ๋งํฌ(Inpock link), ๋งํฌ๋ฏน์Šค(Link Mix), ๋ฆฌํ‹€๋ฆฌ(litt.ly), ๋งํฌ์˜จ(Linkon), ๋ฆฌํŠธ๋งํฌ(Lit.Link) ๋“ฑ๋“ฑ

           ์•ฝ 20์—ฌ๊ฐœ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ๋‹ค.

 

๊ฐ„๋‹จํ•œ ์„œ๋น„์Šค์ธ ๋งŒํผ ์‚ฌ์—… ๋ชฉ์ ์œผ๋กœ ๊ฐœ๋ฐœ์ด ์•„๋‹ˆ๋ฏ€๋กœ, ๋ฉ€ํ‹ฐ์œ ์ €๋‚˜ ๋ฉ€ํ‹ฐ์ปดํผ๋‹ˆ ๊ฐ™์€ ์„œ๋น„์Šค๋Š” ์ œ์™ธํ•˜๊ณ , ๊ธฐ๋ณธ ๊ธฐ๋Šฅ๊ณผ ์‚ฌ์ดํŠธ์— ์šด์˜์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ๊ณจ๋ผ ๋งํฌ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด๊ณ ์ž ํ•œ๋‹ค.

 


๋‹ค์ŒํŽธ์€ ๊ฐ„๋‹จํ•œ ์„ค๊ณ„๋ฅผ ์ง„ํ–‰ํ•˜๊ฒ ๋‹ค.

 

โ€ป ๋ณธ ํฌ์ŠคํŒ…์€ ๊ณ„์† ์ˆ˜์ •๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

+ Recent posts