๐ฅ ํ๋ก์ ํธ ์๊ฐ
โถ ์ ์๋๋ฌผ์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ์๋น์ค ํฌํ์ ๊ตฌํํ๋ ํ๋ก์ ํธ
โถ ๊ฐ๋ฐ๊ธฐ๊ฐ
2020๋
11์ ~ 2021๋
1์
โถ ํ ๊ตฌ์ฑ
Front-End & Back-End: 4๋ช
(์ฑ์ ๋น, ์ด์ฃผ์ฝ, ์ด์์ง, ์ด๊ธฐํ)
โถ ๊ฐ๋ฐ ์ค์ผ์ค ๊ด๋ฆฌ์ ์ํต์ ์ํด ์ฌ์ฉํ ํ๋ก๊ทธ๋จ
์ค์ผ์ค ๊ด๋ฆฌ ํ๋ก๊ทธ๋จ: Slack,Discode
์ํต ํ๋ก๊ทธ๋จ: Slack
๐ง ๊ตฌํ ์์
๐ ๋ด๊ฐ ๋งก์ ์ญํ
Front-End & Back-End
๋ฉ์ธ ํ์ด์ง
1. ๋ฉ์ธ ํ์ด์ง์ ํค๋ UI ๊ตฌํ๊ณผ ๋ฉ์ธ ํ์ด์ง์ ๋์์ ํธ์ง
2. ๋ฆฌ์กํธ ๋ผ์ฐํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ถํ์ํ ๋ ๋๋ง ์ต์ํ
์ปค๋ฎค๋ํฐ ํ์ด์ง
1. ์ปค๋ฎค๋ํฐ ํ์ด์ง์ ๊ฒ์ํ UI ๊ตฌํ
2. ์ปค๋ฎค๋ํฐ ํ์ด์ง์ ๊ธฐ๋ณธ์ ์ธ ๊ธ์ฐ๊ธฐ, ์์ , ์ญ์ ๊ธฐ๋ฅ ๊ตฌํ
๋ก๊ทธ์ธ ํ์ด์ง
1. ๋ก๊ทธ์ธ UI ๊ตฌํ
2. Rest API ํ์ฉํ ์์
๋ก๊ทธ์ธ๊ธฐ๋ฅ (์นด์นด์ค, ๋ค์ด๋ฒ)
3. ๋ก๊ทธ์ธ ์ JWTํ ํฐ ์์ฑ์ผ๋ก ์๋ ๋ก๊ทธ์ธ ๊ตฌํ
4. ์ํ๋ฆฌํฐ ํ์ฑํ๋ก ๊ถํ๋ณ ํ์ด์ง ์ฒ๋ฆฌ
5. ๋ก๊ทธ์ธ์ ์ ํจ๊ธฐ๊ฐ์ด ๋ง๋ฃ๋๋ฉด ์๋ ๋ก๊ทธ์์ ๊ตฌํ
ํ์๊ฐ์
ํ์ด์ง
1. ํ์๊ฐ์
์ Kakao Postcode API๋ฅผ ํตํ ์ฃผ์๊ฐ ๊ฐ์ ธ์ค๊ธฐ
3. ํ์๊ฐ์
UI ๊ตฌํ
Jupyter Notebook
1. Selenium๊ณผ BS4๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฃ ๋ฐ์ดํฐ๋ฅผ ํฌ๋กค๋ง
๐ฌ ์ํ ์ / ์์ฌ์ด ์ / ํด๊ฒฐ or ๊ฐ์ ๋ฐฉ๋ฒ
๐ ์ํ ์
ํ์๊ณผ์ ์ํต
์ฐ๋ฆฌ ํ์ ์ ๋ฐ์ ์ผ๋ก ๋ชจ๋ ํ์๊ณผ ์ํต์ด ์๋์๋ค. ์์นจ๋ง๋ค 5๋ถ ํ์๋ฅผ ํตํด ์๋ก ๊ณํ์ ๊ณต์ ํ๋ฉฐ ํ๋ฃจ๋ฅผ ์์ํ์๋ค. ์ด ๋๋ถ์ ์๋ก ์ด๋ค ๊ฐ๋ฐ์ ์งํ ์ค์ด๊ณ ์ด๋ค ์ด๋ ค์์ ์ฒํด์๋์ง๊น์ง ๋ค ์๊ณ ์์๋ค. ํผ๋๋ฐฑ ๋ํ ์๋ก ๋ฐ๋ก ์ ๋ฌํ ์ ์์ด์ ์ค์๋ฅผ ๋น ๋ฅด๊ฒ ๋ฐ๊ฒฌํ๊ณ ๋๋ถ์ ์ฒ์๋ถํฐ ๋ฐฉํฅ์ ์ ์ก์ ์ ์์๋ค. ์ ๋ง ์ํ ๋ถ๋ถ์ด ๋ง์ง๋ง, ์ฐ๋ฆฌ ํ์ด ์ฑ๊ณต์ ์ผ๋ก ํ๋ก์ ํธ๋ฅผ ๋ง์น ์ ์์๋ ์ด์ ์ค ๊ฐ์ฅ ํฐ ๋ถ๋ถ์ด ์ํต์ด๋ผ๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ์ ์ผ ์ฒ์์ผ๋ก ์ ์๋ค. ๋ฌผ๋ก ๊ฐ์์ ์ญํ ์ด ์์์ง๋ง, ํ์๋ค์ ์งํ๊ฐ ํฉ์ณ์ก๊ธฐ์ ์์ ์ ์ญํ ์ ์ถฉ๋ถํ ํด๋ผ ์ ์์๋ค๊ณ ์๊ฐํ๋ค.
๋ฐฑ์๋์ ํ๋ฐํธ ์ ๋ฌด์ ํตํฉ
๋ฐฑ์๋์ ๋ฌด์ ํ๋ก ํธ ์ ๋ฌด๋ฅผ ๋๋์ง ์์ ๊ฒ์ ์ฐ๋ฆฌ ๋ชจ๋ ๊ฐ์ ์ ๋ฌด๋ฅผ ํตํด ์ฒ์๋ถํฐ ๋๊น์ง ๊ฐ์ ๋งก์ ๋ฐ๋ฅผ ๋คํ๋ ๊ฒ์ ๋ํ ๋ชฉํ๊ฐ ์์๊ธฐ ๋๋ฌธ์ด์๋ค. ํ๋ฐํธ์ ๋ฌด๋ฅผ ํตํ ์น์ฌ์ดํธ ๊ตฌ์ฑ๊ณผ ๊ทธ์ ๋ฐ๋ฅธ ๊ธฐ๋ฅ์ ๋ถ์ด๋ฃ๋ ๋ฐฑ์๋์ ์์ ์ ์ ๋ง ๋ง์ ์๊ฐ์ด ๋ค์์ง๋ง ๊ทธ๋งํผ ๋ป๊น์๋ค.
์ฒซ ๋ฒ์งธ๋ก ํ๋ก ํธ์ ๋ฌด๋ฅผ ํ๋ฉฐ ์ฌ์ฉ์ ํธ์์ ๋ฐ๋ฅธ ๊ตฌ์ฑ์ ๋ํด ์๊ฐํ๋ ์๊ฐ์ ํตํด ๊ตฌ์ฑ๋์ ๋ํ ์ค์์ฑ์ ๋ฐฐ์ ๋ค. ์ด๋ ์์น์ ๋ฐ๋ผ ๋ณด์ด๋ ์ด๋ฏธ์ง, ์์น์ ๋ฐ๋ผ ๋ฐ์๋ค์ด๋ ๋๋์ด ๋ฌ๋ผ ์ด๊ฒ์ ์กฐ์ ํ๋๋ฐ ๋ง์ ๊ณต์ ๋ค์๋ค.
๋ ๋ฒ์งธ๋ก ์ธ์ฌํ ํ ์ด๋ธ์ ์ง์์ด ์ค์ํ๋ค๋ ๊ฒ์ ๋ฐฐ์ ๋ค. ์ฒ์ DB ๋ชจ๋ธ๋ง์ ์งค ๋ ๊ณ ๋ฏผ์ ํ๊ณ ํ์๋ฅผ ํตํด ์ง์์ ์๋ ํ ์ด๋ธ๊ตฌ์ฑ๋๋ฅผ ๋ง๋ค๋ ค๊ณ ๋ ธ๋ ฅํ์์ง๋ง, ํ๋ก์ ํธ์ ์งํ๋ ์๋ก ๊ณ์ ์์ ํด์ผ ํ๋ ๋ถ๋ถ์ด ์๊ฒผ๊ณ ๊น๋ํ์ง ๋ชปํ ๋ถ๋ถ์ด ๋ํ๋ฌ๋ค. ์ ๋ง ๋๋ฌด ์์ฌ์ด ๋ถ๋ถ์ด์๋ค. ์ด ๋ถ๋ถ์์ ํ์๋ค๊ณผ ์๊ธฐ๋ ๋ง์ด ํ๊ณ ์์ ๋ ๋ง์ด ํ์ฌ ๊ทธ ๊ณผ์ ์ ๋ค์ ์ ๋ฆฌํ๊ณ ์ ๋ง์ด ๋ ธ๋ ฅํ ๊ฒ ๊ฐ๋ค.
๐ ์์ฌ์ด ์
๋ฆฌํํ ๋ง
์์ง ์๋ จ๋์ง ๋ชปํ ์ฃผ๋์ด๊ฐ๋ฐ์์ด๊ธฐ ๋๋ฌธ์ ์๊ธฐ๋ ๋ถ๋ถ์ด๊ธด ํ์ง๋ง ์ฒ์์ผ๋ก ํ๋ก์ ํธ๋ฅผ ๊ตฌ์ฑํ ๋์๋ ๋ง์ ์์ด๋์ด์ ๋ฌด์ธ๊ฐ๋ฅผ ์ด๋ฃจ๊ณ ์ถ์ ์๊ตฌ๊ฐ ๋ง์ด ์์๋ค.
๊ธฐ๋ฅ ๋จ์๋ก ๊ตฌํ ๋ชฉํ๋ฅผ ์ก์๋๋ฐ ์ฒ์์๋ ๊ณํํ ๋๋ก ๊ธฐ๋ฅ๊ตฌํ์ ํ๋ ์๋ฒฝํ ํ๋ก์ ํธ๊ฐ ๋ ์ ์์ ๊ฒ ๊ฐ์ ์๊ฐ์ด ๋ค์์๋ค. ํ์ง๋ง ๋ง์ ํ๋ฐํธ์๋/ ๋ฐฑ์๋ ์์ผ๋ก ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉฐ ์ฒ์๋ถํฐ ์ฝ์ง ์๋ค๋ ๊ฒ์ ๋๊ผ๋ค. ์นํ์ด์ง๋ฅผ ๊ตฌ์ฑํ๋ ์ฒซ ๋ถ๋ถ๋ถํฐ ๋ณด์ด๋ ๊ฒ์ด ๋ค๊ฐ ์๋๋ผ๋ ๊ฒ์ ๊นจ๋ฌ์๋ค. ๊ณ์ํด์ ์ฌ์ฉ์ ์
์ฅ์์ ์๊ฐํ๋ ค๊ณ ์ ์ผ๋ค.
๋ํ ์ฒซ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ฉฐ ํ์๋คํํ ์ฝ๋๋ฅผ ๋ณด์ฌ์คฌ์ ๋ ์๊ฐ๋ณด๋ค ๋ด๊ฐ ์๋ ๊ฒ์ด ๋ค๋ฅธ ์ฌ๋์ผ๋ก์๋ ์ด๋ ต๊ณ ๋ณต์กํ๊ณ ๊ธธ๋ค๊ณ ๋๊ปด์ง๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋ค. ์ฐ๋นํ ์๋์ ํ์ง๋ง ๋ณด๋ ์ฌ๋์ด ํ๋ ์ฝ๋์๋ค. ๊ทธ ํ ์ฝ๋๋ฅผ ์ง๊ณ ๊ธฐ๋ฅ์ ๊ตฌํํ ๋ ์ฃผ์์ ๊น๋ํ ์ฐ๊ณ ๋ณด๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๋ ธ๋ ฅํ์๋ค. ์ด๋ค ์ฝ๋์ด๊ณ ์ด๋ค ๊ธฐ๋ฅ์ ๊ตฌํํ ๋ ์ด๊ฒ์ด ์คํ๋๋์ง ๋๊ตฌ๋ ๋ณด๊ธฐ ์ฝ๊ฒ ํ๊ณ ์ ํ๋ ๋ง์์ด ์ ๋ง ์ค์ํ ๊ฒ์ด๋ค. ์์ง๋ ๋ถ์กฑํ์ง๋ง, ์ฝ๋์ ์ฃผ์์ ๊ผญ ๋ฌ๊ณ ๋ณด๊ธฐ ์ฝ๊ฒ ์์ฑํ๊ณ ์ ํญ์ ์ ๊ฒฝ์ ์จ์ผ๊ฒ ๋ค๊ณ ๋๊ผ๋ ๊ฒฝํ์ด ๋์๋ค.
๐ ํด๊ฒฐ or ๊ฐ์ ๋ฐฉ๋ฒ
์ฒ์ฒํ ํ์คํ ๊ฒ๋งํผ ์ค์ํ ๊ฒ ์๋ค.
์ํ๊ณ ์ถ์ ๋ง์์ ๋ง์ ๊ธฐ๋ฅ๊ตฌํ์ ํ๊ณ ์ ๋ฌ๋ ค๊ฐ๋ค ๋ณด๋ ๋์๊ฒ ๋จ๋ ๊ฒ ์๋ค๋ ์๊ฐ์ด ๊ฐํ๊ฒ ๋ค์๋ค. ์ค์ํ ๊ธฐ๋ฅ๊ตฌํ์ ๋ค ํ๊ณ ๋ค๋์๋ณด๋ ๊ธฐ๋ณธ์ด ํํํ์ง ๋ชปํ ๊ฒ์ ๋ํ ํํ๊ฐ ๋ง์ด ๋ค์๋ค. ๋ ๋ง์ ๊ธฐ๋ฅ์ ๋น ๋ฅด๊ฒ ๊ตฌํํ๊ณ ์ถ์ ์์ฌ์ด ์๊ธฐ๋ ๊ฒ์ ๋น์ฐํ์ง๋ง ๊ธฐ๋ณธ์ ๊น๊ฒ ๊ณต๋ถํด์ ์ฝ๋๋ฅผ ํ๋ ๊ฒ์ด ๋ ์ค์ํ ๊ฒ์ด๋ค. ๊ฒฝํ์ด ์์ด๋ฉด์ ์์ฐ์ค๋ฝ๊ฒ ๊ตฌํ ์๋๋ ๋นจ๋ผ์ง๊ณ ํ ์ ์๋ ๊ฒ๋ ๋์ด๋๊ฒ ์ง๋ง, ๊ธฐ์ด๋ถํฐ ์ฅ์ฅ ์ฒ์ฒํ ํ ๋ ๋ ํ์ด ์์ ๊ฒ์ด๋ค. ํญ์ ์ด๊ฒ์ ๋ช ์ฌํด์ผ๊ฒ ๋ค.
์์ผ๋ก๋ ๋ด ์ฝ๋๋ฅผ ๋์๋ณด๋ฉฐ ๊ณต๋ถ๋ฅผ ํ๊ณ ๊ณ์ ๋ฐ์ ํด ๋์๊ฐ ๋ ๊ทธ ํญ์ด ํด ๊ฒ์ด๋ค. ๊ธฐ๋ฅ๊ตฌํ์ ๋ง์กฑํ๋ ๊ฒ์ด ์๋๋ผ, ๋ด๊ฐ ์ด๋ป๊ฒ ๊ตฌํํ์๋์ง ์ ๊ฒํ๋ฉฐ ๊ฐ๋ฐํด ๋๊ฐ์ผ๊ฒ ๋ค.
๐ ๊ธฐ๋กํ๊ณ ์ถ์ ์ฝ๋ / ํจ์ / ๋ก์ง
import { React,useEffect,useState } from "react";
import "../../styles/Login.css";
import { Link } from 'react-router-dom';
import axios from "axios";
import Kakao from "./Kakao";
import NaverLogin from "./Naver";
import { useNavigate } from 'react-router-dom';
import { API_BASE_URL } from "../../Api-config";
function Login() {
const navigate = useNavigate();
const [memberId, setMemberId] = useState("");
const [memberPw, setMemberPw] = useState("");
function handleLogin(e){
e.preventDefault();
if(memberId === "" || memberPw === ""){
window.alert("์์ด๋์ ํจ์ค์๋๋ฅผ ํ์ธํด ์ฃผ์ธ์")
return;
}
try {
axios.post(API_BASE_URL+"/api/Login",null,
{
params:
{
memberId:memberId,
memberPw:memberPw,
},
})
.then((res) =>{
if(res !== undefined && res !== null){
localStorage.setItem('access_token',res.data.accessToken);
const {accessToken} = res.data;
axios.defaults.baseURL = 'http://localhost:3000';
axios.defaults.headers.common['Authorization'] = accessToken;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
if(localStorage.getItem('refresh_token') === null){
localStorage.setItem('refresh_token',res.data.refreshToken);
}
if(res.status === 404 || res.status === 500 || res.status === 403){
window.alert("์๋ชป๋ ๋ก๊ทธ์ธ ์
๋๋ค.");
navigate("/");
}
if(res.status === 200){
axios.defaults.headers.common["Authorization"]=`Bearer ${accessToken}`;
axios.post(API_BASE_URL+"/api/me")
.then((res)=>{
console.log(res);
}).catch((error)=>{
console.log(error);
})
navigate("/");
}
}else{
console.log("Login res localstorage Null Value");
window.alert("๋ก๊ทธ์ธ ํ ํฐ๊ฐ์ด ์์ต๋๋ค.");
document.location = "/Login";
}
})
}catch(error){
alert("๋ก๊ทธ์ธ ์คํจ");
if(error.statusCode === '401'){
console.log("401 ์ค๋ฅ ์
๋๋ค.");
}else if(error.statusCode === '403'){
console.log("403 ์ค๋ฅ ์
๋๋ค.");
}
}
}
useEffect(()=>{
console.log("--- ๋ก๊ทธ์ธ ํ์ด์ง ๋ ๋ ์ค --- ")
},[])
return(
<div className="LoginContainer">
<div className="MainSection">
<div>
<h1 className="LoginBody">๋ก๊ทธ์ธ ๋ฐ ํ์๊ฐ์
์ ์์ํฉ๋๋ค.</h1>
</div>
<div className="MainLogin">
<input type="text" id="memberEmail" name="memberEmail" placeholder="์์ด๋๋ฅผ ์
๋ ฅํด์ฃผ์ธ์" maxLength={"30"}
onChange={(e)=>{setMemberId(e.target.value);}}
/>
</div>
<div className="MainLogin">
<input type="password" id="memberPW" name="memberPW" placeholder="๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์"
onChange={(e)=>{setMemberPw(e.target.value);}}
/>
</div>
<div className="MainLogin">
<button id="Membersubmit" type="button" onClick={handleLogin}>๋ก๊ทธ์ธ</button>
</div>
<div className="LoginStartButton">
<div className="loginStart">
<button type="button" className="LoginKakao">
<Kakao/>
</button>
<NaverLogin className="naver"/>
</div>
<button type="button" className="LoginEmail">
<div className="LoginEmailStart">
<Link to="/Registeration" className="LoginEmailStart"> ํ์๊ฐ์
์์ํ๊ธฐ</Link>
</div>
</button>
</div>
</div>
</div>
)
}
export default Login;
์ฝ๋์ค๋ช
AXOIS๋ฅผ ํตํด SpringBoot์ Rest APIํต์ ์ ํ๊ธฐ ์ํ ๋ก๊ทธ์ธ ๋ถ๋ถ์
๋๋ค.
1. ๋ก๊ทธ์ธํ์ ๊ฒฝ์ฐ ๋ฐฑ์๋์์ AccessToken๊ณผ RefreshToken์ด ์์ฑ์ด ๋๊ณ ๊ทธ ์๊ฐ๋ถํฐ ์ ํจ๊ธฐ๊ฐ ์นด์ดํธ๊ฐ ์์๋ฉ๋๋ค.
2. ๋ฐ์์จ AccessToken๋ ํค๋์ RefreshToken๊ฐ์ LocalStorege๋ก ์ ์ฅ๋ฉ๋๋ค.
2. ์ ์ฅ๋ ํ ํฐ๊ฐ๋ค๋ก ์๋๋ก๊ทธ์ธ ์๋ ๋ก๊ทธ์์์ ๊ธฐ๋ฅ์ ํ ์ ์์ต๋๋ค.
- Axois : Node.js์ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ํ Promise๊ธฐ๋ฐ HTTP ํด๋ผ์ด์ธํธ์ ๋๋ค.