728x90
반응형

1. aws에 접속하여 IAM 사용자를 생성한다

 

 

2. 권한으로 AmazonS3FullAccess를 할당해준다.

 

3. 해당 Access key ID, Secret access key를 알고 있어야 한다.

 

4. aws s3 화면에 접속해서 버킷을 만들어준다.

 

 

5. 퍼블릭 액세스 차단을 해제하고 만들어준다. (차후에 필요하면 수정 가능)

추가로 버킷정책과 CORS까지 설정해주자.

버킷정책

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicListGet",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:List*",
                "s3:Get*"
            ],
            "Resource": [
                "arn:aws:s3:::00nomubucket1",
                "arn:aws:s3:::00nomubucket1/*"
            ]
        }
    ]
}

 

CORS

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "PUT",
            "POST",
            "DELETE",
            "GET"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]

 

 

이제 버킷까지 만들었으니 node.js 로 파일 입출력 하는 로직을 구성해보자.

 

6. node.js 프로젝트에 필요한 패키지를 설치해준다.

npm i multer aws-sdk --save

 

7. 클라이언트에서 파일 업로드에 필요한 state를 만들어준다.

(file_location은 나중에 받아올 데이터입니다.)

    // ----- 파일 상태값 -----
    const initFileState : any = {
        file_object: "",
        file_url: "",
        file_location: ""
    }

    function fileReducer(state: any, action: any) {

        switch (action.type) {
            default:
                return {
                    ...state,
                    [action.name]: action.value
                }
        }
    }

    const [fileState, fileDispatch] = useReducer(fileReducer, initFileState)

 

8. 클라이언트에 file input을 만들어준다 ( Next.js Mui 사용했으나 일반 input 태그도 가능합니다 )

<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>
}

 

9. 대충 이런 모습을 볼 수 있다. ( 스타일은 신경쓰지 않아도 됩니다. 아래는 사진 미리보기  )

10. 백엔드에 데이터를 전송하는 로직을 구성해준다. ( 저장하기 버튼 클릭 시 )

const formData = new FormData();

formData.append("file_customer_code", infoState.customer_code); // 파일의 고유 코드 (임의로 지정 가능)
formData.append("file_object", fileState.file_object);
formData.append("file_url", fileState.file_url);

const config = {
    headers: {
        "content-type": "multipart/form-data",
    },
};

axios.post('/api/fileupload', formData, config)
    .then(({ data }) => {
        if (data.success) {
            alert('파일 업로드에 성공하였습니다.')
        }
        else {
            alert('파일 업로드에 실패하였습니다.')
        }
    })

 

클라이언트에서 파일을 업로드하고 백엔드로 데이터를 전송하였다. 다음 포스트에서는 백엔드에서의 파일 저장을 살펴보겠다.

 

728x90
반응형
728x90
반응형

1. 설치

$npm install --save multer

 

2. multer 가져오기 ( 조건문에 따라 파일의 로컬 저장 위치를 변환시킬 수 있음)

const fs = require("fs");
const bodyParser = require("body-parser");
const path = require("path");
router.use("/image_file", express.static("./upload")); // 사용자가 접근할 수 있게 공유
const multer = require("multer");

const uploadCustomer = multer({
    storage: multer.diskStorage({
        destination(req, file, cb) {
            if (!fs.existsSync("../client/public/upload")) {
                fs.mkdirSync("../client/public/upload");
            }

            if (!fs.existsSync("../client/public/upload/customer")) {
                fs.mkdirSync("../client/public/upload/customer");
            }

            if (!fs.existsSync("../client/public/upload/customer/" + file.originalname.split('-')[0])) { // 경로가 존재하지 않을 때
                fs.mkdirSync("../client/public/upload/customer/" + file.originalname.split('-')[0]);

            } else {
                fs.rmdirSync("../client/public/upload/customer/" + file.originalname.split('-')[0], { recursive: true, force: true }); // 기존폴더 및 하위 자료 삭제 
                fs.mkdirSync("../client/public/upload/customer/" + file.originalname.split('-')[0]); // 폴더 생성 
            }
            cb(null, "../client/public/upload/customer/" + file.originalname.split('-')[0]); // 이미지 생성

        },
        filename(req, file, cb) {

            const ext = path.extname(file.originalname);
            cb(null, file.originalname.split('-')[1]);
        },
    }),
    limits: { fileSize: 5 * 1024 * 1024 },
});

 

 

3. upload.single()

router.post('/', upload.single('image'), (req, res) => {
 
    console.log(req.file); 
  // 클라이언트에서 넘어온 파일에 대한 정보가 req.file에 FILE 객체로 저장되어 있습니다. 

})


출처: https://juhi.tistory.com/10 [주하히의 기술 블로그]

 

4. upload.array()

router.post('/', upload.array('photos', 4), (req, res) => { 

console.log(req.files);
console.log(req.files[0]); // 파일의 인덱스로 접근

// 위 single에서와 다르게 req.file이 아닌 req.files에로 넘어옵니다.

})

출처: https://juhi.tistory.com/10 [주하히의 기술 블로그]



// 미발송 근로계약서 이미지 및 서명, 데이터 요청
router.post("/sendLabor", uploadCustomer.array("image_file"), function (req, res, next) {
    const laborCode = req.body.laborCode;

    const state = JSON.parse(req.body.state);
    const 기타입력정보 = state.기타입력정보;
    const 근로자동의 = state.근로자동의;
    const 메인서명 = state.메인서명;

    console.log("req : ", req.files);



    const update_column = [
        "기타입력정보=JSON_OBJECT('근무장소', '" + 기타입력정보.근무장소 + "','담당업무', '" + 기타입력정보.담당업무 + "','주휴요일', '" + 기타입력정보.주휴요일 + "')",
        "근로자동의=JSON_OBJECT('동의여부_1', '" + 근로자동의.동의여부_1 + "','동의여부_2', '" + 근로자동의.동의여부_2 + "','동의여부_3', '" + 근로자동의.동의여부_3 + "','동의여부_4', '" + 근로자동의.동의여부_4 + "','동의여부_5', '" + 근로자동의.동의여부_5 + "','동의여부_6', '" + 근로자동의.동의여부_6 + "','동의여부_7', '" + 근로자동의.동의여부_7 + "','동의여부_8', '" + 근로자동의.동의여부_8 + "')",
        "메인서명=JSON_OBJECT('근로계약서_동의', '" + 메인서명.근로계약서_동의 + "','개인정보_동의', '" + 메인서명.개인정보_동의 + "','사용자_서명', '" + 메인서명.사용자_서명 + "', '근로자_서명', '" + 메인서명.근로자_서명 + "','사용자_서명날짜', '" + 메인서명.사용자_서명날짜 + "','근로자_서명날짜', '" + 메인서명.근로자_서명날짜 + "','사용자서명경로', '" + 'upload/customer/' + laborCode + '/' + "customer.png" + "','근로자서명경로', '" + 메인서명.근로자서명경로 + "')",
    ]

    console.log(update_column);

    const update_data_query = "UPDATE LABOR SET  " + update_column + " WHERE labor_code ='" + laborCode + "'";

    db.sequelize.query(
        update_data_query,
        {
            type: QueryTypes.UPDATE
        }
    ).then((result) => {

        return res.send({ success: true, result });

    })
})

 

5. upload.fields()

router.post('/',
	upload.fields([
    	{ name: 'mainImage', maxCount: 1 },
        { name: 'subImages', maxCount: 5 } ]),
        (req, res) => {
        	console.log(req.files);
            console.log(req.files['접근하려는 fieldname']);
})

출처: https://juhi.tistory.com/10 [주하히의 기술 블로그]
728x90
반응형
728x90
반응형

location.href 메소드를 이용해서 아주 간단하게 전화걸기 기능을 구현할 수 있다.

 

1. 전화걸기

function phoneCall(phoneNumber) {
  location.href = "tel:" + num;
}

phoneCall("01011112222");

 

2. 영상전화걸기 

function phoneCall(phoneNumber) {
  location.href = "tel-av:" + num;
}

phoneCall("01011112222");

 

3. 문자 보내기

function phoneCall(phoneNumber) {
  location.href = "sms:" + num;
}

phoneCall("01011112222");

 

4. 메일 보내기

function phoneCall(phoneNumber) {
  location.href = "mailto:" + num;
}

phoneCall("01011112222");

 

 

이것들은 a 태그 또는 버튼태그로도 사용할 수 있다.

<button onclick="document.location.href='tel:010-1234-5678'"> 

<a href="tel:010-1234-5678">010-1234-5678로 전화걸기</a> </div>
728x90
반응형
728x90
반응형

특정 사이트에서 로그인을 한 뒤 원하는 데이터를 얻어야 될 경우가 생겼다.

api 사이트를 이용할 경우 편하긴 하지만 트랜젝션이 발생 할 때마다의 비용이 발생하기 때문에 

node.js 에서 사용할 수 있는 puppeteer 를 경험해보기로 했다.

 

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

$npm i puppeteer

 

2. 함수를 구현한다.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch(); // puppeteer 시작
  const page = await browser.newPage(); // 브라우저 실행
  await page.goto('https://www.google.com'); // 해당 페이지로 이동
  // other actions...
  await browser.close();  // 브라우저 종료
})();

 

이러한 함수를 만들어두고 백엔드에서 api 요청이 들어올 때 원하는 사이트에 접속 후 원하는 데이터를 가져올 수 있게끔 구현하면 된다.

 

예시)

var puppeteer = require('puppeteer');

(async () => {

    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    const hisnet_id = '히즈넷 아이디';
    const hisnet_pw = '히즈넷 비밀번호';

    //페이지로 가라
    await page.goto('https://hisnet.handong.edu/login/login.php');

    //아이디랑 비밀번호 란에 값을 넣어라
    await page.evaluate((id, pw) => {
    document.querySelector('input[name="id"]').value = id;
    document.querySelector('input[name="password"]').value = pw;
    }, hisnet_id, hisnet_pw);

    //로그인 버튼을 클릭해라
    await page.click('input[src="/2012_images/intro/btn_login.gif"]');

    //로그인 화면이 전환될 때까지 .5초만 기다려라
    await page.waitFor(500);

    //로그인 실패시(화면 전환 실패시)
    if(page.url() === 'https://hisnet.handong.edu/login/_login.php'){
        student_id = 'nope';
        name = 'nope';
    }
    //로그인 성공시
    else{
        //학사 페이지로 가서
        await page.goto('https://hisnet.handong.edu/haksa/hakjuk/HHAK110M.php');
        //학번을 가져오고
        const element1 = await page.$('input[name="hakbun"]');
        student_id = await page.evaluate(element1 => element1.value, element1);
        //이름을 가져와라
        const element2 = await page.$('td[width="240"]');
        name = await page.evaluate(element2 => element2.textContent, element2);
    }
    //브라우저 꺼라
    await browser.close();        
})();

 

 

참조

https://zoomkoding.github.io/web/nodejs/histime/2019/01/24/crawler.html

 

줌코딩의 코딩일기

Zoom in Coding from the Basic.

zoomkoding.github.io

 

728x90
반응형
728x90
반응형

 

var originText = "This is example text.";
console.log("Original : ", originText);

// Base64 Encoding
base64EncodedText = Buffer.from(originText, "utf8").toString('base64');
console.log("Base64 Encoded Text : ", base64EncodedText);

// Base64 Decoding
base64DecodedText = Buffer.from(base64EncodedText, "base64").toString('utf8');
console.log("Base64 Decoded Text : ", base64DecodedText);

 

728x90
반응형
728x90
반응형
// 쿠키 생성
res.cookie('userid', userid); // 응답 객체에 쿠키를 생성한다.

// 쿠키삭제
res.clearCookie('userid'); // 응답 객체에 쿠키를 삭제한다.

// 쿠키 조회
req.cookies["userid"] // 요청 객체에서 쿠키를 조회한다



// 쿠키 생성할 때 옵션 주기
res.cookie('userid', userid, { maxAge: 60*60*1000, httpOnly: true, path:'/' });

//maxAge : 만료 시간을 밀리초 단위로 설정

//expires : 만료 날짜를 시간으로 설정

//path : cookie의 경로 default “/“

//domain : 도메인 네임

//secure : https에서만 cookie 사용

//httpOnly : 웹서버를 통해서만 cookie 접근
728x90
반응형
728x90
반응형

코드에 누출되어선 안되는 기밀정보를 보통 루트 폴더 밑에 .env파일을 만들어 관리한다.

git을 사용할 때도 .gitignore 파일에 env를 추가하여 중요한 정보는 git에 등록되지 않게끔 하는 방법도 있다.

 

1. 먼저 dotenv npm 모듈을 설치한다.

$ npm i dotenv

 

 

2. .env 파일을 루트 폴더 밑에 작성한다.

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

 

 

3. 그 다음 node.js 환경의 파일들에 아래와 같이 추가하면 사용할 수 있다.

// index.js

require("dotenv").config();

console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);

 

 

728x90
반응형
728x90
반응형

node js 홈페이지 메인

 

1. 업데이트를 실행해준다.

sudo apt-get update

 

2. 업그레이드 해준다.

sudo apt-get upgrade

 

3. npm을 설치한다.

sudo apt-get install npm

 

4. n을 설치한다.

sudo npm install n -g

 

5. 설치한 n을 이용해 node.js를 설치한다.

sudo n 18.4.0

 

6. 버전을 확인해본다.

sudo n

 

7. helloworld를 만들어준다.

cd ~
mkdir helloworld

 

 

 

 

 

 

 

 

 

728x90
반응형

+ Recent posts