728x90

while문 해보려는데..

나와같은 의문을 가지신 분

프로시저 꼭 만들어서 써야돼?

https://stackoverflow.com/questions/12954095/mysql-declare-while-outside-stored-procedure-how

 

mysql DECLARE WHILE outside stored procedure how?

I fairly new to mysql but have MS SQL experience. Is it possible to declare variables and use while statement outside stored procedure? I only found examples where guys doing like this 1. proced...

stackoverflow.com

안된데 따흑.

https://dev.mysql.com/doc/refman/8.0/en/sql-compound-statements.html

^공식문서...

 

 

방금 스택오버 따라서 코드 처보는데

DELIMITER 

이거 맨앞에 넣어야 빨간줄 안뜨네

너 뭐야..

 

공식문서가 말하길,,

"기본적으로 mysql 자체는 세미콜론을 명령문 구분 기호로 인식하므로 mysql 이 전체 ​​저장 프로그램 정의를 서버에 전달하도록 하려면 구분 기호를 일시적으로 재정의해야 합니다.

mysql 구분 기호 를 재정의하려면 delimiter명령을 사용하십시오. //전체 정의를 단일 명령문으로 서버에 전달한 다음 ;프로시저를 호출하기 전에 로 복원할 수 있도록 구분 기호가 변경됩니다 . 이렇게 하면 프로시저 본문에 사용된 구분 기호가 mysql 자체 ; 에서 해석되지 않고 서버로 전달될 수 있습니다."

 

어 그렇구나..(이해못함)

https://dev.mysql.com/doc/refman/8.0/en/stored-programs-defining.html

 

식 사이를 구분지어주는 거같음

 

아니!! 근데!!! 아무것도 안나와 

-> 계속 생기고 뭐지

세미콜론으로 끝내려는데도 안됨

뭘까..?

 

 

 

 

 

아하!

 

MySQL 콘솔창은 쌍반점(;)이 입력되면 어떤 경우에서건 일단 쌍반점(;) 이전 단계까지 명령문을 실행하게 됩니다.

구분 문자(;) 변경하기

명령분이 완성되지 않은 상태에서 실행되면 곤란합니다. 저장 프로시저에서 END를 입력하고 나서 CREATE PROCEDURE 명령이 실행되도록 환경을 변경해야 합니다.

 

그러려면 저장 프로시저를 작성하기 전에 구분 문자를 쌍반점(;)이 아닌 다른 문자로 변경해 둡니다. 일반적으로는 //을 사용합니다.

 

구분 문자를 //으로 변경할 때에는 DELIMITER 명령을 사용합니다.


맨 마지막의 DELIMITER ;는 구분 문자를 원래대로 되돌려 놓는 명령입니다. 구분 문자를 쌍반점(;)으로 되돌려 놓는 것을 잊지 않도록 합니다.

출처: https://recoveryman.tistory.com/186 [회복맨 블로그]  회복맨, 당신은 최고의 정리맨이자 설명맨입니다. 짱짱~


 

DELIMITER 가 구본문자를 바꾸는 명령어구나

구본문자를 세미콜론에서 //이걸로 바꿔놓고 

안된다고 하고 있었구나....ㅋㅋㅋㅋㅋㅋ

 

 

 

DELIMITER //
create procedure pro()
begin 
select name from sequence;
select deposit_date from sequence;
end
//




DELIMITER ;

call pro;

 

 

삭제하고 다시 만들어봐야지

 drop procedure if exists 프로시저 이름;

 

 

임의로 값 넣어놓음

 

DELIMITER //

구본문자//로 바꾸고

create procedure pro(d int)

프로시저 pro만들고 int형 인수d들어가게끔 사용할거임
begin 

시작
select * from sequence where interest_amount < d;

다가져와 seuquence 테이블에서 interest_amount가 d보다 작은 것중에서
end


//

프로시저 끝


DELIMITER ;

구본문자 다시 ;로 바꿈

call pro(3);

프로시저 실행. 인수에 3넣고 (3보다 작은 interest_amount 가져올거임)

 

 

 

 

이제 다시 while문 해봐야지..

 

https://recoveryman.tistory.com/186

 

[MySQL & PHP] 12장 저장 프로시저 활용하기

정리 1. 저장 프로시저의 의미와 작성 방법 1. 저장 프로시저란? 1.1 이용할 수 있는 버전 저장 프로시저를 학습하기 전에 MySQL의 버전을 확인하도록 합니다. 저장 프로시저는 MySQL 버전 5.0 이상에

recoveryman.tistory.com

 

이글은 보고 또 봐야지.. 뒤에는 다 안해봄!

 

 

 

 

728x90
728x90

https://stepby-yun.tistory.com/185

 

mysql 이자액 계산기 식 만들기 (값 띄우기select,넣기insert,삭제TRUNCATE)

목표 년 이자 4프로를 12개월로 나눠서 매월 찍히는걸로 하는건데 이름은 그대로 입금날짜는 한달씩 증가로 찍혀야함!! 이자율 계산 INSERT INTO test.sequence (interest_amount) SELECT (deposit_amount ..

stepby-yun.tistory.com

 

지난시간..

복잡한 식을 깔끔하게 만들어주고자 변수를 사용해봤다.

 

 

(찾아보니까 declare(타입선언)랑 set(변수할당)있었는데 어째서인제 declare은 자꾸 빨간선뜸.

변수 설정할때 @이름 으로 씀)

 

use test;
insert into sequence (name,deposit_date,deposit_amount) values ('이소윤',now(),'10000000');

set @lastDate = (select deposit_date from sequence order by id desc limit 1) ;
set @initial_amount = (select deposit_amount from sequence where id='1');
set @name = (select name from sequence where id='1');


INSERT INTO sequence (name,deposit_date,interest_amount)
select @name,
 (select date_add(@lastDate,INTERVAL 1 MONTH)),
@initial_amount* 0.04 /12;

 

 

 

하.지.만.

 

 

마지막 행 날짜값에다가 한달씩 더해야되는데 

자꾸 첫번째 행값에 더했다.

 

 

 

 

 

예상했던대로 변수 재할당 다시 해야만 

마지막 값을 가져왔다. 허허...

 

어떻게 해결할 것인가~ 

 

 

 

만약에 행이 추가되면 변수 재할당으로 해야하나????

???

 

 

 

 

728x90
728x90

 

mysql 시작

mysql -u root -p [비번]

 

 

mysql 실행

service mysql start

https://i5i5.tistory.com/260

 

[MySQL] 기본 명령어 (접속/포트/시작/중단, 데이터베이스, 테이블 관련)

MySQL 접속 명령어 $ mysql -uroot -p[비밀번호] // 비밀번호 없을 경우 $ mysql -uroot MySQL 3306 포트 열기 만약 iptable이 실행되고 있다면 외부에서 접속할 수 있도록, MySQL 3306 포트 여는 명령어. $ sudo..

i5i5.tistory.com

 

테이블 내용 삭제

TRUNCATE [테이블명]

 

https://patiencelee.tistory.com/590

 

Mysql 테이블 데이터 지우기 Delete / Truncate

MySQL - 테이블 내용 삭제 - DELETE, TRUNCATE 차이점 테이블에서 내용을 삭제할때는 DELETE, TRUNCATE를 자주 사용하게됩니다 DELETE, TRUNCATE 둘다 테이블의 내용을 삭제하지만 차이점이 존재합니다 1. DELETE..

patiencelee.tistory.com

 

728x90
728x90

 

목표

년 이자 4프로를 12개월로 나눠서

매월 찍히는걸로 하는건데

이름은 그대로 입금날짜는 한달씩 증가로 찍혀야함!!

 

<1차시도>

이자율 계산

 

 

INSERT INTO test.sequence (interest_amount) SELECT (deposit_amount * 0.04 /12)  from test.sequence;

 

 

 

이거 참고함 https://velog.io/@gillog/MySQL-SELECT%EB%90%9C-%EA%B2%B0%EA%B3%BC%EB%A1%9C-INSERT-%ED%95%98%EA%B8%B0

 

 

<2차시도>

한달씩 증가한 날짜 찍기

 

날짜 

https://allmana.tistory.com/7

 

[MySQL] 날짜 더하기 빼기 date_add

[MySQL] 날짜 더하기 빼기 date_add MySQL에서는 날짜를 더하고 뺄때 쓰는 함수가 있다. 바로 date_add 사용법 DATE_ADD(date, INTERVAL 계산수 계산형식) 계산형식이란 월,일,시간 중 어떤걸 더할꺼냐를 선택하

allmana.tistory.com

현재를 기준으로 1달씩 더함

select date_add(now(),INTERVAL 1 MONTH) ;

 

지금을 기준으로 식만들면 다시 재사용하기 힘듦..

 

INSERT INTO test.sequence (deposit_date) select date_add(now(),INTERVAL 1 MONTH);

 

 

 

테이블 내용 삭제하고 다시~

 

TRUNCATE

  • 테이블의 전체 데이터를 삭제
  • 테이블에 외부키(foreign key)가 없다면 DELETE보다 훨씬 빠르게 삭제됨
# 문법
TRUNCATE 테이블명

# 예제
TRUNCATE student;

https://wayhome25.github.io/mysql/2017/03/20/mysql-05-table-insert-delete-modify/

 

MySQL 05. MySQL - Table (insert, update, delete) · 초보몽키의 개발공부로그

 

wayhome25.github.io

<3차시도>

 

위에 한거 동시에 적용해보기

 

 

sequence테이블에 날짜항목, 이자액항목에   지금에 한달추가한 날짜값,  계산한 이자금액 넣는다.

 

INSERT INTO sequence (deposit_date,interest_amountselect date_add(now(),INTERVAL 1 MONTH),10000000* 0.04 /12;

 

 

 

 

숫자로 넣어서 하긴했는데 실제는 이렇게 하면 안될듯 

재사용할 수 있게 변수지정해야되지 않을까

 

 

 

 

 

<4차시도>

 

 

 

 

 

 

INSERT INTO sequence (deposit_date,interest_amount) select date_add((select deposit_date from sequence where id='1'),INTERVAL 1 MONTH),(select deposit_amount from sequence where id='1')* 0.04 /12;

 

 

where id="1"

로 첫번째 행에 있는 값을 사용하게 했다. 금액은 괜찮은데

하지만 날짜는 이전행을 기준으로 한달씩 증가되어야한다.

 

<5차시도>

 

LAG함수쓰면 될거같은데 안되네....

아 된건가?

SELECT * FROM test.sequence;
use test;
insert into sequence (name,deposit_date,deposit_amount) values ('이소윤','20200509','10000000');
INSERT INTO sequence (deposit_date,interest_amount) select date_add(now(),INTERVAL 1 MONTH),10000000* 0.04 /12;
 select deposit_date, LAG(deposit_date) over(order by deposit_date) from sequence;

 

<6차시도>

흠...

select deposit_date from sequence order by id desc limit 1;

마지막행선택함.

이렇게  마지막 행의 날짜를 선택하고 거기에 한달씩 더해주면 되지 않을까?

 


select date_add(deposit_date,INTERVAL 1 MONTH) from sequence where  deposit_date order by id desc limit 1;

오 됐다

한달 추가하겠다 마지막행으로 찾은 날짜에

 

 

 

 

 

ㅇㄴㄹㄴ

 

오됐다

 

 

INSERT INTO sequence (deposit_date,interest_amountselect date_add((select deposit_date from sequence where  deposit_date order by id desc limit 1),INTERVAL 1 MONTH),(select deposit_amount from sequence where id='1')* 0.04 /12;

 

 

 

 

<종합해보면>

 

SELECT * FROM test.sequence;
use test;
insert into sequence (name,deposit_date,deposit_amount) values ('이소윤','20200509','10000000');

 

INSERT INTO sequence (deposit_date,interest_amount) select date_add((select deposit_date from sequence where  deposit_date order by id desc limit 1),INTERVAL 1 MONTH),(select deposit_amount from sequence where id='1')* 0.04 /12;

 

<7차시도>

아 이름도 같이 들어가게끔

INSERT INTO sequence (name, deposit_date,interest_amount) 
select (select name from sequence order by id desc limit 1) ,date_add((select deposit_date from sequence where  deposit_date order by id desc limit 1),INTERVAL 1 MONTH),
(select deposit_amount from sequence where id='1')* 0.04 /12 ;

 

 

<결과>

 

 

use test;
insert into sequence (name,deposit_date,deposit_amount) values ('이소윤','20200509','10000000');
INSERT INTO sequence (name, deposit_date,interest_amount) 
select (select name from sequence order by id desc limit 1) ,date_add((select deposit_date from sequence where  deposit_date order by id desc limit 1),INTERVAL 1 MONTH),
(select deposit_amount from sequence where id='1')* 0.04 /12 ;

근데 식이 너무 더러운데..

다시 정리해보자~

728x90
728x90

axios는

지원하는 브라우저가 더 많고 

에러핸들링이 좋고

자동으로 데이터가 json형태로 되어 넘어간다

Automatic JSON data transformation

As we saw earlier, Axios automatically stringifies the data when sending requests (though you can override the default behavior and define a different transformation mechanism). When using fetch(), however, you’d have to do it manually.

Compare:

// axios
axios.get('https://api.github.com/orgs/axios')
  .then(response => {
    console.log(response.data);
  }, error => {
    console.log(error);
  });

// fetch()
fetch('https://api.github.com/orgs/axios')
  .then(response => response.json())    // one extra step
  .then(data => {
    console.log(data) 
  })
  .catch(error => console.error(error));

fetch는 직접 json화를 해줘야하지만

지원하는 브라우저 문제 등을 충분히  해결할 수 있다.

 

 

결론

Axios는 대부분의 HTTP통신 요구사항을 위해 컴팩트 패키지로 사용하기 쉬운 API를 제공한다.

하지만 fetch()메소드를 사용해서도 Axios 라이브러리의 주요기능을 완벽하게 재현할 수 있다.

는 글

https://blog.logrocket.com/axios-vs-fetch-best-http-requests/

 

Axios vs. fetch(): Which is best for making HTTP requests? - LogRocket Blog

Axios is not always an ideal solution; depending on your needs, there are sometimes better options for making HTTP requests. The Fetch API is one of them.

blog.logrocket.com

 

728x90
728x90

https://stepby-yun.tistory.com/181

 

지난시간,,,

 

 

 

 

바디파서 해봐도 (express로 사용) 안되고 무한히 헤매었다

한번에 저장안하고 따로 할까 싶어서 마이페이지 만들어서 뺐다가 

생각해보니 해당 id에 프로필을 저장하는거라서 더 복잡해지겠다 싶었다(프로필 수정도 만들 때 그거 해야겠지만..)

어쨌든 같은 데이터 행에 넣어줘야하니까.

 

 

방법은 여러가지 있겠지만 내가 찾은 거는 

formdata.append로 아이디랑 유저도 저장하는 방법이었다.

(method) FormData.append(name: string, value: string | Blob, fileName?: string): void

append(키, 값) 

이란 거는 알았는데 multer쓰면서 

upload.single(키) 값과 같아야된대서 

 

이미지 아닌 아이디와 비번은 좀 다른 줄 알았다. (multer사용한 이미지는 req.body로 가져오는 것도 아니어서 좀 실제로 다르기도 함)

 

해당하는 키값을 

req.body.키값

으로 찍어보니 나왔다. 

 

req.body가 잘나오는게 append로 넣어줘서 그런건가..?

(바디파서 빼봐도 잘나옴)

 

 

req만 콘솔로 찍어보니 엄청 길게 나오는데 그중에 body랑 file이 보이네

 

 

 

 

 

 

으어 한번에 user정보랑 이미지경로 저장성공

 

react 프론트 코드

import React, { useState } from "react";
import Axios from "axios";
import "./signup.css";

function Signup() {
  //회원가입 값
  const [id, setId] = useState("");
  const [password, setPassword] = useState("");

  // const [imageUpload, setImageUpload] = useState(null);

  const [image, setImage] = useState({
    preview:
      "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAM1BMVEXk5ueutLfn6eqrsbTp6+zg4uOwtrnJzc/j5earsbW0uby4vcDQ09XGyszU19jd3+G/xMamCvwDAAAFLklEQVR4nO2d2bLbIAxAbYE3sDH//7WFbPfexG4MiCAcnWmnrzkjIRaD2jQMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMw5wQkHJczewxZh2lhNK/CBOQo1n0JIT74/H/qMV0Z7GU3aCcVPuEE1XDCtVLAhgtpme7H0s1N1U7QjO0L8F7llzGeh1hEG/8Lo7TUmmuSrOfns9xnGXpXxsONPpA/B6OqqstjC6Ax/0ujkNdYQQbKNi2k64qiiEZ+ohi35X+2YcZw/WujmslYewiAliVYrxgJYrdwUmwXsU+RdApUi83oNIE27YvrfB/ZPg8+BJETXnqh9CVzBbTQHgojgiCvtqU9thFJg/CKz3VIMKMEkIXxIWqIpIg2SkjYj+xC816mrJae2aiWGykxRNsW0UwiJghJDljYI5CD8GRiCtIsJxizYUPQ2pzItZy5pcisTRdk/a9m4amtNNfBuQkdVhSaYqfpNTSFGfb9GRIakrE2Pm+GFLaCQPqiu0OpWP+HMPQQcgQMiQprWXNmsVwIjQjYi/ZrhAqNTCgr2gu0Jnz85RSSjso0HkMFZ0YZjKkc26a/jlmh9JiDyDxi9oeorTYAzZkwwoMz19pzj9bnH/GP/+qbchjSGflneWYhtTuKdMOmNKZcJ5TjInQKcYXnESd/jQxy0ENpULTNGOGgxpap/oyw9pbUAqhfx2Dbkhovvfgz4iUzoM9+GlK6/Mh4q29hyC1mwro30hpVVLPF9wYQr71RazOeM5/cw81iBRD+A03aM9/C/obbrKjbYSpCmIVG3qT/Q8oeUo3Rz0IL7vI1tEbCB9pSiu8I/aV8x3Kg/BGWrWp4ZVs0nZfmAoEG4h/61yHYIJiFSl6Q0Vk6tTW1N8kYp8hdOkfHYYMXd2Qft+8CYwqYDSKvqIh+MCF8Wgca2u/cwdgeW3TtuVn6+1oBs3yLo5C2JpK6CvQzGpfUkz9UG/87gCsi5o2LIXolxN0FbwAsjOLEr+YJmXn7iR6N0BCt5p5cMxm7eAsfS+/CACQf4CTpKjzgkvr2cVarVTf96372yut7XLJ1sa7lv6VcfgYrWaxqr3Wlo1S6pvStr22sxOtTNPLzdY3nj20bPP+ejFdJYkLsjGLdtPBEbe/mr2bQKiXWJDroA+vtzc0p9aahuwqHMDYrQEXHEw9jwQl3drMpts9JBU1SdktPe5FBRdJQ6bwXBpa57ib2A8kukQDzMjh++Uo7Fo6Wd02Pkf4fknqoo4HtvAIjsqUcjx6DIPgWCaOML9rKI/oqD9/lgNrn+eF+p7j8tnzHBiR7+kdUGw/+V1Kzkc75mMy6U+FMaxjPibiM1U1uGM+puInHpmALZCgP4pt7i840MV8+0R1zPsRB6UTcqpizncYwZ89syDydfyWCwXB1l8/zRNGWbTG/GHKUm9AkxHMc/EGSk3z2+ArEhPEV5TUBLEvUGFcjEUH80J/jveTGOAJEljJbILWGQT3zRYiwuKsUXN1EEJAzBhRJFll7mBUG7KD8EqPkKekBREaL8hMDZLQSG6AQjtHPYmvTQnX0TtpC1SYCe2YdkkyLP3jj5BSbKiuR585eQhTgoje6yIb0Yb0C+mV6EYvebqw5SDy2WmubogZiF2AVxPC2FpDf8H2Q9QWo6IkjUxTWVEI3WY/wrCeSuqJ+eRWzXR/JXwgVjUMozbCOfoEZiSiKVGepqv5CJ8RyR4D7xBeamqa7z3BJ/z17JxuBPdv93d/a2Ki878MMAzDMAzDMAzDMAzDMF/KP09VUmxBAiI3AAAAAElFTkSuQmCC",
    data: "",
    // Headers: " 'Content-Type': 'multipart/form-data'",
  });

  //다 userlist에 담아서 db저장하기
  // const [userList, setUserList] = useState([]);

  const onChangeId = (event) => {
    setId(event.target.value);
  };

  const onChagePassword = (event) => {
    setPassword(event.target.value);
  };

  const Submit = (e) => {
    e.preventDefault();

    let formData = new FormData();
    formData.append("file", image.data);

    formData.append("iddd", id);
    formData.append("password", password);

    console.log(image.data, "선택한이미지! ");
    console.log(formData, "들어가기전폼데이터");

    Axios.post(
      "http://localhost:3001/submit",

      // {
      //   id: id,
      //   password: password,
      // },

      formData,

      {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      }
    ).then(() =>
      console.log(
        formData,
        "then이후 폼데이터",
        image,
        "이건뭐",
        image.data,
        "이미지데이터"
      )
    );
  };

  const handleFileChange = (e) => {
    const img = {
      preview: URL.createObjectURL(e.target.files[0]),
      data: e.target.files[0],
    };

    setImage(img);
  };

  return (
    <div className="formBox">
      <div className="signup_id">
        <input placeholder="아이디" onChange={onChangeId}></input>
      </div>
      <div className="signup_password">
        <input placeholder="비밀번호" onChange={onChagePassword}></input>
      </div>
      <div>
        <input placeholder="비밀번호 확인"></input>
      </div>
      {image.preview && <img src={image.preview} width="100" height="100" />}
      <input
        type="file"
        onChange={handleFileChange}
        name="Images"
        accept="Images/*"
      />

      <button onClick={Submit}>제출</button>
    </div>
  );
}

export default Signup;

 

백 코드

 

const express = require("express");
const app = express();

const mysql = require("mysql");
const cors = require("cors");
const multer = require("multer");
const path = require("path");
app.use(cors());

//이거 필요한거임?
// app.use(express.static("Images"));

const db = mysql.createConnection({
  user: "*",
  host: "*",
  password: "*",
  database: "*",
});

///////

const upload = multer({
  storage: multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, "Images/");
    },
    filename: function (req, file, cb) {
      cb(null, new Date().valueOf() + path.extname(file.originalname));
    },
  }),
});

app.post("/submit", upload.single("file"), (req, res) => {
  // console.log(req.body.posts, "레큐바디");
  console.log(JSON.stringify(req.body), "JSON.stringify(req.body)");
  console.log(req.body, "바디");

  const profile = req.file.path;
  const id = req.body.iddd;
  const password = req.body.password;

  console.log(id, password, "아이디랑 패스워드");

  console.log(req.file, "파일");
  console.log(profile, "프로파일");

  console.log(profile, "프로필 들어갈 정보");

  db.query(
    "INSERT INTO userlist (userId,userPassword,userProfile) VALUES (?,?,?) ",
    [id, password, profile],

    (err, result) => {
      if (err) {
        console.log(err, "실패ㅠㅠㅠ");
      } else {
        res.send("userlist values inserted");
        // console.log("성공~");
      }
    }
  );
});

app.listen(3001, () => {
  console.log("your server is running on 3001~! yeah");
});

 

 

 

이제 

유효성검사

비밀번호 암호화 해봐야지..

 

아 그전에 데이터 삭제부터하자

 

 

 

 

https://limdef.tistory.com/m/7

728x90
728x90

지난시간,,

https://stepby-yun.tistory.com/180

 

[mySQL 이미지 저장] BLOB말고 문자열로 하는 이유 (+string문자열 VAR / CHAR 차이)

지난 시간,,, https://stepby-yun.tistory.com/179 formData 이미지데이터 보내고 받기 (react,nodejs,header) 회원가입시 아이디 비번 프로필을 등록하려했다. id password는 넘겨주고 req.body.id로 받았는데 프..

stepby-yun.tistory.com

db에 이미지 저장까지 마쳤다.

formData로 이미지를 받았다.

이미지를 불러오는걸 하기 전에

id와 password도 함께 보내는 걸 하고 싶다.

 

formData를 쓰면 req.body를 쓸 수 없고id, password는 req.body로 받아와야하니 분리해야하나 싶었는데 역시나 방법이 있었어

 

 

 참조

<form> 파일, 텍스트 </form> 다 가져오고싶은데

  • 파일업로드 미들웨어의 필수조건인 <form enctype="multipart/form-data">을 쓰면 req.body를 undefined로 받고
  • 그렇다고 req.body를 받기위해 <form enctype="multipart/form-data">를 안쓰면 express-fileuplode나 multer를 못쓴다.

 

bodyParser를 쓰면 된다고 함 (팀플할때 무지성으로 썼는데 혼자하니 이렇게 깨닫는구나 역시 왜 쓰는지 생각해봐야함)

 

 

 

파싱이란 HTML 형식으로 사용자가 제출한 데이터에 접근하는 것을 의미합니다. 'GET' 방식으로 폼을 제출하면 '쿼리 문자열'에 데이터가 추가되어 쉽게 접근할 수 있지만 'POST' 방식으로 폼을 제출하면 데이터에 접근하기가 다소 어렵습니다. 보안을 위해 인코딩되었습니다. 데이터를 매우 쉽게 파싱할 수 있는 바디 파서 NPM 방법이 있지만 이 파싱 방법을 처음부터 구현하려고 하면 몇 가지 단계가 필요합니다.

 

Parsing means accessing the data submitted by user with HTML form. When the form is submitted with the ‘GET’ method, data are appended in ‘query string’ and can access easily but when a form is submitted using the ‘POST’ method, it is somewhat difficult to get access over those data since they are encoded because of security purpose. 
There exist a body-parser NPM method that makes it very easy to parse the data but if we try to implement this parsing method from scratch, there’s involve some steps.

 

 

근데 드는 의문이

bodyParser쓰면 multer지금 쓰고 있는거 필요없는거 아닌가?

걔도 미들웨어... 둘다 쓰는건가..

 

어라라 찾아보니까

하지만, express 버전 4.16이상 부터는 'express bodyparser deprecated ( bodyParser는 더이상 지원되지 않습니다.)' 와 같은 문제가 발생한다.

그 이유는, 4.16버전 이상 부터는 express 내부에 bodyParser가 포함되기 때문이다.

라고 한다.

 

 

- app.use(express.bodyParser())
+ app.use(express.json())
+ app.use(express.urlencoded())

이렇게 바디파서 대신 밑에 두줄을 쓴다는 건데...뭔지 잘모르겠는데요

 

 

 

 

일단 코드 추가하고 실행해보니 

일단 body-parser 모듈을 사용할 때 아무 옵션을 주지 않는 다면
body-parser deprecated undefined extended: provide extended option 같은 문구가 뜬다.

 

bodyParser 미들웨어의 여러 옵션 중에 하나로 false 값일 시 node.js에 기본으로 내장된 queryString, true 값일 시 따로 설치가 필요한 npm qs 라이브러리를 사용한다.

queryString 과 qs 라이브러리 둘 다 url 쿼리 스트링을 파싱해주는 같은 맥락에 있으나 qs가 추가적인 보안이 가능한 말 그대로 extended 확장된 형태이다.
기본이 true 값이니 qs 모듈을 설치하지 않는다면 아래와 같이 false 값으로 따로 설정을 해주어야 한다.

 

오 그렇군요 감사합니다

그래도 아직 req.body는 아무것도 안들어온다

이미지만 들어오고 흠흠

 

 

 

보낼때 id랑 password추가하면 body값만 찍히고 

이미지는 안되고...

 

 

라는데 왜...안되지..

https://blog.naver.com/bunggl/221699257359

 

 

이미지 넣은 것처럼 id랑 password도 formdata에 넣어봄

 

'id,password'이렇게 한 배열로 들어가서 안됨

 

 

 

https://hyc7575.github.io/2017/05/24/2017-05-24-node-js-bodyparserAndMulter/

 

Node.js(express) - body-parser와 multer

Node.js에서 form양식을 submit을 하기위해 사용되는 body-parser와 multer 미들웨어에 대해서 간단하게 알아보려 합니다. 각 미들웨어의 용도를 짧게 소개하면 body-parser는 라우터와 미들웨어 예제때 언급

hyc7575.github.io

 

https://kirkim.github.io/javascript/2021/10/16/body_parser.html

 

[NodeJs] express.json()과 express.urlencoded()의 차이점 알아보기

1️⃣ 사용이유 (1) .json()과 .urlencoded()를 사용하지 않을 때

kirkim.github.io

 

 

 

 

 

 

 

res.json/res.send차이https://haeguri.github.io/2018/12/30/compare-response-json-send-func/

출처

res.json

https://jin2rang.tistory.com/entry/express-bodyparser-deprecated-bodyparser%EB%8A%94-%EB%8D%94%EC%9D%B4%EC%83%81-%EC%82%AC%EC%9A%A9%EB%90%98%EC%A7%80-%EC%95%8A%EC%8A%B5%EB%8B%88%EB%8B%A4-%EB%AC%B8%EC%A0%9C%ED%95%B4%EA%B2%B0

 

https://velog.io/@hyunju-song/body-parser%EC%9D%98-urlencoded%EB%8A%94-%EB%8F%84%EB%8C%80%EC%B2%B4-%EC%96%B4%EB%96%A4-%EC%97%AD%ED%95%A0%EC%9D%84-%ED%95%98%EB%8A%94-%EA%B1%B8%EA%B9%8C

++

바디파서써서 req.body랑 이미지 파일 전송하기 

https://velog.io/@yuna_song/enctypemultipartform-data-%EC%82%AC%EC%9A%A9-%EC%8B%9C-req.body-%EC%82%AC%EC%9A%A9%EB%B2%95

formData 객체전송

https://melius.tistory.com/51

728x90
728x90

지난 시간,,,

https://stepby-yun.tistory.com/179

 

formData 이미지데이터 보내고 받기 (react,nodejs,header)

회원가입시 아이디 비번 프로필을 등록하려했다. id password는 넘겨주고 req.body.id로 받았는데 프로필은 formData 객체로 묶어서 그자체로 넘겨줬는데 자꾸 undefined 떴다. formData는 req.body가 안된다길

stepby-yun.tistory.com

formData 로 이미지 받는 걸 Header를 뒤늦게 추가해서 넣었다.

이제 mySQL 데이터베이스에 넣으려는데

아무것도 없고  BLOB만 달랑 저장됨

이미지 저장은 보통 BLOB로 한다고 해서 타입을 이렇게 넣었는데 

저렇게만 보이니 당황,, 

 

 

BLOB은 뭘까?

A Binary Large Object (BLOB) is a MySQL data type that can store binary data such as images, multimedia, and PDF files.

바이너리 데이터를 DB외부에 저장하기 위한 타입이다

"blob의 경우 4GB의 이진 데이터를 저장할 수 있다고 합니다. 하지만 이건 DB에 직접 저장하는 것이 아니라 DB에는 Large Object의 위치 포인터만 저장하게 됩니다."

그말은 즉, 컴퓨터가 인식하는 모든 파일(이진 데이터)를 저장하는 타입이라고 한다. 오 찾아보니까 볼 수 있긴하네

이렇게 확인할 수는 있구만 

 

 

하지만 BLOB보다는 URL자체로 저장을 선호한다고 한다.

그 이유는데이터베이스 서버는 애플리케이션이 확장될 때 종종 성능병목 현상이 일어나는데 이미지와 함께 로드하면 더 큰 병목현상이 발생한다고 함.

Many web app designers don't store images in database BLOBS, but rather store them in a file system, and store their URLs in database strings. Why? Database servers often become a performance bottleneck when an application scales up. If you load them with images, they'll become even bigger bottlenecks.

 

그럼 string문자열로 바꿔줘야지~

하고 string찾는데 없어 아 맞다 VAR이지하고 보다가

 

VARCHAR과 CHAR의 차이가 뭔가 궁금해졌다

VARCHAR은 '가변길이'

실질적인 데이터와 길이 정보도 같이 저장된다.

CHAR은 길이가 고정되어있어야한다. 남는 공간은 공백으로 채운다 공간낭비 발생!

VARCHAR is variable length, while CHAR is fixed length

https://petri.com/sql-server-string-data-types/

 

 

 

경로저장함

 

 

 

이제 id랑 password 도 함께 저장해봐야지 

 

 

 

 

 

 

출처

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=magnking&logNo=220950061851

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=rlasksdud53&logNo=220595010315

 

 

728x90
728x90

회원가입시

아이디 비번

프로필을 등록하려했다.

 

id password는 

넘겨주고 req.body.id로 받았는데 

프로필은 formData 객체로 묶어서 

그자체로 넘겨줬는데 자꾸 undefined 떴다. 

 

formData는 req.body가 안된다길래 

 

 

 

multer을 써봤는데도 안됨

(req.body대신 req.file 또는 files를 찍어봤지만 안됐다. )

 

formData쓸때 헤더에 타입을 넣어줘야한대서 

 

뒤늦게 

  {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      }

를 추가했다. 위치는 보내는 formdata 다음에 넣어줬다.

 

이걸로도 해결이 안됐는데 신기하게 

같이보낸 id, password를 지우니 

undefined가 안뜨고 이미지가 전송돼서 images폴더에 이미지도 담겼다!

 

req.file에 이미지url이 찍혔다.

 

import React, { useState } from "react";
import Axios from "axios";
import "./signup.css";
import FormData from "form-data";

function Signup() {
  //회원가입 값
  const [id, setId] = useState("");
  const [password, setPassword] = useState("");

  // const [imageUpload, setImageUpload] = useState(null);

  const [image, setImage] = useState({
    preview:
      "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAM1BMVEXk5ueutLfn6eqrsbTp6+zg4uOwtrnJzc/j5earsbW0uby4vcDQ09XGyszU19jd3+G/xMamCvwDAAAFLklEQVR4nO2d2bLbIAxAbYE3sDH//7WFbPfexG4MiCAcnWmnrzkjIRaD2jQMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMw5wQkHJczewxZh2lhNK/CBOQo1n0JIT74/H/qMV0Z7GU3aCcVPuEE1XDCtVLAhgtpme7H0s1N1U7QjO0L8F7llzGeh1hEG/8Lo7TUmmuSrOfns9xnGXpXxsONPpA/B6OqqstjC6Ax/0ujkNdYQQbKNi2k64qiiEZ+ohi35X+2YcZw/WujmslYewiAliVYrxgJYrdwUmwXsU+RdApUi83oNIE27YvrfB/ZPg8+BJETXnqh9CVzBbTQHgojgiCvtqU9thFJg/CKz3VIMKMEkIXxIWqIpIg2SkjYj+xC816mrJae2aiWGykxRNsW0UwiJghJDljYI5CD8GRiCtIsJxizYUPQ2pzItZy5pcisTRdk/a9m4amtNNfBuQkdVhSaYqfpNTSFGfb9GRIakrE2Pm+GFLaCQPqiu0OpWP+HMPQQcgQMiQprWXNmsVwIjQjYi/ZrhAqNTCgr2gu0Jnz85RSSjso0HkMFZ0YZjKkc26a/jlmh9JiDyDxi9oeorTYAzZkwwoMz19pzj9bnH/GP/+qbchjSGflneWYhtTuKdMOmNKZcJ5TjInQKcYXnESd/jQxy0ENpULTNGOGgxpap/oyw9pbUAqhfx2Dbkhovvfgz4iUzoM9+GlK6/Mh4q29hyC1mwro30hpVVLPF9wYQr71RazOeM5/cw81iBRD+A03aM9/C/obbrKjbYSpCmIVG3qT/Q8oeUo3Rz0IL7vI1tEbCB9pSiu8I/aV8x3Kg/BGWrWp4ZVs0nZfmAoEG4h/61yHYIJiFSl6Q0Vk6tTW1N8kYp8hdOkfHYYMXd2Qft+8CYwqYDSKvqIh+MCF8Wgca2u/cwdgeW3TtuVn6+1oBs3yLo5C2JpK6CvQzGpfUkz9UG/87gCsi5o2LIXolxN0FbwAsjOLEr+YJmXn7iR6N0BCt5p5cMxm7eAsfS+/CACQf4CTpKjzgkvr2cVarVTf96372yut7XLJ1sa7lv6VcfgYrWaxqr3Wlo1S6pvStr22sxOtTNPLzdY3nj20bPP+ejFdJYkLsjGLdtPBEbe/mr2bQKiXWJDroA+vtzc0p9aahuwqHMDYrQEXHEw9jwQl3drMpts9JBU1SdktPe5FBRdJQ6bwXBpa57ib2A8kukQDzMjh++Uo7Fo6Wd02Pkf4fknqoo4HtvAIjsqUcjx6DIPgWCaOML9rKI/oqD9/lgNrn+eF+p7j8tnzHBiR7+kdUGw/+V1Kzkc75mMy6U+FMaxjPibiM1U1uGM+puInHpmALZCgP4pt7i840MV8+0R1zPsRB6UTcqpizncYwZ89syDydfyWCwXB1l8/zRNGWbTG/GHKUm9AkxHMc/EGSk3z2+ArEhPEV5TUBLEvUGFcjEUH80J/jveTGOAJEljJbILWGQT3zRYiwuKsUXN1EEJAzBhRJFll7mBUG7KD8EqPkKekBREaL8hMDZLQSG6AQjtHPYmvTQnX0TtpC1SYCe2YdkkyLP3jj5BSbKiuR585eQhTgoje6yIb0Yb0C+mV6EYvebqw5SDy2WmubogZiF2AVxPC2FpDf8H2Q9QWo6IkjUxTWVEI3WY/wrCeSuqJ+eRWzXR/JXwgVjUMozbCOfoEZiSiKVGepqv5CJ8RyR4D7xBeamqa7z3BJ/z17JxuBPdv93d/a2Ki878MMAzDMAzDMAzDMAzDMF/KP09VUmxBAiI3AAAAAElFTkSuQmCC",
    data: "",
    // Headers: " 'Content-Type': 'multipart/form-data'",
  });

  //다 userlist에 담아서 db저장하기
  // const [userList, setUserList] = useState([]);

  const onChangeId = (event) => {
    setId(event.target.value);
  };

  const onChagePassword = (event) => {
    setPassword(event.target.value);
  };

  const Submit = (e) => {
    e.preventDefault();

    let formData = new FormData();
    formData.append("file", image.data);

    console.log(image.data, "선택한이미지! ");
    console.log(formData, "들어가기전폼데이터");

    Axios.post(
      "http://localhost:3001/submit",

      // {
      //   id: id,
      //   password: password,
      //   formData,
      //   headers: { "Content-Type": "application/x-www-form-urlencoded" },
      // }
      // {
      //   id: id,
      //   password: password,
      // },

      formData,

      {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      }
    ).then(() =>
      console.log(
        formData,
        "then이후 폼데이터",
        image,
        "이건뭐",
        image.data,
        "이미지데이터"
      )
    );
  };

  const handleFileChange = (e) => {
    const img = {
      preview: URL.createObjectURL(e.target.files[0]),
      data: e.target.files[0],
    };

    setImage(img);
  };

  return (
    <div className="formBox">
      <div className="signup_id">
        <input placeholder="아이디" onChange={onChangeId}></input>
      </div>
      <div className="signup_password">
        <input placeholder="비밀번호" onChange={onChagePassword}></input>
      </div>
      <div>
        <input placeholder="비밀번호 확인"></input>
      </div>
      {image.preview && <img src={image.preview} width="100" height="100" />}
      <input
        type="file"
        onChange={handleFileChange}
        name="Images"
        accept="Images/*"
      />

      <button onClick={Submit}>제출</button>
    </div>
  );
}

export default Signup;

 

 

 

const express = require("express");
const app = express();

const mysql = require("mysql");
const cors = require("cors");
const multer = require("multer");
const path = require("path");
app.use(cors());

app.use(express.json());
//이거 필요한거임?
app.use(express.static("Images"));

const db = mysql.createConnection({
  user: "*",
  host: "*",
  password: "*",
  database: "*",
});

const upload = multer({
  storage: multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, "Images/");
    },
    filename: function (req, file, cb) {
      cb(null, new Date().valueOf() + path.extname(file.originalname));
    },
  }),
});
// const upload = multer({
//   dest: "Images/",
//   limits: { fileSize: 5 * 1024 * 1024 },
// });

// app.post("/up", upload.array("img"), (req, res) => {
//   console.log(req.files);
// });

app.post("/submit", upload.single("file"), (req, res) => {
  console.log(req.files, "레큐파일ㄴ");
  console.log(req.body, "레큐바디");
  // console.log(req.body, "레큐바디");
  // const id = req.body.id;
  // const password = req.body.password;
  const profile = req.file;

  console.log(req.file, "파일");
  // res.json({ url: `/img/${req.file.filename}` });
  // FormData의 경우 req로 부터 데이터를 얻을수 없다.
  // upload 핸들러(multer)를 통해서 데이터를 읽을 수 있다

  //   function insertRecord(req, res) {
  // req.files.forEach((e) => {
  // // console.log(e.filename);
  // // });
  // console.log(req.file, "파일");
  // console.log(profile, "이미지");

  db.query(
    "INSERT INTO userlist (userProfile) VALUES (?) ",
    [profile],
    (err, result) => {
      if (err) {
        console.log(err);
      } else {
        res.send("userlist values inserted");
      }
    }
  );
});

app.listen(3001, () => {
  console.log("your server is running on 3001~! yeah");
});

 

문제는 id랑 password를 빼고 보내서 그런지 

 

Error: ER_WRONG_VALUE_COUNT_ON_ROW: Column count doesn't match value count at row 1

오류: ER_WRONG_VALUE_COUNT_ON_ROW: 열 개수가 행 1의 값 개수와 일치하지 않습니다.

이게 뜬다

 

아직 db저장도 안됐고 해결안된게 많지만 이미지를 받아서 행복함...

id랑 password를 같이 받으면 왜 undefined로 뜨는걸까?

따로 해야되는것인가..

 

 

 

아무튼 

header의 역할 ,context Type에 대해 공부하고

https://jw910911.tistory.com/117

formData(json으로 변환하라는 얘기도 있던데...나는 그거 안되던데..왜지?), multer

에 대해 더 공부하고 정리해봐야겠다.

+

app/router차이도 헷갈리니까 확인해놓자.

http://expressjs.com/ko/guide/routing.html

express가져와서 app으로 선언해서 썼는데 검색하다가 코드보면 express.router로 쓰는 게 무슨 차인가 싶어서..

728x90
728x90

scoop는 설치 프로그램

scoop로 설치한 프로그램은 scoop update *로 한번에 업데이트할 수 있음

 

 

파워셸에서 관리자 메뉴로 실행

Set-ExecutionPolicy RemoteSigned -scope CurrentUser

A-예 로 응답.

$env:SCOOP='C:\Scoop'

"환경변수 편집" 검색

새로 만들기 눌러서

변수이름 SCOOP

변수값 C:\Scoop

로 하고

 

다음명령어 실행했는데

 

계속 이 에러 떴음

Running the installer as administrator is disabled by default, see https://github.com/ScoopInstaller/Install#for-admin for details. 

 

(결국 환경변수 편집한거 삭제해봤는데 그게 문제는 아니었음. 하지만 다음 진행하다보니 삭제한 상태에서 깔아버린 나.. 사용자 안에 C:\안에 scoop가 생겼더라고)

 

해결)

관리자모드였던 창 끄고 새로운 power shell 창에서 실행했다

 

iex (new-object net.webclient).downloadstring('https://get.scoop.sh')

node 설치   (-> 이미 설치되어있어서 스킵)

LTS버전이 바람직하다고 함 리액트 네이티브 개발은 Nodejs버전에 영향을 받기 때문에!

에러 나면 나도 다시 깔아야지..

 

scoop install nodejs-lts
node -v

git 설치 -> 이미 설치되어있는데 무심코 깔아버린 나

scoop install git

 

자바8설치

리액트 네이티브 사용해서 안드로이드 앱만들려면 안드로이드 SDK빌드 도구가 필요하다. 근데 앱이 동작하는 안드로이드폰의 운영체제는 자바버전8이다. 자바버전8JDK 설치해야한다

scoop bucket add java

scoop install adopt8-hotspot

에러 뜸 ) Couldn't find manifest for 'adopt8-hotspot'.

자바버전 체크도 안됨

 

해결)

scoop install temurin8-jdk

버전 체크

java -version

 

 

비주얼 스튜디오도 깔려 있어서 넘어가고 

안깔려있따면 이거 하기

더보기

 (이제보니까 여기서 버킷을 하고 했으면 다음에 문제 없었겠구만!)

scoop bucket add extras
scoop install vscode

 

 

 

안드로이드 스튜디오와 개발도구인 안드로이드 SDK 설치할거야

scoop install android-studio android-sdk

에러) Couldn't find manifest for 'android-sdk'.

 

해결 )

scoop bucket add extras

 

다시 설치 실행

scoop install android-studio android-sdk

 

근데 스튜디오는 중간에 끊김..

다시 설치~

scoop install android-studio

 

 

휴~~

 

<에러에  도움 준 글>

https://www.pabburi.co.kr/content/javascript/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EB%B0%98-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EC%9C%88%EB%8F%84%EC%9A%B010-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95/

 

728x90
728x90

노마드코더 강의 보는중

 

리액트 네이티브는 브라우저가 없음, 웹사이트가 아니야!

 

앱개발하는데 필요한 java 등등 깔아줄게 많음

 

그래서 강의에서는 네이티브 코드 바로 시작할 수 있게 expo 써서 한다.

핸드폰에 expo앱깔면 연동으로 보이네 신기하다

(expo 설치 내용 https://docs.expo.dev/)

 

( https://snack.expo.dev/ 여기서 작업하면 visual studio도 필요없고 node, npm 설치 안했어도 바로 테스트할 수 있음)

 

 

리액트 네이티브는 웹사이트가 아님!

HTML이 아니기 때문에 div쓸 수 없음

대신에 view를 씀 얘는 container컨테이너다 (react Native에서 import해와야 쓸 수 있음!)

(The most fundamental component for building UI, View is a container that supports layout with flexbox, style, some touch handling,,,)

 

react native에 있는 모든 텍스트는 text component안에 들어가야한다

border css는 사용불가능하다

 

처음에 react Native는 많은 컴포넌트와 API를 지원했는데 버그많고 비효율적이어서 

빠르게 만드는데 초첨맞추고 두 개를 축소시킴

 

(components와 API의 차이는 무엇인가?>

components는 화면에 렌더링할 항목이다

API는 (운영체제와 소통하는) 자바스크립트 코드이다)

 

reactNative 커뮤니티에서 쓸 수도 있지만

expo가 우리에게 필요한 Package를 제공한다.  https://docs.expo.dev/versions/v44.0.0/sdk/async-storage/

 

여기서는 이미 container View가 Flew container다

모바일에서는 Flex direction 기본값이 colum(열-세로)

(원래 웹에서는 Flex direction 기본값이 Row(행-가로) 였음)

 

레이아웃에서 대부분 width, height안씀. 반응형 페이지 생각해야함!!! 매번화면 달라지는데말여

React Native에서는 flex 비율로 레이아웃 채워서 씀

 

 

 

728x90
728x90

결론>

헤더와 푸터를 만들기 위해서 컴포넌트를 만들었는데

헤더랑 푸터 스크립트 안에 또 <Header/>로 컴포넌트 부르고 있어서 그랬다.

 

 

삽질>

캐시 지우고 

 

컴퓨터 고급 설정으로 메모리 더 사용하게 바꾸고

 

더 큰 메모리 할당하는 방법, 옵션 주는 것도 해봤는데 안됐다. 

 

728x90
728x90

따라하면서

순서, 필요한 내용 적기 

<이 순간, 최고의 강의_별점 백개 드립니다_>

https://www.youtube.com/watch?v=re3OIOr9dJI 

 

client -react 프론트

server -express, 백단

 

client/ npx create-react-app .

(.은 현재 위치를 의미함)

server/ npm init 

해서 package.json 생성하고

필요한 

mysql express 

설치

 

client/

Login.js

import { useState } from "react";
import "./login.css";

function Login() {
  const [name, setName] = useState("");
  const [age, setAge] = useState(0);
  const [country, setCountry] = useState("");
  const [position, setPosition] = useState("");
  const [wage, setWage] = useState(0);

  const onChangefun = (event) => {
    setName(event.target.value);
    console.log(event.target.value);
  };
  return (
    <div className="login">
      <div className="information">
        <label>Name : </label>
        <input type="text" onChange={onChangefun}></input>
        <label>Age : </label>
        <input
          type="number"
          onChange={(event) => {
            setAge(event.target.value);
          }}
        ></input>
        <label>Country : </label>
        <input
          type="text"
          onChange={(event) => {
            setCountry(event.target.value);
          }}
        ></input>
        <label>Position : </label>
        <input
          type="text"
          onChange={(event) => {
            setPosition(event.target.value);
          }}
        ></input>
        <label>Wage: </label>
        <input
          type="number"
          onChange={(event) => {
            setWage(event.target.value);
          }}
        ></input>
        <button>직원 등록</button>
      </div>
    </div>
  );
}

export default Login;

 

server/

index.js

const express = require("express");
const app = express();

app.listen(3001, () => {
  console.log("your server is running on 3001~! yeah");
});

 

이제 mysql 설정해줄거임

 

mysql 워크벤치에서 

스키마 생성

테이블 생성

server/

디비저장 코드 입력

 

const express = require("express");
const app = express();
const mysql = require("mysql");

const db = mysql.createConnection({
  user: "root",
  host: "localhost",
  password: "비밀번호",
  database: "crudtest",
});

app.post("/create", (req, res) => {
  const name = req.body.frontname;
  const age = req.body.frontage;
  const country = req.body.frontcountry;
  const position = req.body.frontposition;
  const wage = req.body.frontwage;

  db.query(
    "INSERT INTO employees (name, age, country, position, wage) VALUES (?,?,?,?,?)",
    [name, age, country, position, wage],
    //콜백함수
    (err, result) => {
      if (err) {
        console.log(err);
      } else {
        res.send("values Inserted");
      }
    }
  );
});

app.listen(3001, () => {
  console.log("your server is running on 3001~! yeah");
});

client/

import { useState } from "react";
import "./login.css";
import Axios from "axios";

function Login() {
  const [name, setName] = useState("");
  const [age, setAge] = useState(0);
  const [country, setCountry] = useState("");
  const [position, setPosition] = useState("");
  const [wage, setWage] = useState(0);

  const addEmployee = () => {
    Axios.post("http://localhost:3001/create", {
      frontname: name,
      frontage: age,
      frontcountry: country,
      frontposition: position,
      frontwage: wage,
    }).then(() => {
      console.log("success");
    });
  };

  const onChangefun = (event) => {
    setName(event.target.value);
    console.log(event.target.value);
  };
  return (
    <div className="login">
      <div className="information">
        <label>Name : </label>
        <input type="text" onChange={onChangefun}></input>
        <label>Age : </label>
        <input
          type="number"
          onChange={(event) => {
            setAge(event.target.value);
          }}
        ></input>
        <label>Country : </label>
        <input
          type="text"
          onChange={(event) => {
            setCountry(event.target.value);
          }}
        ></input>
        <label>Position : </label>
        <input
          type="text"
          onChange={(event) => {
            setPosition(event.target.value);
          }}
        ></input>
        <label>Wage: </label>
        <input
          type="number"
          onChange={(event) => {
            setWage(event.target.value);
          }}
        ></input>
        <button onClick={addEmployee}>직원 등록</button>
      </div>
    </div>
  );
}

export default Login;

프런트에서 백 전달할때 

우리는 api허용해주기 위해서 cors 라이브러리 사용할거임

npm i cors

 

server/ index.js 파일에

const cors = require("cors");
app.use(cors());

추가

 

 

 

 

근데 여전히 막상보면 백으로 못넘어옴

이렇게 req.body 콘솔 찍어보면 

undefined 뜸 

 

json 미들웨어를 제공안해서였음

프런트에서 보낼때 

 

 

index.js/

app.use(express.json());

이거 추가

 

유튜브영상에서는 이거 추가하면 db넣기 성공했는데 난 안됨. ㅎ

 

 db에 안들어가고 

에러 뜸

Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client

 

 

이거 mysql에 외부접근안돼서 그런거라고 함  

그래서 이걸로 해결가능하다고 함( 비번 사용해서 db계정사용하게끔 하는 설정인듯!)

 

+해결방법중에 mysql2쓰는 것도 있음 이번에는 안해봄 

 ALTER user '[유저]'@'localhost' IDENTIFIED WITH mysql_native_password by '[비번]';

 바꿔주기 위해서 mysql로 ㄱㄱ

mysql에 바로 use mysql하면 접속이 안됨

mysql -u root -p도 당연히 안됨

 

 

'use'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는
배치 파일이 아닙니다

워크벤치 경로로 들어가서 해야함~~~

C:\Program Files\MySQL\MySQL Server 8.0\bin

 

 

cd C:\Program Files\MySQL\MySQL Server 8.0\bin

mysql -u root -p

 

이제 mysql켜짐

 

mysql>

 

 

계정 뭐있는지 확인 먼저 함

 

SELECT user,authentication_string,plugin,host FROM mysql.user;

 

내가 쓸 root계정 있는거 확인함

 

 

 

 

 ALTER user '[유저]'@'localhost' IDENTIFIED WITH mysql_native_password by '[비번]';

 

flush privileges;

 

 

 

index.js 

서버 끄고 다시 실행

node index.js

로 실행

 

 

직원등록 눌러서 보내보면 

 

잘 들어왔다~!~!~!~!~!

 

 

 

이제 우리가 할거는

백-> 프런트로 

정보 가져오는걸 할거임

우리는 필요할 때 정보를 봐야하니까 

 

 

client/

//초기에는 빈배열이니까 []로 넣어줌 
 const [employeesList, setEmployeesList] = useState([]);
 //가져올 함수// 백가져온 응답반은걸 콘솔로 보여주겠음 response가져온거의 data로
   const getEmployee = () => {
    Axios.get("http://localhost:3001/employees").then((response) => {
      setEmployeesList(response.data);
    });
  };
  
  
 //버튼
   <div className="showDB">
      //버튼눌렀을 때 가져올 함수 실행
        <button className="showDB-button" onClick={getEmployee}>
          show employees
        </button>
      </div>

 

server/

app.get("/employees", (req, res) => {
//db에서 employess테이블 다 가져와
  db.query("SELECT * FROM employees", (err, result) => {
    if (err) {
      console.log(err);
    } else {
      res.send(result);
    }
  });
});

버튼 누르면

이건 response임 

object 객체로 가져옴

(status 200 -> 작동한거임)

이안에 우리가 원하는 정보가 잘 담겨져있음

 

 

이제 백에서 가져온 것들을 화면에 띄워줄거임

맵함수 사용해서

배열에서 하나씩 꺼내오기 

 

        <div>
          {employeesList.map((val, index) => {
            return (
              <div className="employee">
                <h3>{val.name}</h3>
                <h3>{val.age}</h3>
                <h3>{val.country}</h3>
                <h3>{val.position}</h3>
                <h3>{val.wage}</h3>
              </div>
            );
          })}
        </div>

성공~~~

 

 

근데 다른 방법도 있대 

post에 넣고 바로 화면에 띄우게 하는법

 

const addEmployee = () => {
    console.log(name, "dfdfd");
    Axios.post("http://localhost:3001/create", {
      frontname: name,
      frontage: age,
      frontcountry: country,
      frontposition: position,
      frontwage: wage,
    }).then(
      //   () => {
      //   console.log("success");
      // }
      () => {
        //기존 배열에 방금 입력한 걸 추가하고 그걸 setEmployessList함수에 넣음! 배경은 뜨는데 값이 안띄워지네..흠
        //암튼 여러 방법이 있다고 함 있다가 해보자
        setEmployeesList([
          ...employeesList,
          {
            frontname: name,
            frontage: age,
            frontcountry: country,
            frontposition: position,
            frontwage: wage,
          },
        ]);
      }
    );
  };

나는 왜인지 빈값만 뜸

 

db에는 잘들어갔는데...

왜 안뜨는 것인가...

이부분은 다른 날에 해보겟음

 

 

이제 

삭제 하고 수정하고 다음에 해봐야지

db에서 가져온 목록 선택해서 나열하게 하고

이런 것도 해보고 싶네 

 

아 그리고 지금은 새로고침하면 db에서 블러온 애들이 화면에서 사라지거든

그것도 막아야겠다.

728x90
728x90

state변경할 때 모든 code들은 항상 다시 실행됨

근데 api가져와서 쓸때를 예를 들면 매번 다시 가져오면 번거로워지지

 

몇몇 코드를 처음에 딱 한번만 실행되고 다시 실행안되게 하고 싶음

 

useEffect(우리가 실행시킬함수,[변경되는지 지켜볼애])

 

 

 

 

처음 렌더링됐을 때 한번만 실행되고

버튼 눌러서 state바뀔 때 실행되지 않음

 


+코드제어

 

클릭할때 keyword 검색코드 다시 실행안되게 막기

키워드를 검색할 때만 실행되게 하기

[keyword]로 넣어서 이 keyword  state값이 변경될때만 이 코드 실행됨

조건으로 keyword가 비어있고 keyword길이가 5이상일때만 실행되게 하였음

 

 

 

처음에는 실행안됐고

검색창에 6자넣으니까 실행됨 

 

 

 

---

[] 아무것도 지켜보지 않거나

[keyword] 키워드 변경하는지 보거나

[keyword, counter] 둘다 변경하는지 보거나 (둘중 하나 변경될때 실행)

이렇게 쓸 수 있음

728x90
728x90
npm i prop-types

728x90
728x90

server.js에서 db확인할게 있어서

 

npm start했는데

  

UnhandledPromiseRejectionWarning: Error: Could not find a production build in the 

이 에러 뜸

 

그래서 

npm run build

했는데 에러

 

 

 

 throw er; // Unhandled 'error' event
      ^

Error: EPERM: operation not permitted, open 경로
Emitted 'error' event on WriteStream instance at:

 

해결: 실행해놓은 npm run dev 취소하고 하니까 됨

이거 하기 전에 build해야되는거임

 

 

 

빌드 잘됨

728x90
728x90

https://dukdukz.tistory.com/entry/210604-Sequelize-auto-%EB%A1%9C-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%83%9D%EC%84%B1-%EA%B5%AC%EB%AC%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0

https://www.hanumoka.net/2018/11/23/node-20181123-express-setting-sequelize/

 

Node Express에 sequelize를 이용해 mysql접속하기

들어가기Express 프로젝트에 sequelize(시퀄라이저)를 이용하여 로컬에 있는 mysql에 접속하는 예제를 정리해본다. 미리 로컬에 mysql을 설치하고, 스키마와 계정을 생성 해놨다. 테스트용 Express 프로젝

www.hanumoka.net

MySql에서 워크벤치로 테이블구성을 다 하고 

코드에서 시퀄라이즈 연동을 하려니까 번거로웠다. 뿐만 아니라 타입이 일치한데 해당하는 테이블을 찾을 수 없다고 연결이 안돼서 답답했다. 찾아보니 역시 자동으로 구성된 테이블 코드를 짜주는 방법이 있었다!!

 

나는 EER 에서 다이어그램으로 테이블을 먼저 짰다.

그리고 Forward Enginner를 누르면 

만든 다이어그램이 테이블로 생성이 된다. (Synchronize Model하면 기존에 있는 테이블을 수정하고 업데이트할 수 있다.)

 

 

이제 코드에서 만져보자

 

시퀄라이즈 세팅을 먼저 한다. 

(npm i express

npm i -D nodemon

)

npm i sequelize //시퀄라이즈

npm i mysql2   //mysql과 시퀄라이즈를 이어주는 드라이버이다. 

npm i sequelize-cli   //시퀄라이즈 명령어를 실행하기 위한 패키지다

 

npx sequelize init //하면 기본 폴더가 생성된다.

이제 자동으로 db테이블 코드가져와주는

npm i sequelize-auto

를 깐다. 

 

터미널에 명령어를 입력한다.

npx sequelize-auto -o "./models" -d nodejs -h "localhost" -u "root" -p "3306" -x "비밀번호" -e mysql

 

 

-o "경로"
-d "db 이름"
-h "url"->localhost
-u "root"
-p "port"
-x "password"
-e "mysql"

 

 

그럼 필요한 user, music,artist 코드가 자동으로 생긴다. 

근데 문제는 코드가 좀 다르다 function이다.

 

내가 db구조 짤때 참고한 nodejs책에서는 class로 해서 

안에 내용을 기존에 참고했던 식으로 바꿔줬다. 큰틀만 바꾸면 됨

artist.js

그리고 init-model.js도 생겼는데

나는 index.js로 작업하고 잘모르겠고 구조도 바꿔줘서 

주석처리했다. 

대신 관계정의할 때 필요한 것들은 참고해서 넣었다.

artist.js

수정한다음에 혹시몰라서 

워크벤치에 있는 database를 삭제하고

 

npx sequelize db:create로 다시 db를 만들고

npm start 실행했다. 

 

연결잘된다. 

 

 

(

문제는 내가 원하는건 user랑 artist의 1대1관계인데

분명 user에 hasOne, artist에 belongsTo로 줬는데 

왜 다이어그램을 뽑아보면 1대다로 나오는지 모르겠다....)

 

 

 

 

그리고 일대다에도 종류가 두개있어서 놀람

https://jins-dev.tistory.com/entry/RDBMS%EC%9D%98-%EA%B4%80%EA%B3%84-Identifying-NonIdentifying-Relationship-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC

 

RDBMS의 관계 - Identifying & Non-Identifying Relationship 에 대하여

 RDB에서 관계를 맺는데 있어서 식별관계(Identifying Relationship)와 비식별관계(Non-Identifying Reltationship)가 존재한다. 정확히는 RDBMS에서 나누는 관계가 아닌 ER Diagram 상에서 논리상 나누는 개념이..

jins-dev.tistory.com

 

이건그냥 공식문서 필요할때 보라고 넣어둠

https://sequelize.org/master/manual/legacy.html

 

Manual | Sequelize

Working with Legacy Tables While out of the box Sequelize will seem a bit opinionated it's easy to work legacy tables and forward proof your application by defining (otherwise generated) table and field names. Tables class User extends Model {} User.init({

sequelize.org

 

728x90
728x90

nodejs책 340쪽 필기함

 

공식문서도 좋음

 

 

https://sequelize.org/v4/manual/tutorial/associations.html

 

Tutorial | Sequelize | The node.js ORM for PostgreSQL, MySQL, SQLite and MSSQL

Associations This section describes the various association types in sequelize. When calling a method such as User.hasOne(Project), we say that the User model (the model that the function is being invoked on) is the source and the Project model (the model

sequelize.org

 

728x90

+ Recent posts