Home

0

리엑트 블로그 만들기 8 - 로그인 & 로그아웃

리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃//LOGINexport const LOGIN_REQUEST = "LOGIN_REQUEST";export const LOGIN_SUCCESS = "LOGIN_SUCCESS";export const LOGIN_FAILURE = "LOGIN_FAILURE";//LOGINexport const LOGOUT_REQUEST = "LOGOUT_REQUEST";export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS";export const LOGOUT_FAILURE = "LOGOUT_FAILURE";// CLEAR ERRORexport const CLEAR_ERROR_REQUEST = "CLEAR_REQUEST";export const CLEAR_ERROR_SUCCESS = "CLEAR_SUCCESS";export const CLEAR_ERROR_FAILURE = "CLEAR_FAILURE"; import { LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE, CLEAR_ERROR_REQUEST, CLEAR_ERROR_SUCCESS, CLEAR_ERROR_FAILURE, LOGOUT_REQUEST, LOGOUT_SUCCESS, LOGOUT_FAILURE,} from "../types";const initialState = { token: localStorage.getItem("token"), isAuthenticated: null, isLoading: false, user: "", userId: "", userName: "", userRole: "", errorMsg: "", successMsg: "",};const authReducer = (state = initialState, action) => { switch (action.type) { case LOGOUT_REQUEST: case LOGIN_REQUEST: return { ...state, errorMsg: "", }; case LOGIN_SUCCESS: localStorage.setItem("token", action.payload.token); return { ...state, ...action.payload, isAuthenticated: true, isLoading: false, userId: action.payload.user.id, userRole: action.payload.user.role, errorMsg: "", }; case LOGOUT_FAILURE: case LOGIN_FAILURE: localStorage.removeItem("token"); return { ...state, ...action.payload, token: null, user: null, userId: null, userRole: null, errorMsg: action.payload.data.msg, }; case LOGOUT_SUCCESS: localStorage.removeItem("token"); return { ...state, ...action.payload, token: null, user: null, userId: null, isAuthenticated: false, isLoading: false, userRole: null, errorMsg: "", }; case CLEAR_ERROR_REQUEST: return { ...state, errorMsg: null, }; case CLEAR_ERROR_SUCCESS: return { ...state, errorMsg: null, }; case CLEAR_ERROR_FAILURE: return { ...state, errorMsg: null, }; default: return state; }};export default authReducer; import { all, put } from "@redux-saga/core/effects";import axios from "axios";import { call, fork, takeEvery } from "redux-saga/effects";import { LOGIN_FAILURE, LOGIN_REQUEST, LOGIN_SUCCESS, LOGOUT_REQUEST,} from "../types";const loginUserAPI = (loginData) => { console.log(loginData, "loginData"); const config = { headers: { "Content-Type": "application/json", }, }; return axios.post("api/auth", loginData, config);};function* loginUser(action) { try { const result = yield call(loginUserAPI, action.payload); console.log(result); yield put({ type: LOGIN_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: LOGIN_FAILURE, payload: e.response, }); }}function* logout(action) { try { const result = yield call(loginUserAPI, action.payload); console.log(result); yield put({ type: LOGIN_SUCCESS, }); } catch (e) { yield put({ type: LOGIN_FAILURE, }); console.log(e); }}function* watchLoginUser() { yield takeEvery(LOGIN_REQUEST, loginUser);}function* watchLogout() { yield takeEvery(LOGOUT_REQUEST, logout);}export default function* authSaga() { yield all([fork(watchLoginUser), fork(watchLogout)]);} import React, { useCallback, useEffect, useState } from "react";import { useDispatch, useSelector } from "react-redux";import { Link } from "react-router-dom";import { Collapse, Container, Nav, Navbar, NavbarToggler } from "reactstrap";import { LOGOUT_REQUEST } from "../redux/types";import LoginModal from "./auth/LoginModal";const AppNavbar = () => { const [isOpen, setIsOpen] = useState(false); const { isAuthenticated, user, userRole } = useSelector( (state) => state.auth ); console.log(userRole, "UserRole"); const dispatch = useDispatch(); const onLogout = useCallback(() => { dispatch({ type: LOGOUT_REQUEST, }); }, [dispatch]); useEffect(() => { setIsOpen(false); }, [user]); const handleToggle = () => { setIsOpen(!isOpen); }; return ( <div> <Navbar color="dark" dark expand="lg" className="sticky-top"> <Container> <Link to="/" className="text-white text-decoration-none"> Victor의 블로그 </Link> <NavbarToggler onClick={handleToggle} /> <Collapse isOpen={isOpen} navbar> <Nav className="ml-auto d-flex justify-content-around" navbar> {isAuthenticated ? ( <h1 className="text-white">authLink</h1> ) : ( <LoginModal /> )} </Nav> </Collapse> </Container> </Navbar> </div> );};export default AppNavbar;

0

리엑트 블로그 만들기 7 - Login Modal 만들기 2

리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 7 - Login Modal 만들기 2import React, { useEffect, useState } from "react";import { useDispatch, useSelector } from "react-redux";import { NavLink } from "react-router-dom";import { Alert, Button, Form, FormGroup, Input, Label, Modal, ModalBody, ModalHeader,} from "reactstrap";import { CLEAR_ERROR_REQUEST, LOGIN_REQUEST } from "../../redux/types";const LoginModal = () => { const [modal, setModal] = useState(false); const [localMsg, setLocalMsg] = useState(""); const [form, setValues] = useState({ email: "", password: "", }); const dispatch = useDispatch(); const { errorMsg } = useSelector((state) => state.auth); useEffect(() => { try { setLocalMsg(errorMsg); } catch (e) { console.log(e); } }, [errorMsg]); const handleToggle = () => { dispatch({ type: CLEAR_ERROR_REQUEST, }); setModal(!modal); }; const onChange = (e) => { setValues({ ...form, [e.target.name]: e.target.value, }); }; const onSubmit = (e) => { e.preventDefault(); const { email, password } = form; const user = { email, password }; console.log(user); dispatch({ type: LOGIN_REQUEST, data: user, }); }; return ( <div> <NavLink onClick={handleToggle} href="#"> Login </NavLink> <Modal isOpen={modal} toggle={handleToggle}> <ModalHeader toggle={handleToggle}>Login</ModalHeader> <ModalBody> {localMsg ? <Alert color="danger">{localMsg}</Alert> : null} <Form> <FormGroup> <Label for="email">Email</Label> <Input type="email" name="email" id="email" placeholder="Email" onChange={onChange} /> <Label for="passowrd">Passowrd</Label> <Input type="passowrd" name="passowrd" id="passowrd" placeholder="Passowrd" onChange={onChange} /> <Button color="dark" style={{ marginTop: "2rem" }} block /> </FormGroup> </Form> </ModalBody> </Modal> </div> );};export default LoginModal;

0

리엑트 블로그 만들기 6 - Login Modal 만들기 1

리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 6 - Login Modal 만들기 1import { all, put } from "@redux-saga/core/effects";import axios from "axios";import { takeEvery } from "redux-saga";import { call, fork } from "redux-saga/effects";import { LOGIN_FAILURE, LOGIN_REQUEST, LOGIN_SUCCESS } from "../types";const loginUserAPI = (loginData) => { console.log(loginData, "loginData"); const config = { headers: { "Content-Type": "application/json", }, }; return axios.post("api/auth", loginData, config);};function* loginUser(action) { try { const result = yield call(loginUserAPI, action.payload); console.log(result); yield put({ ytpe: LOGIN_SUCCESS, payload: result.data, }); } catch (e) { yield put({ type: LOGIN_FAILURE, payload: e.response, }); }}function* watchLoginUser() { yield takeEvery(LOGIN_REQUEST, loginUser);}export default function* authSaga(){ yield all([ fork(watchLoginUser) ])}

0

리엑트 블로그 만들기 5 - 리덕스 세팅하기

리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 5 - 리덕스 세팅하기//LOGINexport const LOGIN_REQUEST = "LOGIN_REQUEST";export const LOGIN_SUCCESS = "LOGIN_SUCCESS";export const LOGIN_FAILURE = "LOGIN_FAILURE";// CLEAR ERRORexport const CLEAR_ERROR_REQUEST = "CLEAR_REQUEST";export const CLEAR_ERROR_SUCCESS = "CLEAR_SUCCESS";export const CLEAR_ERROR_FAILURE = "CLEAR_FAILURE"; import { LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE, CLEAR_ERROR_REQUEST, CLEAR_ERROR_SUCCESS, CLEAR_ERROR_FAILURE,} from "../types";const initialState = { token: localStorage.getItem("token"), isAuthenticated: null, isLoading: false, user: "", userId: "", userName: "", userRole: "", errorMsg: "", successMsg: "",};const authReducer = (state = initialState, action) => { switch (action.type) { case LOGIN_REQUEST: return { ...state, errorMsg: "", }; case LOGIN_SUCCESS: localStorage.setItem("token", action.payload.token); return { ...state, ...action.payload, isAuthenticated: true, isLoading: false, userId: action.payload.user.id, userRole: action.payload.user.role, errorMsg: "", }; case LOGIN_FAILURE: localStorage.removeItem("token"); return { ...state, ...action.payload, token: null, user: null, userId: null, userRole: null, errorMsg: action.payload.data.msg, }; case CLEAR_ERROR_REQUEST: return { ...state, errorMsg: null, }; case CLEAR_ERROR_SUCCESS: return { ...state, errorMsg: null, }; case CLEAR_ERROR_FAILURE: return { ...state, errorMsg: null, }; default: return state; }};export default authReducer;

0

리엑트 블로그 만들기 4 - Navbar 작성하기

리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 4 - Navbar 작성하기import React from "react";import { Link } from "react-router-dom";import { Collapse, Container, Nav, Navbar, NavbarToggler } from "reactstrap";const AppNavbar = () => { return ( <div> <Navbar color="dark" dark expand="lg" className="sticky-top"> <Container> <Link to="/" className="text-white text-decoration-none"> Victor의 블로그 </Link> <NavbarToggler /> <Collapse isOpen={true} navbar> <Nav className="ml-auto d-flex justify-content-around" navbar> {true ? ( <h1 className="text-white">authLink</h1> ) : ( <h1 className="text-white">gestLink</h1> )} </Nav> </Collapse> </Container> </Navbar> </div> );};export default AppNavbar; import React, { Fragment } from "react";import Header from "../components/Header";import Footer from "../components/Footer";import AppNavbar from "../components/AppNavbar";const MyRouter = () => ( <Fragment> <AppNavbar /> <Header> <h1>Hello Body</h1> </Header> <Footer></Footer> </Fragment>);export default MyRouter;

0

리엑트 블로그 만들기 3 - Header 작성하기

리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 3 - Header 작성하기import React from "react";import { Row, Col } from "reactstrap";const Header = () => { return ( <div id="page-header"> <Row> <Col md="6" sm="auto" className="text-center m-auto"> <h1>Read Our Blog</h1> <p>Victor의 사이드 블로그 입니다.</p> </Col> </Row> </div> );};export default Header; #main-footer{ background: #343a40; color:#fff;}#page-header{ height:200px; background: url(./img/free-image.jpeg); background-position: 54% 94%; background-attachment: fixed; color: #fff; border-bottom: 1px #eee solid; padding-top: 60px;}

0

리엑트 블로그 만들기 2 - Footer 작성하기

리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 2 - Footer 작성하기import React from "react";import { Row, Col } from "reactstrap";const Footer = () => { const thisYear = () => { const year = new Date().getFullYear(); return year; }; return ( <div id="main-footer" className="text-center m-center p-2"> <Row> <Col> <p> Copyright Copy <span>{thisYear()}</span> </p> </Col> </Row> </div> );};export default Footer; 패키지 설치 npm install node-sass sass-loaderyarn add node-sass sass-loader #main-footer{ background: #343a40; color:#fff;} import React from "react"import { Provider } from 'react-redux'import { ConnectedRouter } from 'connected-react-router'import store, { history } from "./store"import MyRouter from './routes/Router'import "bootstrap/dist/css/bootstrap.min.css";import "./assets/custom.scss"const App = () => { return ( <Provider store={store}> <ConnectedRouter history={history}> <MyRouter /> </ConnectedRouter> </Provider> );}export default App;

0

리엑트 블로그 만들기 1 - 초기 setting 하기

리엑트 블로그 만들기 1 - 초기 setting 하기 리엑트 블로그 만들기 2 - Footer 작성하기 리엑트 블로그 만들기 3 - Header 작성하기 리엑트 블로그 만들기 4 - Navbar 작성하기 리엑트 블로그 만들기 5 - 리덕스 세팅하기 리엑트 블로그 만들기 6 - Login Modal 만들기 1 리엑트 블로그 만들기 7 - Login Modal 만들기 2 리엑트 블로그 만들기 8 - 로그인 & 로그아웃 리엑트 블로그 만들기 9 - 회원가입 리엑트 블로그 만들기 10 - 회원가입 2 리엑트 블로그 만들기 11 - 회원가입 리덕스 작업 리엑트 블로그 만들기 12 - Loading 만들기 리엑트 블로그 만들기 13 - 라우트 리엑트 블로그 만들기 14 - Post Card List 만들기 리엑트 블로그 만들기 15 - Post Card List 만들기 2 리엑트 블로그 만들기 1 - 초기 setting 하기yarn add axios redux react-redux redux-saga react-router-dom connected-react-router dotenv bootstrap reactstrap Root Reducer 생성/src/redux/reducers/index.js import { connectRouter } from 'connected-react-router';import { combineReducers } from "redux";// Root Reducer를 생성한다.const createRootReducer = (history) => combineReducers({ router: connectRouter(history),});export default createRootReducer; Root Saga 생성/src/redux/sagas/index.js import { all } from 'redux-saga/effects';// Root Saga를 생성한다.export default function* rootSaga() { yield all([]);}

0

프로그래머스 - 카드 짝 맞추기 (Cpp)

https://programmers.co.kr/learn/courses/30/lessons/72415 문제 풀이좌표를 이동할 때 고려해야 하는 상황이 2가지가 있다 첫 번째 상, 하, 좌, 우 한칸씩 이동하는 경우와 한번에 카드가 있는 곳이나 벽쪽으로 바로 이동하는 경우다.카드를 찾는 경우의 수를 만드는데 있어 고려해야 하는 사항이 2가지가 있다. 첫번째는 서로 다른 카드를 찾아가는 경우의 수와 같은 숫자를 찾는 순서를 정하는 경우의 수다.예를 들어 1 -> 2 -> 3 의 순서로 카드를 찾아간다고 하면 (1 -> 1 짝 찾는 순서) -> (2 -> 2 짝 찾는 순서) -> (3 -> 3 짝 찾는 순서) 를 고려해야 한다는 의미다. 경우의 수가 만들어지면 각 순서에 맞게 BFS를 이용해 최단거리를 구해주면 된다. 다만, 카드는 짝을 만다면 사라지므로 최단 거리를 찾을 때 board 에서 카드가 사라졌는지에 대한 여부도 고려하면서 이동해줘야 한다. 고려 사항 enter를 누르는 것도 count 1을 갖는다. 카드 뒤집는 모든 경우의 수를 계산해야 한다. 1, 2, 3 서로 다른 카드를 찾아가는 경우의 수를 찾는다. 각각의 순서를 고려 하므로 순열의 경우의 수를 갖는다. 1 -> 1, 2 -> 2, 3 -> 3 각각 짝을 만드는 방향이 단방향으로 정해진 것이 아니기 때문에 반대 방향에 대해서도 고려애 줘야 한다. 즉, 최대 경우의 수는 6! * 2 ^ 6 이된다. 이동할 때 카드가 사라졌는지 확인해야 한다. board 에서 각 카드의 위치 찾기int findCards(vector<vector<int>>& board) { int count = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int value = board[i][j]; if (value > 0) { cards[value].push_back({i, j}); count++; } } } return (count / 2);} 카드를 뒤집는 모든 경우의 수 찾기

0

Spring Data JPA - Auditing

목차 Spring Data JPA - 벌크성 수정 쿼리 Spring Data JPA - Convertor Spring Data JPA - Auditing Spring Data JPA - Paging Request Paramater Spring Data JPA - 페이징과 정렬 Post not found: spring/spring-data-jpa/07-spring-data-jpa Spring Data JPA - 반환 타입 Spring Data JPA - Query 파라미터 바인딩 Spring Data JPA - Query 를 이용한 조회 결과를 특정 값으로 반환하기 Spring Data JPA - JPQL (Java Persistence Query Lange) 사용하기 Spring Data JPA - 메소드 이름으로 쿼리 생성하기 Spring Data JPA - 시작하기 참고https://docs.spring.io/spring-data/jpa/docs/1.7.0.DATAJPA-580-SNAPSHOT/reference/html/auditing.html Spring Data JPA - Auditing(감사) 데이터가 언제 누구에 의해서 생성, 수정 됐는지 추적할 필요가 있는데Spring Data JPA 에서는 쉽게 Audit 를 할 수 있는 기능들을 제공한다. Spring Data JPA Auditing 사용하기EnableJpaAuditing 어노테이션을 이용해 프로젝트에 Auditing 기능을 사용할 수 있도록 설정한다. @SpringBootApplication@EnableJpaAuditingpublic class DataJpaApplication { public static void main(String[] args) { SpringApplication.run(DataJpaApplication.class, args); } // 데이터가 생성 및 수정될 때 생성한 사람과 수정한 사람 정보를 넣기 위한 Bean 을 만들어준다. @Bean public AuditorAware<String> auditorProvider(){ return () -> Optional.of(UUID.randomUUID().toString()); }}