100일 챌린지/빅데이터기반 인공지능 융합 서비스 개발자

Day 79 - React로 CRUD 프로그램 만들기 (3) Nodejs API 서비스 이용

ksyke 2024. 11. 20. 17:48

API 프로젝트 만들기

app.js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require('cors');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
// app.set('views', path.join(__dirname, 'views'));
// app.set('view engine', 'jade');

var corsOptions = {
  origin: 'http://localhost:3000',
  optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}

app.use(cors(corsOptions));
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// app.use('/', indexRouter);
// app.use('/users', usersRouter);
app.use('/dept',require('./routes/dept'));

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

dept.js

const mysql = require('mysql2');
const express =require('express');
const router=express.Router();
const info={
    host: 'localhost',
    user: 'scott',
    password: 'tiger',
    database: 'xe'
  };

router.get('/',(req,res)=>{
    const connection = mysql.createConnection(info);
    connection.connect();
    connection.query('select * from dept', (err, rows, fields) => {
          if (err) throw err
          res.json({'result':rows});      
    });
    connection.end();
});

router.post('/',(req,res)=>{
    const {deptno,dname,loc}=(req.body);
    const connection = mysql.createConnection(info);
    connection.connect();
    connection.query('insert into dept values (?)',[[deptno,dname,loc]], (err, rows, fields) => {
          if (err) throw err
          res.status(201);
          res.end();
    });
    connection.end();
});

router.get('/:deptno',(req,res)=>{
    const {deptno}=(req.params);
    const connection = mysql.createConnection(info);
    connection.connect();
    connection.query(`select * from dept where deptno=${deptno}`, (err, rows, fields) => {
          if (err) throw err
          res.json({...rows[0]});   
    });
    connection.end();
});

module.exports=router;


FrontEnd 프로젝트 만들기

Frame.js

import React, { useState } from 'react'
import { Link, NavLink, Outlet } from 'react-router-dom'

function Frame() {

    const [menu,setMenu]=useState(false);

  return (
    <>
    {/* 메뉴 */}
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
            <Link class="navbar-brand" to="#">
                인제대학교
            </Link>
            </div>
            <ul class="nav navbar-nav">
                <li className={menu=='Home'?'active':''}><NavLink className={({ isActive }) =>
                        {if(isActive){setMenu('Home');}}
                    } to='/'>Home </NavLink></li>
                <li className={menu=='Intro'?'active':''}><NavLink className={({ isActive }) =>
                        {if(isActive){setMenu('Intro');}}
                    } to='/intro'>Intro</NavLink></li>
                <li className={menu=='Dept'?'active':''}><NavLink className={({ isActive }) =>
                        {if(isActive){setMenu('Dept');}}
                    } to='/dept/'>Dept</NavLink></li>
            </ul>
        </div>
    </nav>
    {/* 컨텐츠 */}
    <div className='container'>
        <div className='content'>
            <Outlet/>
        </div>
        <div className='footer'>
            <p>김해캠퍼스 (50834) 경남 김해시 인제로 197</p>
            <p>Copyright(c) 1996-2022 INJE University. All rights reserved.</p>
        </div>
    </div>
    </>
  )
}

export default Frame

Main.js

import React from 'react'

function Main() {
  return (
    <div className='jumbotron'>
        <h2>환영합니다.</h2>
    </div>
  )
}

export default Main

Intro.js

import React,{Image} from 'react'

function Intro() {
  return (
    <div>
        <img src='https://www.inje.ac.kr/kor/assets/images/sub/gimhae-campus-1-241008.jpg'/>
    </div>
  )
}

export default Intro

Depts.js

import React, { Suspense, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
// import Row from './components/Row';
const Row=React.lazy(()=>import('./components/Row'));

function Depts() {

    const [arr,setArr]=useState([]);

    useEffect(()=>{
        fetch('http://localhost:3030/dept/')
        .then(res=>res.json())
        .then(json=>{
            console.log(json.result);
            setArr([...json.result]);
        }).catch(e=>alert(e));
    },[]);

  return (
    <>
        <h2 className='page-header'>List page</h2>
        <div class="list-group">
            <div className="list-group-item active">
                <h4 class='list-group-item-heading'>DNAME</h4>
                <p>LOCATION</p>
            </div>
            <Suspense fallback={<h3>로딩중...</h3>}>
                {arr.map(ele=><Row dname={ele.dname} loc={ele.loc} deptno={ele.deptno}/>)}
            </Suspense>
        </div>
    </>
  )
}

export default Depts

Row.js

import React from 'react'
import { Link } from 'react-router-dom'

function Row({dname,loc,deptno}) {
  return (
    <Link to={"/dept/"+deptno} className="list-group-item">
        <h4 class="list-group-item-heading">{dname}</h4>
        <p class="list-group-item-text">{loc}</p>
    </Link>
  )
}

export default Row

DeptAdd.js

import React, { useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import FormInput from './components/FormInput';

function DeptAdd() {
  const [inputVals,setInputVals]=useState({deptno:'',dname:'',loc:''});
  const navigate=  useNavigate();
  const refInp1=useRef();
  const refInp2=useRef();
  const refInp3=useRef();
  const deptSend=e=>{
    e.preventDefault();
    fetch('http://localhost:3030/dept/',{
        method:'POST',
        body:JSON.stringify({deptno:refInp1.current.value,dname:refInp2.current.value,loc:refInp3.current.value}),
        headers:{
            'Content-Type':'application/json'
        }
    }).then(e=>{
        if(e.ok) 
            navigate('/dept/');
    }).catch(err=>{
        alert(err);
    });

  };
//   const editVal=e=>{
//     if(e.target.name=='deptno')
//         setInputVals({...inputVals,deptno:e.target.value});
//     if(e.target.name=='dname')
//         setInputVals({...inputVals,dname:e.target.value});
//     if(e.target.name=='loc')
//         setInputVals({...inputVals,loc:e.target.value});
//   };
  return (
    <>
        <h2 className='page-header'>입력 페이지</h2>
        <form onSubmit={deptSend}>
            {/* 
            <FormInput ref={refInp1} name='deptno' val={inputVals.deptno} editVal={editVal}/>
            <FormInput ref={refInp2} name='dname' val={inputVals.dname} editVal={editVal}/>
            <FormInput ref={refInp3} name={'loc'} val={inputVals.loc} editVal={editVal}/> 
            */}

            <FormInput ref={refInp1} name='deptno'/>
            <FormInput ref={refInp2} name='dname'/>
            <FormInput ref={refInp3} name={'loc'}/>
            <div className='form-group'>
                <button type='submit' className='btn btn-primary btn-block'>입력</button>
                <button type='reset' className='btn btn-default btn-block'>취소</button>
                <button type='button' className='btn btn-default btn-block' onClick={navigate(-1)}>뒤로</button>
            </div>
        </form>
    </>
  )
}

export default DeptAdd

FormInput.js

import React, { useState } from 'react'

function FormInput({ref,name}) {
    const [val,setVal]=useState('');
    return (
    <div className='form-group'>
        <input ref={ref} name={name} placeholder={name} value={val} onChange={e=>{setVal(e.target.value)}} className='form-control'/>
    </div>
  )
}

export default FormInput

Dept.js

import React, { useEffect } from 'react'
import { useParams } from 'react-router-dom'

function Dept() {
    const {deptno}=useParams();
    useEffect(()=>{
    });
  return (
    <>
    <h2>Dept detail <small>deptno:{deptno}</small></h2>

    </>
  )
}

export default Dept

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './css/bootstrap.min.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Frame from './pages/components/Frame';
import Main from './pages/Main';
import Intro from './pages/Intro';
import Depts from './pages/Depts';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  // https://react.dev/reference/react/StrictMode
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path='/' element={<Frame/>} >
          <Route index element={<Main/>} />
          <Route path='/intro' element={<Intro/>} />
          <Route path='/dept/' element={<Depts/>} />
        </Route>
      </Routes>
    </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();