2022.07.21 - [Coding/React] - [React] 고객관리 사이트 (Client) redux로 구현하기
[React] 고객관리 사이트 (Client) redux로 구현하기
2022.07.07 - [Coding/React] - [React] 고객관리 사이트 구현 (Client) [React] 고객관리 사이트 구현 (Client) green_customer_client Header Footer CustomerList Customer DetailCustomer - 라이브러리 설치 a..
7ingout.tistory.com
1. MySQL 데이터베이스에 table 생성
2. 서버 구현
1) join 경로 post 요청시
customer_members 테이블에 데이터 추가하기
비밀번호는 암호화하여 저장
등록일은 Now()함수를 사용해서 현재 날짜를 저장
패스워드 암호화 알고리즘 라이브러리 - bcrypt 설치
npm install bcrypt
2) login 경로 post 요청시
usermail 값으로 일치하는 데이터를 조회(select)
입력받은 userpass를 암호화하여 조회한 데이터의 암호화된 값과 비교하여 일치하는지 확인
일치하면 조회한 데이터를 응답해줌
3. 클라이언트 구현
JoinForm.js 생성
1) 로그인 리듀서 작성
logincheck.js
2) Login 컴포넌트 생성
3) util 폴더 안에 cookie.js 생성
npm install react-cookie
https://www.npmjs.com/package/bcrypt
bcrypt
A bcrypt library for NodeJS.. Latest version: 5.0.1, last published: a year ago. Start using bcrypt in your project by running `npm i bcrypt`. There are 3418 other projects in the npm registry using bcrypt.
www.npmjs.com
이 구문들을 사용할 것임 !
MIDDLEWARE_GREEN_CUSTOMER_SERVER
npm install bcrypt
설치 후
const bcrypt = require('bcrypt');
const saltRounds = 10;
맨 위에 이 코드 추가
// 포스트맨으로 회원가입 확인
good 😊
// 포스트맨으로 로그인 확인
index.js // 회원가입, 로그인 요청 부분 추가
const express = require("express");
const cors = require("cors");
const app = express();
const port = 3001;
const mysql = require("mysql");
const fs = require("fs")
const bcrypt = require('bcrypt');
const saltRounds = 10;
const dbinfo = fs.readFileSync('./database.json');
// 받아온 json 데이터를 객체형태로 변경 JSON.parse
const conf = JSON.parse(dbinfo)
// connection mysql연결 createConnection()
// connection.connect() 연결하기
// connection.end()연결종료
// connection.query('쿼리문', callback함수)
// callback(error, result, result의 field정보)
const connection = mysql.createConnection({
host: conf.host,
user: conf.user,
password: conf.password,
port: conf.port,
database: conf.database
})
app.use(express.json());
app.use(cors());
// app.get("경로", 함수)
// connection.query("쿼리문", 함수)
app.get('/customers', async (req, res)=> {
// connection.connect();
connection.query(
"select * from customers_table",
(err, rows, fields)=> {
// res.send("고객정보입니다.")
res.send(rows)
console.log(fields);
}
)
// connection.end();
})
app.get('/detailview/:no', async (req, res)=> {
const params = req.params;
// const { no } = params;
connection.query(
`select * from customers_table where no=${params.no}`,
(err, rows, fields)=> {
res.send(rows[0])
}
)
})
// 내가한 것
// // addCustomer post 요청이 오면 처리
// app.post("/addCustomer", (req, res)=>{
// const body = req.body;
// const { c_name, c_phone, c_birth, c_gender, c_add, c_adddetail} = body;
// if(!c_name || !c_phone || !c_birth || !c_gender || !c_add || !c_adddetail) {
// res.send("모든 필드를 입력해주세요");
// } else {
// connection.query(
// `insert into customers_table (name, phone, birth, gender, add1, add2) values ('${c_name}', '${c_phone}', '${c_birth}', '${c_gender}', '${c_add}', '${c_adddetail}')`,
// (err, rows,fields) => {
// res.send("등록되셨습니다.")
// }
// )
// }
// })
// addCustomer post 요청이 오면 처리 req => 요청하는 객체, res => 응답하는 객체
// mysql 쿼리 select / update / delete / insert
// insert into 테이블(컬럼1, 컬럼2, 컬럼3, ...) values(?, ?, ?)
// query("쿼리", [값1, 값2, 값3, 값4, 값5, 값6], 함수)
// insert into customers_table(name, phone, birth, gender, add1, add2)
// values(?, ?, ?, ?, ?, ?)
app.post("/addCustomer", async (req, res)=>{
console.log(req)
// const body = req.body;
const { c_name, c_phone, c_birth, c_gender, c_add, c_adddetail} = req.body;
connection.query(
// `insert into customers_table (name, phone, birth, gender, add1, add2) values ('${c_name}', '${c_phone}', '${c_birth}', '${c_gender}', '${c_add}', '${c_adddetail}')`,
"insert into customers_table(name, phone, birth, gender, add1, add2) values(?, ?, ?, ?, ?, ?)",
[c_name, c_phone, c_birth, c_gender, c_add, c_adddetail],
(err, rows,fields) => {
res.send("등록되셨습니다.")
}
)
})
// 삭제요청 쳐리 /detailview/${no}
// delete from 테이블명 조건명
// delete from customers_table where no = no
app.delete('/detailview/:no', async (req, res)=> {
const params = req.params;
console.log('삭제');
connection.query(
`delete from customers_table where no=${params.no}`,
(err, rows, fields)=> {
res.send(rows)
}
)
})
// 수정요청
// update 테이블이름 set 컬럼명 = 값 where no = 값
// update customers_table set name='', phone='', birth='', gender='', add1='', add2='' where no=
// http://localhost:3001/edit/1
app.put('/edit/:no', async (req, res)=> {
// 파라미터 값을 가지고 있는 객체
const params = req.params;
const { c_name, c_phone, c_birth, c_gender, c_add, c_adddetail} = req.body;
console.log('수정');
console.log(req.body);
connection.query(
`update customers_table set name='${c_name}', phone='${c_phone}', birth='${c_birth}', gender='${c_gender}', add1='${c_add}', add2='${c_adddetail}' where no=${params.no}`,
(err, rows, fields)=> {
res.send(rows)
}
)
})
// 회원가입 요청
app.post("/join", async (req,res)=> {
// green1234
let myPlaintextPass = req.body.userpass;
let myPass = "";
if(myPlaintextPass != '' && myPlaintextPass != undefined) {
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPass, salt, function(err, hash) {
// Store hash in your password DB.
myPass = hash;
console.log(myPass);
// 쿼리 작성
const { username, userphone, userorg, usermail } = req.body;
// connection.query 인자 첫번째: 쿼리문, 두번째: 쿼리문에 들어갈 값, 세번째: 처리 되면 하는 애
connection.query("insert into customer_members(username, userpass, userphone, userorg, usermail, regdate) values(?,?,?,?,?,DATE_FORMAT(now(),'%Y-%m-%d'))",
[username, myPass, userphone, userorg, usermail],
(err, result, fields) => {
console.log(result)
console.log(err)
res.send("등록되었습니다.")
}
)
});
});
}
})
// 로그인 요청
app.post('/login', async (req, res)=> {
// usermail 값에 일치하는 데이터가 있는지 select 문
// userpass 암호화해서 쿼리 결과의 패스워드랑 일치하는지를 체크
const {usermail, userpass} = req.body;
connection.query(`select * from customer_members where usermail = '${usermail}'`,
(err, rows, fileds)=>{
if(rows != undefined) {
if(rows[0] == undefined) {
res.send(null)
} else {
// Load hash from your password DB.
bcrypt.compare(userpass, rows[0].userpass, function(err, result) {
// result == true
if(result == true) {
res.send(rows[0])
} else {
res.send('실패')
}
});
}
} else {
res.send('실패')
}
}
)
})
// 서버실행
app.listen(port, () => {
console.log("고객 서버가 돌아가고 있습니다.")
})
MIDDLEWARE_GREEN_CUSTOMER_CLIENT
npm install react-cookie
components/JoinForm.js
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Table, TableBody, TableRow, TableCell } from '@mui/material';
import axios from "axios";
import { API_URL } from '../config/contansts';
const JoinForm = () => {
const navigate = useNavigate();
const [formData, setFormData] = useState({
username: "",
userpass: "",
userpassck: "",
userphone:"",
userorg:"",
usermail:""
})
const onChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]:value
})
}
const onSumbit = (e) => {
// form에 원래 연결된 이벤트를 제거
e.preventDefault();
console.log(formData);
// 전화번호가 숫자인지 체크하기
if(isNaN(formData.userphone)){
alert('전화번호는 숫자만 입력해주세요');
setFormData({
...formData,
userphone: ""
})
}
// input에 값이 있는지 체크하고
// 입력이 다되어있으면 post전송
else if( formData.username !== "" && formData.userpass !== "" &&
formData.userphone !== "" && formData.userpassck !=="" &&
formData.userorg !== "" && formData.usermail !== "" ){
addMember();
} else {
alert('모든 항목을 기입해주세요');
}
}
function addMember(){
axios.post(`${API_URL}/join`, formData)
.then((res)=>{
alert('등록되었습니다.');
navigate("/");
})
.catch((e)=> {
console.log(e);
})
}
return (
<div>
<h2>신규 고객 등록하기</h2>
<form onSubmit={onSumbit}>
<Table>
<TableBody>
<TableRow>
<TableCell>이름</TableCell>
<TableCell>
<input name="username" type="text"
value={formData.username}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>비밀번호</TableCell>
<TableCell>
<input name="userpass" type="text"
value={formData.userpass}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>비밀번호체크</TableCell>
<TableCell>
<input name="userpassck" type="text"
value={formData.userpassck}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>연락처</TableCell>
<TableCell>
<input name="userphone" type="text"
value={formData.userphone}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>이메일</TableCell>
<TableCell>
<input name="usermail" type="text"
value={formData.usermail}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>소속</TableCell>
<TableCell>
<input name="userorg" type="text"
value={formData.userorg}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={2}>
<button type="submit">등록</button>
<button type="reset">취소</button>
</TableCell>
</TableRow>
</TableBody>
</Table>
</form>
</div>
);
};
export default JoinForm;
components/Login.js
import React, { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import axios from 'axios';
import { API_URL } from '../config/contansts';
import { setCookie } from '../util/cookie';
import { goToHome, setLogin } from '../modules/logincheck';
import { useDispatch } from 'react-redux';
const Login = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const [ loginData, setLoginData ] = useState({
usermail: "",
userpass: "",
})
const onChange = (e) => {
const { name, value } = e.target;
setLoginData ({
...loginData,
[name]: value
})
}
const onSubmit = (e) => {
e.preventDefault();
// input에 입력했는지 체크
if(loginData.usermail === '' || loginData.userpass === '') {
alert('이메일과 비밀번호를 입력해주세요');
} else {
axios.post (`${API_URL}/login`, loginData)
// 로그인이 되었을 때
.then(result => {
let { usermail, username } = result.data;
console.log(result);
// usermail에 값이 있을 때
if(usermail !== null && usermail !== '' && usermail !== undefined) {
alert('로그인되었습니다.');
// 현재시간 객체를 생성
let expires = new Date();
// 60분 더한 값으로 변경
expires.setMinutes(expires.getMinutes()+60)
setCookie('usermail', `${usermail}`, {path: '/', expires});
setCookie('username', `${username}`, {path: '/', expires});
dispatch(setLogin());
dispatch(goToHome(navigate));
}
})
.catch(e => {
console.log(e);
alert('ssssssssss 비밀번호를 확인해주세요');
})
}
}
return (
<div>
<form onSubmit={onSubmit}>
<p><input type="text" name="usermail" value={loginData.usermail} onChange={onChange}/></p>
<p><input type="password" name="userpass" value={loginData.userpass} onChange={onChange}/></p>
<p>
<button type='submit'>로그인</button>
<Link to="/join"><button>회원가입</button></Link>
</p>
</form>
</div>
);
};
export default Login;
components/header.js
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import { setLogout } from '../modules/logincheck'
import { useDispatch, useSelector } from 'react-redux';
import { getCookie, removeCookie } from '../util/cookie';
const Header = () => {
const uname = getCookie('username');
const isLogin = useSelector(state=>state.logincheck.isLogin);
const dispatch = useDispatch();
const logoutClick = () => {
removeCookie('username');
removeCookie('usermail');
dispatch(setLogout());
}
useEffect(()=>{
// setLogin(true);
},[isLogin]);
return (
<div id="header">
<h1>그린고객센터</h1>
<ul>
<li><Link to="/">고객리스트보기</Link></li>
<li><Link to="/write">신규 고객 등록하기</Link></li>
{ isLogin &&
<>
<li>{uname}님 환영합니다!</li>
<li onClick={logoutClick}>로그아웃</li>
<li><Link to="/">회원정보수정</Link></li>
</>
}
{ isLogin ||
<>
<li><Link to="/login">로그인</Link></li>
<li><Link to="/join">회원가입</Link></li>
</>
}
<li>고객 검색</li>
</ul>
</div>
);
};
export default Header;
modules/index.js
import { combineReducers } from "redux";
import customers from './customers';
import logincheck from "./logincheck";
const rootReducer = combineReducers({ customers, logincheck });
export default rootReducer;
modules/logincheck.js
// 리덕스 액션타입, 액션 생성함수, 초기값, 리듀서
const SET_LOGIN = "SET_LOGIN";
const SET_LOGOUT = "SET_LOGOUT";
// 액션 생성함수
// const setLogin = () => {
// return {
// type: SET_LOGIN
// }
// }
export const setLogin = () => ({
type: SET_LOGIN
})
export const setLogout = () => ({
type: SET_LOGOUT
})
// 초기값 설정
const initialState = {
isLogin: false
}
// 홈으로 이동 함수
export const goToHome = (navigate) => () => {
navigate('/');
}
// 리듀서 만들기
export default function logincheck(state=initialState, action) {
switch(action.type){
case SET_LOGIN:
return {
isLogin: true
}
case SET_LOGOUT: {
return {
isLogin: false
}
}
default:
return state;
}
}
util/cookie.js
import { Cookies } from 'react-cookie';
const cookies = new Cookies();
// 쿠키 생성함수
export const setCookie = (name, value, options) => {
return cookies.set(name, value, {...options});
}
// 쿠키 접근함수
export const getCookie = (name) => {
return cookies.get(name);
}
// 쿠키 삭제함수
export const removeCookie = (name) => {
return cookies.remove(name)
}
App.js
import './App.css';
// import CustomerList from './components/CustomerList';
import DetailCustomer from './components/DetailCustomer';
import Footer from './components/Footer';
import Header from './components/Header';
import { Route, Routes } from "react-router-dom";
// import CreateCustomer from './components/CreateCustomer';
import EditCustomer from './components/EditCustomer';
import CustomerContainer from './components/CustomerContainer';
import CreateCustomerContainer from './components/CreateCustomerContainer';
import JoinForm from './components/JoinForm';
import Login from './components/Login';
// const customers = [
// {
// no: 1,
// name: "고객",
// phone: "01012345678",
// birth: "19920206",
// gender: "여성",
// add: "울산시 남구"
// },
// {
// no: 2,
// name: "그린",
// phone: "01012345678",
// birth: "19920206",
// gender: "남성",
// add: "울산시 동구"
// },
// {
// no: 3,
// name: "kh",
// phone: "01012345678",
// birth: "19920206",
// gender: "여성",
// add: "울산시 남구"
// }
// ]
function App() {
return (
<div className="App">
<Header />
<Routes>
{/* props로 위에 {customers}를 CustomerList로 전달 */}
{/* <Route path="/" element={<CustomerList customers={customers}/>} /> */}
<Route path="/" element={<CustomerContainer/>} />
<Route path="/detailview/:no" element={<DetailCustomer/>} />
<Route path="/edit/:no" element={<EditCustomer/>} />
{/* <Route path="/write" element={<CreateCustomer/>} /> */}
<Route path="/write" element={<CreateCustomerContainer/>} />
<Route path="/join" element={<JoinForm />} />
<Route path="/login" element={<Login />} />
</Routes>
<Footer/>
</div>
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import { applyMiddleware, legacy_createStore as createStore } from 'redux';
import rootReducer from './modules';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { CookiesProvider } from 'react-cookie';
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));
console.log(store.getState());
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<Provider store={store}>
<CookiesProvider>
<App />
</CookiesProvider>
</Provider>
</BrowserRouter>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
'Stack > React' 카테고리의 다른 글
[React / 스터디] 모두의 일기장 클론 코딩 (2) | 2022.09.30 |
---|---|
[React] 고객관리 사이트에 이미지 업로드 부분 추가 (0) | 2022.08.05 |
[React] 고객관리 사이트 (Client) redux로 구현하기 (0) | 2022.07.21 |
[React] json-server을 이용하여 데이터 받아오기 (0) | 2022.07.15 |
[React] Redux Middleware - 리덕스 미들웨어 (0) | 2022.07.14 |